github.com/Finschia/finschia-sdk@v0.48.1/third_party/proto/confio/proofs.proto (about) 1 syntax = "proto3"; 2 3 package ics23; 4 option go_package = "github.com/confio/ics23/go"; 5 6 enum HashOp { 7 // NO_HASH is the default if no data passed. Note this is an illegal argument some places. 8 NO_HASH = 0; 9 SHA256 = 1; 10 SHA512 = 2; 11 KECCAK = 3; 12 RIPEMD160 = 4; 13 BITCOIN = 5; // ripemd160(sha256(x)) 14 } 15 16 /** 17 LengthOp defines how to process the key and value of the LeafOp 18 to include length information. After encoding the length with the given 19 algorithm, the length will be prepended to the key and value bytes. 20 (Each one with it's own encoded length) 21 */ 22 enum LengthOp { 23 // NO_PREFIX don't include any length info 24 NO_PREFIX = 0; 25 // VAR_PROTO uses protobuf (and go-amino) varint encoding of the length 26 VAR_PROTO = 1; 27 // VAR_RLP uses rlp int encoding of the length 28 VAR_RLP = 2; 29 // FIXED32_BIG uses big-endian encoding of the length as a 32 bit integer 30 FIXED32_BIG = 3; 31 // FIXED32_LITTLE uses little-endian encoding of the length as a 32 bit integer 32 FIXED32_LITTLE = 4; 33 // FIXED64_BIG uses big-endian encoding of the length as a 64 bit integer 34 FIXED64_BIG = 5; 35 // FIXED64_LITTLE uses little-endian encoding of the length as a 64 bit integer 36 FIXED64_LITTLE = 6; 37 // REQUIRE_32_BYTES is like NONE, but will fail if the input is not exactly 32 bytes (sha256 output) 38 REQUIRE_32_BYTES = 7; 39 // REQUIRE_64_BYTES is like NONE, but will fail if the input is not exactly 64 bytes (sha512 output) 40 REQUIRE_64_BYTES = 8; 41 } 42 43 /** 44 ExistenceProof takes a key and a value and a set of steps to perform on it. 45 The result of peforming all these steps will provide a "root hash", which can 46 be compared to the value in a header. 47 48 Since it is computationally infeasible to produce a hash collission for any of the used 49 cryptographic hash functions, if someone can provide a series of operations to transform 50 a given key and value into a root hash that matches some trusted root, these key and values 51 must be in the referenced merkle tree. 52 53 The only possible issue is maliablity in LeafOp, such as providing extra prefix data, 54 which should be controlled by a spec. Eg. with lengthOp as NONE, 55 prefix = FOO, key = BAR, value = CHOICE 56 and 57 prefix = F, key = OOBAR, value = CHOICE 58 would produce the same value. 59 60 With LengthOp this is tricker but not impossible. Which is why the "leafPrefixEqual" field 61 in the ProofSpec is valuable to prevent this mutability. And why all trees should 62 length-prefix the data before hashing it. 63 */ 64 message ExistenceProof { 65 bytes key = 1; 66 bytes value = 2; 67 LeafOp leaf = 3; 68 repeated InnerOp path = 4; 69 } 70 71 /* 72 NonExistenceProof takes a proof of two neighbors, one left of the desired key, 73 one right of the desired key. If both proofs are valid AND they are neighbors, 74 then there is no valid proof for the given key. 75 */ 76 message NonExistenceProof { 77 bytes key = 1; // TODO: remove this as unnecessary??? we prove a range 78 ExistenceProof left = 2; 79 ExistenceProof right = 3; 80 } 81 82 /* 83 CommitmentProof is either an ExistenceProof or a NonExistenceProof, or a Batch of such messages 84 */ 85 message CommitmentProof { 86 oneof proof { 87 ExistenceProof exist = 1; 88 NonExistenceProof nonexist = 2; 89 BatchProof batch = 3; 90 CompressedBatchProof compressed = 4; 91 } 92 } 93 94 /** 95 LeafOp represents the raw key-value data we wish to prove, and 96 must be flexible to represent the internal transformation from 97 the original key-value pairs into the basis hash, for many existing 98 merkle trees. 99 100 key and value are passed in. So that the signature of this operation is: 101 leafOp(key, value) -> output 102 103 To process this, first prehash the keys and values if needed (ANY means no hash in this case): 104 hkey = prehashKey(key) 105 hvalue = prehashValue(value) 106 107 Then combine the bytes, and hash it 108 output = hash(prefix || length(hkey) || hkey || length(hvalue) || hvalue) 109 */ 110 message LeafOp { 111 HashOp hash = 1; 112 HashOp prehash_key = 2; 113 HashOp prehash_value = 3; 114 LengthOp length = 4; 115 // prefix is a fixed bytes that may optionally be included at the beginning to differentiate 116 // a leaf node from an inner node. 117 bytes prefix = 5; 118 } 119 120 /** 121 InnerOp represents a merkle-proof step that is not a leaf. 122 It represents concatenating two children and hashing them to provide the next result. 123 124 The result of the previous step is passed in, so the signature of this op is: 125 innerOp(child) -> output 126 127 The result of applying InnerOp should be: 128 output = op.hash(op.prefix || child || op.suffix) 129 130 where the || operator is concatenation of binary data, 131 and child is the result of hashing all the tree below this step. 132 133 Any special data, like prepending child with the length, or prepending the entire operation with 134 some value to differentiate from leaf nodes, should be included in prefix and suffix. 135 If either of prefix or suffix is empty, we just treat it as an empty string 136 */ 137 message InnerOp { 138 HashOp hash = 1; 139 bytes prefix = 2; 140 bytes suffix = 3; 141 } 142 143 144 /** 145 ProofSpec defines what the expected parameters are for a given proof type. 146 This can be stored in the client and used to validate any incoming proofs. 147 148 verify(ProofSpec, Proof) -> Proof | Error 149 150 As demonstrated in tests, if we don't fix the algorithm used to calculate the 151 LeafHash for a given tree, there are many possible key-value pairs that can 152 generate a given hash (by interpretting the preimage differently). 153 We need this for proper security, requires client knows a priori what 154 tree format server uses. But not in code, rather a configuration object. 155 */ 156 message ProofSpec { 157 // any field in the ExistenceProof must be the same as in this spec. 158 // except Prefix, which is just the first bytes of prefix (spec can be longer) 159 LeafOp leaf_spec = 1; 160 InnerSpec inner_spec = 2; 161 // max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries) 162 int32 max_depth = 3; 163 // min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries) 164 int32 min_depth = 4; 165 } 166 167 /* 168 InnerSpec contains all store-specific structure info to determine if two proofs from a 169 given store are neighbors. 170 171 This enables: 172 173 isLeftMost(spec: InnerSpec, op: InnerOp) 174 isRightMost(spec: InnerSpec, op: InnerOp) 175 isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp) 176 */ 177 message InnerSpec { 178 // Child order is the ordering of the children node, must count from 0 179 // iavl tree is [0, 1] (left then right) 180 // merk is [0, 2, 1] (left, right, here) 181 repeated int32 child_order = 1; 182 int32 child_size = 2; 183 int32 min_prefix_length = 3; 184 int32 max_prefix_length = 4; 185 // empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0) 186 bytes empty_child = 5; 187 // hash is the algorithm that must be used for each InnerOp 188 HashOp hash = 6; 189 } 190 191 /* 192 BatchProof is a group of multiple proof types than can be compressed 193 */ 194 message BatchProof { 195 repeated BatchEntry entries = 1; 196 } 197 198 // Use BatchEntry not CommitmentProof, to avoid recursion 199 message BatchEntry { 200 oneof proof { 201 ExistenceProof exist = 1; 202 NonExistenceProof nonexist = 2; 203 } 204 } 205 206 207 /****** all items here are compressed forms *******/ 208 209 message CompressedBatchProof { 210 repeated CompressedBatchEntry entries = 1; 211 repeated InnerOp lookup_inners = 2; 212 } 213 214 // Use BatchEntry not CommitmentProof, to avoid recursion 215 message CompressedBatchEntry { 216 oneof proof { 217 CompressedExistenceProof exist = 1; 218 CompressedNonExistenceProof nonexist = 2; 219 } 220 } 221 222 message CompressedExistenceProof { 223 bytes key = 1; 224 bytes value = 2; 225 LeafOp leaf = 3; 226 // these are indexes into the lookup_inners table in CompressedBatchProof 227 repeated int32 path = 4; 228 } 229 230 message CompressedNonExistenceProof { 231 bytes key = 1; // TODO: remove this as unnecessary??? we prove a range 232 CompressedExistenceProof left = 2; 233 CompressedExistenceProof right = 3; 234 }