github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/storage/merkle/node.go (about)

     1  package merkle
     2  
     3  import (
     4  	"golang.org/x/crypto/blake2b"
     5  )
     6  
     7  // The node represents a generic vertex in the sparse Merkle trie.
     8  // CONVENTION:
     9  //   - This implementation guarantees that within the trie there are
    10  //     _never_ nil-references to descendants. We completely avoid this by
    11  //     utilizing `short nodes` that represent any path-segment without branching.
    12  type node interface {
    13  	// Hash computes recursively the hash of this respective sub trie.
    14  	// To simplify enforcing cryptographic security, we introduce the convention
    15  	// that hashing a nil node is an illegal operation, which panics.
    16  	// If cacheEnabled is set the node stores the computed hash value for future
    17  	// calls to the Hash function. Note that the cached value is only returned
    18  	// when cacheEnabled is also set for the future calls.
    19  	Hash(cacheEnabled bool) []byte
    20  
    21  	// MaxDepthOfDescendants returns the length of the longest path from this node to any of the decedent leaf nodes,
    22  	// i.e. it returns the maximum depth of the subtree under this node.
    23  	MaxDepthOfDescendants() uint
    24  }
    25  
    26  // NodeTags encodes the type of node when hashing it. Required for cryptographic
    27  // safety to prevent collision attacks (replacing a full node with a short node
    28  // that has identical hash would otherwise be possible).
    29  // Values are intended to be global constants and must be unique.
    30  var (
    31  	leafNodeTag  = []byte{0}
    32  	fullNodeTag  = []byte{1}
    33  	shortNodeTag = []byte{2}
    34  )
    35  
    36  // Short Node
    37  // Per convention a Short node has always _one child_, which is either
    38  // a full node or a leaf.
    39  
    40  type short struct {
    41  	count           int    // holds the count of bits in the path
    42  	path            []byte // holds the common path to the next node
    43  	child           node   // holds the child after the common path; never nil
    44  	cachedHashValue []byte // cached hash value
    45  }
    46  
    47  var _ node = &short{}
    48  
    49  func computeShortHash(count int, path []byte, childHash []byte) []byte {
    50  	c := serializedPathSegmentLength(count)
    51  	h, _ := blake2b.New256(shortNodeTag) // blake2b.New256(..) never errors for given MAC (verified in tests)
    52  	_, _ = h.Write(c[:])                 // blake2b.Write(..) never errors for _any_ input
    53  	_, _ = h.Write(path)                 // blake2b.Write(..) never errors for _any_ input
    54  	_, _ = h.Write(childHash)            // blake2b.Write(..) never errors for _any_ input
    55  	return h.Sum(nil)
    56  }
    57  
    58  func (n *short) Hash(cacheEnabled bool) []byte {
    59  	if !cacheEnabled {
    60  		return computeShortHash(n.count, n.path, n.child.Hash(cacheEnabled))
    61  	}
    62  	if len(n.cachedHashValue) == 0 {
    63  		n.cachedHashValue = computeShortHash(n.count, n.path, n.child.Hash(cacheEnabled))
    64  	}
    65  	return n.cachedHashValue
    66  }
    67  
    68  func (n *short) MaxDepthOfDescendants() uint {
    69  	return n.child.MaxDepthOfDescendants() + 1
    70  }
    71  
    72  // serializedPathSegmentLength serializes the bitCount into two bytes.
    73  // We are able to represent key length of up to 65528 bits
    74  func serializedPathSegmentLength(bitCount int) [2]byte {
    75  	var byteCount [2]byte
    76  	byteCount[0] = byte(bitCount >> 8)
    77  	byteCount[1] = byte(bitCount)
    78  	return byteCount
    79  }
    80  
    81  //Full Node
    82  // Per convention a Full Node has always _two children_. Nil values not allowed.
    83  
    84  type full struct {
    85  	left            node   // holds the left path node (bit 0); never nil
    86  	right           node   // holds the right path node (bit 1); never nil
    87  	cachedHashValue []byte // cached hash value
    88  }
    89  
    90  var _ node = &full{}
    91  
    92  func computeFullHash(leftChildHash, rightChildHash []byte) []byte {
    93  	h, _ := blake2b.New256(fullNodeTag) // blake2b.New256(..) never errors for given MAC (verified in tests)
    94  	_, _ = h.Write(leftChildHash)       // blake2b.Write(..) never errors for _any_ input
    95  	_, _ = h.Write(rightChildHash)      // blake2b.Write(..) never errors for _any_ input
    96  	return h.Sum(nil)
    97  }
    98  
    99  func (n *full) Hash(cacheEnabled bool) []byte {
   100  	if !cacheEnabled {
   101  		return computeFullHash(n.left.Hash(cacheEnabled), n.right.Hash(cacheEnabled))
   102  	}
   103  	if len(n.cachedHashValue) == 0 {
   104  		n.cachedHashValue = computeFullHash(n.left.Hash(cacheEnabled), n.right.Hash(cacheEnabled))
   105  	}
   106  	return n.cachedHashValue
   107  }
   108  
   109  func (n *full) MaxDepthOfDescendants() uint {
   110  	left := n.left.MaxDepthOfDescendants()
   111  	right := n.right.MaxDepthOfDescendants()
   112  	if left < right {
   113  		return right + 1
   114  	}
   115  	return left + 1
   116  }
   117  
   118  // Leaf Node
   119  // Leaf represents a key-value pair. We only store the value, because the
   120  // key is implicitly stored as the merkle path through the tree.
   121  
   122  type leaf struct {
   123  	val             []byte
   124  	cachedHashValue []byte // cached hash value
   125  }
   126  
   127  var _ node = &leaf{}
   128  
   129  func computeLeafHash(value []byte) []byte {
   130  	h, _ := blake2b.New256(leafNodeTag) // blake2b.New256(..) never errors for given MAC (verified in tests)
   131  	_, _ = h.Write(value)               // blake2b.Write(..) never errors for _any_ input
   132  	return h.Sum(nil)
   133  }
   134  
   135  func (n *leaf) Hash(cacheEnabled bool) []byte {
   136  	if !cacheEnabled {
   137  		return computeLeafHash(n.val)
   138  	}
   139  	if len(n.cachedHashValue) == 0 {
   140  		n.cachedHashValue = computeLeafHash(n.val)
   141  	}
   142  	return n.cachedHashValue
   143  }
   144  
   145  func (n *leaf) MaxDepthOfDescendants() uint {
   146  	return 0
   147  }
   148  
   149  // Dummy Node
   150  // Dummy node type as substitute for `nil`. Not used in the trie, but as zero
   151  // value for auxiliary variables during trie update operations. This reduces
   152  // complexity of the business logic, as we can then also apply the convention of
   153  // "nodes are never nil" to the auxiliary variables.
   154  
   155  type dummy struct{}
   156  
   157  var _ node = &dummy{}
   158  
   159  func (n *dummy) Hash(_ bool) []byte {
   160  	// Per convention, Hash should never be called by the business logic but
   161  	// is required to implement the node interface
   162  	panic("dummy node has no hash")
   163  }
   164  
   165  func (n *dummy) MaxDepthOfDescendants() uint {
   166  	return 0
   167  }