@@ -12,7 +12,6 @@ import (
1212 "github.com/consensys/gnark/std/conversion"
1313 "github.com/consensys/gnark/std/lookup/logderivlookup"
1414 "github.com/consensys/gnark/std/math/bits"
15- "github.com/consensys/gnark/std/math/cmp"
1615 "github.com/consensys/gnark/std/math/uints"
1716)
1817
@@ -276,7 +275,7 @@ func (f *FriVerifier) verifyFirstLayer(queries []logderivlookup.Table, evaluatio
276275 decommitmentPositions := make ([]logderivlookup.Table , 32 )
277276 sparseEvaluationsFlattened := make ([]m31.M31 , 0 )
278277 sparseEvaluations := make ([]SparseEvaluations , 0 )
279- previousFriWitnessIndex := frontend . Variable ( 0 )
278+ previousFriWitnessIndex := 0
280279
281280 columnBoundsIndex := 0
282281 maxLogSize := f .circuitData .ColumnBounds [0 ]
@@ -364,7 +363,11 @@ func (f *FriVerifier) verifyFirstLayer(queries []logderivlookup.Table, evaluatio
364363
365364 // verify the merkle decommitment
366365 merkleVerifier := NewMerkleVerifier (f .api , f .uapi , f .FirstLayerVerifier .proof .Commitment , columnLogSizes , nColumnsPerLogSize )
367- merkleVerifier .Verify (decommitmentPositions , sparseEvaluationsFlattened , f .FirstLayerVerifier .proof .Decommitment , queriesShape )
366+ firstLayerBranching := f .circuitData .FriFirstLayerBranching
367+ if len (firstLayerBranching ) == 0 {
368+ panic ("missing FRI first layer branching data" )
369+ }
370+ merkleVerifier .Verify (decommitmentPositions , sparseEvaluationsFlattened , f .FirstLayerVerifier .proof .Decommitment , queriesShape , firstLayerBranching )
368371
369372 return sparseEvaluations
370373}
@@ -487,7 +490,11 @@ func (f *FriVerifier) verifyInnerLayers(queries []logderivlookup.Table, firstLay
487490 nColumnsPerLogSize [logSize + 1 ] = 4
488491
489492 merkleVerifier := NewMerkleVerifier (f .api , f .uapi , f .InnerLayerVerifiers [innerLayerVerifier .layerIndex ].proof .Commitment , columnLogSizes , nColumnsPerLogSize )
490- merkleVerifier .Verify (decommitmentPositions , sparseEvaluationsFlattened , f .InnerLayerVerifiers [innerLayerVerifier .layerIndex ].proof .Decommitment , queryShape )
493+ if innerLayerVerifier .layerIndex >= len (f .circuitData .FriInnerLayerBranching ) {
494+ panic ("missing FRI inner layer branching data" )
495+ }
496+ innerBranching := f .circuitData .FriInnerLayerBranching [innerLayerVerifier .layerIndex ]
497+ merkleVerifier .Verify (decommitmentPositions , sparseEvaluationsFlattened , f .InnerLayerVerifiers [innerLayerVerifier .layerIndex ].proof .Decommitment , queryShape , innerBranching )
491498
492499 // currentLayerEvals contains g_{i-1}(x_j) folded
493500 currentLayerEvals = make ([]m31.QM31 , f .circuitData .DedupedQueriesShape [logSize ])
@@ -535,23 +542,34 @@ func (f *FriVerifier) computeDecommitmentPositionsAndRebuildEvals(
535542 layerQueries logderivlookup.Table ,
536543 evalAtQueries logderivlookup.Table ,
537544 witnessEvals []m31.QM31 ,
538- previousFriWitnessIndex frontend. Variable ,
545+ previousFriWitnessIndex int ,
539546 layerQueriesShape int ,
540547 logSize int ,
541- ) (logderivlookup.Table , []m31.M31 , SparseEvaluations , frontend. Variable ) {
548+ ) (logderivlookup.Table , []m31.M31 , SparseEvaluations , int ) {
542549 layerDecommitmentPositions := logderivlookup .New (f .api )
543550 pairedEvalsFlattened := make ([]m31.M31 , 0 )
544551 pairedEvals := make ([][2 ]m31.QM31 , 0 )
545552 queryInitials := make ([]uints.U32 , 0 )
546- offset := frontend . Variable ( 0 )
553+ offset := 0
547554 witnessIndex := previousFriWitnessIndex
555+ if logSize <= 0 {
556+ panic ("log size must be positive for decommitment branching" )
557+ }
558+ if logSize - 1 >= len (f .circuitData .QueriesBranching ) {
559+ panic ("queries branching missing layer data" )
560+ }
561+ branching := f .circuitData .QueriesBranching [logSize - 1 ]
562+ if layerQueriesShape > len (branching ) {
563+ panic ("queries branching length mismatch" )
564+ }
548565
549566 for i := 0 ; i < layerQueriesShape ; i ++ {
550- base := f . api . Add ( offset , frontend . Variable ( i ))
567+ base := offset + i
551568
552569 // get the query initial (query >> 1)
553- leftQuery := layerQueries .Lookup (base )[0 ]
554- rightQuery := layerQueries .Lookup (f .api .Add (base , frontend .Variable (1 )))[0 ]
570+ leftQuery := layerQueries .Lookup (frontend .Variable (base ))[0 ]
571+ rightQuery := layerQueries .Lookup (frontend .Variable (base + 1 ))[0 ]
572+ _ = rightQuery // keep lookup constraints even though branching is static
555573 queryU32 := f .uapi .ValueOf (leftQuery )
556574 queryInitialU32 := f .uapi .Rshift (queryU32 , 1 )
557575 queryInitial := f .uapi .ToValue (queryInitialU32 )
@@ -562,40 +580,39 @@ func (f *FriVerifier) computeDecommitmentPositionsAndRebuildEvals(
562580 layerDecommitmentPositions .Insert (leftCandidate )
563581 layerDecommitmentPositions .Insert (rightCandidate )
564582
565- isLeftQueried := cmp .IsEqual (f .api , leftQuery , leftCandidate )
566- isRightQueried := cmp .IsEqual (f .api , rightQuery , rightCandidate )
583+ branchCode := branching [i ]
584+ leftPresent := branchCode & 1 == 1
585+ rightPresent := branchCode & 2 == 2
567586
568- // aggregate the arguments to comply with the hint signature
569- args := []frontend.Variable {isLeftQueried , isRightQueried , witnessIndex }
570- for _ , witnessEval := range witnessEvals {
571- args = append (args , witnessEval .AReal .Limb , witnessEval .AImag .Limb , witnessEval .BReal .Limb , witnessEval .BImag .Limb )
572- }
573- // the soundness relies on the fact that it is too costly to forge a valid witness for a given query, so it doesn't need to be checked
574- hintedFriWitness , err := f .api .Compiler ().NewHint (friWitnessHint , 4 + 1 , args ... )
575- if err != nil {
576- panic (err )
587+ witness := f .qm31Chip .Zero ()
588+ if ! leftPresent || ! rightPresent {
589+ witness = witnessEvals [witnessIndex ]
590+ witnessIndex ++
577591 }
578- witness := m31 .NewQM31FromComponents (
579- m31 .NewM31Unchecked (hintedFriWitness [0 ]),
580- m31 .NewM31Unchecked (hintedFriWitness [1 ]),
581- m31 .NewM31Unchecked (hintedFriWitness [2 ]),
582- m31 .NewM31Unchecked (hintedFriWitness [3 ]),
583- )
584- witnessIndex = hintedFriWitness [4 ]
585592
586593 eval0Native := evalAtQueries .Lookup (base )[0 ]
587594 eval0 := f .qm31Chip .DecodeNative (eval0Native )
588- eval1Native := evalAtQueries .Lookup (f . api . Add ( base , frontend .Variable (1 ) ))[0 ]
595+ eval1Native := evalAtQueries .Lookup (frontend .Variable (base + 1 ))[0 ]
589596 eval1 := f .qm31Chip .DecodeNative (eval1Native )
590597
591- leftEval := f .qm31Chip .Select (isLeftQueried , eval0 , witness )
592- intermediate := f .qm31Chip .Select (isRightQueried , eval1 , witness )
593- rightEval := f .qm31Chip .Select (isLeftQueried , intermediate , eval0 )
598+ var leftEval m31.QM31
599+ var rightEval m31.QM31
600+ if leftPresent {
601+ leftEval = eval0
602+ if rightPresent {
603+ rightEval = eval1
604+ } else {
605+ rightEval = witness
606+ }
607+ } else {
608+ leftEval = witness
609+ rightEval = eval0
610+ }
594611
595612 // update the offset
596- offsetPlusOne := f . api . Add ( offset , frontend . Variable ( 1 ))
597- intermediate2 := f . api . Select ( isRightQueried , offsetPlusOne , offset )
598- offset = f . api . Select ( isLeftQueried , intermediate2 , offset )
613+ if leftPresent && rightPresent {
614+ offset ++
615+ }
599616
600617 // flatten the evaluations into 4 M31 elements for use in the merkle decommitment verifier
601618 leftEvalComponents := leftEval .Components ()
0 commit comments