github.com/devwanda/aphelion-staking@v0.33.9/crypto/merkle/proof.go (about)

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