246 lines
8.2 KiB
Go
Raw Normal View History

package plonk
2022-10-28 06:54:31 -07:00
import (
2022-11-01 16:35:21 -07:00
"github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
2023-10-11 14:53:34 -07:00
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/variables"
2022-10-28 06:54:31 -07:00
)
type PlonkChip struct {
api frontend.API `gnark:"-"`
2022-10-28 06:54:31 -07:00
2023-10-11 14:53:34 -07:00
commonData types.CommonCircuitData `gnark:"-"`
2022-10-31 19:51:51 -07:00
// These are global constant variables that we use in this Chip that we save here.
// This avoids having to recreate them every time we use them.
2023-10-11 11:37:45 -07:00
DEGREE gl.Variable `gnark:"-"`
DEGREE_BITS_F gl.Variable `gnark:"-"`
DEGREE_QE gl.QuadraticExtensionVariable `gnark:"-"`
commonDataKIs []gl.Variable `gnark:"-"`
evaluateGatesChip *gates.EvaluateGatesChip
2022-10-31 19:51:51 -07:00
}
2023-10-11 14:53:34 -07:00
func NewPlonkChip(api frontend.API, commonData types.CommonCircuitData) *PlonkChip {
// Create the gates based on commonData GateIds
createdGates := []gates.Gate{}
for _, gateId := range commonData.GateIds {
createdGates = append(createdGates, gates.GateInstanceFromId(gateId))
}
evaluateGatesChip := gates.NewEvaluateGatesChip(
api,
createdGates,
commonData.NumGateConstraints,
commonData.SelectorsInfo,
)
2022-10-31 19:51:51 -07:00
return &PlonkChip{
api: api,
2022-10-31 19:51:51 -07:00
commonData: commonData,
DEGREE: gl.NewVariable(1 << commonData.DegreeBits),
DEGREE_BITS_F: gl.NewVariable(commonData.DegreeBits),
DEGREE_QE: gl.NewVariable(1 << commonData.DegreeBits).ToQuadraticExtension(),
commonDataKIs: gl.Uint64ArrayToVariableArray(commonData.KIs),
evaluateGatesChip: evaluateGatesChip,
2022-10-31 19:51:51 -07:00
}
2022-10-28 06:54:31 -07:00
}
func (p *PlonkChip) expPowerOf2Extension(x gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
glApi := gl.New(p.api)
2022-10-28 06:54:31 -07:00
for i := uint64(0); i < p.commonData.DegreeBits; i++ {
x = glApi.MulExtension(x, x)
2022-10-28 06:54:31 -07:00
}
return x
}
func (p *PlonkChip) evalL0(x gl.QuadraticExtensionVariable, xPowN gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
2022-10-28 06:54:31 -07:00
// L_0(x) = (x^n - 1) / (n * (x - 1))
glApi := gl.New(p.api)
evalZeroPoly := glApi.SubExtension(
2022-10-28 06:54:31 -07:00
xPowN,
gl.OneExtension(),
2022-10-28 06:54:31 -07:00
)
denominator := glApi.SubExtension(
glApi.ScalarMulExtension(x, p.DEGREE),
2022-10-31 19:51:51 -07:00
p.DEGREE_QE,
2022-10-28 06:54:31 -07:00
)
return glApi.DivExtension(
2022-10-28 17:02:55 -07:00
evalZeroPoly,
2022-10-28 06:54:31 -07:00
denominator,
)
}
2022-10-28 15:29:25 -07:00
func (p *PlonkChip) checkPartialProducts(
numerators []gl.QuadraticExtensionVariable,
denominators []gl.QuadraticExtensionVariable,
2022-10-28 17:02:55 -07:00
challengeNum uint64,
openings variables.OpeningSet,
) []gl.QuadraticExtensionVariable {
glApi := gl.New(p.api)
2022-10-28 15:29:25 -07:00
numPartProds := p.commonData.NumPartialProducts
quotDegreeFactor := p.commonData.QuotientDegreeFactor
productAccs := make([]gl.QuadraticExtensionVariable, 0, numPartProds+2)
2022-11-17 17:33:12 -08:00
productAccs = append(productAccs, openings.PlonkZs[challengeNum])
productAccs = append(productAccs, openings.PartialProducts[challengeNum*numPartProds:(challengeNum+1)*numPartProds]...)
productAccs = append(productAccs, openings.PlonkZsNext[challengeNum])
2022-10-28 06:54:31 -07:00
partialProductChecks := make([]gl.QuadraticExtensionVariable, 0, numPartProds)
2022-10-28 06:54:31 -07:00
2022-10-31 19:51:51 -07:00
for i := uint64(0); i <= numPartProds; i += 1 {
2022-10-28 15:29:25 -07:00
ppStartIdx := i * quotDegreeFactor
2022-10-28 06:54:31 -07:00
numeProduct := numerators[ppStartIdx]
denoProduct := denominators[ppStartIdx]
2022-10-28 15:29:25 -07:00
for j := uint64(1); j < quotDegreeFactor; j++ {
numeProduct = glApi.MulExtension(numeProduct, numerators[ppStartIdx+j])
denoProduct = glApi.MulExtension(denoProduct, denominators[ppStartIdx+j])
2022-10-28 06:54:31 -07:00
}
partialProductCheck := glApi.SubExtension(
glApi.MulExtension(productAccs[i], numeProduct),
glApi.MulExtension(productAccs[i+1], denoProduct),
2022-10-28 06:54:31 -07:00
)
partialProductChecks = append(partialProductChecks, partialProductCheck)
}
return partialProductChecks
}
func (p *PlonkChip) evalVanishingPoly(
vars gates.EvaluationVars,
proofChallenges variables.ProofChallenges,
openings variables.OpeningSet,
zetaPowN gl.QuadraticExtensionVariable,
) []gl.QuadraticExtensionVariable {
glApi := gl.New(p.api)
constraintTerms := p.evaluateGatesChip.EvaluateGateConstraints(vars)
2022-10-28 06:54:31 -07:00
// Calculate the k[i] * x
sIDs := make([]gl.QuadraticExtensionVariable, p.commonData.Config.NumRoutedWires)
2022-10-28 06:54:31 -07:00
for i := uint64(0); i < p.commonData.Config.NumRoutedWires; i++ {
sIDs[i] = glApi.ScalarMulExtension(proofChallenges.PlonkZeta, p.commonDataKIs[i])
2022-10-28 06:54:31 -07:00
}
// Calculate L_0(zeta)
2022-11-17 17:33:12 -08:00
l0Zeta := p.evalL0(proofChallenges.PlonkZeta, zetaPowN)
2022-10-28 06:54:31 -07:00
vanishingZ1Terms := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumChallenges)
vanishingPartialProductsTerms := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumChallenges*p.commonData.NumPartialProducts)
2022-10-28 06:54:31 -07:00
for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
// L_0(zeta) (Z(zeta) - 1) = 0
z1_term := glApi.MulExtension(
2022-10-28 17:02:55 -07:00
l0Zeta,
glApi.SubExtension(openings.PlonkZs[i], gl.OneExtension()))
2022-10-28 17:02:55 -07:00
vanishingZ1Terms = append(vanishingZ1Terms, z1_term)
2022-10-28 06:54:31 -07:00
numeratorValues := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumRoutedWires)
denominatorValues := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumRoutedWires)
2022-10-28 06:54:31 -07:00
for j := uint64(0); j < p.commonData.Config.NumRoutedWires; j++ {
// The numerator is `beta * s_id + wire_value + gamma`, and the denominator is
// `beta * s_sigma + wire_value + gamma`.
wireValuePlusGamma := glApi.AddExtension(
2022-11-17 17:33:12 -08:00
openings.Wires[j],
gl.NewQuadraticExtensionVariable(proofChallenges.PlonkGammas[i], gl.Zero()),
2022-10-28 15:51:53 -07:00
)
2022-10-28 17:02:55 -07:00
numerator := glApi.AddExtension(
glApi.MulExtension(
gl.NewQuadraticExtensionVariable(proofChallenges.PlonkBetas[i], gl.Zero()),
2022-10-28 17:02:55 -07:00
sIDs[j],
2022-10-28 06:54:31 -07:00
),
2022-10-28 17:02:55 -07:00
wireValuePlusGamma,
2022-10-28 06:54:31 -07:00
)
denominator := glApi.AddExtension(
glApi.MulExtension(
gl.NewQuadraticExtensionVariable(proofChallenges.PlonkBetas[i], gl.Zero()),
2022-11-17 17:33:12 -08:00
openings.PlonkSigmas[j],
2022-10-28 06:54:31 -07:00
),
2022-10-28 17:02:55 -07:00
wireValuePlusGamma,
2022-10-28 06:54:31 -07:00
)
2022-10-28 17:02:55 -07:00
numeratorValues = append(numeratorValues, numerator)
denominatorValues = append(denominatorValues, denominator)
2022-10-28 06:54:31 -07:00
}
2022-10-28 15:29:25 -07:00
2022-10-28 17:02:55 -07:00
vanishingPartialProductsTerms = append(
vanishingPartialProductsTerms,
2022-11-17 17:33:12 -08:00
p.checkPartialProducts(numeratorValues, denominatorValues, i, openings)...,
2022-10-28 15:29:25 -07:00
)
2022-10-28 06:54:31 -07:00
}
2022-11-01 16:07:03 -07:00
vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...)
vanishingTerms = append(vanishingTerms, constraintTerms...)
2022-11-01 16:07:03 -07:00
reducedValues := make([]gl.QuadraticExtensionVariable, p.commonData.Config.NumChallenges)
2022-11-01 16:07:03 -07:00
for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
reducedValues[i] = gl.ZeroExtension()
2022-11-01 16:07:03 -07:00
}
// reverse iterate the vanishingPartialProductsTerms array
for i := len(vanishingTerms) - 1; i >= 0; i-- {
for j := uint64(0); j < p.commonData.Config.NumChallenges; j++ {
reducedValues[j] = glApi.AddExtension(
2022-11-01 16:07:03 -07:00
vanishingTerms[i],
glApi.ScalarMulExtension(
2022-11-01 16:07:03 -07:00
reducedValues[j],
2022-11-17 17:33:12 -08:00
proofChallenges.PlonkAlphas[j],
2022-11-01 16:07:03 -07:00
),
)
}
}
return reducedValues
2022-10-28 06:54:31 -07:00
}
func (p *PlonkChip) Verify(
proofChallenges variables.ProofChallenges,
openings variables.OpeningSet,
publicInputsHash poseidon.GoldilocksHashOut,
) {
glApi := gl.New(p.api)
2022-11-01 16:35:21 -07:00
// Calculate zeta^n
2022-11-17 17:33:12 -08:00
zetaPowN := p.expPowerOf2Extension(proofChallenges.PlonkZeta)
2022-11-01 16:35:21 -07:00
localConstants := openings.Constants
localWires := openings.Wires
vars := gates.NewEvaluationVars(
localConstants,
localWires,
publicInputsHash,
)
vanishingPolysZeta := p.evalVanishingPoly(*vars, proofChallenges, openings, zetaPowN)
2022-11-01 16:35:21 -07:00
// Calculate Z(H)
zHZeta := glApi.SubExtension(zetaPowN, gl.OneExtension())
2022-11-01 16:35:21 -07:00
// `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.
2022-11-17 17:33:12 -08:00
for i := 0; i < len(vanishingPolysZeta); i++ {
2022-11-22 16:50:43 -08:00
quotientPolysStartIdx := i * int(p.commonData.QuotientDegreeFactor)
quotientPolysEndIdx := quotientPolysStartIdx + int(p.commonData.QuotientDegreeFactor)
prod := glApi.MulExtension(
2022-11-01 16:35:21 -07:00
zHZeta,
glApi.ReduceWithPowers(
2022-11-17 17:33:12 -08:00
openings.QuotientPolys[quotientPolysStartIdx:quotientPolysEndIdx],
2022-11-01 16:35:21 -07:00
zetaPowN,
),
)
glApi.AssertIsEqualExtension(vanishingPolysZeta[i], prod)
2022-11-01 16:35:21 -07:00
}
2022-10-28 06:54:31 -07:00
}