github.com/Finschia/finschia-sdk@v0.48.1/store/internal/proofs/convert.go (about) 1 package proofs 2 3 import ( 4 "fmt" 5 "math/bits" 6 7 ics23 "github.com/confio/ics23/go" 8 "github.com/tendermint/tendermint/proto/tendermint/crypto" 9 ) 10 11 // ConvertExistenceProof will convert the given proof into a valid 12 // existence proof, if that's what it is. 13 // 14 // This is the simplest case of the range proof and we will focus on 15 // demoing compatibility here 16 func ConvertExistenceProof(p *crypto.Proof, key, value []byte) (*ics23.ExistenceProof, error) { 17 path, err := convertInnerOps(p) 18 if err != nil { 19 return nil, err 20 } 21 22 proof := &ics23.ExistenceProof{ 23 Key: key, 24 Value: value, 25 Leaf: convertLeafOp(), 26 Path: path, 27 } 28 return proof, nil 29 } 30 31 // this is adapted from merkle/hash.go:leafHash() 32 // and merkle/simple_map.go:KVPair.Bytes() 33 func convertLeafOp() *ics23.LeafOp { 34 prefix := []byte{0} 35 36 return &ics23.LeafOp{ 37 Hash: ics23.HashOp_SHA256, 38 PrehashKey: ics23.HashOp_NO_HASH, 39 PrehashValue: ics23.HashOp_SHA256, 40 Length: ics23.LengthOp_VAR_PROTO, 41 Prefix: prefix, 42 } 43 } 44 45 func convertInnerOps(p *crypto.Proof) ([]*ics23.InnerOp, error) { 46 inners := make([]*ics23.InnerOp, 0, len(p.Aunts)) 47 path := buildPath(p.Index, p.Total) 48 49 if len(p.Aunts) != len(path) { 50 return nil, fmt.Errorf("calculated a path different length (%d) than provided by SimpleProof (%d)", len(path), len(p.Aunts)) 51 } 52 53 for i, aunt := range p.Aunts { 54 auntRight := path[i] 55 56 // combine with: 0x01 || lefthash || righthash 57 inner := &ics23.InnerOp{Hash: ics23.HashOp_SHA256} 58 if auntRight { 59 inner.Prefix = []byte{1} 60 inner.Suffix = aunt 61 } else { 62 inner.Prefix = append([]byte{1}, aunt...) 63 } 64 inners = append(inners, inner) 65 } 66 return inners, nil 67 } 68 69 // buildPath returns a list of steps from leaf to root 70 // in each step, true means index is left side, false index is right side 71 // code adapted from merkle/simple_proof.go:computeHashFromAunts 72 func buildPath(idx, total int64) []bool { 73 if total < 2 { 74 return nil 75 } 76 numLeft := getSplitPoint(total) 77 goLeft := idx < numLeft 78 79 // we put goLeft at the end of the array, as we recurse from top to bottom, 80 // and want the leaf to be first in array, root last 81 if goLeft { 82 return append(buildPath(idx, numLeft), goLeft) 83 } 84 return append(buildPath(idx-numLeft, total-numLeft), goLeft) 85 } 86 87 func getSplitPoint(length int64) int64 { 88 if length < 1 { 89 panic("Trying to split a tree with size < 1") 90 } 91 uLength := uint(length) 92 bitlen := bits.Len(uLength) 93 k := int64(1 << uint(bitlen-1)) 94 if k == length { 95 k >>= 1 96 } 97 return k 98 }