arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/plonky2_verifier/plonk.go
plonky2_verifier/plonk.goRaw
  1package plonky2_verifier
  2
  3import (
  4	. "gnark-ed25519/field"
  5)
  6
  7type PlonkChip struct {
  8	qe *QuadraticExtensionAPI
  9
 10	commonData      CommonCircuitData
 11	proofChallenges ProofChallenges
 12	openings        OpeningSet
 13
 14	DEGREE        F
 15	DEGREE_BITS_F F
 16	DEGREE_QE     QuadraticExtension
 17}
 18
 19func NewPlonkChip(qe *QuadraticExtensionAPI, commonData CommonCircuitData) *PlonkChip {
 20	// TODO:  Should degreeBits be verified that it fits within the field and that degree is within uint64?
 21
 22	return &PlonkChip{
 23		qe: qe,
 24
 25		commonData: commonData,
 26
 27		DEGREE:        NewFieldElement(1 << commonData.DegreeBits),
 28		DEGREE_BITS_F: NewFieldElement(commonData.DegreeBits),
 29		DEGREE_QE:     QuadraticExtension{NewFieldElement(1 << commonData.DegreeBits), NewFieldElement(0)},
 30	}
 31}
 32
 33func (p *PlonkChip) expPowerOf2Extension(x QuadraticExtension) QuadraticExtension {
 34	for i := uint64(0); i < p.commonData.DegreeBits; i++ {
 35		x = p.qe.SquareExtension(x)
 36	}
 37
 38	return x
 39}
 40
 41func (p *PlonkChip) evalL0(x QuadraticExtension, xPowN QuadraticExtension) QuadraticExtension {
 42	// L_0(x) = (x^n - 1) / (n * (x - 1))
 43	evalZeroPoly := p.qe.SubExtension(
 44		xPowN,
 45		p.qe.ONE,
 46	)
 47	denominator := p.qe.SubExtension(
 48		p.qe.ScalarMulExtension(x, p.DEGREE),
 49		p.DEGREE_QE,
 50	)
 51	return p.qe.DivExtension(
 52		evalZeroPoly,
 53		denominator,
 54	)
 55}
 56
 57func (p *PlonkChip) checkPartialProducts(
 58	numerators []QuadraticExtension,
 59	denominators []QuadraticExtension,
 60	challengeNum uint64,
 61) []QuadraticExtension {
 62	numPartProds := p.commonData.NumPartialProducts
 63	quotDegreeFactor := p.commonData.QuotientDegreeFactor
 64
 65	productAccs := make([]QuadraticExtension, 0, numPartProds+2)
 66	productAccs = append(productAccs, p.openings.PlonkZs[challengeNum])
 67	productAccs = append(productAccs, p.openings.PartialProducts[challengeNum*numPartProds:(challengeNum+1)*numPartProds]...)
 68	productAccs = append(productAccs, p.openings.PlonkZsNext[challengeNum])
 69
 70	partialProductChecks := make([]QuadraticExtension, 0, numPartProds)
 71
 72	for i := uint64(0); i <= numPartProds; i += 1 {
 73		ppStartIdx := i * quotDegreeFactor
 74		numeProduct := numerators[ppStartIdx]
 75		denoProduct := denominators[ppStartIdx]
 76		for j := uint64(1); j < quotDegreeFactor; j++ {
 77			numeProduct = p.qe.MulExtension(numeProduct, numerators[ppStartIdx+j])
 78			denoProduct = p.qe.MulExtension(denoProduct, denominators[ppStartIdx+j])
 79		}
 80
 81		partialProductCheck := p.qe.SubExtension(
 82			p.qe.MulExtension(productAccs[i], numeProduct),
 83			p.qe.MulExtension(productAccs[i+1], denoProduct),
 84		)
 85
 86		partialProductChecks = append(partialProductChecks, partialProductCheck)
 87	}
 88	return partialProductChecks
 89}
 90
 91func (p *PlonkChip) evalVanishingPoly() []QuadraticExtension {
 92	// Calculate the k[i] * x
 93	sIDs := make([]QuadraticExtension, p.commonData.Config.NumRoutedWires)
 94
 95	for i := uint64(0); i < p.commonData.Config.NumRoutedWires; i++ {
 96		sIDs[i] = p.qe.ScalarMulExtension(p.proofChallenges.PlonkZeta, p.commonData.KIs[i])
 97	}
 98
 99	// Calculate zeta^n
100	zetaPowN := p.expPowerOf2Extension(p.proofChallenges.PlonkZeta)
101
102	// Calculate L_0(zeta)
103	l0Zeta := p.evalL0(p.proofChallenges.PlonkZeta, zetaPowN)
104
105	vanishingZ1Terms := make([]QuadraticExtension, 0, p.commonData.Config.NumChallenges)
106	vanishingPartialProductsTerms := make([]QuadraticExtension, 0, p.commonData.Config.NumChallenges*p.commonData.NumPartialProducts)
107	for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
108		// L_0(zeta) (Z(zeta) - 1) = 0
109		z1_term := p.qe.MulExtension(
110			l0Zeta,
111			p.qe.SubExtension(p.openings.PlonkZs[i], p.qe.ONE))
112		vanishingZ1Terms = append(vanishingZ1Terms, z1_term)
113
114		numeratorValues := make([]QuadraticExtension, 0, p.commonData.Config.NumRoutedWires)
115		denominatorValues := make([]QuadraticExtension, 0, p.commonData.Config.NumRoutedWires)
116		for j := uint64(0); j < p.commonData.Config.NumRoutedWires; j++ {
117			// The numerator is `beta * s_id + wire_value + gamma`, and the denominator is
118			// `beta * s_sigma + wire_value + gamma`.
119
120			wireValuePlusGamma := p.qe.AddExtension(
121				p.openings.Wires[j],
122				p.qe.FieldToQE(p.proofChallenges.PlonkGammas[i]),
123			)
124
125			numerator := p.qe.AddExtension(
126				p.qe.MulExtension(
127					p.qe.FieldToQE(p.proofChallenges.PlonkBetas[i]),
128					sIDs[j],
129				),
130				wireValuePlusGamma,
131			)
132
133			denominator := p.qe.AddExtension(
134				p.qe.MulExtension(
135					p.qe.FieldToQE(p.proofChallenges.PlonkBetas[i]),
136					p.openings.PlonkSigmas[j],
137				),
138				wireValuePlusGamma,
139			)
140
141			numeratorValues = append(numeratorValues, numerator)
142			denominatorValues = append(denominatorValues, denominator)
143		}
144
145		vanishingPartialProductsTerms = append(
146			vanishingPartialProductsTerms,
147			p.checkPartialProducts(numeratorValues, denominatorValues, i)...,
148		)
149	}
150
151	vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...)
152
153	reducedValues := make([]QuadraticExtension, p.commonData.Config.NumChallenges)
154	for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
155		reducedValues[i] = p.qe.ZERO_QE
156	}
157
158	// TODO:  Enable this check once the custom gate evaluations are added to the
159	//        vanishingTerms array
160	/*
161		if len(vanishingTerms) != int(p.commonData.QuotientDegreeFactor) {
162			panic("evalVanishingPoly: len(vanishingTerms) != int(p.commonData.QuotientDegreeFactor)")
163		}
164	*/
165
166	// reverse iterate the vanishingPartialProductsTerms array
167	for i := len(vanishingTerms) - 1; i >= 0; i-- {
168		for j := uint64(0); j < p.commonData.Config.NumChallenges; j++ {
169			reducedValues[j] = p.qe.AddExtension(
170				vanishingTerms[i],
171				p.qe.ScalarMulExtension(
172					reducedValues[j],
173					p.proofChallenges.PlonkAlphas[j],
174				),
175			)
176		}
177	}
178
179	return reducedValues
180}
181
182func (p *PlonkChip) Verify() {
183	vanishingPolysZeta := p.evalVanishingPoly()
184
185	for _, vp := range vanishingPolysZeta {
186		p.qe.Println(vp)
187	}
188
189	/*
190			let alphas = &alphas.iter().map(|&a| a.into()).collect::<Vec<_>>();
191		    plonk_common::reduce_with_powers_multi(&vanishing_terms, alphas)
192
193		    // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta.
194		    let quotient_polys_zeta = &proof.openings.quotient_polys;
195		    let zeta_pow_deg = challenges
196		        .plonk_zeta
197		        .exp_power_of_2(common_data.degree_bits());
198		    let z_h_zeta = zeta_pow_deg - F::Extension::ONE;
199		    // `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations.
200		    // Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)`
201		    // where the "real" quotient polynomial is `t(X) = t_0(X) + t_1(X)*X^n + t_2(X)*X^{2n} + ...`.
202		    // So to reconstruct `t(zeta)` we can compute `reduce_with_powers(chunk, zeta^n)` for each
203		    // `quotient_degree_factor`-sized chunk of the original evaluations.
204		    for (i, chunk) in quotient_polys_zeta
205		        .chunks(common_data.quotient_degree_factor)
206		        .enumerate()
207		    {
208		        ensure!(vanishing_polys_zeta[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg));
209		    }
210	*/
211}