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  }