@@ -83,58 +83,6 @@ proc chainRlpNodes(
8383 # Recursion!
8484 db.chainRlpNodes ((rvid.root,vtx.bVid (nibble)), rest, chain, nodesCache)
8585
86-
87- proc trackRlpNodes (
88- chain: openArray [seq [byte ]];
89- topKey: HashKey ;
90- path: NibblesBuf ;
91- start = false ;
92- ): Result [seq [byte ], AristoError ]
93- {.gcsafe , raises : [RlpError ]} =
94- # # Verify rlp-encoded node chain created by `chainRlpNodes()`.
95- if path.len == 0 :
96- return err (PartTrkEmptyPath )
97- if chain.len () == 0 :
98- return err (PartTrkEmptyProof )
99-
100- # Verify key against rlp-node
101- let digest = chain[0 ].digestTo (HashKey )
102- if start:
103- if topKey.to (Hash32 ) != digest.to (Hash32 ):
104- return err (PartTrkFollowUpKeyMismatch )
105- else :
106- if topKey != digest:
107- return err (PartTrkFollowUpKeyMismatch )
108-
109- var
110- node = rlpFromBytes chain[0 ]
111- nChewOff = 0
112- link: seq [byte ]
113-
114- # Decode rlp-node and prepare for recursion
115- case node.listLen
116- of 2 :
117- let (isLeaf, segm) = NibblesBuf .fromHexPrefix node.listElem (0 ).toBytes
118- nChewOff = sharedPrefixLen (path, segm)
119- link = node.listElem (1 ).toBytes # link or payload
120- if isLeaf:
121- if nChewOff == path.len:
122- return ok (link)
123- return err (PartTrkLeafPfxMismatch )
124- of 17 :
125- nChewOff = 1
126- link = node.listElem (path[0 ].int ).toBytes
127- else :
128- return err (PartTrkGarbledNode )
129-
130- let nextKey = HashKey .fromBytes (link).valueOr:
131- return err (PartTrkLinkExpected )
132-
133- if chain.len () > 1 :
134- chain.toOpenArray (1 , chain.len () - 1 ).trackRlpNodes (nextKey, path.slice nChewOff)
135- else :
136- err (PartTrkLinkExpected )
137-
13886proc makeProof (
13987 db: AristoTxRef ;
14088 root: VertexID ;
@@ -251,16 +199,148 @@ proc makeMultiProof*(
251199
252200 ok ()
253201
202+ proc trackRlpNodes (
203+ chain: openArray [seq [byte ]];
204+ nextIndex: int ;
205+ topKey: HashKey ;
206+ path: NibblesBuf ;
207+ start = false ;
208+ ): Result [seq [byte ], AristoError ]
209+ {.gcsafe , raises : [RlpError ]} =
210+ # # Verify rlp-encoded node chain created by `chainRlpNodes()`.
211+
212+ if nextIndex > chain.high:
213+ return err (PartTrkLinkExpected )
214+ if path.len == 0 :
215+ return err (PartTrkEmptyPath )
216+
217+ # Verify key against rlp-node
218+ let digest = chain[nextIndex].digestTo (HashKey )
219+ if start:
220+ if topKey.to (Hash32 ) != digest.to (Hash32 ):
221+ return err (PartTrkFollowUpKeyMismatch )
222+ else :
223+ if topKey != digest:
224+ return err (PartTrkFollowUpKeyMismatch )
225+
226+ var
227+ rlpNode = rlpFromBytes chain[nextIndex]
228+ nChewOff = 0
229+ link: seq [byte ]
230+
231+ # Decode rlp-node and prepare for recursion
232+ case rlpNode.listLen
233+ of 2 :
234+ let (isLeaf, segm) = NibblesBuf .fromHexPrefix rlpNode.listElem (0 ).toBytes
235+ nChewOff = sharedPrefixLen (path, segm)
236+ link = rlpNode.listElem (1 ).toBytes # link or payload
237+ if isLeaf:
238+ if nChewOff == path.len:
239+ return ok (link)
240+ return err (PartTrkLeafPfxMismatch )
241+ of 17 :
242+ nChewOff = 1
243+ link = rlpNode.listElem (path[0 ].int ).toBytes
244+ else :
245+ return err (PartTrkGarbledNode )
246+
247+ let nextKey = HashKey .fromBytes (link).valueOr:
248+ return err (PartTrkLinkExpected )
249+
250+ trackRlpNodes (chain, nextIndex + 1 , nextKey, path.slice nChewOff)
251+
252+ proc trackRlpNodes (
253+ nodes: Table [Hash32 , seq [byte ]];
254+ visitedNodes: var HashSet [Hash32 ];
255+ topKey: HashKey ;
256+ path: NibblesBuf ;
257+ start = false ;
258+ ): Result [seq [byte ], AristoError ]
259+ {.gcsafe , raises : [RlpError ]} =
260+ # # Verify rlp-encoded node chain created by `chainRlpNodes()`.
261+
262+ let nodeHash = topKey.to (Hash32 )
263+ if visitedNodes.contains (nodeHash):
264+ return err (PartTrkFollowUpKeyMismatch )
265+ if nodeHash notin nodes:
266+ if start:
267+ return err (PartTrkFollowUpKeyMismatch )
268+ else :
269+ return err (PartTrkLinkExpected )
270+ if path.len == 0 :
271+ return err (PartTrkEmptyPath )
272+
273+ let node = nodes.getOrDefault (nodeHash)
274+ visitedNodes.incl (nodeHash)
275+
276+ # Verify key against rlp-node
277+ let digest = node.digestTo (HashKey )
278+ if start:
279+ if topKey.to (Hash32 ) != digest.to (Hash32 ):
280+ return err (PartTrkFollowUpKeyMismatch )
281+ else :
282+ if topKey != digest:
283+ return err (PartTrkFollowUpKeyMismatch )
284+
285+ var
286+ rlpNode = rlpFromBytes node
287+ nChewOff = 0
288+ link: seq [byte ]
289+
290+ # Decode rlp-node and prepare for recursion
291+ case rlpNode.listLen
292+ of 2 :
293+ let (isLeaf, segm) = NibblesBuf .fromHexPrefix rlpNode.listElem (0 ).toBytes
294+ nChewOff = sharedPrefixLen (path, segm)
295+ link = rlpNode.listElem (1 ).toBytes # link or payload
296+ if isLeaf:
297+ if nChewOff == path.len:
298+ return ok (link)
299+ return err (PartTrkLeafPfxMismatch )
300+ of 17 :
301+ nChewOff = 1
302+ link = rlpNode.listElem (path[0 ].int ).toBytes
303+ else :
304+ return err (PartTrkGarbledNode )
305+
306+ let nextKey = HashKey .fromBytes (link).valueOr:
307+ return err (PartTrkLinkExpected )
308+
309+ trackRlpNodes (nodes, visitedNodes, nextKey, path.slice nChewOff)
310+
254311proc verifyProof * (
255312 chain: openArray [seq [byte ]];
256313 root: Hash32 ;
257314 path: Hash32 ;
258315 ): Result [Opt [seq [byte ]], AristoError ] =
259- # # Variant of `partUntwigGeneric()`.
316+ if chain.len () == 0 :
317+ return err (PartTrkEmptyProof )
318+
319+ try :
320+ let
321+ nibbles = NibblesBuf .fromBytes path.data
322+ rc = trackRlpNodes (chain, 0 , root.to (HashKey ), nibbles, start= true )
323+ if rc.isOk:
324+ return ok (Opt .some rc.value)
325+ if rc.error in TrackRlpNodesNoEntry :
326+ return ok (Opt .none seq [byte ])
327+ return err (rc.error)
328+ except RlpError :
329+ return err (PartTrkRlpError )
330+
331+ proc verifyProof * (
332+ nodes: Table [Hash32 , seq [byte ]];
333+ root: Hash32 ;
334+ path: Hash32 ;
335+ ): Result [Opt [seq [byte ]], AristoError ] =
336+ if nodes.len () == 0 :
337+ return err (PartTrkEmptyProof )
338+
260339 try :
340+ var visitedNodes: HashSet [Hash32 ]
261341 let
262342 nibbles = NibblesBuf .fromBytes path.data
263- rc = chain. trackRlpNodes (root.to (HashKey ), nibbles, start= true )
343+ rc = trackRlpNodes (nodes, visitedNodes, root.to (HashKey ), nibbles, start= true )
264344 if rc.isOk:
265345 return ok (Opt .some rc.value)
266346 if rc.error in TrackRlpNodesNoEntry :
0 commit comments