github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/internal/proofs/convert.go (about)

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