Search Apps Documentation Source Content File Folder Download Copy Actions Download

specs.gno

4.90 Kb · 147 lines
  1package ics23
  2
  3import (
  4	"gno.land/p/aib/encoding/proto"
  5)
  6
  7// GetSDKSpecs returns the proof specs of an SDK chain.
  8func GetSDKProofSpecs() []*ProofSpec {
  9	return []*ProofSpec{IavlSpec(), TendermintSpec()}
 10}
 11
 12// IavlSpec constrains the format from proofs-iavl (iavl merkle proofs)
 13func IavlSpec() *ProofSpec {
 14	return &ProofSpec{
 15		LeafSpec: &LeafOp{
 16			Prefix:       []byte{0},
 17			PrehashKey:   HashOp_NO_HASH,
 18			Hash:         HashOp_SHA256,
 19			PrehashValue: HashOp_SHA256,
 20			Length:       LengthOp_VAR_PROTO,
 21		},
 22		InnerSpec: &InnerSpec{
 23			ChildOrder:      []int32{0, 1},
 24			MinPrefixLength: 4,
 25			MaxPrefixLength: 12,
 26			ChildSize:       33, // (with length byte)
 27			EmptyChild:      nil,
 28			Hash:            HashOp_SHA256,
 29		},
 30	}
 31}
 32
 33// TendermintSpec constrains the format from proofs-tendermint (crypto/merkle SimpleProof)
 34func TendermintSpec() *ProofSpec {
 35	return &ProofSpec{
 36		LeafSpec: &LeafOp{
 37			Prefix:       []byte{0},
 38			PrehashKey:   HashOp_NO_HASH,
 39			Hash:         HashOp_SHA256,
 40			PrehashValue: HashOp_SHA256,
 41			Length:       LengthOp_VAR_PROTO,
 42		},
 43		InnerSpec: &InnerSpec{
 44			ChildOrder:      []int32{0, 1},
 45			MinPrefixLength: 1,
 46			MaxPrefixLength: 1,
 47			ChildSize:       32, // (no length byte)
 48			Hash:            HashOp_SHA256,
 49		},
 50	}
 51}
 52
 53// ProofSpec defines what the expected parameters are for a given proof type.
 54// This can be stored in the client and used to validate any incoming proofs.
 55//
 56// verify(ProofSpec, Proof) -> Proof | Error
 57//
 58// As demonstrated in tests, if we don't fix the algorithm used to calculate the
 59// LeafHash for a given tree, there are many possible key-value pairs that can
 60// generate a given hash (by interpretting the preimage differently).
 61// We need this for proper security, requires client knows a priori what
 62// tree format server uses. But not in code, rather a configuration object.
 63type ProofSpec struct {
 64	// any field in the ExistenceProof must be the same as in this spec.
 65	// except Prefix, which is just the first bytes of prefix (spec can be longer)
 66	LeafSpec  *LeafOp
 67	InnerSpec *InnerSpec
 68	// max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries)
 69	// the max_depth is interpreted as 128 if set to 0
 70	MaxDepth int32
 71	// min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries)
 72	MinDepth int32
 73	// prehash_key_before_comparison is a flag that indicates whether to use the
 74	// prehash_key specified by LeafOp to compare lexical ordering of keys for
 75	// non-existence proofs.
 76	PrehashKeyBeforeComparison bool
 77}
 78
 79// InnerSpec contains all store-specific structure info to determine if two proofs from a
 80// given store are neighbors.
 81//
 82// This enables:
 83//
 84// isLeftMost(spec: InnerSpec, op: InnerOp)
 85// isRightMost(spec: InnerSpec, op: InnerOp)
 86// isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp)
 87type InnerSpec struct {
 88	// Child order is the ordering of the children node, must count from 0
 89	// iavl tree is [0, 1] (left then right)
 90	// merk is [0, 2, 1] (left, right, here)
 91	ChildOrder      []int32
 92	ChildSize       int32
 93	MinPrefixLength int32
 94	MaxPrefixLength int32
 95	// empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0)
 96	EmptyChild []byte
 97	// hash is the algorithm that must be used for each InnerOp
 98	Hash HashOp
 99}
100
101// ProtoMarshal returns the proto3 wire encoding of the ProofSpec, matching
102// the format produced by gogoproto in cosmos/ics23. A nil receiver is encoded
103// as an empty byte slice (proto3 unset message).
104func (p *ProofSpec) ProtoMarshal() []byte {
105	if p == nil {
106		return nil
107	}
108	var bz []byte
109	bz = proto.AppendLengthDelimited(bz, 1, p.LeafSpec.ProtoMarshal())
110	bz = proto.AppendLengthDelimited(bz, 2, p.InnerSpec.ProtoMarshal())
111	bz = proto.AppendVarint(bz, 3, uint64(int64(p.MaxDepth)))
112	bz = proto.AppendVarint(bz, 4, uint64(int64(p.MinDepth)))
113	if p.PrehashKeyBeforeComparison {
114		bz = proto.AppendVarint(bz, 5, 1)
115	}
116	return bz
117}
118
119// ProtoMarshal returns the proto3 wire encoding of the LeafOp.
120func (p *LeafOp) ProtoMarshal() []byte {
121	if p == nil {
122		return nil
123	}
124	var bz []byte
125	bz = proto.AppendVarint(bz, 1, uint64(int64(p.Hash)))
126	bz = proto.AppendVarint(bz, 2, uint64(int64(p.PrehashKey)))
127	bz = proto.AppendVarint(bz, 3, uint64(int64(p.PrehashValue)))
128	bz = proto.AppendVarint(bz, 4, uint64(int64(p.Length)))
129	bz = proto.AppendLengthDelimited(bz, 5, p.Prefix)
130	return bz
131}
132
133// ProtoMarshal returns the proto3 wire encoding of the InnerSpec. ChildOrder
134// is encoded as a packed repeated int32 field per proto3 default.
135func (p *InnerSpec) ProtoMarshal() []byte {
136	if p == nil {
137		return nil
138	}
139	var bz []byte
140	bz = proto.AppendPackedVarintInt32(bz, 1, p.ChildOrder)
141	bz = proto.AppendVarint(bz, 2, uint64(int64(p.ChildSize)))
142	bz = proto.AppendVarint(bz, 3, uint64(int64(p.MinPrefixLength)))
143	bz = proto.AppendVarint(bz, 4, uint64(int64(p.MaxPrefixLength)))
144	bz = proto.AppendLengthDelimited(bz, 5, p.EmptyChild)
145	bz = proto.AppendVarint(bz, 6, uint64(int64(p.Hash)))
146	return bz
147}