arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/plonky2_verifier/coset_interpolation_gate.go
plonky2_verifier/coset_interpolation_gate.goRaw
  1package plonky2_verifier
  2
  3import (
  4	"fmt"
  5	. "gnark-plonky2-verifier/field"
  6
  7	"github.com/consensys/gnark-crypto/field/goldilocks"
  8)
  9
 10type CosetInterpolationGate struct {
 11	subgroupBits       uint64
 12	degree             uint64
 13	barycentricWeights []goldilocks.Element
 14}
 15
 16func NewCosetInterpolationGate(subgroupBits uint64, degree uint64, barycentricWeights []goldilocks.Element) *CosetInterpolationGate {
 17	return &CosetInterpolationGate{
 18		subgroupBits:       subgroupBits,
 19		degree:             degree,
 20		barycentricWeights: barycentricWeights,
 21	}
 22}
 23
 24func (g *CosetInterpolationGate) Id() string {
 25
 26	return fmt.Sprintf(
 27		"CosetInterpolationGate { subgroup_bits: %d, degree: %d, barycentric_weights: %s }",
 28		g.subgroupBits,
 29		g.degree,
 30		fmt.Sprint(g.barycentricWeights),
 31	)
 32}
 33
 34func (g *CosetInterpolationGate) numPoints() uint64 {
 35	return 1 << g.subgroupBits
 36}
 37
 38// Wire index of the coset shift.
 39func (g *CosetInterpolationGate) wireShift() uint64 {
 40	return 0
 41}
 42
 43func (g *CosetInterpolationGate) startValues() uint64 {
 44	return 1
 45}
 46
 47// Wire indices of the `i`th interpolant value.
 48func (g *CosetInterpolationGate) wiresValue(i uint64) Range {
 49	if i >= g.numPoints() {
 50		panic("Invalid point index")
 51	}
 52	start := g.startValues() + i*D
 53	return Range{start, start + D}
 54}
 55
 56func (g *CosetInterpolationGate) startEvaluationPoint() uint64 {
 57	return g.startValues() + g.numPoints()*D
 58}
 59
 60// Wire indices of the point to evaluate the interpolant at.
 61func (g *CosetInterpolationGate) wiresEvaluationPoint() Range {
 62	start := g.startEvaluationPoint()
 63	return Range{start, start + D}
 64}
 65
 66func (g *CosetInterpolationGate) startEvaluationValue() uint64 {
 67	return g.startEvaluationPoint() + D
 68}
 69
 70// Wire indices of the interpolated value.
 71func (g *CosetInterpolationGate) wiresEvaluationValue() Range {
 72	start := g.startEvaluationValue()
 73	return Range{start, start + D}
 74}
 75
 76func (g *CosetInterpolationGate) startIntermediates() uint64 {
 77	return g.startEvaluationValue() + D
 78}
 79
 80func (g *CosetInterpolationGate) numIntermediates() uint64 {
 81	return (g.numPoints() - 2) / (g.degree - 1)
 82}
 83
 84// The wires corresponding to the i'th intermediate evaluation.
 85func (g *CosetInterpolationGate) wiresIntermediateEval(i uint64) Range {
 86	if i >= g.numIntermediates() {
 87		panic("Invalid intermediate index")
 88	}
 89	start := g.startIntermediates() + D*i
 90	return Range{start, start + D}
 91}
 92
 93// The wires corresponding to the i'th intermediate product.
 94func (g *CosetInterpolationGate) wiresIntermediateProd(i uint64) Range {
 95	if i >= g.numIntermediates() {
 96		panic("Invalid intermediate index")
 97	}
 98	start := g.startIntermediates() + D*(g.numIntermediates()+i)
 99	return Range{start, start + D}
100}
101
102// Wire indices of the shifted point to evaluate the interpolant at.
103func (g *CosetInterpolationGate) wiresShiftedEvaluationPoint() Range {
104	start := g.startIntermediates() + D*2*g.numIntermediates()
105	return Range{start, start + D}
106}
107
108func (g *CosetInterpolationGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
109	constraints := []QuadraticExtension{}
110
111	shift := vars.localWires[g.wireShift()]
112	evaluationPoint := vars.GetLocalExtAlgebra(g.wiresEvaluationPoint())
113	shiftedEvaluationPoint := vars.GetLocalExtAlgebra(g.wiresShiftedEvaluationPoint())
114
115	negShift := p.qeAPI.ScalarMulExtension(shift, NEG_ONE_F)
116
117	tmp := p.qeAPI.ScalarMulExtensionAlgebra(negShift, shiftedEvaluationPoint)
118	tmp = p.qeAPI.AddExtensionAlgebra(tmp, evaluationPoint)
119
120	for i := 0; i < D; i++ {
121		constraints = append(constraints, tmp[i])
122	}
123
124	domain := TwoAdicSubgroup(g.subgroupBits)
125	values := []QEAlgebra{}
126	for i := uint64(0); i < g.numPoints(); i++ {
127		values = append(values, vars.GetLocalExtAlgebra(g.wiresValue(i)))
128	}
129	weights := g.barycentricWeights
130
131	initialEval := p.qeAPI.ZERO_QE_ALGEBRA
132	initialProd := QEAlgebra{p.qeAPI.ONE_QE, p.qeAPI.ZERO_QE}
133	computedEval, computedProd := p.qeAPI.PartialInterpolateExtAlgebra(
134		domain[:g.degree],
135		values[:g.degree],
136		weights[:g.degree],
137		shiftedEvaluationPoint,
138		initialEval,
139		initialProd,
140	)
141
142	for i := uint64(0); i < g.numIntermediates(); i++ {
143		intermediateEval := vars.GetLocalExtAlgebra(g.wiresIntermediateEval(i))
144		intermediateProd := vars.GetLocalExtAlgebra(g.wiresIntermediateProd(i))
145
146		evalDiff := p.qeAPI.SubExtensionAlgebra(intermediateEval, computedEval)
147		for j := 0; j < D; j++ {
148			constraints = append(constraints, evalDiff[j])
149		}
150
151		prodDiff := p.qeAPI.SubExtensionAlgebra(intermediateProd, computedProd)
152		for j := 0; j < D; j++ {
153			constraints = append(constraints, prodDiff[j])
154		}
155
156		startIndex := 1 + (g.degree-1)*(i+1)
157		endIndex := startIndex + g.degree - 1
158		computedEval, computedProd = p.qeAPI.PartialInterpolateExtAlgebra(
159			domain[startIndex:endIndex],
160			values[startIndex:endIndex],
161			weights[startIndex:endIndex],
162			shiftedEvaluationPoint,
163			intermediateEval,
164			intermediateProd,
165		)
166	}
167
168	evaluationValue := vars.GetLocalExtAlgebra(g.wiresEvaluationValue())
169	evalDiff := p.qeAPI.SubExtensionAlgebra(evaluationValue, computedEval)
170	for j := 0; j < D; j++ {
171		constraints = append(constraints, evalDiff[j])
172	}
173
174	return constraints
175}