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	. "gnark-ed25519/field"
  6
  7	"github.com/consensys/gnark/frontend"
  8)
  9
 10type PlonkOracle struct {
 11	index    uint64
 12	blinding bool
 13}
 14
 15var CONSTANTS_SIGMAS = PlonkOracle{
 16	index:    0,
 17	blinding: false,
 18}
 19
 20var WIRES = PlonkOracle{
 21	index:    1,
 22	blinding: true,
 23}
 24
 25var ZS_PARTIAL_PRODUCTS = PlonkOracle{
 26	index:    2,
 27	blinding: true,
 28}
 29
 30var QUOTIENT = PlonkOracle{
 31	index:    3,
 32	blinding: true,
 33}
 34
 35type PlonkChip struct {
 36	api frontend.API
 37	qe  *QuadraticExtensionAPI
 38
 39	commonData      CommonCircuitData
 40	proofChallenges ProofChallenges
 41	openings        OpeningSet
 42
 43	DEGREE        F
 44	DEGREE_BITS_F F
 45	DEGREE_QE     QuadraticExtension
 46}
 47
 48func NewPlonkChip(api frontend.API, qe *QuadraticExtensionAPI, commonData CommonCircuitData) *PlonkChip {
 49	// TODO:  Should degreeBits be verified that it fits within the field and that degree is within uint64?
 50
 51	return &PlonkChip{
 52		api: api,
 53		qe:  qe,
 54
 55		commonData: commonData,
 56
 57		DEGREE:        NewFieldElement(1 << commonData.DegreeBits),
 58		DEGREE_BITS_F: NewFieldElement(commonData.DegreeBits),
 59		DEGREE_QE:     QuadraticExtension{NewFieldElement(1 << commonData.DegreeBits), field.ZERO_F},
 60	}
 61}
 62
 63func (p *PlonkChip) expPowerOf2Extension(x QuadraticExtension) QuadraticExtension {
 64	for i := uint64(0); i < p.commonData.DegreeBits; i++ {
 65		x = p.qe.SquareExtension(x)
 66	}
 67
 68	return x
 69}
 70
 71func (p *PlonkChip) evalL0(x QuadraticExtension, xPowN QuadraticExtension) QuadraticExtension {
 72	// L_0(x) = (x^n - 1) / (n * (x - 1))
 73	evalZeroPoly := p.qe.SubExtension(
 74		xPowN,
 75		p.qe.ONE_QE,
 76	)
 77	denominator := p.qe.SubExtension(
 78		p.qe.ScalarMulExtension(x, p.DEGREE),
 79		p.DEGREE_QE,
 80	)
 81	return p.qe.DivExtension(
 82		evalZeroPoly,
 83		denominator,
 84	)
 85}
 86
 87func (p *PlonkChip) checkPartialProducts(
 88	numerators []QuadraticExtension,
 89	denominators []QuadraticExtension,
 90	challengeNum uint64,
 91) []QuadraticExtension {
 92	numPartProds := p.commonData.NumPartialProducts
 93	quotDegreeFactor := p.commonData.QuotientDegreeFactor
 94
 95	productAccs := make([]QuadraticExtension, 0, numPartProds+2)
 96	productAccs = append(productAccs, p.openings.PlonkZs[challengeNum])
 97	productAccs = append(productAccs, p.openings.PartialProducts[challengeNum*numPartProds:(challengeNum+1)*numPartProds]...)
 98	productAccs = append(productAccs, p.openings.PlonkZsNext[challengeNum])
 99
100	partialProductChecks := make([]QuadraticExtension, 0, numPartProds)
101
102	for i := uint64(0); i <= numPartProds; i += 1 {
103		ppStartIdx := i * quotDegreeFactor
104		numeProduct := numerators[ppStartIdx]
105		denoProduct := denominators[ppStartIdx]
106		for j := uint64(1); j < quotDegreeFactor; j++ {
107			numeProduct = p.qe.MulExtension(numeProduct, numerators[ppStartIdx+j])
108			denoProduct = p.qe.MulExtension(denoProduct, denominators[ppStartIdx+j])
109		}
110
111		partialProductCheck := p.qe.SubExtension(
112			p.qe.MulExtension(productAccs[i], numeProduct),
113			p.qe.MulExtension(productAccs[i+1], denoProduct),
114		)
115
116		partialProductChecks = append(partialProductChecks, partialProductCheck)
117	}
118	return partialProductChecks
119}
120
121func (p *PlonkChip) evalVanishingPoly(zetaPowN QuadraticExtension) []QuadraticExtension {
122	// Calculate the k[i] * x
123	sIDs := make([]QuadraticExtension, p.commonData.Config.NumRoutedWires)
124
125	for i := uint64(0); i < p.commonData.Config.NumRoutedWires; i++ {
126		sIDs[i] = p.qe.ScalarMulExtension(p.proofChallenges.PlonkZeta, p.commonData.KIs[i])
127	}
128
129	// Calculate L_0(zeta)
130	l0Zeta := p.evalL0(p.proofChallenges.PlonkZeta, zetaPowN)
131
132	vanishingZ1Terms := make([]QuadraticExtension, 0, p.commonData.Config.NumChallenges)
133	vanishingPartialProductsTerms := make([]QuadraticExtension, 0, p.commonData.Config.NumChallenges*p.commonData.NumPartialProducts)
134	for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
135		// L_0(zeta) (Z(zeta) - 1) = 0
136		z1_term := p.qe.MulExtension(
137			l0Zeta,
138			p.qe.SubExtension(p.openings.PlonkZs[i], p.qe.ONE_QE))
139		vanishingZ1Terms = append(vanishingZ1Terms, z1_term)
140
141		numeratorValues := make([]QuadraticExtension, 0, p.commonData.Config.NumRoutedWires)
142		denominatorValues := make([]QuadraticExtension, 0, p.commonData.Config.NumRoutedWires)
143		for j := uint64(0); j < p.commonData.Config.NumRoutedWires; j++ {
144			// The numerator is `beta * s_id + wire_value + gamma`, and the denominator is
145			// `beta * s_sigma + wire_value + gamma`.
146
147			wireValuePlusGamma := p.qe.AddExtension(
148				p.openings.Wires[j],
149				p.qe.FieldToQE(p.proofChallenges.PlonkGammas[i]),
150			)
151
152			numerator := p.qe.AddExtension(
153				p.qe.MulExtension(
154					p.qe.FieldToQE(p.proofChallenges.PlonkBetas[i]),
155					sIDs[j],
156				),
157				wireValuePlusGamma,
158			)
159
160			denominator := p.qe.AddExtension(
161				p.qe.MulExtension(
162					p.qe.FieldToQE(p.proofChallenges.PlonkBetas[i]),
163					p.openings.PlonkSigmas[j],
164				),
165				wireValuePlusGamma,
166			)
167
168			numeratorValues = append(numeratorValues, numerator)
169			denominatorValues = append(denominatorValues, denominator)
170		}
171
172		vanishingPartialProductsTerms = append(
173			vanishingPartialProductsTerms,
174			p.checkPartialProducts(numeratorValues, denominatorValues, i)...,
175		)
176	}
177
178	vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...)
179
180	reducedValues := make([]QuadraticExtension, p.commonData.Config.NumChallenges)
181	for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
182		reducedValues[i] = p.qe.ZERO_QE
183	}
184
185	// TODO:  Enable this check once the custom gate evaluations are added to the
186	//        vanishingTerms array
187	/*
188		if len(vanishingTerms) != int(p.commonData.QuotientDegreeFactor) {
189			panic("evalVanishingPoly: len(vanishingTerms) != int(p.commonData.QuotientDegreeFactor)")
190		}
191	*/
192
193	// reverse iterate the vanishingPartialProductsTerms array
194	for i := len(vanishingTerms) - 1; i >= 0; i-- {
195		for j := uint64(0); j < p.commonData.Config.NumChallenges; j++ {
196			reducedValues[j] = p.qe.AddExtension(
197				vanishingTerms[i],
198				p.qe.ScalarMulExtension(
199					reducedValues[j],
200					p.proofChallenges.PlonkAlphas[j],
201				),
202			)
203		}
204	}
205
206	return reducedValues
207}
208
209func (p *PlonkChip) Verify() {
210	// Calculate zeta^n
211	zetaPowN := p.expPowerOf2Extension(p.proofChallenges.PlonkZeta)
212
213	vanishingPolysZeta := p.evalVanishingPoly(zetaPowN)
214
215	// Calculate Z(H)
216	zHZeta := p.qe.SubExtension(zetaPowN, p.qe.ONE_QE)
217
218	// `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations.
219	// Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)`
220	// where the "real" quotient polynomial is `t(X) = t_0(X) + t_1(X)*X^n + t_2(X)*X^{2n} + ...`.
221	// So to reconstruct `t(zeta)` we can compute `reduce_with_powers(chunk, zeta^n)` for each
222	// `quotient_degree_factor`-sized chunk of the original evaluations.
223	for i := 0; i < len(p.openings.QuotientPolys); i += int(p.commonData.QuotientDegreeFactor) {
224		prod := p.qe.MulExtension(
225			zHZeta,
226			p.qe.ReduceWithPowers(
227				p.openings.QuotientPolys[i:i+int(p.commonData.QuotientDegreeFactor)],
228				zetaPowN,
229			),
230		)
231
232		// TODO: Uncomment this after adding in the custom gates evaluations
233		//p.api.AssertIsEqual(vanishingPolysZeta[i], prod)
234	}
235}