package merkle import ( "bytes" "crypto/sha256" "github.com/tendermint/tendermint/binary" . "github.com/tendermint/tendermint/common" ) type IAVLProof struct { LeafNode IAVLProofLeafNode InnerNodes []IAVLProofInnerNode RootHash []byte } func (proof *IAVLProof) Verify(keyBytes, valueBytes, rootHash []byte) bool { if !bytes.Equal(keyBytes, proof.LeafNode.KeyBytes) { return false } if !bytes.Equal(valueBytes, proof.LeafNode.ValueBytes) { return false } if !bytes.Equal(rootHash, proof.RootHash) { return false } hash := proof.LeafNode.Hash() // fmt.Printf("leaf hash: %X\n", hash) for _, branch := range proof.InnerNodes { hash = branch.Hash(hash) // fmt.Printf("branch hash: %X\n", hash) } // fmt.Printf("root: %X, computed: %X\n", proof.RootHash, hash) return bytes.Equal(proof.RootHash, hash) } type IAVLProofInnerNode struct { Height int8 Size int Left []byte Right []byte } func (branch IAVLProofInnerNode) Hash(childHash []byte) []byte { hasher := sha256.New() buf := new(bytes.Buffer) n, err := int64(0), error(nil) binary.WriteInt8(branch.Height, buf, &n, &err) binary.WriteVarint(branch.Size, buf, &n, &err) if branch.Left == nil { binary.WriteByteSlice(childHash, buf, &n, &err) binary.WriteByteSlice(branch.Right, buf, &n, &err) } else { binary.WriteByteSlice(branch.Left, buf, &n, &err) binary.WriteByteSlice(childHash, buf, &n, &err) } if err != nil { panic(Fmt("Failed to hash IAVLProofInnerNode: %v", err)) } // fmt.Printf("InnerNode hash bytes: %X\n", buf.Bytes()) hasher.Write(buf.Bytes()) return hasher.Sum(nil) } type IAVLProofLeafNode struct { KeyBytes []byte ValueBytes []byte } func (leaf IAVLProofLeafNode) Hash() []byte { hasher := sha256.New() buf := new(bytes.Buffer) n, err := int64(0), error(nil) binary.WriteInt8(0, buf, &n, &err) binary.WriteVarint(1, buf, &n, &err) binary.WriteByteSlice(leaf.KeyBytes, buf, &n, &err) binary.WriteByteSlice(leaf.ValueBytes, buf, &n, &err) if err != nil { panic(Fmt("Failed to hash IAVLProofLeafNode: %v", err)) } // fmt.Printf("LeafNode hash bytes: %X\n", buf.Bytes()) hasher.Write(buf.Bytes()) return hasher.Sum(nil) } func (node *IAVLNode) constructProof(t *IAVLTree, key interface{}, proof *IAVLProof) (exists bool) { if node.height == 0 { if t.keyCodec.Compare(node.key, key) == 0 { keyBuf, valueBuf := new(bytes.Buffer), new(bytes.Buffer) n, err := int64(0), error(nil) t.keyCodec.Encode(node.key, keyBuf, &n, &err) if err != nil { panic(Fmt("Failed to encode node.key: %v", err)) } t.valueCodec.Encode(node.value, valueBuf, &n, &err) if err != nil { panic(Fmt("Failed to encode node.value: %v", err)) } leaf := IAVLProofLeafNode{ KeyBytes: keyBuf.Bytes(), ValueBytes: valueBuf.Bytes(), } proof.LeafNode = leaf return true } else { return false } } else { if t.keyCodec.Compare(key, node.key) < 0 { exists := node.getLeftNode(t).constructProof(t, key, proof) if !exists { return false } branch := IAVLProofInnerNode{ Height: node.height, Size: node.size, Left: nil, Right: node.getRightNode(t).hash, } proof.InnerNodes = append(proof.InnerNodes, branch) return true } else { exists := node.getRightNode(t).constructProof(t, key, proof) if !exists { return false } branch := IAVLProofInnerNode{ Height: node.height, Size: node.size, Left: node.getLeftNode(t).hash, Right: nil, } proof.InnerNodes = append(proof.InnerNodes, branch) return true } } } // Returns nil if key is not in tree. func (t *IAVLTree) ConstructProof(key interface{}) *IAVLProof { if t.root == nil { return nil } t.root.hashWithCount(t) // Ensure that all hashes are calculated. proof := &IAVLProof{ RootHash: t.root.hash, } t.root.constructProof(t, key, proof) return proof }