@@ -58,12 +58,14 @@ type Proof struct {
58
58
Cs []* Point // commitments, sorted by their path in the tree
59
59
PoaStems [][]byte // stems proving another stem is absent
60
60
Keys [][]byte
61
- Values [][]byte
61
+ PreValues [][]byte
62
+ PostValues [][]byte
62
63
}
63
64
64
65
type SuffixStateDiff struct {
65
66
Suffix byte `json:"suffix"`
66
67
CurrentValue * [32 ]byte `json:"currentValue"`
68
+ NewValue * [32 ]byte `json:"newValue"`
67
69
}
68
70
69
71
type SuffixStateDiffs []SuffixStateDiff
@@ -80,38 +82,78 @@ func GetCommitmentsForMultiproof(root VerkleNode, keys [][]byte, resolver NodeRe
80
82
return root .GetProofItems (keylist (keys ), resolver )
81
83
}
82
84
83
- func MakeVerkleMultiProof (root VerkleNode , keys [][]byte , resolver NodeResolverFn ) (* Proof , []* Point , []byte , []* Fr , error ) {
85
+ // getProofElementsFromTree factors the logic that is used both in the proving and verification methods. It takes a pre-state
86
+ // tree and an optional post-state tree, extracts the proof data from them and returns all the items required to build/verify
87
+ // a proof.
88
+ func getProofElementsFromTree (preroot , postroot VerkleNode , keys [][]byte , resolver NodeResolverFn ) (* ProofElements , []byte , [][]byte , [][]byte , []* Point , [][]Fr , []* Fr , []byte , error ) {
84
89
// go-ipa won't accept no key as an input, catch this corner case
85
90
// and return an empty result.
86
91
if len (keys ) == 0 {
87
- return nil , nil , nil , nil , errors .New ("no key provided for proof" )
92
+ return nil , nil , nil , nil , nil , nil , nil , nil , errors .New ("no key provided for proof" )
88
93
}
89
94
90
- tr := common .NewTranscript ("vt" )
91
- root .Commit ()
95
+ pe , es , poas , err := GetCommitmentsForMultiproof (preroot , keys , resolver )
96
+ if err != nil {
97
+ return nil , nil , nil , nil , nil , nil , nil , nil , fmt .Errorf ("error getting pre-state proof data: %w" , err )
98
+ }
99
+
100
+ // List of points and vectors and indices used to generate the IPA proof
101
+ // If only a pre-state root is available, it's a simple copy, but if both
102
+ // pre- and post-state root are present, it's merging the two lists.
103
+ var (
104
+ proof_cis []* Point
105
+ proof_fs [][]Fr
106
+ proof_zs []uint8
107
+ proof_ys []* Fr
108
+ postvals = make ([][]byte , len (keys ))
109
+ )
110
+ for i := range pe .Cis {
111
+ proof_cis = append (proof_cis , pe .Cis [i ])
112
+ proof_fs = append (proof_fs , pe .Fis [i ])
113
+ proof_ys = append (proof_ys , pe .Yis [i ])
114
+ proof_zs = append (proof_zs , pe .Zis [i ])
115
+ }
92
116
93
- pe , es , poas , err := GetCommitmentsForMultiproof (root , keys , resolver )
117
+ // if a post-state tree is present, merge its proof elements with
118
+ // those of the pre-state tree, so that they can be proved together.
119
+ if postroot != nil {
120
+ pe_post , _ , _ , err := GetCommitmentsForMultiproof (postroot , keys , resolver )
121
+ if err != nil {
122
+ return nil , nil , nil , nil , nil , nil , nil , nil , fmt .Errorf ("error getting post-state proof data: %w" , err )
123
+ }
124
+
125
+ for i := range pe_post .Cis {
126
+ proof_cis = append (proof_cis , pe_post .Cis [i ])
127
+ proof_fs = append (proof_fs , pe_post .Fis [i ])
128
+ proof_ys = append (proof_ys , pe_post .Yis [i ])
129
+ proof_zs = append (proof_zs , pe_post .Zis [i ])
130
+ }
131
+
132
+ // Set the post values, if they are untouched, leave them `nil`
133
+ for i , v := range pe .Vals {
134
+ if ! bytes .Equal (v , pe_post .Vals [i ]) {
135
+ postvals [i ] = pe_post .Vals [i ]
136
+ }
137
+ }
138
+ }
139
+
140
+ // [0:3]: proof elements of the pre-state trie for serialization,
141
+ // 3: values to be inserted in the post-state trie for serialization
142
+ // [4:8]: aggregated pre+post elements for proving
143
+ return pe , es , poas , postvals , proof_cis , proof_fs , proof_ys , proof_zs , nil
144
+ }
145
+
146
+ func MakeVerkleMultiProof (preroot , postroot VerkleNode , keys [][]byte , resolver NodeResolverFn ) (* Proof , []* Point , []byte , []* Fr , error ) {
147
+ pe , es , poas , postvals , proof_cis , proof_fs , _ , proof_zs , err := getProofElementsFromTree (preroot , postroot , keys , resolver )
94
148
if err != nil {
95
149
return nil , nil , nil , nil , fmt .Errorf ("get commitments for multiproof: %s" , err )
96
150
}
97
151
98
- // NOTE this is leftover code from the time the proof was
99
- // made against the POST state. Since proofs are expected
100
- // to prove PRE and POST state in the future, I'm leaving
101
- // this for reference - eventhough it's unlikely that the
102
- // final version will look like this, but you never know.
103
- // var vals [][]byte
104
- // for _, k := range keys {
105
- // // TODO at the moment, do not include the post-data
106
- // // val, _ := root.Get(k, nil)
107
- // // vals = append(vals, val)
108
- // vals = append(vals, keyvals[string(k)])
109
- // }
110
-
111
152
cfg := GetConfig ()
112
- mpArg , err := ipa .CreateMultiProof (tr , cfg .conf , pe .Cis , pe .Fis , pe .Zis )
153
+ tr := common .NewTranscript ("vt" )
154
+ mpArg , err := ipa .CreateMultiProof (tr , cfg .conf , proof_cis , proof_fs , proof_zs )
113
155
if err != nil {
114
- return nil , nil , nil , nil , fmt .Errorf ("creating multiproof: %s " , err )
156
+ return nil , nil , nil , nil , fmt .Errorf ("creating multiproof: %w " , err )
115
157
}
116
158
117
159
// It's wheel-reinvention time again 🎉: reimplement a basic
@@ -130,17 +172,34 @@ func MakeVerkleMultiProof(root VerkleNode, keys [][]byte, resolver NodeResolverF
130
172
for i , path := range paths {
131
173
cis [i ] = pe .ByPath [path ]
132
174
}
175
+
133
176
proof := & Proof {
134
177
Multipoint : mpArg ,
135
178
Cs : cis ,
136
179
ExtStatus : es ,
137
180
PoaStems : poas ,
138
181
Keys : keys ,
139
- Values : pe .Vals ,
182
+ PreValues : pe .Vals ,
183
+ PostValues : postvals ,
140
184
}
141
185
return proof , pe .Cis , pe .Zis , pe .Yis , nil
142
186
}
143
187
188
+ // VerifyVerkleProofWithPreAndPostTrie takes a pre-state trie, a post-state trie and a list of keys, and verifies that
189
+ // the provided proof verifies. If the post-state trie is `nil`, the behavior is the same as `VerifyVerkleProof`.
190
+ func VerifyVerkleProofWithPreAndPostTrie (proof * Proof , preroot , postroot VerkleNode ) error {
191
+ _ , _ , _ , _ , proof_cis , _ , proof_ys , proof_zs , err := getProofElementsFromTree (preroot , postroot , proof .Keys , nil )
192
+ if err != nil {
193
+ return fmt .Errorf ("error getting proof elements: %w" , err )
194
+ }
195
+
196
+ if ok , err := VerifyVerkleProof (proof , proof_cis , proof_zs , proof_ys , GetConfig ()); ! ok || err != nil {
197
+ return fmt .Errorf ("error verifying proof: verifies=%v, error=%w" , ok , err )
198
+ }
199
+
200
+ return nil
201
+ }
202
+
144
203
func VerifyVerkleProof (proof * Proof , Cs []* Point , indices []uint8 , ys []* Fr , tc * Config ) (bool , error ) {
145
204
tr := common .NewTranscript ("vt" )
146
205
return ipa .CheckMultiProof (tr , tc .conf , proof .Multipoint , Cs , ys , indices )
@@ -181,26 +240,35 @@ func SerializeProof(proof *Proof) (*VerkleProof, StateDiff, error) {
181
240
stemdiff = & statediff [len (statediff )- 1 ]
182
241
copy (stemdiff .Stem [:], key [:31 ])
183
242
}
184
- var valueLen = len (proof .Values [i ])
243
+ stemdiff .SuffixDiffs = append (stemdiff .SuffixDiffs , SuffixStateDiff {Suffix : key [31 ]})
244
+ newsd := & stemdiff .SuffixDiffs [len (stemdiff .SuffixDiffs )- 1 ]
245
+
246
+ var valueLen = len (proof .PreValues [i ])
247
+ switch valueLen {
248
+ case 0 :
249
+ // null value
250
+ case 32 :
251
+ newsd .CurrentValue = (* [32 ]byte )(proof .PreValues [i ])
252
+ default :
253
+ var aligned [32 ]byte
254
+ copy (aligned [:valueLen ], proof .PreValues [i ])
255
+ newsd .CurrentValue = (* [32 ]byte )(unsafe .Pointer (& aligned [0 ]))
256
+ }
257
+
258
+ valueLen = len (proof .PostValues [i ])
185
259
switch valueLen {
186
260
case 0 :
187
- stemdiff .SuffixDiffs = append (stemdiff .SuffixDiffs , SuffixStateDiff {
188
- Suffix : key [31 ],
189
- })
261
+ // null value
190
262
case 32 :
191
- stemdiff .SuffixDiffs = append (stemdiff .SuffixDiffs , SuffixStateDiff {
192
- Suffix : key [31 ],
193
- CurrentValue : (* [32 ]byte )(proof .Values [i ]),
194
- })
263
+ newsd .NewValue = (* [32 ]byte )(proof .PostValues [i ])
195
264
default :
265
+ // TODO remove usage of unsafe
196
266
var aligned [32 ]byte
197
- copy (aligned [:valueLen ], proof .Values [i ])
198
- stemdiff .SuffixDiffs = append (stemdiff .SuffixDiffs , SuffixStateDiff {
199
- Suffix : key [31 ],
200
- CurrentValue : (* [32 ]byte )(unsafe .Pointer (& aligned [0 ])),
201
- })
267
+ copy (aligned [:valueLen ], proof .PostValues [i ])
268
+ newsd .NewValue = (* [32 ]byte )(unsafe .Pointer (& aligned [0 ]))
202
269
}
203
270
}
271
+
204
272
return & VerkleProof {
205
273
OtherStems : otherstems ,
206
274
DepthExtensionPresent : proof .ExtStatus ,
@@ -218,10 +286,11 @@ func SerializeProof(proof *Proof) (*VerkleProof, StateDiff, error) {
218
286
// can be used to rebuild a stateless version of the tree.
219
287
func DeserializeProof (vp * VerkleProof , statediff StateDiff ) (* Proof , error ) {
220
288
var (
221
- poaStems , keys , values [][]byte
222
- extStatus []byte
223
- commitments []* Point
224
- multipoint ipa.MultiProof
289
+ poaStems , keys [][]byte
290
+ prevalues , postvalues [][]byte
291
+ extStatus []byte
292
+ commitments []* Point
293
+ multipoint ipa.MultiProof
225
294
)
226
295
227
296
poaStems = make ([][]byte , len (vp .OtherStems ))
@@ -259,9 +328,15 @@ func DeserializeProof(vp *VerkleProof, statediff StateDiff) (*Proof, error) {
259
328
k [31 ] = suffixdiff .Suffix
260
329
keys = append (keys , k [:])
261
330
if suffixdiff .CurrentValue != nil {
262
- values = append (values , suffixdiff .CurrentValue [:])
331
+ prevalues = append (prevalues , suffixdiff .CurrentValue [:])
263
332
} else {
264
- values = append (values , nil )
333
+ prevalues = append (prevalues , nil )
334
+ }
335
+
336
+ if suffixdiff .NewValue != nil {
337
+ postvalues = append (postvalues , suffixdiff .NewValue [:])
338
+ } else {
339
+ postvalues = append (postvalues , nil )
265
340
}
266
341
}
267
342
}
@@ -272,7 +347,8 @@ func DeserializeProof(vp *VerkleProof, statediff StateDiff) (*Proof, error) {
272
347
commitments ,
273
348
poaStems ,
274
349
keys ,
275
- values ,
350
+ prevalues ,
351
+ postvalues ,
276
352
}
277
353
return & proof , nil
278
354
}
@@ -285,8 +361,8 @@ type stemInfo struct {
285
361
stem []byte
286
362
}
287
363
288
- // TreeFromProof builds a stateless tree from the proof
289
- func TreeFromProof (proof * Proof , rootC * Point ) (VerkleNode , error ) { // skipcq: GO-R1005
364
+ // PreStateTreeFromProof builds a stateless prestate tree from the proof.
365
+ func PreStateTreeFromProof (proof * Proof , rootC * Point ) (VerkleNode , error ) { // skipcq: GO-R1005
290
366
stems := make ([][]byte , 0 , len (proof .Keys ))
291
367
for _ , k := range proof .Keys {
292
368
if len (stems ) == 0 || ! bytes .Equal (stems [len (stems )- 1 ], k [:31 ]) {
@@ -322,8 +398,8 @@ func TreeFromProof(proof *Proof, rootC *Point) (VerkleNode, error) { // skipcq:
322
398
stemPath := stems [stemIndex ][:len (path )]
323
399
si .values = map [byte ][]byte {}
324
400
for i , k := range proof .Keys {
325
- if bytes .Equal (k [:len (path )], stemPath ) && proof .Values [i ] != nil {
326
- si .values [k [31 ]] = proof .Values [i ]
401
+ if bytes .Equal (k [:len (path )], stemPath ) && proof .PreValues [i ] != nil {
402
+ si .values [k [31 ]] = proof .PreValues [i ]
327
403
si .has_c1 = si .has_c1 || (k [31 ] < 128 )
328
404
si .has_c2 = si .has_c2 || (k [31 ] >= 128 )
329
405
// This key has values, its stem is the one that
@@ -356,14 +432,14 @@ func TreeFromProof(proof *Proof, rootC *Point) (VerkleNode, error) { // skipcq:
356
432
// but not for block validation.
357
433
values := make ([][]byte , NodeWidth )
358
434
for i , k := range proof .Keys {
359
- if len (proof .Values [i ]) == 0 {
435
+ if len (proof .PreValues [i ]) == 0 {
360
436
// Skip the nil keys, they are here to prove
361
437
// an absence.
362
438
continue
363
439
}
364
440
365
441
if bytes .Equal (k [:31 ], info [string (p )].stem ) {
366
- values [k [31 ]] = proof .Values [i ]
442
+ values [k [31 ]] = proof .PreValues [i ]
367
443
}
368
444
}
369
445
comms , err = root .CreatePath (p , info [string (p )], comms , values )
@@ -374,3 +450,36 @@ func TreeFromProof(proof *Proof, rootC *Point) (VerkleNode, error) { // skipcq:
374
450
375
451
return root , nil
376
452
}
453
+
454
+ // PostStateTreeFromProof uses the pre-state trie and the list of updated values
455
+ // to produce the stateless post-state trie.
456
+ func PostStateTreeFromProof (preroot VerkleNode , statediff StateDiff ) (VerkleNode , error ) {
457
+ postroot := preroot .Copy ()
458
+
459
+ for _ , stemstatediff := range statediff {
460
+ var (
461
+ values = make ([][]byte , NodeWidth )
462
+ overwrites bool
463
+ )
464
+
465
+ for _ , suffixdiff := range stemstatediff .SuffixDiffs {
466
+ if /* len(suffixdiff.NewValue) > 0 - this only works for a slice */ suffixdiff .NewValue != nil {
467
+ // if this value is non-nil, it means InsertStem should be
468
+ // called, otherwise, skip updating the tree.
469
+ overwrites = true
470
+ values [suffixdiff .Suffix ] = suffixdiff .NewValue [:]
471
+ }
472
+ }
473
+
474
+ if overwrites {
475
+ var stem [31 ]byte
476
+ copy (stem [:31 ], stemstatediff .Stem [:])
477
+ if err := postroot .(* InternalNode ).InsertStem (stem [:], values , nil ); err != nil {
478
+ return nil , fmt .Errorf ("error overwriting value in post state: %w" , err )
479
+ }
480
+ }
481
+ }
482
+ postroot .Commit ()
483
+
484
+ return postroot , nil
485
+ }
0 commit comments