Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

ics23 source pure

Constants 2

const HashOp_NO_HASH, HashOp_SHA256

1const (
2	// NO_HASH is the default if no data passed. Note this is an illegal argument some places.
3	HashOp_NO_HASH HashOp = 0
4	HashOp_SHA256  HashOp = 1
5)
source

const LengthOp_NO_PREFIX, LengthOp_VAR_PROTO

1const (
2	// NO_PREFIX don't include any length info
3	LengthOp_NO_PREFIX LengthOp = 0
4	// VAR_PROTO uses protobuf (and go-amino) varint encoding of the length
5	LengthOp_VAR_PROTO LengthOp = 1
6)
source

Functions 6

func IsLeftMost

1func IsLeftMost(spec *InnerSpec, path []*InnerOp) (bool, error)
source

IsLeftMost returns true if this is the left-most path in the tree, excluding placeholder (empty child) nodes

func IsLeftNeighbor

1func IsLeftNeighbor(spec *InnerSpec, left []*InnerOp, right []*InnerOp) (bool, error)
source

IsLeftNeighbor returns true if `right` is the next possible path right of `left`

Example
1Find the common suffix from the Left.Path and Right.Path and remove it. We have LPath and RPath now, which must be neighbors.
2Validate that LPath[len-1] is the left neighbor of RPath[len-1]
3For step in LPath[0..len-1], validate step is right-most node
4For step in RPath[0..len-1], validate step is left-most node

func IsRightMost

1func IsRightMost(spec *InnerSpec, path []*InnerOp) (bool, error)
source

IsRightMost returns true if this is the right-most path in the tree, excluding placeholder (empty child) nodes

func GetSDKProofSpecs

1func GetSDKProofSpecs() []*ProofSpec
source

GetSDKSpecs returns the proof specs of an SDK chain.

func IavlSpec

1func IavlSpec() *ProofSpec
source

IavlSpec constrains the format from proofs-iavl (iavl merkle proofs)

func TendermintSpec

1func TendermintSpec() *ProofSpec
source

TendermintSpec constrains the format from proofs-tendermint (crypto/merkle SimpleProof)

Types 11

type CommitmentProof

interface
1type CommitmentProof interface {
2	GetExist() *ExistenceProof
3	GetNonexist() *NonExistenceProof
4}
source

type CommitmentProof_Exist

struct
1type CommitmentProof_Exist struct {
2	Exist *ExistenceProof
3}
source

Methods on CommitmentProof_Exist

func GetExist

method on CommitmentProof_Exist
1func (c CommitmentProof_Exist) GetExist() *ExistenceProof
source

func GetNonexist

method on CommitmentProof_Exist
1func (c CommitmentProof_Exist) GetNonexist() *NonExistenceProof
source

type CommitmentProof_Nonexist

struct
1type CommitmentProof_Nonexist struct {
2	Nonexist *NonExistenceProof
3}
source

Methods on CommitmentProof_Nonexist

func GetExist

method on CommitmentProof_Nonexist
1func (c CommitmentProof_Nonexist) GetExist() *ExistenceProof
source

func GetNonexist

method on CommitmentProof_Nonexist
1func (c CommitmentProof_Nonexist) GetNonexist() *NonExistenceProof
source

type ExistenceProof

struct
1type ExistenceProof struct {
2	Key   []byte
3	Value []byte
4	Leaf  *LeafOp
5	Path  []*InnerOp
6}
source

ExistenceProof takes a key and a value and a set of steps to perform on it. The result of peforming all these steps will provide a "root hash", which can be compared to the value in a header.

Since it is computationally infeasible to produce a hash collission for any of the used cryptographic hash functions, if someone can provide a series of operations to transform a given key and value into a root hash that matches some trusted root, these key and values must be in the referenced merkle tree.

The only possible issue is maliablity in LeafOp, such as providing extra prefix data, which should be controlled by a spec. Eg. with lengthOp as NONE, prefix = FOO, key = BAR, value = CHOICE and prefix = F, key = OOBAR, value = CHOICE would produce the same value.

With LengthOp this is tricker but not impossible. Which is why the "leafPrefixEqual" field in the ProofSpec is valuable to prevent this mutability. And why all trees should length-prefix the data before hashing it.

Methods on ExistenceProof

func Calculate

