github.com/aergoio/aergo@v1.3.1/pkg/trie/trie_merkle_proof.go (about) 1 /** 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package trie 7 8 import ( 9 "bytes" 10 ) 11 12 // MerkleProof generates a Merke proof of inclusion or non-inclusion 13 // for the current trie root 14 // returns the audit path, bool (key included), key, value, error 15 // (key,value) can be 1- (nil, value), value of the included key, 2- the kv of a LeafNode 16 // on the path of the non-included key, 3- (nil, nil) for a non-included key 17 // with a DefaultLeaf on the path 18 func (s *Trie) MerkleProof(key []byte) ([][]byte, bool, []byte, []byte, error) { 19 s.lock.RLock() 20 defer s.lock.RUnlock() 21 s.atomicUpdate = false // so loadChildren doesnt return a copy 22 return s.merkleProof(s.Root, key, nil, s.TrieHeight, 0) 23 } 24 25 // MerkleProofPast generates a Merke proof of inclusion or non-inclusion 26 // for a given past trie root 27 // returns the audit path, bool (key included), key, value, error 28 // (key,value) can be 1- (nil, value), value of the included key, 2- the kv of a LeafNode 29 // on the path of the non-included key, 3- (nil, nil) for a non-included key 30 // with a DefaultLeaf on the path 31 func (s *Trie) MerkleProofR(key, root []byte) ([][]byte, bool, []byte, []byte, error) { 32 s.lock.RLock() 33 defer s.lock.RUnlock() 34 s.atomicUpdate = false // so loadChildren doesnt return a copy 35 return s.merkleProof(root, key, nil, s.TrieHeight, 0) 36 } 37 38 // MerkleProofCompressed returns a compressed merkle proof in the given trie 39 func (s *Trie) MerkleProofCompressedR(key, root []byte) ([]byte, [][]byte, int, bool, []byte, []byte, error) { 40 return s.merkleProofCompressed(key, root) 41 } 42 43 // MerkleProofCompressed returns a compressed merkle proof 44 func (s *Trie) MerkleProofCompressed(key []byte) ([]byte, [][]byte, int, bool, []byte, []byte, error) { 45 return s.merkleProofCompressed(key, s.Root) 46 } 47 48 func (s *Trie) merkleProofCompressed(key, root []byte) ([]byte, [][]byte, int, bool, []byte, []byte, error) { 49 s.lock.RLock() 50 defer s.lock.RUnlock() 51 s.atomicUpdate = false // so loadChildren doesnt return a copy 52 // create a regular merkle proof and then compress it 53 mpFull, included, proofKey, proofVal, err := s.merkleProof(root, key, nil, s.TrieHeight, 0) 54 if err != nil { 55 return nil, nil, 0, true, nil, nil, err 56 } 57 // the height of the shortcut in the tree will be needed for the proof verification 58 height := len(mpFull) 59 var mp [][]byte 60 bitmap := make([]byte, len(mpFull)/8+1) 61 for i, node := range mpFull { 62 if !bytes.Equal(node, DefaultLeaf) { 63 bitSet(bitmap, i) 64 mp = append(mp, node) 65 } 66 } 67 return bitmap, mp, height, included, proofKey, proofVal, nil 68 } 69 70 // merkleProof generates a Merke proof of inclusion or non-inclusion 71 // for a given trie root. 72 // returns the audit path, bool (key included), key, value, error 73 // (key,value) can be 1- (nil, value), value of the included key, 2- the kv of a LeafNode 74 // on the path of the non-included key, 3- (nil, nil) for a non-included key 75 // with a DefaultLeaf on the path 76 func (s *Trie) merkleProof(root, key []byte, batch [][]byte, height, iBatch int) ([][]byte, bool, []byte, []byte, error) { 77 if len(root) == 0 { 78 // proove that an empty subtree is on the path of the key 79 return nil, false, nil, nil, nil 80 } 81 // Fetch the children of the node 82 batch, iBatch, lnode, rnode, isShortcut, err := s.loadChildren(root, height, iBatch, batch) 83 if err != nil { 84 return nil, false, nil, nil, err 85 } 86 if isShortcut || height == 0 { 87 if bytes.Equal(lnode[:HashLength], key) { 88 // return the value so a call to trie.Get() is not needed. 89 return nil, true, nil, rnode[:HashLength], nil 90 } 91 // Return the proof of the leaf key that is on the path of the non included key 92 return nil, false, lnode[:HashLength], rnode[:HashLength], nil 93 } 94 95 // append the left or right node to the proof 96 if bitIsSet(key, s.TrieHeight-height) { 97 mp, included, proofKey, proofValue, err := s.merkleProof(rnode, key, batch, height-1, 2*iBatch+2) 98 if err != nil { 99 return nil, false, nil, nil, err 100 } 101 if len(lnode) != 0 { 102 return append(mp, lnode[:HashLength]), included, proofKey, proofValue, nil 103 } else { 104 return append(mp, DefaultLeaf), included, proofKey, proofValue, nil 105 } 106 107 } 108 mp, included, proofKey, proofValue, err := s.merkleProof(lnode, key, batch, height-1, 2*iBatch+1) 109 if err != nil { 110 return nil, false, nil, nil, err 111 } 112 if len(rnode) != 0 { 113 return append(mp, rnode[:HashLength]), included, proofKey, proofValue, nil 114 } else { 115 return append(mp, DefaultLeaf), included, proofKey, proofValue, nil 116 } 117 } 118 119 // VerifyInclusion verifies that key/value is included in the trie with latest root 120 func (s *Trie) VerifyInclusion(ap [][]byte, key, value []byte) bool { 121 leafHash := s.hash(key, value, []byte{byte(s.TrieHeight - len(ap))}) 122 return bytes.Equal(s.Root, s.verifyInclusion(ap, 0, key, leafHash)) 123 } 124 125 // verifyInclusion returns the merkle root by hashing the merkle proof items 126 func (s *Trie) verifyInclusion(ap [][]byte, keyIndex int, key, leafHash []byte) []byte { 127 if keyIndex == len(ap) { 128 return leafHash 129 } 130 if bitIsSet(key, keyIndex) { 131 return s.hash(ap[len(ap)-keyIndex-1], s.verifyInclusion(ap, keyIndex+1, key, leafHash)) 132 } 133 return s.hash(s.verifyInclusion(ap, keyIndex+1, key, leafHash), ap[len(ap)-keyIndex-1]) 134 } 135 136 // VerifyNonInclusion verifies a proof of non inclusion, 137 // Returns true if the non-inclusion is verified 138 func (s *Trie) VerifyNonInclusion(ap [][]byte, key, value, proofKey []byte) bool { 139 // Check if an empty subtree is on the key path 140 if len(proofKey) == 0 { 141 // return true if a DefaultLeaf in the key path is included in the trie 142 return bytes.Equal(s.Root, s.verifyInclusion(ap, 0, key, DefaultLeaf)) 143 } 144 // Check if another kv leaf is on the key path in 2 steps 145 // 1- Check the proof leaf exists 146 if !s.VerifyInclusion(ap, proofKey, value) { 147 // the proof leaf is not included in the trie 148 return false 149 } 150 // 2- Check the proof leaf is on the key path 151 var b int 152 for b = 0; b < len(ap); b++ { 153 if bitIsSet(key, b) != bitIsSet(proofKey, b) { 154 // the proofKey leaf node is not on the path of the key 155 return false 156 } 157 } 158 // return true because we verified another leaf is on the key path 159 return true 160 } 161 162 // VerifyInclusionC verifies that key/value is included in the trie with latest root 163 func (s *Trie) VerifyInclusionC(bitmap, key, value []byte, ap [][]byte, length int) bool { 164 leafHash := s.hash(key, value, []byte{byte(s.TrieHeight - length)}) 165 return bytes.Equal(s.Root, s.verifyInclusionC(bitmap, key, leafHash, ap, length, 0, 0)) 166 } 167 168 // verifyInclusionC returns the merkle root by hashing the merkle proof items 169 func (s *Trie) verifyInclusionC(bitmap, key, leafHash []byte, ap [][]byte, length, keyIndex, apIndex int) []byte { 170 if keyIndex == length { 171 return leafHash 172 } 173 if bitIsSet(key, keyIndex) { 174 if bitIsSet(bitmap, length-keyIndex-1) { 175 return s.hash(ap[len(ap)-apIndex-1], s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex+1)) 176 } 177 return s.hash(DefaultLeaf, s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex)) 178 179 } 180 if bitIsSet(bitmap, length-keyIndex-1) { 181 return s.hash(s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex+1), ap[len(ap)-apIndex-1]) 182 } 183 return s.hash(s.verifyInclusionC(bitmap, key, leafHash, ap, length, keyIndex+1, apIndex), DefaultLeaf) 184 } 185 186 // VerifyNonInclusionC verifies a proof of non inclusion, 187 // Returns true if the non-inclusion is verified 188 func (s *Trie) VerifyNonInclusionC(ap [][]byte, length int, bitmap, key, value, proofKey []byte) bool { 189 // Check if an empty subtree is on the key path 190 if len(proofKey) == 0 { 191 // return true if a DefaultLeaf in the key path is included in the trie 192 return bytes.Equal(s.Root, s.verifyInclusionC(bitmap, key, DefaultLeaf, ap, length, 0, 0)) 193 } 194 // Check if another kv leaf is on the key path in 2 steps 195 // 1- Check the proof leaf exists 196 if !s.VerifyInclusionC(bitmap, proofKey, value, ap, length) { 197 // the proof leaf is not included in the trie 198 return false 199 } 200 // 2- Check the proof leaf is on the key path 201 var b int 202 for b = 0; b < length; b++ { 203 if bitIsSet(key, b) != bitIsSet(proofKey, b) { 204 // the proofKey leaf node is not on the path of the key 205 return false 206 } 207 } 208 // return true because we verified another leaf is on the key path 209 return true 210 }