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 }