diff --git a/client/client.go b/client/client.go index f4c83efe28..cb65dabc2e 100644 --- a/client/client.go +++ b/client/client.go @@ -27,6 +27,7 @@ import ( "github.com/google/trillian" "github.com/google/trillian/client/backoff" "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -40,7 +41,7 @@ type LogClient struct { } // New returns a new LogClient. -func New(logID int64, client trillian.TrillianLogClient, hasher merkle.LogHasher, pubKey crypto.PublicKey) *LogClient { +func New(logID int64, client trillian.TrillianLogClient, hasher hashers.LogHasher, pubKey crypto.PublicKey) *LogClient { return &LogClient{ LogID: logID, client: client, diff --git a/client/verifier.go b/client/verifier.go index becf5099aa..0d2484c674 100644 --- a/client/verifier.go +++ b/client/verifier.go @@ -21,17 +21,18 @@ import ( "github.com/google/trillian" tcrypto "github.com/google/trillian/crypto" "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" ) // logVerifier contains state needed to verify output from Trillian Logs. type logVerifier struct { - hasher merkle.LogHasher + hasher hashers.LogHasher pubKey crypto.PublicKey v merkle.LogVerifier } // NewLogVerifier returns an object that can verify output from Trillian Logs. -func NewLogVerifier(hasher merkle.LogHasher, pubKey crypto.PublicKey) LogVerifier { +func NewLogVerifier(hasher hashers.LogHasher, pubKey crypto.PublicKey) LogVerifier { return &logVerifier{ hasher: hasher, pubKey: pubKey, diff --git a/log/sequencer.go b/log/sequencer.go index 0047a69370..8ee58b20c4 100644 --- a/log/sequencer.go +++ b/log/sequencer.go @@ -28,6 +28,7 @@ import ( "github.com/google/trillian/crypto" "github.com/google/trillian/crypto/sigpb" "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/monitoring" "github.com/google/trillian/quota" "github.com/google/trillian/storage" @@ -78,7 +79,7 @@ func createMetrics(mf monitoring.MetricFactory) { // There is no strong ordering guarantee but in general entries will be processed // in order of submission to the log. type Sequencer struct { - hasher merkle.LogHasher + hasher hashers.LogHasher timeSource util.TimeSource logStorage storage.LogStorage signer *crypto.Signer @@ -93,7 +94,7 @@ const maxTreeDepth = 64 // NewSequencer creates a new Sequencer instance for the specified inputs. func NewSequencer( - hasher merkle.LogHasher, + hasher hashers.LogHasher, timeSource util.TimeSource, logStorage storage.LogStorage, signer *crypto.Signer, diff --git a/merkle/compact_merkle_tree.go b/merkle/compact_merkle_tree.go index 4ecded918e..9360cc280f 100644 --- a/merkle/compact_merkle_tree.go +++ b/merkle/compact_merkle_tree.go @@ -21,6 +21,7 @@ import ( "fmt" log "github.com/golang/glog" + "github.com/google/trillian/merkle/hashers" ) // RootHashMismatchError indicates a unexpected root hash value. @@ -36,7 +37,7 @@ func (r RootHashMismatchError) Error() string { // CompactMerkleTree is a compact Merkle tree representation. // Uses log(n) nodes to represent the current on-disk tree. type CompactMerkleTree struct { - hasher LogHasher + hasher hashers.LogHasher root []byte // the list of "dangling" left-hand nodes, NOTE: index 0 is the leaf, not the root. nodes [][]byte @@ -66,7 +67,7 @@ type GetNodeFunc func(depth int, index int64) ([]byte, error) // |f| will be called a number of times with the co-ordinates of internal MerkleTree nodes whose hash values are // required to initialize the internal state of the CompactMerkleTree. |expectedRoot| is the known-good tree root // of the tree at |size|, and is used to verify the correct initial state of the CompactMerkleTree after initialisation. -func NewCompactMerkleTreeWithState(hasher LogHasher, size int64, f GetNodeFunc, expectedRoot []byte) (*CompactMerkleTree, error) { +func NewCompactMerkleTreeWithState(hasher hashers.LogHasher, size int64, f GetNodeFunc, expectedRoot []byte) (*CompactMerkleTree, error) { sizeBits := bitLen(size) r := CompactMerkleTree{ @@ -108,7 +109,7 @@ func NewCompactMerkleTreeWithState(hasher LogHasher, size int64, f GetNodeFunc, } // NewCompactMerkleTree creates a new CompactMerkleTree with size zero. This always succeeds. -func NewCompactMerkleTree(hasher LogHasher) *CompactMerkleTree { +func NewCompactMerkleTree(hasher hashers.LogHasher) *CompactMerkleTree { r := CompactMerkleTree{ hasher: hasher, root: hasher.EmptyRoot(), diff --git a/merkle/tree_hasher.go b/merkle/hashers/tree_hasher.go similarity index 56% rename from merkle/tree_hasher.go rename to merkle/hashers/tree_hasher.go index a728354b72..69a24c0cf5 100644 --- a/merkle/tree_hasher.go +++ b/merkle/hashers/tree_hasher.go @@ -12,7 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package merkle +package hashers + +import ( + "fmt" + + "github.com/google/trillian" +) // LogHasher provides the hash functions needed to compute dense merkele trees. type LogHasher interface { @@ -42,3 +48,48 @@ type MapHasher interface { // TODO(gbelvin): Replace Size() with BitLength(). Size() int } + +var ( + logHashers = make(map[trillian.HashStrategy]LogHasher) + mapHashers = make(map[trillian.HashStrategy]MapHasher) +) + +// RegisterLogHasher registers a hasher for use. +func RegisterLogHasher(h trillian.HashStrategy, f LogHasher) { + if h == trillian.HashStrategy_UNKNOWN_HASH_STRATEGY { + panic(fmt.Sprintf("RegisterLogHasher(%s) of unknown hasher", h)) + } + if logHashers[h] != nil { + panic(fmt.Sprintf("%v already registered as a LogHasher", h)) + } + logHashers[h] = f +} + +// RegisterMapHasher registers a hasher for use. +func RegisterMapHasher(h trillian.HashStrategy, f MapHasher) { + if h == trillian.HashStrategy_UNKNOWN_HASH_STRATEGY { + panic(fmt.Sprintf("RegisterMapHasher(%s) of unknown hasher", h)) + } + if mapHashers[h] != nil { + panic(fmt.Sprintf("%v already registered as a MapHasher", h)) + } + mapHashers[h] = f +} + +// NewLogHasher returns a LogHasher. +func NewLogHasher(h trillian.HashStrategy) (LogHasher, error) { + f := logHashers[h] + if f != nil { + return f, nil + } + return nil, fmt.Errorf("LogHasher(%s) is an unknown hasher", h) +} + +// NewMapHasher returns a MapHasher. +func NewMapHasher(h trillian.HashStrategy) (MapHasher, error) { + f := mapHashers[h] + if f != nil { + return f, nil + } + return nil, fmt.Errorf("MapHasher(%s) is an unknown hasher", h) +} diff --git a/merkle/hstar2.go b/merkle/hstar2.go index 43ae636d95..4a444b5bfb 100644 --- a/merkle/hstar2.go +++ b/merkle/hstar2.go @@ -19,6 +19,8 @@ import ( "fmt" "math/big" "sort" + + "github.com/google/trillian/merkle/hashers" ) var ( @@ -37,11 +39,11 @@ type HStar2LeafHash struct { // HStar2 is a recursive implementation for calculating the root hash of a sparse // Merkle tree. type HStar2 struct { - hasher MapHasher + hasher hashers.MapHasher } // NewHStar2 creates a new HStar2 tree calculator based on the passed in MapHasher. -func NewHStar2(hasher MapHasher) HStar2 { +func NewHStar2(hasher hashers.MapHasher) HStar2 { return HStar2{ hasher: hasher, } diff --git a/merkle/hstar2_test.go b/merkle/hstar2_test.go index a4ad4f06c0..0e3d4c879b 100644 --- a/merkle/hstar2_test.go +++ b/merkle/hstar2_test.go @@ -21,6 +21,7 @@ import ( "math/big" "testing" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/merkle/maphasher" "github.com/google/trillian/testonly" ) @@ -34,7 +35,7 @@ var sparseEmptyRootHashB64 = testonly.MustDecodeBase64("xmifEIEqCYCXbZUz2Dh1KCFm // passing into a the HStar2 sparse Merkle tree implementation. // The map keys will be SHA256 hashed before being added to the returned // structs. -func createHStar2Leaves(hasher MapHasher, values map[string]string) []HStar2LeafHash { +func createHStar2Leaves(hasher hashers.MapHasher, values map[string]string) []HStar2LeafHash { r := []HStar2LeafHash{} for k := range values { khash := sha256.Sum256([]byte(k)) diff --git a/merkle/log_verifier.go b/merkle/log_verifier.go index bd0c0670db..c7828463aa 100644 --- a/merkle/log_verifier.go +++ b/merkle/log_verifier.go @@ -18,6 +18,8 @@ import ( "bytes" "errors" "fmt" + + "github.com/google/trillian/merkle/hashers" ) // RootMismatchError occurs when an inclusion proof fails. @@ -32,11 +34,11 @@ func (e RootMismatchError) Error() string { // LogVerifier verifies inclusion and consistency proofs for append only logs. type LogVerifier struct { - hasher LogHasher + hasher hashers.LogHasher } // NewLogVerifier returns a new LogVerifier for a tree. -func NewLogVerifier(hasher LogHasher) LogVerifier { +func NewLogVerifier(hasher hashers.LogHasher) LogVerifier { return LogVerifier{ hasher: hasher, } diff --git a/merkle/map_verifier.go b/merkle/map_verifier.go index 788fe57c8b..1a116420ab 100644 --- a/merkle/map_verifier.go +++ b/merkle/map_verifier.go @@ -18,6 +18,7 @@ import ( "bytes" "fmt" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/storage" ) @@ -28,7 +29,7 @@ import ( // append-only logs, but adds support for nil/"default" proof nodes. // // Returns nil on a successful verification, and an error otherwise. -func VerifyMapInclusionProof(index, leafHash, expectedRoot []byte, proof [][]byte, h MapHasher) error { +func VerifyMapInclusionProof(index, leafHash, expectedRoot []byte, proof [][]byte, h hashers.MapHasher) error { hBits := h.Size() * 8 if got, want := len(proof), hBits; got != want { diff --git a/merkle/maphasher/maphasher.go b/merkle/maphasher/maphasher.go index 883e76ad5b..3783c0acf9 100644 --- a/merkle/maphasher/maphasher.go +++ b/merkle/maphasher/maphasher.go @@ -18,8 +18,15 @@ package maphasher import ( "crypto" "fmt" + + "github.com/google/trillian" + "github.com/google/trillian/merkle/hashers" ) +func init() { + hashers.RegisterMapHasher(trillian.HashStrategy_TEST_MAP_HASHER, Default) +} + // Domain separation prefixes const ( leafHashPrefix = 0 @@ -38,7 +45,7 @@ type MapHasher struct { } // New creates a new merkel.MapHasher using the passed in hash function. -func New(h crypto.Hash) *MapHasher { +func New(h crypto.Hash) hashers.MapHasher { m := &MapHasher{Hash: h} m.initNullHashes() return m diff --git a/merkle/maphasher/maphasher_test.go b/merkle/maphasher/maphasher_test.go index ff657d0944..8f62e63e06 100644 --- a/merkle/maphasher/maphasher_test.go +++ b/merkle/maphasher/maphasher_test.go @@ -19,7 +19,7 @@ import ( "encoding/base64" "testing" - "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" ) const ( @@ -58,7 +58,7 @@ func TestHStar2Equivalence(t *testing.T) { // Old hstar2 empty cache algorithm. type hstar struct { - hasher merkle.MapHasher + hasher hashers.MapHasher hStarEmptyCache [][]byte } diff --git a/merkle/memory_merkle_tree.go b/merkle/memory_merkle_tree.go index a3e6e70d62..1e1d35687f 100644 --- a/merkle/memory_merkle_tree.go +++ b/merkle/memory_merkle_tree.go @@ -32,6 +32,8 @@ package merkle import ( "errors" "fmt" + + "github.com/google/trillian/merkle/hashers" ) // TreeEntry is used for nodes in the tree for better readability. Just holds a hash but could be extended @@ -99,7 +101,7 @@ type InMemoryMerkleTree struct { tree [][]TreeEntry leavesProcessed int64 levelCount int64 - hasher LogHasher + hasher hashers.LogHasher } // isPowerOfTwoPlusOne tests whether a number is (2^x)-1 for some x. From MerkleTreeMath in C++ @@ -125,7 +127,7 @@ func sibling(leaf int64) int64 { } // NewInMemoryMerkleTree creates a new empty Merkle Tree using the specified Hasher -func NewInMemoryMerkleTree(hasher LogHasher) *InMemoryMerkleTree { +func NewInMemoryMerkleTree(hasher hashers.LogHasher) *InMemoryMerkleTree { mt := InMemoryMerkleTree{} mt.hasher = hasher diff --git a/merkle/memory_merkle_tree_test.go b/merkle/memory_merkle_tree_test.go index d4d0583925..089b68858a 100644 --- a/merkle/memory_merkle_tree_test.go +++ b/merkle/memory_merkle_tree_test.go @@ -22,6 +22,7 @@ import ( "math/rand" "testing" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/testonly" ) @@ -167,7 +168,7 @@ func downToPowerOfTwo(i int64) int64 { } // Reference implementation of Merkle hash, for cross-checking. -func referenceMerkleTreeHash(inputs [][]byte, treehasher LogHasher) []byte { +func referenceMerkleTreeHash(inputs [][]byte, treehasher hashers.LogHasher) []byte { if len(inputs) == 0 { return treehasher.EmptyRoot() } @@ -186,7 +187,7 @@ func referenceMerkleTreeHash(inputs [][]byte, treehasher LogHasher) []byte { // Reference implementation of Merkle paths. Path from leaf to root, // excluding the leaf and root themselves. -func referenceMerklePath(inputs [][]byte, leaf int64, treehasher LogHasher) [][]byte { +func referenceMerklePath(inputs [][]byte, leaf int64, treehasher hashers.LogHasher) [][]byte { var path [][]byte inputLen := int64(len(inputs)) @@ -218,7 +219,7 @@ func referenceMerklePath(inputs [][]byte, leaf int64, treehasher LogHasher) [][] // Reference implementation of snapshot consistency. // Call with haveRoot1 = true. func referenceSnapshotConsistency(inputs [][]byte, snapshot2 int64, - snapshot1 int64, treehasher LogHasher, haveRoot1 bool) [][]byte { + snapshot1 int64, treehasher hashers.LogHasher, haveRoot1 bool) [][]byte { var proof [][]byte diff --git a/merkle/objhasher/objhasher.go b/merkle/objhasher/objhasher.go index 97d16bfbde..9b251a805f 100644 --- a/merkle/objhasher/objhasher.go +++ b/merkle/objhasher/objhasher.go @@ -17,26 +17,26 @@ package objhasher import ( "github.com/benlaurie/objecthash/go/objecthash" - "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" ) type objmaphasher struct { - merkle.MapHasher + hashers.MapHasher } type objloghasher struct { - merkle.LogHasher + hashers.LogHasher } // NewMapHasher returns a new ObjectHasher based on the passed in MapHasher -func NewMapHasher(baseHasher merkle.MapHasher) merkle.MapHasher { +func NewMapHasher(baseHasher hashers.MapHasher) hashers.MapHasher { return &objmaphasher{ MapHasher: baseHasher, } } // NewLogHasher returns a new ObjectHasher based on the passed in MapHasher -func NewLogHasher(baseHasher merkle.LogHasher) merkle.LogHasher { +func NewLogHasher(baseHasher hashers.LogHasher) hashers.LogHasher { return &objloghasher{ LogHasher: baseHasher, } diff --git a/merkle/rfc6962/rfc6962.go b/merkle/rfc6962/rfc6962.go index b23ab474c7..3cb7d0be9d 100644 --- a/merkle/rfc6962/rfc6962.go +++ b/merkle/rfc6962/rfc6962.go @@ -18,8 +18,15 @@ package rfc6962 import ( "crypto" _ "crypto/sha256" // SHA256 is the default algorithm. + + "github.com/google/trillian" + "github.com/google/trillian/merkle/hashers" ) +func init() { + hashers.RegisterLogHasher(trillian.HashStrategy_RFC6962_SHA256, New(crypto.SHA256)) +} + // Domain separation prefixes const ( RFC6962LeafHashPrefix = 0 diff --git a/merkle/sparse_merkle_tree.go b/merkle/sparse_merkle_tree.go index 84d94e37bc..ecf0aae8ee 100644 --- a/merkle/sparse_merkle_tree.go +++ b/merkle/sparse_merkle_tree.go @@ -22,6 +22,7 @@ import ( "math/big" "sync" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/storage" ) @@ -33,7 +34,7 @@ import ( // to provide proofs etc. type SparseMerkleTreeReader struct { tx storage.ReadOnlyTreeTX - hasher MapHasher + hasher hashers.MapHasher treeRevision int64 } @@ -42,7 +43,7 @@ type newTXFunc func() (storage.TreeTX, error) // SparseMerkleTreeWriter knows how to store/update a stored sparse Merkle tree // via a TreeStorage transaction. type SparseMerkleTreeWriter struct { - hasher MapHasher + hasher hashers.MapHasher treeRevision int64 tree Subtree } @@ -106,7 +107,7 @@ type subtreeWriter struct { tx storage.TreeTX treeRevision int64 - treeHasher MapHasher + treeHasher hashers.MapHasher getSubtree getSubtreeFunc } @@ -298,7 +299,7 @@ var ( // NewSparseMerkleTreeReader returns a new SparseMerkleTreeReader, reading at // the specified tree revision, using the passed in MapHasher for calculating // and verifying tree hashes read via tx. -func NewSparseMerkleTreeReader(rev int64, h MapHasher, tx storage.ReadOnlyTreeTX) *SparseMerkleTreeReader { +func NewSparseMerkleTreeReader(rev int64, h hashers.MapHasher, tx storage.ReadOnlyTreeTX) *SparseMerkleTreeReader { return &SparseMerkleTreeReader{ tx: tx, hasher: h, @@ -316,7 +317,7 @@ func leafQueueSize(depths []int) int { } // newLocalSubtreeWriter creates a new local go-routine based subtree worker. -func newLocalSubtreeWriter(ctx context.Context, rev int64, prefix []byte, depths []int, newTX newTXFunc, h MapHasher) (Subtree, error) { +func newLocalSubtreeWriter(ctx context.Context, rev int64, prefix []byte, depths []int, newTX newTXFunc, h hashers.MapHasher) (Subtree, error) { tx, err := newTX() if err != nil { return nil, err @@ -346,7 +347,7 @@ func newLocalSubtreeWriter(ctx context.Context, rev int64, prefix []byte, depths // NewSparseMerkleTreeWriter returns a new SparseMerkleTreeWriter, which will // write data back into the tree at the specified revision, using the passed // in MapHasher to calculate/verify tree hashes, storing via tx. -func NewSparseMerkleTreeWriter(ctx context.Context, rev int64, h MapHasher, newTX newTXFunc) (*SparseMerkleTreeWriter, error) { +func NewSparseMerkleTreeWriter(ctx context.Context, rev int64, h hashers.MapHasher, newTX newTXFunc) (*SparseMerkleTreeWriter, error) { // TODO(al): allow the tree layering sizes to be customisable somehow. const topSubtreeSize = 8 // must be a multiple of 8 for now. tree, err := newLocalSubtreeWriter(ctx, rev, []byte{}, []int{topSubtreeSize, h.Size()*8 - topSubtreeSize}, newTX, h) diff --git a/server/admin/admin_server.go b/server/admin/admin_server.go index 0082502836..07251af885 100644 --- a/server/admin/admin_server.go +++ b/server/admin/admin_server.go @@ -25,6 +25,8 @@ import ( "github.com/google/trillian/crypto/keys" "github.com/google/trillian/crypto/keyspb" "github.com/google/trillian/extension" + "github.com/google/trillian/merkle/hashers" + _ "github.com/google/trillian/merkle/rfc6962" // Make hashers available "github.com/google/trillian/trees" "golang.org/x/net/context" "google.golang.org/genproto/protobuf/field_mask" @@ -90,11 +92,11 @@ func (s *Server) CreateTree(ctx context.Context, request *trillian.CreateTreeReq } switch tree.TreeType { case trillian.TreeType_LOG: - if _, err := trees.LogHasher(tree); err != nil { + if _, err := hashers.NewLogHasher(tree.HashStrategy); err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to create hasher for tree: %v", err.Error()) } case trillian.TreeType_MAP: - if _, err := trees.MapHasher(tree); err != nil { + if _, err := hashers.NewMapHasher(tree.HashStrategy); err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to create hasher for tree: %v", err.Error()) } default: diff --git a/server/log_rpc_server.go b/server/log_rpc_server.go index 38b65489af..dc429c1729 100644 --- a/server/log_rpc_server.go +++ b/server/log_rpc_server.go @@ -19,6 +19,7 @@ import ( "github.com/google/trillian" "github.com/google/trillian/extension" "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/monitoring" "github.com/google/trillian/storage" "github.com/google/trillian/trees" @@ -456,7 +457,7 @@ func validateLeafHashes(leafHashes [][]byte) bool { // 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 merkle.LogHasher, snapshot, leafIndex, treeSize int64) (trillian.Proof, error) { +func getInclusionProofForLeafIndex(ctx context.Context, tx storage.ReadOnlyLogTreeTX, hasher hashers.LogHasher, snapshot, leafIndex, treeSize 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(snapshot, leafIndex, treeSize, proofMaxBitLen) if err != nil { @@ -493,7 +494,7 @@ func (t *TrillianLogRPCServer) getLeavesByHashInternal(ctx context.Context, desc }, nil } -func (t *TrillianLogRPCServer) getTreeAndHasher(ctx context.Context, treeID int64, readonly bool) (*trillian.Tree, merkle.LogHasher, error) { +func (t *TrillianLogRPCServer) getTreeAndHasher(ctx context.Context, treeID int64, readonly bool) (*trillian.Tree, hashers.LogHasher, error) { tree, err := trees.GetTree( ctx, t.registry.AdminStorage, @@ -502,7 +503,7 @@ func (t *TrillianLogRPCServer) getTreeAndHasher(ctx context.Context, treeID int6 if err != nil { return nil, nil, err } - hasher, err := trees.LogHasher(tree) + hasher, err := hashers.NewLogHasher(tree.HashStrategy) if err != nil { return nil, nil, err } diff --git a/server/proof_fetcher.go b/server/proof_fetcher.go index 135d0ec85d..847a3f1119 100644 --- a/server/proof_fetcher.go +++ b/server/proof_fetcher.go @@ -20,6 +20,7 @@ import ( "github.com/google/trillian" "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/storage" ) @@ -28,7 +29,7 @@ import ( // 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, tx storage.NodeReader, th merkle.LogHasher, treeRevision, leafIndex int64, proofNodeFetches []merkle.NodeFetch) (trillian.Proof, error) { +func fetchNodesAndBuildProof(ctx context.Context, tx storage.NodeReader, th hashers.LogHasher, treeRevision, leafIndex int64, proofNodeFetches []merkle.NodeFetch) (trillian.Proof, error) { proofNodes, err := fetchNodes(ctx, tx, treeRevision, proofNodeFetches) if err != nil { return trillian.Proof{}, err @@ -44,7 +45,7 @@ func fetchNodesAndBuildProof(ctx context.Context, tx storage.NodeReader, th merk // rehasher bundles the rehashing logic into a simple state machine type rehasher struct { - th merkle.LogHasher + th hashers.LogHasher rehashing bool rehashNode storage.Node proof [][]byte diff --git a/server/sequencer_manager.go b/server/sequencer_manager.go index c66601bf85..a23e58858b 100644 --- a/server/sequencer_manager.go +++ b/server/sequencer_manager.go @@ -26,6 +26,7 @@ import ( "github.com/google/trillian/crypto" "github.com/google/trillian/extension" "github.com/google/trillian/log" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/trees" ) @@ -67,7 +68,7 @@ func (s *SequencerManager) ExecutePass(ctx context.Context, logID int64, info *L } ctx = trees.NewContext(ctx, tree) - hasher, err := trees.LogHasher(tree) + hasher, err := hashers.NewLogHasher(tree.HashStrategy) if err != nil { return 0, fmt.Errorf("error getting hasher for log %v: %v", logID, err) } diff --git a/server/trillian_map_server.go b/server/trillian_map_server.go index 58e8b7f004..61bb63a527 100644 --- a/server/trillian_map_server.go +++ b/server/trillian_map_server.go @@ -21,6 +21,7 @@ import ( "github.com/google/trillian" "github.com/google/trillian/extension" "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/storage" "github.com/google/trillian/trees" @@ -270,7 +271,7 @@ func (t *TrillianMapServer) GetSignedMapRootByRevision(ctx context.Context, req }, nil } -func (t *TrillianMapServer) getTreeAndHasher(ctx context.Context, treeID int64, readonly bool) (*trillian.Tree, merkle.MapHasher, error) { +func (t *TrillianMapServer) getTreeAndHasher(ctx context.Context, treeID int64, readonly bool) (*trillian.Tree, hashers.MapHasher, error) { tree, err := trees.GetTree( ctx, t.registry.AdminStorage, @@ -279,7 +280,7 @@ func (t *TrillianMapServer) getTreeAndHasher(ctx context.Context, treeID int64, if err != nil { return nil, nil, err } - th, err := trees.MapHasher(tree) + th, err := hashers.NewMapHasher(tree.HashStrategy) if err != nil { return nil, nil, err } diff --git a/server/trillian_map_server/main.go b/server/trillian_map_server/main.go index a56308b323..457c061b03 100644 --- a/server/trillian_map_server/main.go +++ b/server/trillian_map_server/main.go @@ -19,7 +19,8 @@ import ( "flag" _ "net/http/pprof" - _ "github.com/go-sql-driver/mysql" // Load MySQL driver + _ "github.com/go-sql-driver/mysql" // Load MySQL driver + _ "github.com/google/trillian/merkle/maphasher" // Make hashers available "github.com/golang/glog" "github.com/google/trillian" diff --git a/storage/cache/subtree_cache.go b/storage/cache/subtree_cache.go index 2d5b33ef11..02ce4097fc 100644 --- a/storage/cache/subtree_cache.go +++ b/storage/cache/subtree_cache.go @@ -23,6 +23,7 @@ import ( "github.com/golang/glog" "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/storage" "github.com/google/trillian/storage/storagepb" ) @@ -415,7 +416,7 @@ func makeSuffixKey(depth int, index int64) (string, error) { // subtree Leaves map. // // This uses HStar2 to repopulate internal nodes. -func PopulateMapSubtreeNodes(treeHasher merkle.MapHasher) storage.PopulateSubtreeFunc { +func PopulateMapSubtreeNodes(hasher hashers.MapHasher) storage.PopulateSubtreeFunc { return func(st *storagepb.SubtreeProto) error { st.InternalNodes = make(map[string][]byte) rootID := storage.NewNodeIDFromHash(st.Prefix) @@ -433,8 +434,8 @@ func PopulateMapSubtreeNodes(treeHasher merkle.MapHasher) storage.PopulateSubtre Index: big.NewInt(int64(k[1])), }) } - hs2 := merkle.NewHStar2(treeHasher) - fullTreeDepth := treeHasher.Size() * 8 + hs2 := merkle.NewHStar2(hasher) + fullTreeDepth := hasher.Size() * 8 offset := fullTreeDepth - rootID.PrefixLenBits - int(st.Depth) root, err := hs2.HStar2Nodes(int(st.Depth), offset, leaves, func(depth int, index *big.Int) ([]byte, error) { @@ -464,9 +465,9 @@ func PopulateMapSubtreeNodes(treeHasher merkle.MapHasher) storage.PopulateSubtre // handle imperfect (but left-hand dense) subtrees. Note that we only rebuild internal // nodes when the subtree is fully populated. For an explanation of why see the comments // below for PrepareLogSubtreeWrite. -func PopulateLogSubtreeNodes(treeHasher merkle.LogHasher) storage.PopulateSubtreeFunc { +func PopulateLogSubtreeNodes(hasher hashers.LogHasher) storage.PopulateSubtreeFunc { return func(st *storagepb.SubtreeProto) error { - cmt := merkle.NewCompactMerkleTree(treeHasher) + cmt := merkle.NewCompactMerkleTree(hasher) if st.Depth < 1 { return fmt.Errorf("populate log subtree with invalid depth: %d", st.Depth) } diff --git a/storage/memory/log_storage.go b/storage/memory/log_storage.go index 954da97994..af504d54e3 100644 --- a/storage/memory/log_storage.go +++ b/storage/memory/log_storage.go @@ -27,6 +27,7 @@ import ( "github.com/google/btree" "github.com/google/trillian" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/monitoring" "github.com/google/trillian/storage" "github.com/google/trillian/storage/cache" @@ -134,7 +135,7 @@ func (m *memoryLogStorage) beginInternal(ctx context.Context, treeID int64, read if err != nil { return nil, err } - hasher, err := trees.LogHasher(tree) + hasher, err := hashers.NewLogHasher(tree.HashStrategy) if err != nil { return nil, err } diff --git a/storage/mysql/log_storage.go b/storage/mysql/log_storage.go index 351c466e0e..e3f9d6aa24 100644 --- a/storage/mysql/log_storage.go +++ b/storage/mysql/log_storage.go @@ -30,6 +30,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/google/trillian" spb "github.com/google/trillian/crypto/sigpb" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/monitoring" "github.com/google/trillian/storage" "github.com/google/trillian/storage/cache" @@ -238,7 +239,7 @@ func (m *mySQLLogStorage) beginInternal(ctx context.Context, treeID int64, reado if err != nil { return nil, err } - hasher, err := trees.LogHasher(tree) + hasher, err := hashers.NewLogHasher(tree.HashStrategy) if err != nil { return nil, err } diff --git a/storage/mysql/map_storage.go b/storage/mysql/map_storage.go index a4f6622f79..597a6f300c 100644 --- a/storage/mysql/map_storage.go +++ b/storage/mysql/map_storage.go @@ -22,6 +22,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/google/trillian" spb "github.com/google/trillian/crypto/sigpb" + "github.com/google/trillian/merkle/hashers" "github.com/google/trillian/storage" "github.com/google/trillian/storage/cache" "github.com/google/trillian/trees" @@ -101,7 +102,7 @@ func (m *mySQLMapStorage) begin(ctx context.Context, treeID int64, readonly bool if err != nil { return nil, err } - hasher, err := trees.MapHasher(tree) + hasher, err := hashers.NewMapHasher(tree.HashStrategy) if err != nil { return nil, err } diff --git a/storage/testonly/admin_storage_tester.go b/storage/testonly/admin_storage_tester.go index 2d5e8404c2..152a907328 100644 --- a/storage/testonly/admin_storage_tester.go +++ b/storage/testonly/admin_storage_tester.go @@ -28,6 +28,7 @@ import ( ktestonly "github.com/google/trillian/crypto/keys/testonly" "github.com/google/trillian/crypto/keyspb" spb "github.com/google/trillian/crypto/sigpb" + _ "github.com/google/trillian/merkle/maphasher" // TEST_MAP_HASHER "github.com/google/trillian/storage" ttestonly "github.com/google/trillian/testonly" "github.com/kylelemons/godebug/pretty" diff --git a/trees/trees.go b/trees/trees.go index 6baf91fa8e..4634ad7a08 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -27,9 +27,6 @@ import ( "github.com/google/trillian/crypto/keys" "github.com/google/trillian/crypto/sigpb" "github.com/google/trillian/errors" - "github.com/google/trillian/merkle" - "github.com/google/trillian/merkle/maphasher" - "github.com/google/trillian/merkle/rfc6962" "github.com/google/trillian/storage" "golang.org/x/net/context" ) @@ -110,32 +107,6 @@ func Hash(tree *trillian.Tree) (crypto.Hash, error) { return crypto.SHA256, fmt.Errorf("unexpected hash algorithm: %s", tree.HashAlgorithm) } -// LogHasher returns a merkle.LogHasher of the kind configured fore the tree. -// TODO(gbelvin): Create merkle tree registration. -func LogHasher(tree *trillian.Tree) (merkle.LogHasher, error) { - switch tree.HashStrategy { - case trillian.HashStrategy_RFC6962_SHA256: - return rfc6962.New(crypto.SHA256), nil - case trillian.HashStrategy_TEST_MAP_HASHER: - return nil, fmt.Errorf("Cannot use map hash strategy: %s in log", tree.HashStrategy) - default: - return nil, fmt.Errorf("unexpected hash strategy: %s", tree.HashStrategy) - } -} - -// MapHasher returns a merkle.MapHasher of the kind configured fore the tree. -// TODO(gbelvin): Create merkle tree registration. -func MapHasher(tree *trillian.Tree) (merkle.MapHasher, error) { - switch tree.HashStrategy { - case trillian.HashStrategy_RFC6962_SHA256: - return nil, fmt.Errorf("Cannot use log hash strategy: %s in map", tree.HashStrategy) - case trillian.HashStrategy_TEST_MAP_HASHER: - return maphasher.Default, nil - default: - return nil, fmt.Errorf("unexpected hash strategy: %s", tree.HashStrategy) - } -} - // Signer returns a Trillian crypto.Signer configured by the tree. func Signer(ctx context.Context, sf keys.SignerFactory, tree *trillian.Tree) (*tcrypto.Signer, error) { if tree.SignatureAlgorithm == sigpb.DigitallySigned_ANONYMOUS { diff --git a/trees/trees_test.go b/trees/trees_test.go index 752321802a..a3dba1bd75 100644 --- a/trees/trees_test.go +++ b/trees/trees_test.go @@ -30,9 +30,6 @@ import ( tcrypto "github.com/google/trillian/crypto" "github.com/google/trillian/crypto/keys" "github.com/google/trillian/crypto/sigpb" - "github.com/google/trillian/merkle" - "github.com/google/trillian/merkle/maphasher" - "github.com/google/trillian/merkle/rfc6962" "github.com/google/trillian/storage" "github.com/google/trillian/storage/testonly" "github.com/kylelemons/godebug/pretty" @@ -238,62 +235,6 @@ func TestHash(t *testing.T) { } } -func TestLogHasher(t *testing.T) { - for _, test := range []struct { - strategy trillian.HashStrategy - wantHasher merkle.LogHasher - wantErr bool - }{ - {strategy: trillian.HashStrategy_UNKNOWN_HASH_STRATEGY, wantErr: true}, - {strategy: trillian.HashStrategy_TEST_MAP_HASHER, wantErr: true}, - {strategy: trillian.HashStrategy_RFC6962_SHA256, wantHasher: rfc6962.New(crypto.SHA256)}, - } { - tree := *testonly.LogTree - tree.HashAlgorithm = sigpb.DigitallySigned_SHA256 - tree.HashStrategy = test.strategy - - hasher, err := LogHasher(&tree) - if hasErr := err != nil; hasErr != test.wantErr { - t.Errorf("Hasher(%s) = (_, %q), wantErr = %v", test.strategy, err, test.wantErr) - continue - } else if hasErr { - continue - } - - if got, want := hasher.Size(), test.wantHasher.Size(); got != want { - t.Errorf("Hasher(%s) = (%v, nil), want = (%v, nil)", test.strategy, got, want) - } - } -} - -func TestMapHasher(t *testing.T) { - for _, test := range []struct { - strategy trillian.HashStrategy - wantHasher merkle.MapHasher - wantErr bool - }{ - {strategy: trillian.HashStrategy_UNKNOWN_HASH_STRATEGY, wantErr: true}, - {strategy: trillian.HashStrategy_RFC6962_SHA256, wantErr: true}, - {strategy: trillian.HashStrategy_TEST_MAP_HASHER, wantHasher: maphasher.Default}, - } { - tree := *testonly.LogTree - tree.HashAlgorithm = sigpb.DigitallySigned_SHA256 - tree.HashStrategy = test.strategy - - hasher, err := MapHasher(&tree) - if hasErr := err != nil; hasErr != test.wantErr { - t.Errorf("Hasher(%s) = (_, %q), wantErr = %v", test.strategy, err, test.wantErr) - continue - } else if hasErr { - continue - } - - if got, want := hasher.Size(), test.wantHasher.Size(); got != want { - t.Errorf("Hasher(%s) = (%v, nil), want = (%v, nil)", test.strategy, got, want) - } - } -} - func TestSigner(t *testing.T) { ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil {