github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/merkle/compact_merkle_tree.go (about)

     1  // Copyright 2016 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package merkle
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/base64"
    20  	"encoding/hex"
    21  	"fmt"
    22  	"math/bits"
    23  
    24  	log "github.com/golang/glog"
    25  	"github.com/google/trillian/merkle/hashers"
    26  )
    27  
    28  // RootHashMismatchError indicates a unexpected root hash value.
    29  type RootHashMismatchError struct {
    30  	ExpectedHash []byte
    31  	ActualHash   []byte
    32  }
    33  
    34  func (r RootHashMismatchError) Error() string {
    35  	return fmt.Sprintf("root hash mismatch got: %v expected: %v", r.ActualHash, r.ExpectedHash)
    36  }
    37  
    38  // CompactMerkleTree is a compact Merkle tree representation.
    39  // Uses log(n) nodes to represent the current on-disk tree.
    40  type CompactMerkleTree struct {
    41  	hasher hashers.LogHasher
    42  	root   []byte
    43  	// the list of "dangling" left-hand nodes, NOTE: index 0 is the leaf, not the root.
    44  	nodes [][]byte
    45  	size  int64
    46  }
    47  
    48  func isPerfectTree(x int64) bool {
    49  	return x != 0 && (x&(x-1) == 0)
    50  }
    51  
    52  // GetNodeFunc is a function prototype which can look up particular nodes within a non-compact Merkle tree.
    53  // Used by the CompactMerkleTree to populate itself with correct state when starting up with a non-empty tree.
    54  type GetNodeFunc func(depth int, index int64) ([]byte, error)
    55  
    56  // NewCompactMerkleTreeWithState creates a new CompactMerkleTree for the passed in |size|.
    57  // This can fail if the nodes required to recreate the tree state cannot be fetched or the calculated
    58  // root hash after population does not match the value we expect.
    59  // |f| will be called a number of times with the co-ordinates of internal MerkleTree nodes whose hash values are
    60  // required to initialize the internal state of the CompactMerkleTree.  |expectedRoot| is the known-good tree root
    61  // of the tree at |size|, and is used to verify the correct initial state of the CompactMerkleTree after initialisation.
    62  func NewCompactMerkleTreeWithState(hasher hashers.LogHasher, size int64, f GetNodeFunc, expectedRoot []byte) (*CompactMerkleTree, error) {
    63  	sizeBits := bits.Len64(uint64(size))
    64  
    65  	r := CompactMerkleTree{
    66  		hasher: hasher,
    67  		nodes:  make([][]byte, sizeBits),
    68  		root:   hasher.EmptyRoot(),
    69  		size:   size,
    70  	}
    71  
    72  	if isPerfectTree(size) {
    73  		log.V(1).Info("Is perfect tree.")
    74  		r.root = append(make([]byte, 0, len(expectedRoot)), expectedRoot...)
    75  		r.nodes[sizeBits-1] = r.root
    76  	} else {
    77  		// Pull in the nodes we need to repopulate our compact tree and verify the root
    78  		for depth := 0; depth < sizeBits; depth++ {
    79  			if size&1 == 1 {
    80  				index := size - 1
    81  				log.V(1).Infof("fetching d: %d i: %d, leaving size %d", depth, index, size)
    82  				h, err := f(depth, index)
    83  				if err != nil {
    84  					log.Warningf("Failed to fetch node depth %d index %d: %s", depth, index, err)
    85  					return nil, err
    86  				}
    87  				r.nodes[depth] = h
    88  			}
    89  			size >>= 1
    90  		}
    91  		r.recalculateRoot(func(depth int, index int64, hash []byte) error {
    92  			return nil
    93  		})
    94  	}
    95  	if !bytes.Equal(r.root, expectedRoot) {
    96  		log.Warningf("Corrupt state, expected root %s, got %s", hex.EncodeToString(expectedRoot[:]), hex.EncodeToString(r.root[:]))
    97  		return nil, RootHashMismatchError{ActualHash: r.root, ExpectedHash: expectedRoot}
    98  	}
    99  	log.V(1).Infof("Resuming at size %d, with root: %s", r.size, base64.StdEncoding.EncodeToString(r.root[:]))
   100  	return &r, nil
   101  }
   102  
   103  // NewCompactMerkleTree creates a new CompactMerkleTree with size zero. This always succeeds.
   104  func NewCompactMerkleTree(hasher hashers.LogHasher) *CompactMerkleTree {
   105  	r := CompactMerkleTree{
   106  		hasher: hasher,
   107  		root:   hasher.EmptyRoot(),
   108  		nodes:  make([][]byte, 0),
   109  		size:   0,
   110  	}
   111  	return &r
   112  }
   113  
   114  // CurrentRoot returns the current root hash.
   115  func (c CompactMerkleTree) CurrentRoot() []byte {
   116  	return c.root
   117  }
   118  
   119  // DumpNodes logs the internal state of the CompactMerkleTree, and is used for debugging.
   120  func (c CompactMerkleTree) DumpNodes() {
   121  	log.Infof("Tree Nodes @ %d", c.size)
   122  	mask := int64(1)
   123  	numBits := bits.Len64(uint64(c.size))
   124  	for bit := 0; bit < numBits; bit++ {
   125  		if c.size&mask != 0 {
   126  			log.Infof("%d:  %s", bit, base64.StdEncoding.EncodeToString(c.nodes[bit][:]))
   127  		} else {
   128  			log.Infof("%d:  -", bit)
   129  		}
   130  		mask <<= 1
   131  	}
   132  }
   133  
   134  type setNodeFunc func(depth int, index int64, hash []byte) error
   135  
   136  func (c *CompactMerkleTree) recalculateRoot(f setNodeFunc) error {
   137  	if c.size == 0 {
   138  		return nil
   139  	}
   140  
   141  	index := c.size
   142  
   143  	var newRoot []byte
   144  	first := true
   145  	mask := int64(1)
   146  	numBits := bits.Len64(uint64(c.size))
   147  	for bit := 0; bit < numBits; bit++ {
   148  		index >>= 1
   149  		if c.size&mask != 0 {
   150  			if first {
   151  				newRoot = c.nodes[bit]
   152  				first = false
   153  			} else {
   154  				newRoot = c.hasher.HashChildren(c.nodes[bit], newRoot)
   155  				if err := f(bit+1, index, newRoot); err != nil {
   156  					return err
   157  				}
   158  			}
   159  		}
   160  		mask <<= 1
   161  	}
   162  	c.root = newRoot
   163  	return nil
   164  }
   165  
   166  // AddLeaf calculates the leafhash of |data| and appends it to the tree.
   167  // |f| is a callback which will be called multiple times with the full MerkleTree coordinates of nodes whose hash should be updated.
   168  func (c *CompactMerkleTree) AddLeaf(data []byte, f setNodeFunc) (int64, []byte, error) {
   169  	h, err := c.hasher.HashLeaf(data)
   170  	if err != nil {
   171  		return 0, nil, err
   172  	}
   173  	seq, err := c.AddLeafHash(h, f)
   174  	if err != nil {
   175  		return 0, nil, err
   176  	}
   177  	return seq, h, err
   178  }
   179  
   180  // AddLeafHash adds the specified |leafHash| to the tree.
   181  // |f| is a callback which will be called multiple times with the full MerkleTree coordinates of nodes whose hash should be updated.
   182  func (c *CompactMerkleTree) AddLeafHash(leafHash []byte, f setNodeFunc) (int64, error) {
   183  	defer func() {
   184  		c.size++
   185  		// TODO(al): do this lazily
   186  		c.recalculateRoot(f)
   187  	}()
   188  
   189  	assignedSeq := c.size
   190  	index := assignedSeq
   191  
   192  	if err := f(0, index, leafHash); err != nil {
   193  		return 0, err
   194  	}
   195  
   196  	if c.size == 0 {
   197  		// new tree
   198  		c.nodes = append(c.nodes, leafHash)
   199  		return assignedSeq, nil
   200  	}
   201  
   202  	// Initialize our running hash value to the leaf hash
   203  	hash := leafHash
   204  	bit := 0
   205  	// Iterate over the bits in our tree size
   206  	for t := c.size; t > 0; t >>= 1 {
   207  		index >>= 1
   208  		if t&1 == 0 {
   209  			// Just store the running hash here; we're done.
   210  			c.nodes[bit] = hash
   211  			// Don't re-write the leaf hash node (we've done it above already)
   212  			if bit > 0 {
   213  				// Store the leaf hash node
   214  				if err := f(bit, index, hash); err != nil {
   215  					return 0, err
   216  				}
   217  			}
   218  			return assignedSeq, nil
   219  		}
   220  		// The bit is set so we have a node at that position in the nodes list so hash it with our running hash:
   221  		hash = c.hasher.HashChildren(c.nodes[bit], hash)
   222  		// Store the resulting parent hash.
   223  		if err := f(bit+1, index, hash); err != nil {
   224  			return 0, err
   225  		}
   226  		// Now, clear this position in the nodes list as the hash it formerly contained will be propagated upwards.
   227  		c.nodes[bit] = nil
   228  		// Figure out if we're done:
   229  		if bit+1 >= len(c.nodes) {
   230  			// If we're extending the node list then add a new entry with our
   231  			// running hash, and we're done.
   232  			c.nodes = append(c.nodes, hash)
   233  			return assignedSeq, nil
   234  		} else if t&0x02 == 0 {
   235  			// If the node above us is unused at this tree size, then store our
   236  			// running hash there, and we're done.
   237  			c.nodes[bit+1] = hash
   238  			return assignedSeq, nil
   239  		}
   240  		// Otherwise, go around again.
   241  		bit++
   242  	}
   243  	// We should never get here, because that'd mean we had a running hash which
   244  	// we've not stored somewhere.
   245  	return 0, fmt.Errorf("AddLeaf failed running hash not cleared: h: %v seq: %d", leafHash, assignedSeq)
   246  }
   247  
   248  // Size returns the current size of the tree, that is, the number of leaves ever added to the tree.
   249  func (c CompactMerkleTree) Size() int64 {
   250  	return c.size
   251  }
   252  
   253  // Hashes returns a copy of the set of node hashes that comprise the compact representation of the tree.
   254  func (c CompactMerkleTree) Hashes() [][]byte {
   255  	if isPerfectTree(c.size) {
   256  		return nil
   257  	}
   258  	n := make([][]byte, len(c.nodes))
   259  	copy(n, c.nodes)
   260  	return n
   261  }
   262  
   263  // Depth returns the number of levels in the tree.
   264  func (c CompactMerkleTree) Depth() int {
   265  	if c.size == 0 {
   266  		return 0
   267  	}
   268  	return bits.Len64(uint64(c.size - 1))
   269  }