From d847bbd8e8336dbdd1618d4af002f5ae40139344 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 15 Nov 2022 12:09:05 -0800 Subject: [PATCH] finished interpolate function in fri round verification --- plonky2_verifier/fri.go | 69 +++++++++++++++++++++---- plonky2_verifier/plonk.go | 37 ++++++++++--- plonky2_verifier/quadratic_extension.go | 22 ++++++-- 3 files changed, 108 insertions(+), 20 deletions(-) diff --git a/plonky2_verifier/fri.go b/plonky2_verifier/fri.go index 776a632..1a72d50 100644 --- a/plonky2_verifier/fri.go +++ b/plonky2_verifier/fri.go @@ -277,6 +277,54 @@ func (f *FriChip) finalPolyEval(finalPoly PolynomialCoeffs, point QuadraticExten return ret } +func (f *FriChip) interpolate(x QuadraticExtension, xPoints []QuadraticExtension, yPoints []QuadraticExtension, barycentricWeights []QuadraticExtension) QuadraticExtension { + if len(xPoints) != len(yPoints) || len(xPoints) != len(barycentricWeights) { + panic("length of xPoints, yPoints, and barycentricWeights are inconsistent") + } + + lX := f.qeAPI.ONE_QE + for i := 0; i < len(xPoints); i++ { + lX = f.qeAPI.MulExtension( + lX, + f.qeAPI.SubExtension( + x, + xPoints[i], + ), + ) + } + + sum := f.qeAPI.ZERO_QE + for i := 0; i < len(xPoints); i++ { + sum = f.qeAPI.AddExtension( + f.qeAPI.MulExtension( + f.qeAPI.DivExtension( + barycentricWeights[i], + f.qeAPI.SubExtension( + x, + xPoints[i], + ), + ), + yPoints[i], + ), + sum, + ) + } + + interpolation := f.qeAPI.MulExtension(lX, sum) + + returnField := interpolation + // Now check if x is already within the xPoints + for i := 0; i < len(xPoints); i++ { + returnField = f.qeAPI.Select( + f.qeAPI.IsZero(f.qeAPI.SubExtension(x, xPoints[i])), + yPoints[i], + returnField, + ) + } + + return returnField +} + func (f *FriChip) computeEvaluation( x F, xIndexWithinCosetBits []frontend.Variable, @@ -314,34 +362,35 @@ func (f *FriChip) computeEvaluation( start := f.expFromBitsConstBase(gInv, revXIndexWithinCosetBits) cosetStart := f.fieldAPI.Mul(start, x).(F) - xPoints := make([]F, len(evals)) + xPoints := make([]QuadraticExtension, len(evals)) yPoints := permutedEvals // TODO: Make g_F a constant g_F := NewFieldElement(g.Uint64()) - xPoints[0] = cosetStart + xPoints[0] = f.qeAPI.FieldToQE(cosetStart) for i := 1; i < len(evals); i++ { - xPoints[i] = f.fieldAPI.Mul(xPoints[i-1], g_F).(F) + xPoints[i] = f.qeAPI.FieldToQE(f.fieldAPI.Mul(xPoints[i-1], g_F).(F)) } // TODO: This is n^2. Is there a way to do this better? // Compute the barycentric weights - barycentricWeights := make([]F, len(xPoints)) + barycentricWeights := make([]QuadraticExtension, len(xPoints)) for i := 0; i < len(xPoints); i++ { - barycentricWeights[i] = ONE_F + barycentricWeights[i] = f.qeAPI.ONE_QE for j := 0; j < len(xPoints); j++ { if i != j { - barycentricWeights[i] = f.fieldAPI.Mul( - f.fieldAPI.Sub(xPoints[i], xPoints[j]), + barycentricWeights[i] = f.qeAPI.MulExtension( + f.qeAPI.SubExtension(xPoints[i], xPoints[j]), barycentricWeights[i], - ).(F) + ) } } // Take the inverse of the barycentric weights // TODO: Can provide a witness to this value - barycentricWeights[i] = f.fieldAPI.Inverse(barycentricWeights[i]).(F) + barycentricWeights[i] = f.qeAPI.InverseExtension(barycentricWeights[i]) } + return f.interpolate(beta, xPoints, yPoints, barycentricWeights) } func (f *FriChip) verifyQueryRound( @@ -405,7 +454,7 @@ func (f *FriChip) verifyQueryRound( newEval := f.qeAPI.Lookup2(xIndexWithinCosetBits[2], xIndexWithinCosetBits[3], evals[0], evals[1], evals[2], evals[3]) f.qeAPI.AssertIsEqual(newEval, oldEval) - oldEval := f.computeEvaluation( + oldEval = f.computeEvaluation( subgroupX, xIndexWithinCosetBits, arityBits, diff --git a/plonky2_verifier/plonk.go b/plonky2_verifier/plonk.go index 4eb7420..523da11 100644 --- a/plonky2_verifier/plonk.go +++ b/plonky2_verifier/plonk.go @@ -1,11 +1,37 @@ package plonky2_verifier import ( + "gnark-ed25519/field" . "gnark-ed25519/field" "github.com/consensys/gnark/frontend" ) +type PlonkOracle struct { + index uint64 + blinding bool +} + +var CONSTANTS_SIGMAS = PlonkOracle{ + index: 0, + blinding: false, +} + +var WIRES = PlonkOracle{ + index: 1, + blinding: true, +} + +var ZS_PARTIAL_PRODUCTS = PlonkOracle{ + index: 2, + blinding: true, +} + +var QUOTIENT = PlonkOracle{ + index: 3, + blinding: true, +} + type PlonkChip struct { api frontend.API qe *QuadraticExtensionAPI @@ -30,7 +56,7 @@ func NewPlonkChip(api frontend.API, qe *QuadraticExtensionAPI, commonData Common DEGREE: NewFieldElement(1 << commonData.DegreeBits), DEGREE_BITS_F: NewFieldElement(commonData.DegreeBits), - DEGREE_QE: QuadraticExtension{NewFieldElement(1 << commonData.DegreeBits), NewFieldElement(0)}, + DEGREE_QE: QuadraticExtension{NewFieldElement(1 << commonData.DegreeBits), field.ZERO_F}, } } @@ -46,7 +72,7 @@ func (p *PlonkChip) evalL0(x QuadraticExtension, xPowN QuadraticExtension) Quadr // L_0(x) = (x^n - 1) / (n * (x - 1)) evalZeroPoly := p.qe.SubExtension( xPowN, - p.qe.ONE, + p.qe.ONE_QE, ) denominator := p.qe.SubExtension( p.qe.ScalarMulExtension(x, p.DEGREE), @@ -109,7 +135,7 @@ func (p *PlonkChip) evalVanishingPoly(zetaPowN QuadraticExtension) []QuadraticEx // L_0(zeta) (Z(zeta) - 1) = 0 z1_term := p.qe.MulExtension( l0Zeta, - p.qe.SubExtension(p.openings.PlonkZs[i], p.qe.ONE)) + p.qe.SubExtension(p.openings.PlonkZs[i], p.qe.ONE_QE)) vanishingZ1Terms = append(vanishingZ1Terms, z1_term) numeratorValues := make([]QuadraticExtension, 0, p.commonData.Config.NumRoutedWires) @@ -187,7 +213,7 @@ func (p *PlonkChip) Verify() { vanishingPolysZeta := p.evalVanishingPoly(zetaPowN) // Calculate Z(H) - zHZeta := p.qe.SubExtension(zetaPowN, p.qe.ONE) + zHZeta := p.qe.SubExtension(zetaPowN, p.qe.ONE_QE) // `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations. // Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)` @@ -197,8 +223,7 @@ func (p *PlonkChip) Verify() { for i := 0; i < len(p.openings.QuotientPolys); i += int(p.commonData.QuotientDegreeFactor) { prod := p.qe.MulExtension( zHZeta, - reduceWithPowers( - p.qe, + p.qe.ReduceWithPowers( p.openings.QuotientPolys[i:i+int(p.commonData.QuotientDegreeFactor)], zetaPowN, ), diff --git a/plonky2_verifier/quadratic_extension.go b/plonky2_verifier/quadratic_extension.go index 29af2a7..d26e5d2 100644 --- a/plonky2_verifier/quadratic_extension.go +++ b/plonky2_verifier/quadratic_extension.go @@ -14,7 +14,7 @@ type QuadraticExtensionAPI struct { W F DTH_ROOT F - ONE QuadraticExtension + ONE_QE QuadraticExtension ZERO_QE QuadraticExtension } @@ -27,7 +27,7 @@ func NewQuadraticExtensionAPI(fieldAPI frontend.API, degreeBits uint64) *Quadrat W: NewFieldElement(7), DTH_ROOT: NewFieldElement(18446744069414584320), - ONE: QuadraticExtension{ONE_F, ZERO_F}, + ONE_QE: QuadraticExtension{ONE_F, ZERO_F}, ZERO_QE: QuadraticExtension{ZERO_F, ZERO_F}, } } @@ -58,6 +58,10 @@ func (c *QuadraticExtensionAPI) DivExtension(a QuadraticExtension, b QuadraticEx return c.MulExtension(a, c.InverseExtension(b)) } +func (c *QuadraticExtensionAPI) IsZero(a QuadraticExtension) frontend.Variable { + return c.fieldAPI.Mul(c.fieldAPI.IsZero(a[0]), c.fieldAPI.IsZero(a[1])) +} + // TODO: Instead of calculating the inverse within the circuit, can witness the // inverse and assert that a_inverse * a = 1. Should reduce # of constraints. func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension { @@ -85,7 +89,7 @@ func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension { func (c *QuadraticExtensionAPI) ExpU64Extension(a QuadraticExtension, exponent uint64) QuadraticExtension { switch exponent { case 0: - return c.ONE + return c.ONE_QE case 1: return a case 2: @@ -94,7 +98,7 @@ func (c *QuadraticExtensionAPI) ExpU64Extension(a QuadraticExtension, exponent u } current := a - product := c.ONE + product := c.ONE_QE for i := 0; i < bits.Len64(exponent); i++ { if i != 0 { @@ -125,6 +129,16 @@ func (c *QuadraticExtensionAPI) ReduceWithPowers(terms []QuadraticExtension, sca return sum } +func (c *QuadraticExtensionAPI) Select(b0 frontend.Variable, qe0, qe1 QuadraticExtension) QuadraticExtension { + var retQE QuadraticExtension + + for i := 0; i < 2; i++ { + retQE[i] = c.fieldAPI.Select(b0, qe0[i], qe1[i]).(F) + } + + return retQE +} + func (c *QuadraticExtensionAPI) Lookup2(b0 frontend.Variable, b1 frontend.Variable, qe0, qe1, qe2, qe3 QuadraticExtension) QuadraticExtension { var retQE QuadraticExtension