/
ics23.go
124 lines (116 loc) · 2.99 KB
/
ics23.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Here we implement proof generation according to the ICS-23 specification:
// https://github.com/cosmos/ibc/tree/master/spec/core/ics-023-vector-commitments
package smt
import (
"crypto/sha256"
"fmt"
dbm "github.com/mycodeku/transtionhelper/db"
ics23 "github.com/confio/ics23/go"
)
func createIcs23Proof(store *Store, key []byte) (*ics23.CommitmentProof, error) {
ret := &ics23.CommitmentProof{}
path := sha256.Sum256(key)
has, err := store.tree.Has(key)
if err != nil {
return nil, err
}
if has { // Membership proof
value, err := store.values.Get(path[:])
if err != nil {
return nil, err
}
if value == nil {
return nil, fmt.Errorf("value not found for: %v", key)
}
proof, err := store.tree.Prove(key)
if err != nil {
return nil, err
}
ret.Proof = &ics23.CommitmentProof_Exist{&ics23.ExistenceProof{
Key: path[:],
Value: value,
Leaf: ics23.SmtSpec.LeafSpec,
Path: convertInnerOps(path[:], proof.SideNodes),
}}
} else { // Non-membership
nonexist, err := toNonExistenceProof(store, path)
if err != nil {
return nil, err
}
ret.Proof = &ics23.CommitmentProof_Nonexist{nonexist}
}
return ret, nil
}
func toNonExistenceProof(store *Store, path [32]byte) (*ics23.NonExistenceProof, error) {
// Seek to our neighbors via the backing DB
getNext := func(it dbm.Iterator) (*ics23.ExistenceProof, error) {
defer it.Close()
if it.Next() {
value, err := store.values.Get(it.Key())
if err != nil {
return nil, err
}
if value == nil {
return nil, fmt.Errorf("value not found for: %v", it.Value())
}
proof, err := store.tree.Prove(it.Value()) // pass the preimage to Prove
if err != nil {
return nil, err
}
return &ics23.ExistenceProof{
Key: it.Key(),
Value: value,
Leaf: ics23.SmtSpec.LeafSpec,
Path: convertInnerOps(it.Key(), proof.SideNodes),
}, nil
}
return nil, nil
}
var lproof, rproof *ics23.ExistenceProof
it, err := store.preimages.ReverseIterator(nil, path[:])
if err != nil {
return nil, err
}
lproof, err = getNext(it)
if err != nil {
return nil, err
}
it, err = store.preimages.Iterator(path[:], nil)
if err != nil {
return nil, err
}
rproof, err = getNext(it)
if err != nil {
return nil, err
}
return &ics23.NonExistenceProof{
Key: path[:],
Left: lproof,
Right: rproof,
}, nil
}
func convertInnerOps(path []byte, sideNodes [][]byte) []*ics23.InnerOp {
depth := len(sideNodes)
inners := make([]*ics23.InnerOp, 0, depth)
for i := 0; i < len(sideNodes); i++ {
op := &ics23.InnerOp{
Hash: ics23.HashOp_SHA256,
Prefix: []byte{1},
}
if getBitAtFromMSB(path[:], depth-1-i) == 1 {
// right child is on path
op.Prefix = append(op.Prefix, sideNodes[i]...)
} else {
op.Suffix = sideNodes[i]
}
inners = append(inners, op)
}
return inners
}
// getBitAtFromMSB gets the bit at an offset from the most significant bit
func getBitAtFromMSB(data []byte, position int) int {
if int(data[position/8])&(1<<(8-1-uint(position)%8)) > 0 {
return 1
}
return 0
}