1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package proof
16
17 import (
18 "bytes"
19 "errors"
20 "fmt"
21 "math/bits"
22
23 "github.com/transparency-dev/merkle"
24 )
25
26
27 type RootMismatchError struct {
28 ExpectedRoot []byte
29 CalculatedRoot []byte
30 }
31
32 func (e RootMismatchError) Error() string {
33 return fmt.Sprintf("calculated root:\n%v\n does not match expected root:\n%v", e.CalculatedRoot, e.ExpectedRoot)
34 }
35
36 func verifyMatch(calculated, expected []byte) error {
37 if !bytes.Equal(calculated, expected) {
38 return RootMismatchError{ExpectedRoot: expected, CalculatedRoot: calculated}
39 }
40 return nil
41 }
42
43
44
45
46 func VerifyInclusion(hasher merkle.LogHasher, index, size uint64, leafHash []byte, proof [][]byte, root []byte) error {
47 calcRoot, err := RootFromInclusionProof(hasher, index, size, leafHash, proof)
48 if err != nil {
49 return err
50 }
51 return verifyMatch(calcRoot, root)
52 }
53
54
55
56
57 func RootFromInclusionProof(hasher merkle.LogHasher, index, size uint64, leafHash []byte, proof [][]byte) ([]byte, error) {
58 if index >= size {
59 return nil, fmt.Errorf("index is beyond size: %d >= %d", index, size)
60 }
61 if got, want := len(leafHash), hasher.Size(); got != want {
62 return nil, fmt.Errorf("leafHash has unexpected size %d, want %d", got, want)
63 }
64
65 inner, border := decompInclProof(index, size)
66 if got, want := len(proof), inner+border; got != want {
67 return nil, fmt.Errorf("wrong proof size %d, want %d", got, want)
68 }
69
70 res := chainInner(hasher, leafHash, proof[:inner], index)
71 res = chainBorderRight(hasher, res, proof[inner:])
72 return res, nil
73 }
74
75
76
77
78 func VerifyConsistency(hasher merkle.LogHasher, size1, size2 uint64, proof [][]byte, root1, root2 []byte) error {
79 switch {
80 case size2 < size1:
81 return fmt.Errorf("size2 (%d) < size1 (%d)", size1, size2)
82 case size1 == size2:
83 if len(proof) > 0 {
84 return errors.New("size1=size2, but proof is not empty")
85 }
86 return verifyMatch(root1, root2)
87 case size1 == 0:
88
89 if len(proof) > 0 {
90 return fmt.Errorf("expected empty proof, but got %d components", len(proof))
91 }
92 return nil
93 case len(proof) == 0:
94 return errors.New("empty proof")
95 }
96
97 inner, border := decompInclProof(size1-1, size2)
98 shift := bits.TrailingZeros64(size1)
99 inner -= shift
100
101
102 seed, start := proof[0], 1
103 if size1 == 1<<uint(shift) {
104 seed, start = root1, 0
105 }
106 if got, want := len(proof), start+inner+border; got != want {
107 return fmt.Errorf("wrong proof size %d, want %d", got, want)
108 }
109 proof = proof[start:]
110
111
112
113
114 mask := (size1 - 1) >> uint(shift)
115 hash1 := chainInnerRight(hasher, seed, proof[:inner], mask)
116 hash1 = chainBorderRight(hasher, hash1, proof[inner:])
117 if err := verifyMatch(hash1, root1); err != nil {
118 return err
119 }
120
121
122 hash2 := chainInner(hasher, seed, proof[:inner], mask)
123 hash2 = chainBorderRight(hasher, hash2, proof[inner:])
124 return verifyMatch(hash2, root2)
125 }
126
127
128
129
130
131
132 func decompInclProof(index, size uint64) (int, int) {
133 inner := innerProofSize(index, size)
134 border := bits.OnesCount64(index >> uint(inner))
135 return inner, border
136 }
137
138 func innerProofSize(index, size uint64) int {
139 return bits.Len64(index ^ (size - 1))
140 }
141
142
143
144
145
146 func chainInner(hasher merkle.LogHasher, seed []byte, proof [][]byte, index uint64) []byte {
147 for i, h := range proof {
148 if (index>>uint(i))&1 == 0 {
149 seed = hasher.HashChildren(seed, h)
150 } else {
151 seed = hasher.HashChildren(h, seed)
152 }
153 }
154 return seed
155 }
156
157
158
159
160 func chainInnerRight(hasher merkle.LogHasher, seed []byte, proof [][]byte, index uint64) []byte {
161 for i, h := range proof {
162 if (index>>uint(i))&1 == 1 {
163 seed = hasher.HashChildren(h, seed)
164 }
165 }
166 return seed
167 }
168
169
170
171 func chainBorderRight(hasher merkle.LogHasher, seed []byte, proof [][]byte) []byte {
172 for _, h := range proof {
173 seed = hasher.HashChildren(h, seed)
174 }
175 return seed
176 }
177
View as plain text