github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/crypto/merkle/simple_proof.go (about) 1 package merkle 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 "github.com/franono/tendermint/crypto/tmhash" 9 ) 10 11 const ( 12 // MaxAunts is the maximum number of aunts that can be included in a SimpleProof. 13 // This corresponds to a tree of size 2^100, which should be sufficient for all conceivable purposes. 14 // This maximum helps prevent Denial-of-Service attacks by limitting the size of the proofs. 15 MaxAunts = 100 16 ) 17 18 // SimpleProof represents a simple Merkle proof. 19 // NOTE: The convention for proofs is to include leaf hashes but to 20 // exclude the root hash. 21 // This convention is implemented across IAVL range proofs as well. 22 // Keep this consistent unless there's a very good reason to change 23 // everything. This also affects the generalized proof system as 24 // well. 25 type SimpleProof struct { 26 Total int `json:"total"` // Total number of items. 27 Index int `json:"index"` // Index of item to prove. 28 LeafHash []byte `json:"leaf_hash"` // Hash of item value. 29 Aunts [][]byte `json:"aunts"` // Hashes from leaf's sibling to a root's child. 30 } 31 32 // SimpleProofsFromByteSlices computes inclusion proof for given items. 33 // proofs[0] is the proof for items[0]. 34 func SimpleProofsFromByteSlices(items [][]byte) (rootHash []byte, proofs []*SimpleProof) { 35 trails, rootSPN := trailsFromByteSlices(items) 36 rootHash = rootSPN.Hash 37 proofs = make([]*SimpleProof, len(items)) 38 for i, trail := range trails { 39 proofs[i] = &SimpleProof{ 40 Total: len(items), 41 Index: i, 42 LeafHash: trail.Hash, 43 Aunts: trail.FlattenAunts(), 44 } 45 } 46 return 47 } 48 49 // Verify that the SimpleProof proves the root hash. 50 // Check sp.Index/sp.Total manually if needed 51 func (sp *SimpleProof) Verify(rootHash []byte, leaf []byte) error { 52 leafHash := leafHash(leaf) 53 if sp.Total < 0 { 54 return errors.New("proof total must be positive") 55 } 56 if sp.Index < 0 { 57 return errors.New("proof index cannot be negative") 58 } 59 if !bytes.Equal(sp.LeafHash, leafHash) { 60 return fmt.Errorf("invalid leaf hash: wanted %X got %X", leafHash, sp.LeafHash) 61 } 62 computedHash := sp.ComputeRootHash() 63 if !bytes.Equal(computedHash, rootHash) { 64 return fmt.Errorf("invalid root hash: wanted %X got %X", rootHash, computedHash) 65 } 66 return nil 67 } 68 69 // Compute the root hash given a leaf hash. Does not verify the result. 70 func (sp *SimpleProof) ComputeRootHash() []byte { 71 return computeHashFromAunts( 72 sp.Index, 73 sp.Total, 74 sp.LeafHash, 75 sp.Aunts, 76 ) 77 } 78 79 // String implements the stringer interface for SimpleProof. 80 // It is a wrapper around StringIndented. 81 func (sp *SimpleProof) String() string { 82 return sp.StringIndented("") 83 } 84 85 // StringIndented generates a canonical string representation of a SimpleProof. 86 func (sp *SimpleProof) StringIndented(indent string) string { 87 return fmt.Sprintf(`SimpleProof{ 88 %s Aunts: %X 89 %s}`, 90 indent, sp.Aunts, 91 indent) 92 } 93 94 // ValidateBasic performs basic validation. 95 // NOTE: it expects the LeafHash and the elements of Aunts to be of size tmhash.Size, 96 // and it expects at most MaxAunts elements in Aunts. 97 func (sp *SimpleProof) ValidateBasic() error { 98 if sp.Total < 0 { 99 return errors.New("negative Total") 100 } 101 if sp.Index < 0 { 102 return errors.New("negative Index") 103 } 104 if len(sp.LeafHash) != tmhash.Size { 105 return fmt.Errorf("expected LeafHash size to be %d, got %d", tmhash.Size, len(sp.LeafHash)) 106 } 107 if len(sp.Aunts) > MaxAunts { 108 return fmt.Errorf("expected no more than %d aunts, got %d", MaxAunts, len(sp.Aunts)) 109 } 110 for i, auntHash := range sp.Aunts { 111 if len(auntHash) != tmhash.Size { 112 return fmt.Errorf("expected Aunts#%d size to be %d, got %d", i, tmhash.Size, len(auntHash)) 113 } 114 } 115 return nil 116 } 117 118 // Use the leafHash and innerHashes to get the root merkle hash. 119 // If the length of the innerHashes slice isn't exactly correct, the result is nil. 120 // Recursive impl. 121 func computeHashFromAunts(index int, total int, leafHash []byte, innerHashes [][]byte) []byte { 122 if index >= total || index < 0 || total <= 0 { 123 return nil 124 } 125 switch total { 126 case 0: 127 panic("Cannot call computeHashFromAunts() with 0 total") 128 case 1: 129 if len(innerHashes) != 0 { 130 return nil 131 } 132 return leafHash 133 default: 134 if len(innerHashes) == 0 { 135 return nil 136 } 137 numLeft := getSplitPoint(total) 138 if index < numLeft { 139 leftHash := computeHashFromAunts(index, numLeft, leafHash, innerHashes[:len(innerHashes)-1]) 140 if leftHash == nil { 141 return nil 142 } 143 return innerHash(leftHash, innerHashes[len(innerHashes)-1]) 144 } 145 rightHash := computeHashFromAunts(index-numLeft, total-numLeft, leafHash, innerHashes[:len(innerHashes)-1]) 146 if rightHash == nil { 147 return nil 148 } 149 return innerHash(innerHashes[len(innerHashes)-1], rightHash) 150 } 151 } 152 153 // SimpleProofNode is a helper structure to construct merkle proof. 154 // The node and the tree is thrown away afterwards. 155 // Exactly one of node.Left and node.Right is nil, unless node is the root, in which case both are nil. 156 // node.Parent.Hash = hash(node.Hash, node.Right.Hash) or 157 // hash(node.Left.Hash, node.Hash), depending on whether node is a left/right child. 158 type SimpleProofNode struct { 159 Hash []byte 160 Parent *SimpleProofNode 161 Left *SimpleProofNode // Left sibling (only one of Left,Right is set) 162 Right *SimpleProofNode // Right sibling (only one of Left,Right is set) 163 } 164 165 // FlattenAunts will return the inner hashes for the item corresponding to the leaf, 166 // starting from a leaf SimpleProofNode. 167 func (spn *SimpleProofNode) FlattenAunts() [][]byte { 168 // Nonrecursive impl. 169 innerHashes := [][]byte{} 170 for spn != nil { 171 switch { 172 case spn.Left != nil: 173 innerHashes = append(innerHashes, spn.Left.Hash) 174 case spn.Right != nil: 175 innerHashes = append(innerHashes, spn.Right.Hash) 176 default: 177 break 178 } 179 spn = spn.Parent 180 } 181 return innerHashes 182 } 183 184 // trails[0].Hash is the leaf hash for items[0]. 185 // trails[i].Parent.Parent....Parent == root for all i. 186 func trailsFromByteSlices(items [][]byte) (trails []*SimpleProofNode, root *SimpleProofNode) { 187 // Recursive impl. 188 switch len(items) { 189 case 0: 190 return nil, nil 191 case 1: 192 trail := &SimpleProofNode{leafHash(items[0]), nil, nil, nil} 193 return []*SimpleProofNode{trail}, trail 194 default: 195 k := getSplitPoint(len(items)) 196 lefts, leftRoot := trailsFromByteSlices(items[:k]) 197 rights, rightRoot := trailsFromByteSlices(items[k:]) 198 rootHash := innerHash(leftRoot.Hash, rightRoot.Hash) 199 root := &SimpleProofNode{rootHash, nil, nil, nil} 200 leftRoot.Parent = root 201 leftRoot.Right = rightRoot 202 rightRoot.Parent = root 203 rightRoot.Left = leftRoot 204 return append(lefts, rights...), root 205 } 206 }