method on ExistenceProof
1func (p *ExistenceProof) Calculate() ([]byte, error)
source

Calculate determines the root hash that matches the given proof. You must validate the result is what you have in a header. Returns error if the calculations cannot be performed.

func CheckAgainstSpec

method on ExistenceProof
1func (p *ExistenceProof) CheckAgainstSpec(spec *ProofSpec) error
source

CheckAgainstSpec will verify the leaf and all path steps are in the format defined in spec

func Verify

method on ExistenceProof
1func (p *ExistenceProof) Verify(spec *ProofSpec, root, key, value []byte) error
source

Verify does all checks to ensure this proof proves this key, value -> root and matches the spec.

type InnerOp

struct
1type InnerOp struct {
2	Hash   HashOp
3	Prefix []byte
4	Suffix []byte
5}
source

InnerOp represents a merkle-proof step that is not a leaf. It represents concatenating two children and hashing them to provide the next result.

The result of the previous step is passed in, so the signature of this op is: innerOp(child) -> output

The result of applying InnerOp should be: output = op.hash(op.prefix || child || op.suffix)

where the || operator is concatenation of binary data, and child is the result of hashing all the tree below this step.

Any special data, like prepending child with the length, or prepending the entire operation with some value to differentiate from leaf nodes, should be included in prefix and suffix. If either of prefix or suffix is empty, we just treat it as an empty string

Methods on InnerOp

func Apply

method on InnerOp
1func (op *InnerOp) Apply(child []byte) ([]byte, error)
source

Apply will calculate the hash of the next step, given the hash of the previous step

func CheckAgainstSpec

method on InnerOp
1func (op *InnerOp) CheckAgainstSpec(spec *ProofSpec, b int) error
source

CheckAgainstSpec will verify the InnerOp is in the format defined in spec

func GetHash

method on InnerOp
1func (m *InnerOp) GetHash() HashOp
source

func GetPrefix

method on InnerOp
1func (m *InnerOp) GetPrefix() []byte
source

type InnerSpec

struct
 1type InnerSpec struct {
 2	// Child order is the ordering of the children node, must count from 0
 3	// iavl tree is [0, 1] (left then right)
 4	// merk is [0, 2, 1] (left, right, here)
 5	ChildOrder      []int32
 6	ChildSize       int32
 7	MinPrefixLength int32
 8	MaxPrefixLength int32
 9	// empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0)
10	EmptyChild []byte
11	// hash is the algorithm that must be used for each InnerOp
12	Hash HashOp
13}
source

InnerSpec contains all store-specific structure info to determine if two proofs from a given store are neighbors.

This enables:

isLeftMost(spec: InnerSpec, op: InnerOp) isRightMost(spec: InnerSpec, op: InnerOp) isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp)

Methods on InnerSpec

func Equal

method on InnerSpec
1func (p *InnerSpec) Equal(other *InnerSpec) bool
source

Equal returns true if the two InnerSpec instances are deeply equal.

func ProtoMarshal

method on InnerSpec
1func (p *InnerSpec) ProtoMarshal() []byte
source

ProtoMarshal returns the proto3 wire encoding of the InnerSpec. ChildOrder is encoded as a packed repeated int32 field per proto3 default.

type LeafOp

struct
1type LeafOp struct {
2	Hash         HashOp
3	PrehashKey   HashOp
4	PrehashValue HashOp
5	Length       LengthOp
6	// prefix is a fixed bytes that may optionally be included at the beginning to differentiate
7	// a leaf node from an inner node.
8	Prefix []byte
9}
source

LeafOp represents the raw key-value data we wish to prove, and must be flexible to represent the internal transformation from the original key-value pairs into the basis hash, for many existing merkle trees.

key and value are passed in. So that the signature of this operation is: leafOp(key, value) -> output

To process this, first prehash the keys and values if needed (ANY means no hash in this case): hkey = prehashKey(key) hvalue = prehashValue(value)

Then combine the bytes, and hash it output = hash(prefix || length(hkey) || hkey || length(hvalue) || hvalue)

Methods on LeafOp

func Apply

method on LeafOp
1func (op *LeafOp) Apply(key []byte, value []byte) ([]byte, error)
source

Apply will calculate the leaf hash given the key and value being proven

func CheckAgainstSpec

