From 1d7f151cc151daa4359eb12bb16890a7d1fd5182 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 1 Nov 2022 16:35:21 -0700 Subject: [PATCH] permutation check for plonk works --- plonky2_verifier/plonk.go | 80 ++++++++++++++++++++-------------- plonky2_verifier/plonk_test.go | 2 +- plonky2_verifier/verifier.go | 2 + 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/plonky2_verifier/plonk.go b/plonky2_verifier/plonk.go index f76df82..d44581c 100644 --- a/plonky2_verifier/plonk.go +++ b/plonky2_verifier/plonk.go @@ -2,10 +2,13 @@ package plonky2_verifier import ( . "gnark-ed25519/field" + + "github.com/consensys/gnark/frontend" ) type PlonkChip struct { - qe *QuadraticExtensionAPI + api frontend.API + qe *QuadraticExtensionAPI commonData CommonCircuitData proofChallenges ProofChallenges @@ -16,11 +19,12 @@ type PlonkChip struct { DEGREE_QE QuadraticExtension } -func NewPlonkChip(qe *QuadraticExtensionAPI, commonData CommonCircuitData) *PlonkChip { +func NewPlonkChip(api frontend.API, qe *QuadraticExtensionAPI, commonData CommonCircuitData) *PlonkChip { // TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64? return &PlonkChip{ - qe: qe, + api: api, + qe: qe, commonData: commonData, @@ -88,7 +92,7 @@ func (p *PlonkChip) checkPartialProducts( return partialProductChecks } -func (p *PlonkChip) evalVanishingPoly() []QuadraticExtension { +func (p *PlonkChip) evalVanishingPoly(zetaPowN QuadraticExtension) []QuadraticExtension { // Calculate the k[i] * x sIDs := make([]QuadraticExtension, p.commonData.Config.NumRoutedWires) @@ -96,9 +100,6 @@ func (p *PlonkChip) evalVanishingPoly() []QuadraticExtension { sIDs[i] = p.qe.ScalarMulExtension(p.proofChallenges.PlonkZeta, p.commonData.KIs[i]) } - // Calculate zeta^n - zetaPowN := p.expPowerOf2Extension(p.proofChallenges.PlonkZeta) - // Calculate L_0(zeta) l0Zeta := p.evalL0(p.proofChallenges.PlonkZeta, zetaPowN) @@ -179,33 +180,46 @@ func (p *PlonkChip) evalVanishingPoly() []QuadraticExtension { return reducedValues } -func (p *PlonkChip) Verify() { - vanishingPolysZeta := p.evalVanishingPoly() +func (p *PlonkChip) reduceWithPowers(terms []QuadraticExtension, scalar QuadraticExtension) QuadraticExtension { + sum := p.qe.ZERO_QE - for _, vp := range vanishingPolysZeta { - p.qe.Println(vp) + for i := len(terms) - 1; i >= 0; i-- { + sum = p.qe.AddExtension( + p.qe.MulExtension( + sum, + scalar, + ), + terms[i], + ) } - /* - let alphas = &alphas.iter().map(|&a| a.into()).collect::>(); - plonk_common::reduce_with_powers_multi(&vanishing_terms, alphas) - - // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta. - let quotient_polys_zeta = &proof.openings.quotient_polys; - let zeta_pow_deg = challenges - .plonk_zeta - .exp_power_of_2(common_data.degree_bits()); - let z_h_zeta = zeta_pow_deg - F::Extension::ONE; - // `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)` - // where the "real" quotient polynomial is `t(X) = t_0(X) + t_1(X)*X^n + t_2(X)*X^{2n} + ...`. - // So to reconstruct `t(zeta)` we can compute `reduce_with_powers(chunk, zeta^n)` for each - // `quotient_degree_factor`-sized chunk of the original evaluations. - for (i, chunk) in quotient_polys_zeta - .chunks(common_data.quotient_degree_factor) - .enumerate() - { - ensure!(vanishing_polys_zeta[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg)); - } - */ + return sum +} + +func (p *PlonkChip) Verify() { + // Calculate zeta^n + zetaPowN := p.expPowerOf2Extension(p.proofChallenges.PlonkZeta) + + vanishingPolysZeta := p.evalVanishingPoly(zetaPowN) + + // Calculate Z(H) + zHZeta := p.qe.SubExtension(zetaPowN, p.qe.ONE) + + // `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)` + // where the "real" quotient polynomial is `t(X) = t_0(X) + t_1(X)*X^n + t_2(X)*X^{2n} + ...`. + // So to reconstruct `t(zeta)` we can compute `reduce_with_powers(chunk, zeta^n)` for each + // `quotient_degree_factor`-sized chunk of the original evaluations. + for i := 0; i < len(p.openings.QuotientPolys); i += int(p.commonData.QuotientDegreeFactor) { + prod := p.qe.MulExtension( + zHZeta, + p.reduceWithPowers( + p.openings.QuotientPolys[i:i+int(p.commonData.QuotientDegreeFactor)], + zetaPowN, + ), + ) + + // TODO: Uncomment this after adding in the custom gates evaluations + //p.api.AssertIsEqual(vanishingPolysZeta[i], prod) + } } diff --git a/plonky2_verifier/plonk_test.go b/plonky2_verifier/plonk_test.go index 3c2ccaa..c440679 100644 --- a/plonky2_verifier/plonk_test.go +++ b/plonky2_verifier/plonk_test.go @@ -37,7 +37,7 @@ func (circuit *TestPlonkCircuit) Define(api frontend.API) error { }, } - plonkChip := NewPlonkChip(qe, commonCircuitData) + plonkChip := NewPlonkChip(api, qe, commonCircuitData) plonkChip.proofChallenges = proofChallenges plonkChip.openings = proofWithPis.Proof.Openings diff --git a/plonky2_verifier/verifier.go b/plonky2_verifier/verifier.go index aba1763..54bdf8c 100644 --- a/plonky2_verifier/verifier.go +++ b/plonky2_verifier/verifier.go @@ -55,6 +55,8 @@ func (c *VerifierChip) GetChallenges(proofWithPis ProofWithPublicInputs, publicI } func (c *VerifierChip) Verify(proofWithPis ProofWithPublicInputs, verifierData VerifierOnlyCircuitData, commonData CommonCircuitData) { + // TODO: Verify shape of the proof? + publicInputsHash := c.GetPublicInputsHash(proofWithPis.PublicInputs) proofChallenges := c.GetChallenges(proofWithPis, publicInputsHash, commonData) fmt.Printf("%+v\n", proofChallenges)