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  }