method on LeafOp
1func (op *LeafOp) CheckAgainstSpec(spec *ProofSpec) error
source

CheckAgainstSpec will verify the LeafOp is in the format defined in spec

func Equal

method on LeafOp
1func (p *LeafOp) Equal(other *LeafOp) bool
source

Equal returns true if the two LeafOp instances are deeply equal.

func GetHash

method on LeafOp
1func (m *LeafOp) GetHash() HashOp
source

func GetPrefix

method on LeafOp
1func (m *LeafOp) GetPrefix() []byte
source

func ProtoMarshal

method on LeafOp
1func (p *LeafOp) ProtoMarshal() []byte
source

ProtoMarshal returns the proto3 wire encoding of the LeafOp.

type LengthOp

ident
1type LengthOp int32
source

LengthOp defines how to process the key and value of the LeafOp to include length information. After encoding the length with the given algorithm, the length will be prepended to the key and value bytes. (Each one with it's own encoded length)

type NonExistenceProof

struct
1type NonExistenceProof struct {
2	Key   []byte
3	Left  *ExistenceProof
4	Right *ExistenceProof
5}
source

NonExistenceProof takes a proof of two neighbors, one left of the desired key, one right of the desired key. If both proofs are valid AND they are neighbors, then there is no valid proof for the given key.

Methods on NonExistenceProof

func Calculate

method on NonExistenceProof
1func (p *NonExistenceProof) Calculate() ([]byte, error)
source

Calculate determines the root hash that matches the given nonexistence proof. You must validate the result is what you have in a header. Returns error if the calculations cannot be performed.

func Verify

method on NonExistenceProof
1func (p *NonExistenceProof) Verify(spec *ProofSpec, root, key []byte) error
source

Verify does all checks to ensure the proof has valid non-existence proofs, and they ensure the given key is not in the CommitmentState

type ProofSpec

struct
 1type ProofSpec struct {
 2	// any field in the ExistenceProof must be the same as in this spec.
 3	// except Prefix, which is just the first bytes of prefix (spec can be longer)
 4	LeafSpec  *LeafOp
 5	InnerSpec *InnerSpec
 6	// max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries)
 7	// the max_depth is interpreted as 128 if set to 0
 8	MaxDepth int32
 9	// min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries)
10	MinDepth int32
11	// prehash_key_before_comparison is a flag that indicates whether to use the
12	// prehash_key specified by LeafOp to compare lexical ordering of keys for
13	// non-existence proofs.
14	PrehashKeyBeforeComparison bool
15}
source

ProofSpec defines what the expected parameters are for a given proof type. This can be stored in the client and used to validate any incoming proofs.

verify(ProofSpec, Proof) -> Proof | Error

As demonstrated in tests, if we don't fix the algorithm used to calculate the LeafHash for a given tree, there are many possible key-value pairs that can generate a given hash (by interpretting the preimage differently). We need this for proper security, requires client knows a priori what tree format server uses. But not in code, rather a configuration object.

Methods on ProofSpec

func Equal

method on ProofSpec
1func (p *ProofSpec) Equal(other *ProofSpec) bool
source

Equal returns true if the two ProofSpec instances are deeply equal across every field. Use this when you need a strict content comparison (e.g. to detect attempts at substituting a different spec for an existing client). For the looser, "same shape" comparison historically used to route proof verification through IavlSpec/TendermintSpec, use SpecEquals instead.

func ProtoMarshal

method on ProofSpec
1func (p *ProofSpec) ProtoMarshal() []byte
source

ProtoMarshal returns the proto3 wire encoding of the ProofSpec, matching the format produced by gogoproto in cosmos/ics23. A nil receiver is encoded as an empty byte slice (proto3 unset message).

func SpecEquals

method on ProofSpec
1func (p *ProofSpec) SpecEquals(spec *ProofSpec) bool
source

SpecEquals returns true if two ProofSpec instances match on the subset of fields that matter for routing proof verification through a known spec (IavlSpec/TendermintSpec). It intentionally ignores MaxDepth/MinDepth, LeafOp.Prefix, ChildOrder contents, and InnerSpec.EmptyChild — it over-declares equality, which we consider fine for that use case. Use Equal for strict field-by-field comparison (e.g. RecoverClient).

Imports 6

Source Files 5