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}