github.com/Oyster-zx/tendermint@v0.34.24-fork/crypto/merkle/proof_op.go (about) 1 package merkle 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 tmcrypto "github.com/tendermint/tendermint/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 }