github.com/vipernet-xyz/tm@v0.34.24/crypto/merkle/proof_op.go (about)

     1  package merkle
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	tmcrypto "github.com/vipernet-xyz/tm/proto/tendermint/crypto"
     9  )
    10  
    11  //----------------------------------------
    12  // ProofOp gets converted to an instance of ProofOperator:
    13  
    14  // ProofOperator is a layer for calculating intermediate Merkle roots
    15  // when a series of Merkle trees are chained together.
    16  // Run() takes leaf values from a tree and returns the Merkle
    17  // root for the corresponding tree. It takes and returns a list of bytes
    18  // to allow multiple leaves to be part of a single proof, for instance in a range proof.
    19  // ProofOp() encodes the ProofOperator in a generic way so it can later be
    20  // decoded with OpDecoder.
    21  type ProofOperator interface {
    22  	Run([][]byte) ([][]byte, error)
    23  	GetKey() []byte
    24  	ProofOp() tmcrypto.ProofOp
    25  }
    26  
    27  //----------------------------------------
    28  // Operations on a list of ProofOperators
    29  
    30  // ProofOperators is a slice of ProofOperator(s).
    31  // Each operator will be applied to the input value sequentially
    32  // and the last Merkle root will be verified with already known data
    33  type ProofOperators []ProofOperator
    34  
    35  func (poz ProofOperators) VerifyValue(root []byte, keypath string, value []byte) (err error) {
    36  	return poz.Verify(root, keypath, [][]byte{value})
    37  }
    38  
    39  func (poz ProofOperators) Verify(root []byte, keypath string, args [][]byte) (err error) {
    40  	keys, err := KeyPathToKeys(keypath)
    41  	if err != nil {
    42  		return
    43  	}
    44  
    45  	for i, op := range poz {
    46  		key := op.GetKey()
    47  		if len(key) != 0 {
    48  			if len(keys) == 0 {
    49  				return fmt.Errorf("key path has insufficient # of parts: expected no more keys but got %+v", string(key))
    50  			}
    51  			lastKey := keys[len(keys)-1]
    52  			if !bytes.Equal(lastKey, key) {
    53  				return fmt.Errorf("key mismatch on operation #%d: expected %+v but got %+v", i, string(lastKey), string(key))
    54  			}
    55  			keys = keys[:len(keys)-1]
    56  		}
    57  		args, err = op.Run(args)
    58  		if err != nil {
    59  			return
    60  		}
    61  	}
    62  	if !bytes.Equal(root, args[0]) {
    63  		return fmt.Errorf("calculated root hash is invalid: expected %X but got %X", root, args[0])
    64  	}
    65  	if len(keys) != 0 {
    66  		return errors.New("keypath not consumed all")
    67  	}
    68  	return nil
    69  }
    70  
    71  //----------------------------------------
    72  // ProofRuntime - main entrypoint
    73  
    74  type OpDecoder func(tmcrypto.ProofOp) (ProofOperator, error)
    75  
    76  type ProofRuntime struct {
    77  	decoders map[string]OpDecoder
    78  }
    79  
    80  func NewProofRuntime() *ProofRuntime {
    81  	return &ProofRuntime{
    82  		decoders: make(map[string]OpDecoder),
    83  	}
    84  }
    85  
    86  func (prt *ProofRuntime) RegisterOpDecoder(typ string, dec OpDecoder) {
    87  	_, ok := prt.decoders[typ]
    88  	if ok {
    89  		panic("already registered for type " + typ)
    90  	}
    91  	prt.decoders[typ] = dec
    92  }
    93  
    94  func (prt *ProofRuntime) Decode(pop tmcrypto.ProofOp) (ProofOperator, error) {
    95  	decoder := prt.decoders[pop.Type]
    96  	if decoder == nil {
    97  		return nil, fmt.Errorf("unrecognized proof type %v", pop.Type)
    98  	}
    99  	return decoder(pop)
   100  }
   101  
   102  func (prt *ProofRuntime) DecodeProof(proof *tmcrypto.ProofOps) (ProofOperators, error) {
   103  	poz := make(ProofOperators, 0, len(proof.Ops))
   104  	for _, pop := range proof.Ops {
   105  		operator, err := prt.Decode(pop)
   106  		if err != nil {
   107  			return nil, fmt.Errorf("decoding a proof operator: %w", err)
   108  		}
   109  		poz = append(poz, operator)
   110  	}
   111  	return poz, nil
   112  }
   113  
   114  func (prt *ProofRuntime) VerifyValue(proof *tmcrypto.ProofOps, root []byte, keypath string, value []byte) (err error) {
   115  	return prt.Verify(proof, root, keypath, [][]byte{value})
   116  }
   117  
   118  // TODO In the long run we'll need a method of classifcation of ops,
   119  // whether existence or absence or perhaps a third?
   120  func (prt *ProofRuntime) VerifyAbsence(proof *tmcrypto.ProofOps, root []byte, keypath string) (err error) {
   121  	return prt.Verify(proof, root, keypath, nil)
   122  }
   123  
   124  func (prt *ProofRuntime) Verify(proof *tmcrypto.ProofOps, root []byte, keypath string, args [][]byte) (err error) {
   125  	poz, err := prt.DecodeProof(proof)
   126  	if err != nil {
   127  		return fmt.Errorf("decoding proof: %w", err)
   128  	}
   129  	return poz.Verify(root, keypath, args)
   130  }
   131  
   132  // DefaultProofRuntime only knows about value proofs.
   133  // To use e.g. IAVL proofs, register op-decoders as
   134  // defined in the IAVL package.
   135  func DefaultProofRuntime() (prt *ProofRuntime) {
   136  	prt = NewProofRuntime()
   137  	prt.RegisterOpDecoder(ProofOpValue, ValueOpDecoder)
   138  	return
   139  }