Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the extracted merkle library #2636

Merged
merged 4 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/log_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import (
"time"

"github.com/google/trillian"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/testonly/integration"
"github.com/google/trillian/types"
"github.com/transparency-dev/merkle/rfc6962"
"google.golang.org/protobuf/proto"

"github.com/google/trillian/storage/testdb"
Expand Down
13 changes: 6 additions & 7 deletions client/log_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,25 @@ import (
"fmt"

"github.com/google/trillian"
"github.com/google/trillian/merkle/hashers"
"github.com/google/trillian/merkle/logverifier"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/types"
"github.com/transparency-dev/merkle"
"github.com/transparency-dev/merkle/rfc6962"
)

// LogVerifier allows verification of output from Trillian Logs, both regular
// and pre-ordered; it is safe for concurrent use (as its contents are fixed
// after construction).
type LogVerifier struct {
// hasher is the hash strategy used to compute nodes in the Merkle tree.
hasher hashers.LogHasher
v logverifier.LogVerifier
hasher merkle.LogHasher
v merkle.LogVerifier
}

// NewLogVerifier returns an object that can verify output from Trillian Logs.
func NewLogVerifier(hasher hashers.LogHasher) *LogVerifier {
func NewLogVerifier(hasher merkle.LogHasher) *LogVerifier {
return &LogVerifier{
hasher: hasher,
v: logverifier.New(hasher),
v: merkle.NewLogVerifier(hasher),
}
}

Expand Down
2 changes: 1 addition & 1 deletion client/log_verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
"testing"

"github.com/google/trillian"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/types"
"github.com/transparency-dev/merkle/rfc6962"
)

func TestVerifyRootErrors(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/client_model v0.2.0
github.com/pseudomuto/protoc-gen-doc v1.5.0
github.com/transparency-dev/merkle v0.0.0-20211104134637-a76aeeada497
go.etcd.io/etcd/client/v3 v3.5.1
go.etcd.io/etcd/etcdctl/v3 v3.5.1
go.etcd.io/etcd/server/v3 v3.5.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
github.com/transparency-dev/merkle v0.0.0-20211104134637-a76aeeada497 h1:Kxv0z2YAoKxSpObcgBCyxwaPS06OExH16EB+anCe4Tg=
github.com/transparency-dev/merkle v0.0.0-20211104134637-a76aeeada497/go.mod h1:B8FIw5LTq6DaULoHsVFRzYIUDkl8yuSwCdZnOZGKL/A=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
Expand Down
10 changes: 5 additions & 5 deletions integration/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import (
"github.com/google/trillian"
"github.com/google/trillian/client/backoff"
"github.com/google/trillian/internal/merkle/inmemory"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/logverifier"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/types"
"github.com/transparency-dev/merkle"
"github.com/transparency-dev/merkle/compact"
"github.com/transparency-dev/merkle/rfc6962"
)

// TestParameters bundles up all the settings for a test run
Expand Down Expand Up @@ -466,7 +466,7 @@ func checkInclusionProofsAtIndex(index int64, logID int64, tree *inmemory.Merkle

// Verify inclusion proof.
root := tree.RootAtSnapshot(treeSize).Hash()
verifier := logverifier.New(rfc6962.DefaultHasher)
verifier := merkle.NewLogVerifier(rfc6962.DefaultHasher)
// Offset by 1 to make up for C++ / Go implementation differences.
merkleLeafHash := tree.LeafHash(index + 1)
if err := verifier.VerifyInclusionProof(index, treeSize, resp.Proof.Hashes, root, merkleLeafHash); err != nil {
Expand Down Expand Up @@ -503,7 +503,7 @@ func checkConsistencyProof(consistParams consistencyProofParams, treeID int64, t
return fmt.Errorf("requested tree size %d > available tree size %d", req.SecondTreeSize, root.TreeSize)
}

verifier := logverifier.New(rfc6962.DefaultHasher)
verifier := merkle.NewLogVerifier(rfc6962.DefaultHasher)
root1 := tree.RootAtSnapshot(req.FirstTreeSize).Hash()
root2 := tree.RootAtSnapshot(req.SecondTreeSize).Hash()
return verifier.VerifyConsistencyProof(req.FirstTreeSize, req.SecondTreeSize,
Expand Down
4 changes: 2 additions & 2 deletions log/sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ import (

"github.com/golang/glog"
"github.com/google/trillian"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/monitoring"
"github.com/google/trillian/quota"
"github.com/google/trillian/storage"
"github.com/google/trillian/storage/tree"
"github.com/google/trillian/types"
"github.com/google/trillian/util/clock"
"github.com/transparency-dev/merkle/compact"
"github.com/transparency-dev/merkle/rfc6962"
"google.golang.org/protobuf/types/known/timestamppb"
)

Expand Down
4 changes: 2 additions & 2 deletions log/sequencer_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/trillian"
"github.com/google/trillian/extension"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/quota"
"github.com/google/trillian/storage"
stestonly "github.com/google/trillian/storage/testonly"
"github.com/google/trillian/storage/tree"
"github.com/google/trillian/testonly"
"github.com/google/trillian/types"
"github.com/google/trillian/util/clock"
"github.com/transparency-dev/merkle/compact"
"github.com/transparency-dev/merkle/rfc6962"
"google.golang.org/protobuf/proto"
)

Expand Down
4 changes: 2 additions & 2 deletions log/sequencer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import (

"github.com/golang/mock/gomock"
"github.com/google/trillian"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/quota"
"github.com/google/trillian/storage"
"github.com/google/trillian/testonly"
"github.com/google/trillian/types"
"github.com/google/trillian/util/clock"
"github.com/transparency-dev/merkle/compact"
"github.com/transparency-dev/merkle/rfc6962"

stestonly "github.com/google/trillian/storage/testonly"
"github.com/google/trillian/storage/tree"
Expand Down
13 changes: 6 additions & 7 deletions server/log_rpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@ import (
"github.com/golang/glog"
"github.com/google/trillian"
"github.com/google/trillian/extension"
"github.com/google/trillian/merkle"
"github.com/google/trillian/merkle/hashers"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/monitoring"
"github.com/google/trillian/storage"
"github.com/google/trillian/trees"
"github.com/google/trillian/types"
"github.com/google/trillian/util/clock"
"github.com/transparency-dev/merkle"
"github.com/transparency-dev/merkle/rfc6962"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand Down Expand Up @@ -120,7 +119,7 @@ func (t *TrillianLogRPCServer) QueueLeaf(ctx context.Context, req *trillian.Queu
return &trillian.QueueLeafResponse{QueuedLeaf: ret[0]}, nil
}

func hashLeaves(leaves []*trillian.LogLeaf, hasher hashers.LogHasher) {
func hashLeaves(leaves []*trillian.LogLeaf, hasher merkle.LogHasher) {
for _, leaf := range leaves {
leaf.MerkleLeafHash = hasher.HashLeaf(leaf.LeafValue)
if len(leaf.LeafIdentityHash) == 0 {
Expand Down Expand Up @@ -398,7 +397,7 @@ func (t *TrillianLogRPCServer) GetLatestSignedLogRoot(ctx context.Context, req *
return r, nil
}

func tryGetConsistencyProof(ctx context.Context, firstTreeSize, secondTreeSize int64, tx storage.ReadOnlyLogTreeTX, hasher hashers.LogHasher) (*trillian.Proof, error) {
func tryGetConsistencyProof(ctx context.Context, firstTreeSize, secondTreeSize int64, tx storage.ReadOnlyLogTreeTX, hasher merkle.LogHasher) (*trillian.Proof, error) {
nodeFetches, err := merkle.CalcConsistencyProofNodeAddresses(firstTreeSize, secondTreeSize)
if err != nil {
return nil, err
Expand Down Expand Up @@ -545,7 +544,7 @@ func (t *TrillianLogRPCServer) closeAndLog(ctx context.Context, logID int64, tx
// getInclusionProofForLeafIndex is used by multiple handlers. It does the storage fetching
// and makes additional checks on the returned proof. Returns a Proof suitable for inclusion in
// an RPC response
func getInclusionProofForLeafIndex(ctx context.Context, tx storage.ReadOnlyLogTreeTX, hasher hashers.LogHasher, size, leafIndex int64) (*trillian.Proof, error) {
func getInclusionProofForLeafIndex(ctx context.Context, tx storage.ReadOnlyLogTreeTX, hasher merkle.LogHasher, size, leafIndex int64) (*trillian.Proof, error) {
// We have the tree size and leaf index so we know the nodes that we need to serve the proof
proofNodeIDs, err := merkle.CalcInclusionProofNodeAddresses(size, leafIndex)
if err != nil {
Expand All @@ -554,7 +553,7 @@ func getInclusionProofForLeafIndex(ctx context.Context, tx storage.ReadOnlyLogTr
return fetchNodesAndBuildProof(ctx, tx, hasher, leafIndex, proofNodeIDs)
}

func (t *TrillianLogRPCServer) getTreeAndHasher(ctx context.Context, treeID int64, opts trees.GetOpts) (*trillian.Tree, hashers.LogHasher, error) {
func (t *TrillianLogRPCServer) getTreeAndHasher(ctx context.Context, treeID int64, opts trees.GetOpts) (*trillian.Tree, merkle.LogHasher, error) {
tree, err := trees.GetTree(ctx, t.registry.AdminStorage, treeID, opts)
if err != nil {
return nil, nil, err
Expand Down
4 changes: 2 additions & 2 deletions server/log_rpc_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/trillian"
"github.com/google/trillian/extension"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/storage"
stestonly "github.com/google/trillian/storage/testonly"
"github.com/google/trillian/storage/tree"
"github.com/google/trillian/types"
"github.com/google/trillian/util/clock"
"github.com/transparency-dev/merkle/compact"
"github.com/transparency-dev/merkle/rfc6962"
"google.golang.org/genproto/googleapis/rpc/code"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down
7 changes: 3 additions & 4 deletions server/proof_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ import (
"fmt"

"github.com/google/trillian"
"github.com/google/trillian/merkle"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/hashers"
"github.com/google/trillian/storage/tree"
"github.com/transparency-dev/merkle"
"github.com/transparency-dev/merkle/compact"
)

// nodeReader provides read-only access to the tree nodes.
Expand All @@ -36,7 +35,7 @@ type nodeReader interface {
// This includes rehashing where necessary to serve proofs for tree sizes between stored tree
// revisions. This code only relies on the nodeReader interface so can be tested without
// a complete storage implementation.
func fetchNodesAndBuildProof(ctx context.Context, nr nodeReader, th hashers.LogHasher, leafIndex int64, proofNodeFetches []merkle.NodeFetch) (*trillian.Proof, error) {
func fetchNodesAndBuildProof(ctx context.Context, nr nodeReader, th merkle.LogHasher, leafIndex int64, proofNodeFetches []merkle.NodeFetch) (*trillian.Proof, error) {
ctx, spanEnd := spanFor(ctx, "fetchNodesAndBuildProof")
defer spanEnd()
proofNodes, err := fetchNodes(ctx, nr, proofNodeFetches)
Expand Down
4 changes: 2 additions & 2 deletions server/proof_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import (
"testing"

"github.com/google/trillian/internal/merkle/inmemory"
"github.com/google/trillian/merkle"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/storage/testonly"
"github.com/transparency-dev/merkle"
"github.com/transparency-dev/merkle/rfc6962"
)

// An arbitrary tree revision to be used in tests.
Expand Down
6 changes: 3 additions & 3 deletions server/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"fmt"

"github.com/google/trillian"
"github.com/google/trillian/merkle/hashers"
"github.com/transparency-dev/merkle"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand All @@ -36,7 +36,7 @@ func validateGetInclusionProofRequest(req *trillian.GetInclusionProofRequest) er
return nil
}

func validateGetInclusionProofByHashRequest(req *trillian.GetInclusionProofByHashRequest, hasher hashers.LogHasher) error {
func validateGetInclusionProofByHashRequest(req *trillian.GetInclusionProofByHashRequest, hasher merkle.LogHasher) error {
if req.TreeSize <= 0 {
return status.Errorf(codes.InvalidArgument, "GetInclusionProofByHashRequest.TreeSize: %v, want > 0", req.TreeSize)
}
Expand Down Expand Up @@ -124,7 +124,7 @@ func validateLogLeaf(leaf *trillian.LogLeaf, errPrefix string) error {
return nil
}

func validateLeafHash(hash []byte, hasher hashers.LogHasher) error {
func validateLeafHash(hash []byte, hasher merkle.LogHasher) error {
if got, want := len(hash), hasher.Size(); got != want {
return fmt.Errorf("%d bytes, want %d", got, want)
}
Expand Down
2 changes: 1 addition & 1 deletion storage/cache/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ package cache
import (
"encoding/binary"

"github.com/google/trillian/merkle/compact"
"github.com/transparency-dev/merkle/compact"
)

// getTileID returns the path from the "virtual" root at level 64 to the root
Expand Down
2 changes: 1 addition & 1 deletion storage/cache/layout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"fmt"
"testing"

"github.com/google/trillian/merkle/compact"
"github.com/transparency-dev/merkle/compact"
)

func TestGetTileID(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions storage/cache/log_tile.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import (
"encoding/binary"
"fmt"

"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/hashers"
"github.com/google/trillian/storage/storagepb"
"github.com/transparency-dev/merkle"
"github.com/transparency-dev/merkle/compact"
)

const (
Expand All @@ -38,7 +38,7 @@ const (
// below for prepareLogTile.
//
// TODO(pavelkalinnikov): Unexport it after the refactoring.
func PopulateLogTile(st *storagepb.SubtreeProto, hasher hashers.LogHasher) error {
func PopulateLogTile(st *storagepb.SubtreeProto, hasher merkle.LogHasher) error {
if st.Depth < 1 {
return fmt.Errorf("populate log subtree with invalid depth: %d", st.Depth)
}
Expand Down
8 changes: 4 additions & 4 deletions storage/cache/subtree_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import (
"fmt"
"sync"

"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/hashers"
"github.com/google/trillian/storage/storagepb"
"github.com/google/trillian/storage/tree"
"github.com/transparency-dev/merkle"
"github.com/transparency-dev/merkle/compact"
"google.golang.org/protobuf/proto"
)

Expand All @@ -43,7 +43,7 @@ type GetSubtreesFunc func(ids [][]byte) ([]*storagepb.SubtreeProto, error)
// SubtreeCache is not thread-safe: GetNodes, SetNodes and Flush methods must
// be called sequentially.
type SubtreeCache struct {
hasher hashers.LogHasher
hasher merkle.LogHasher

// subtrees contains the Subtree data read from storage, and is updated by
// calls to SetNodes.
Expand All @@ -58,7 +58,7 @@ type SubtreeCache struct {

// NewLogSubtreeCache creates and returns a SubtreeCache appropriate for use with a log
// tree. The caller must supply a suitable LogHasher.
func NewLogSubtreeCache(hasher hashers.LogHasher) *SubtreeCache {
func NewLogSubtreeCache(hasher merkle.LogHasher) *SubtreeCache {
if *populateConcurrency <= 0 {
panic(fmt.Errorf("populate_subtree_concurrency must be set to >= 1"))
}
Expand Down
4 changes: 2 additions & 2 deletions storage/cache/subtree_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/storage/storagepb"
"github.com/google/trillian/storage/tree"
"github.com/transparency-dev/merkle/compact"
"github.com/transparency-dev/merkle/rfc6962"

"github.com/golang/mock/gomock"
)
Expand Down
2 changes: 1 addition & 1 deletion storage/cloudspanner/log_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ import (
"cloud.google.com/go/spanner"
"github.com/golang/glog"
"github.com/google/trillian"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/storage"
"github.com/google/trillian/storage/cache"
"github.com/google/trillian/storage/cloudspanner/spannerpb"
"github.com/google/trillian/types"
"github.com/transparency-dev/merkle/rfc6962"
"go.opencensus.io/trace"
"golang.org/x/sync/semaphore"
"google.golang.org/grpc/codes"
Expand Down
2 changes: 1 addition & 1 deletion storage/cloudspanner/tree_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ import (
"cloud.google.com/go/spanner"
"github.com/golang/glog"
"github.com/google/trillian"
"github.com/google/trillian/merkle/compact"
"github.com/google/trillian/storage"
"github.com/google/trillian/storage/cache"
"github.com/google/trillian/storage/cloudspanner/spannerpb"
"github.com/google/trillian/storage/storagepb"
"github.com/google/trillian/storage/tree"
"github.com/transparency-dev/merkle/compact"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down
Loading