mirror of
https://github.com/logos-storage/gnark-plonky2-verifier.git
synced 2026-01-10 09:03:09 +00:00
arity verification check with incomplete compute_evaluation
This commit is contained in:
parent
317f4baf0a
commit
8797fd15ed
@ -7,6 +7,7 @@ import (
|
||||
"gnark-ed25519/poseidon"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/bits"
|
||||
|
||||
"github.com/consensys/gnark-crypto/field/goldilocks"
|
||||
"github.com/consensys/gnark/frontend"
|
||||
@ -47,7 +48,7 @@ func (f *FriChip) fromOpeningsAndAlpha(openings *FriOpenings, alpha QuadraticExt
|
||||
|
||||
reducedOpenings := make([]QuadraticExtension, 0, 2)
|
||||
for _, batch := range openings.Batches {
|
||||
reducedOpenings = append(reducedOpenings, reduceWithPowers(f.qeAPI, batch.values, alpha))
|
||||
reducedOpenings = append(reducedOpenings, f.qeAPI.ReduceWithPowers(batch.values, alpha))
|
||||
}
|
||||
|
||||
return reducedOpenings
|
||||
@ -170,24 +171,12 @@ func (f *FriChip) assertNoncanonicalIndicesOK() {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FriChip) calculateSubgroupX(
|
||||
xIndexBits []frontend.Variable,
|
||||
nLog uint64,
|
||||
func (f *FriChip) expFromBitsConstBase(
|
||||
base goldilocks.Element,
|
||||
exponentBits []frontend.Variable,
|
||||
) F {
|
||||
// Compute x from its index
|
||||
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
|
||||
// TODO - Make these as global values
|
||||
g := field.NewFieldElement(field.GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR.Uint64())
|
||||
base := field.GoldilocksPrimitiveRootOfUnity(nLog)
|
||||
|
||||
product := ONE_F
|
||||
// Create a reverse list of xIndexBits
|
||||
xIndexBitsRev := make([]frontend.Variable, 0)
|
||||
for i := len(xIndexBits) - 1; i >= 0; i-- {
|
||||
xIndexBitsRev = append(xIndexBitsRev, xIndexBits[i])
|
||||
}
|
||||
|
||||
for i, bit := range xIndexBitsRev {
|
||||
for i, bit := range exponentBits {
|
||||
pow := int64(1 << i)
|
||||
// If the bit is on, we multiply product by base^pow.
|
||||
// We can arithmetize this as:
|
||||
@ -208,6 +197,27 @@ func (f *FriChip) calculateSubgroupX(
|
||||
).(F)
|
||||
}
|
||||
|
||||
return product
|
||||
}
|
||||
|
||||
func (f *FriChip) calculateSubgroupX(
|
||||
xIndexBits []frontend.Variable,
|
||||
nLog uint64,
|
||||
) F {
|
||||
// Compute x from its index
|
||||
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
|
||||
// TODO - Make these as global values
|
||||
g := field.NewFieldElement(field.GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR.Uint64())
|
||||
base := field.GoldilocksPrimitiveRootOfUnity(nLog)
|
||||
|
||||
// Create a reverse list of xIndexBits
|
||||
xIndexBitsRev := make([]frontend.Variable, 0)
|
||||
for i := len(xIndexBits) - 1; i >= 0; i-- {
|
||||
xIndexBitsRev = append(xIndexBitsRev, xIndexBits[i])
|
||||
}
|
||||
|
||||
product := f.expFromBitsConstBase(base, xIndexBitsRev)
|
||||
|
||||
return f.fieldAPI.Mul(g, product).(F)
|
||||
}
|
||||
|
||||
@ -237,7 +247,7 @@ func (f *FriChip) friCombineInitial(
|
||||
)
|
||||
}
|
||||
|
||||
reducedEvals := reduceWithPowers(f.qeAPI, evals, friAlpha)
|
||||
reducedEvals := f.qeAPI.ReduceWithPowers(evals, friAlpha)
|
||||
numerator := f.qeAPI.SubExtension(reducedEvals, reducedOpenings)
|
||||
denominator := f.qeAPI.SubExtension(subgroupX_QE, point)
|
||||
sum = f.qeAPI.MulExtension(f.qeAPI.ExpU64Extension(friAlpha, uint64(len(evals))), sum)
|
||||
@ -267,6 +277,44 @@ func (f *FriChip) finalPolyEval(finalPoly PolynomialCoeffs, point QuadraticExten
|
||||
return ret
|
||||
}
|
||||
|
||||
func (f *FriChip) computeEvaluation(
|
||||
x F,
|
||||
xIndexWithinCosetBits []frontend.Variable,
|
||||
arityBits uint64,
|
||||
evals []QuadraticExtension,
|
||||
beta QuadraticExtension,
|
||||
) QuadraticExtension {
|
||||
arity := 1 << arityBits
|
||||
if (len(evals)) != arity {
|
||||
panic("len(evals) ! arity")
|
||||
}
|
||||
|
||||
g := field.GoldilocksPrimitiveRootOfUnity(arityBits)
|
||||
gInv := goldilocks.NewElement(0)
|
||||
gInv.Exp(g, big.NewInt(int64(arity-1)))
|
||||
|
||||
// The evaluation vector needs to be reordered first. Permute the evals array such that each
|
||||
// element's new index is the bit reverse of it's original index.
|
||||
// TODO: Optimization - Since the size of the evals array should be constant (e.g. 2^arityBits),
|
||||
// we can just hard code the permutation.
|
||||
permutedEvals := make([]QuadraticExtension, len(evals))
|
||||
for i := uint(0); i < uint(len(evals)); i++ {
|
||||
bitLen := bits.Len(i)
|
||||
rightPadLen := arityBits - uint64(bitLen)
|
||||
newIndex := bits.Reverse(i) << rightPadLen
|
||||
permutedEvals[newIndex] = evals[i]
|
||||
}
|
||||
|
||||
// Want `g^(arity - rev_x_index_within_coset)` as in the out-of-circuit version. Compute it
|
||||
// as `(g^-1)^rev_x_index_within_coset`.
|
||||
revXIndexWithinCosetBits := make([]frontend.Variable, len(xIndexWithinCosetBits))
|
||||
for i := 0; i < len(xIndexWithinCosetBits); i++ {
|
||||
revXIndexWithinCosetBits[len(xIndexWithinCosetBits)-1-i] = xIndexWithinCosetBits[i]
|
||||
}
|
||||
start := f.expFromBitsConstBase(gInv, revXIndexWithinCosetBits)
|
||||
cosetStart := f.fieldAPI.Mul(start, x)
|
||||
}
|
||||
|
||||
func (f *FriChip) verifyQueryRound(
|
||||
instance FriInstanceInfo,
|
||||
challenges *FriChallenges,
|
||||
@ -299,10 +347,67 @@ func (f *FriChip) verifyQueryRound(
|
||||
precomputedReducedEval,
|
||||
)
|
||||
|
||||
for i, arityBits := range f.friParams.ReductionArityBits {
|
||||
evals := roundProof.Steps[i].Evals
|
||||
|
||||
cosetIndexBits := xIndexBits[arityBits:]
|
||||
xIndexWithinCosetBits := xIndexBits[:arityBits]
|
||||
|
||||
// Assumes that the arity bits will be 4. That means that the range of
|
||||
// xIndexWithCoset is [0,2^4-1]. This is based on plonky2's circuit recursive
|
||||
// config: https://github.com/mir-protocol/plonky2/blob/main/plonky2/src/plonk/circuit_data.rs#L63
|
||||
// Will use a two levels tree of 4-selector gadgets.
|
||||
if arityBits != 4 {
|
||||
panic("assuming arity bits is 4")
|
||||
}
|
||||
|
||||
const NUM_LEAF_LOOKUPS = 4
|
||||
var leafLookups [NUM_LEAF_LOOKUPS]QuadraticExtension
|
||||
// First create the "leaf" lookup2 circuits
|
||||
// The will use the least significant bits of the xIndexWithCosetBits array
|
||||
for i := 0; i < NUM_LEAF_LOOKUPS; i++ {
|
||||
leafLookups[i] = f.qeAPI.Lookup2(
|
||||
xIndexWithinCosetBits[0], xIndexWithinCosetBits[1],
|
||||
evals[i*NUM_LEAF_LOOKUPS], evals[i*NUM_LEAF_LOOKUPS+1], evals[i*NUM_LEAF_LOOKUPS+2], evals[i*NUM_LEAF_LOOKUPS+3],
|
||||
)
|
||||
}
|
||||
|
||||
// Use the most 2 significant bits of the xIndexWithCosetBits array for the "root" lookup
|
||||
newEval := f.qeAPI.Lookup2(xIndexWithinCosetBits[2], xIndexWithinCosetBits[3], evals[0], evals[1], evals[2], evals[3])
|
||||
f.qeAPI.AssertIsEqual(newEval, oldEval)
|
||||
|
||||
oldEval := f.computeEvaluation(
|
||||
subgroupX,
|
||||
xIndexWithinCosetBits,
|
||||
arityBits,
|
||||
evals,
|
||||
challenges.FriBetas[i],
|
||||
)
|
||||
|
||||
// Convert evals (array of QE) to fields by taking their 0th degree coefficients
|
||||
fieldEvals := make([]F, len(evals))
|
||||
for j := 0; j < len(evals); j++ {
|
||||
fieldEvals[j] = evals[j][0]
|
||||
}
|
||||
f.verifyMerkleProofToCapWithCapIndex(
|
||||
fieldEvals,
|
||||
cosetIndexBits,
|
||||
capIndexBits,
|
||||
proof.CommitPhaseMerkleCaps[i],
|
||||
&roundProof.Steps[i].MerkleProof,
|
||||
)
|
||||
|
||||
// Update the point x to x^arity.
|
||||
for j := uint64(0); j < arityBits; j++ {
|
||||
subgroupX = f.fieldAPI.Mul(subgroupX, subgroupX).(F)
|
||||
}
|
||||
|
||||
xIndexBits = cosetIndexBits
|
||||
}
|
||||
|
||||
finalPolyEval := f.finalPolyEval(proof.FinalPoly, subgroupX_QE)
|
||||
|
||||
f.fieldAPI.AssertIsEqual(oldEval[0], finalPolyEval[0])
|
||||
f.fieldAPI.AssertIsEqual(oldEval[1], finalPolyEval[1])
|
||||
f.qeAPI.AssertIsEqual(oldEval, finalPolyEval)
|
||||
}
|
||||
|
||||
func (f *FriChip) VerifyFriProof(
|
||||
|
||||
@ -109,7 +109,7 @@ func (c *QuadraticExtensionAPI) ExpU64Extension(a QuadraticExtension, exponent u
|
||||
return product
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) reduceWithPowers(terms []QuadraticExtension, scalar QuadraticExtension) QuadraticExtension {
|
||||
func (c *QuadraticExtensionAPI) ReduceWithPowers(terms []QuadraticExtension, scalar QuadraticExtension) QuadraticExtension {
|
||||
sum := c.ZERO_QE
|
||||
|
||||
for i := len(terms) - 1; i >= 0; i-- {
|
||||
@ -125,6 +125,22 @@ func (c *QuadraticExtensionAPI) reduceWithPowers(terms []QuadraticExtension, sca
|
||||
return sum
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) Lookup2(b0 frontend.Variable, b1 frontend.Variable, qe0, qe1, qe2, qe3 QuadraticExtension) QuadraticExtension {
|
||||
var retQE QuadraticExtension
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
retQE[i] = c.fieldAPI.Lookup2(b0, b1, qe0[i], qe1[i], qe2[i], qe3[i]).(F)
|
||||
}
|
||||
|
||||
return retQE
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) AssertIsEqual(a, b QuadraticExtension) {
|
||||
for i := 0; i < 2; i++ {
|
||||
c.fieldAPI.AssertIsEqual(a[0], b[0])
|
||||
}
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) {
|
||||
fmt.Print("Degree 0 coefficient")
|
||||
c.fieldAPI.Println(a[0])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user