arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/plonky2_verifier/gate.go
plonky2_verifier/gate.goRaw
  1package plonky2_verifier
  2
  3import (
  4	"fmt"
  5	. "gnark-plonky2-verifier/field"
  6	"regexp"
  7	"strconv"
  8	"strings"
  9
 10	"github.com/consensys/gnark-crypto/field/goldilocks"
 11)
 12
 13type gate interface {
 14	Id() string
 15	EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension
 16}
 17
 18func GateInstanceFromId(gateId string) gate {
 19	if strings.HasPrefix(gateId, "ArithmeticGate") {
 20		numOpsRaw := strings.Split(gateId, ":")[1]
 21		numOpsRaw = strings.Split(numOpsRaw, "}")[0]
 22		numOpsRaw = strings.TrimSpace(numOpsRaw)
 23		numOps, err := strconv.Atoi(numOpsRaw)
 24		if err != nil {
 25			panic("Invalid gate ID for ArithmeticGate")
 26		}
 27		return NewArithmeticGate(uint64(numOps))
 28	}
 29
 30	if strings.HasPrefix(gateId, "ConstantGate") {
 31		numConstsRaw := strings.Split(gateId, ":")[1]
 32		numConstsRaw = strings.Split(numConstsRaw, "}")[0]
 33		numConstsRaw = strings.TrimSpace(numConstsRaw)
 34		numConsts, err := strconv.Atoi(numConstsRaw)
 35		if err != nil {
 36			panic("Invalid gate ID")
 37		}
 38		return NewConstantGate(uint64(numConsts))
 39	}
 40
 41	if gateId == "NoopGate" {
 42		return NewNoopGate()
 43	}
 44
 45	if gateId == "PublicInputGate" {
 46		return NewPublicInputGate()
 47	}
 48
 49	if strings.HasPrefix(gateId, "PoseidonGate") {
 50		return NewPoseidonGate()
 51	}
 52
 53	if strings.HasPrefix(gateId, "BaseSumGate") {
 54		// Has the format "BaseSumGate { num_limbs: 32 } + Base: 2"
 55
 56		regEx := "BaseSumGate { num_limbs: (?P<numLimbs>[0-9]+) } \\+ Base: (?P<base>[0-9]+)"
 57		r, err := regexp.Compile(regEx)
 58		if err != nil {
 59			panic("Invalid BaseSumGate regular expression")
 60		}
 61
 62		matches := getRegExMatches(r, gateId)
 63		numLimbs, hasNumLimbs := matches["numLimbs"]
 64		base, hasBase := matches["base"]
 65		if !hasNumLimbs || !hasBase {
 66			panic("Invalid BaseSumGate ID")
 67		}
 68
 69		return NewBaseSumGate(uint64(numLimbs), uint64(base))
 70	}
 71
 72	if strings.HasPrefix(gateId, "RandomAccessGate") {
 73		// Has the format "RandomAccessGate { bits: 2, num_copies: 13, num_extra_constants: 2, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
 74
 75		regEx := "RandomAccessGate { bits: (?P<bits>[0-9]+), num_copies: (?P<numCopies>[0-9]+), num_extra_constants: (?P<numExtraConstants>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>"
 76		r, err := regexp.Compile(regEx)
 77		if err != nil {
 78			panic("Invalid RandomAccessGate regular expression")
 79		}
 80
 81		matches := getRegExMatches(r, gateId)
 82		bits, hasBits := matches["bits"]
 83		numCopies, hasNumCopies := matches["numCopies"]
 84		numExtraConstants, hasNumExtraConstants := matches["numExtraConstants"]
 85		if !hasBits || !hasNumCopies || !hasNumExtraConstants {
 86			panic("Invalid RandomAccessGate ID")
 87		}
 88
 89		return NewRandomAccessGate(uint64(bits), uint64(numCopies), uint64(numExtraConstants))
 90	}
 91
 92	if strings.HasPrefix(gateId, "ArithmeticExtension") {
 93		// Has the format "ArithmeticExtensionGate { num_ops: 10 }"
 94
 95		regEx := "ArithmeticExtensionGate { num_ops: (?P<numOps>[0-9]+) }"
 96		r, err := regexp.Compile(regEx)
 97		if err != nil {
 98			panic("Invalid ArithmeticExtensionGate regular expression")
 99		}
100
101		matches := getRegExMatches(r, gateId)
102		numOps, hasNumOps := matches["numOps"]
103		if !hasNumOps {
104			panic("Invalid ArithmeticExtensionGate ID")
105		}
106
107		return NewArithmeticExtensionGate(uint64(numOps))
108	}
109
110	if strings.HasPrefix(gateId, "MulExtensionGate") {
111		// Has the format "MulExtensionGate { num_ops: 13 }"
112
113		regEx := "MulExtensionGate { num_ops: (?P<numOps>[0-9]+) }"
114		r, err := regexp.Compile(regEx)
115		if err != nil {
116			panic("Invalid MulExtensionGate regular expression")
117		}
118
119		matches := getRegExMatches(r, gateId)
120		numOps, hasNumOps := matches["numOps"]
121		if !hasNumOps {
122			panic("Invalid MulExtensionGate ID")
123		}
124
125		return NewMultiplicationExtensionGate(uint64(numOps))
126	}
127
128	if strings.HasPrefix(gateId, "ReducingExtensionGate") {
129		// Has the format "ReducingExtensionGate { num_coeffs: 33 }"
130
131		regEx := "ReducingExtensionGate { num_coeffs: (?P<numCoeffs>[0-9]+) }"
132		r, err := regexp.Compile(regEx)
133		if err != nil {
134			panic("Invalid ReducingExtensionGate regular expression")
135		}
136
137		matches := getRegExMatches(r, gateId)
138		numCoeffs, hasNumCoeffs := matches["numCoeffs"]
139		if !hasNumCoeffs {
140			panic("Invalid ReducingExtensionGate ID")
141		}
142
143		return NewReducingExtensionGate(uint64(numCoeffs))
144	}
145
146	if strings.HasPrefix(gateId, "ReducingGate") {
147		// Has the format "ReducingGate { num_coeffs: 33 }"
148
149		regEx := "ReducingGate { num_coeffs: (?P<numCoeffs>[0-9]+) }"
150		r, err := regexp.Compile(regEx)
151		if err != nil {
152			panic("Invalid ReducingGate regular expression")
153		}
154
155		matches := getRegExMatches(r, gateId)
156		numCoeffs, hasNumCoeffs := matches["numCoeffs"]
157		if !hasNumCoeffs {
158			panic("Invalid ReducingGate ID")
159		}
160
161		return NewReducingGate(uint64(numCoeffs))
162	}
163
164	if strings.HasPrefix(gateId, "ExponentiationGate") {
165		// Has the format "ExponentiationGate { num_power_bits: 67, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
166
167		regEx := "ExponentiationGate { num_power_bits: (?P<numPowerBits>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>"
168		r, err := regexp.Compile(regEx)
169		if err != nil {
170			panic("Invalid ExponentiationGate regular expression")
171		}
172
173		matches := getRegExMatches(r, gateId)
174		numPowerBits, hasNumPowerBits := matches["numPowerBits"]
175		if !hasNumPowerBits {
176			panic("Invalid ExponentiationGate ID")
177		}
178
179		return NewExponentiationGate(uint64(numPowerBits))
180	}
181
182	// CosetInterpolationGate { subgroup_bits: 4, degree: 6, barycentric_weights: [17293822565076172801, 18374686475376656385, 18446744069413535745, 281474976645120, 17592186044416, 18446744069414584577, 18446744000695107601, 18446744065119617025, 1152921504338411520, 72057594037927936, 18446744069415632897, 18446462594437939201, 18446726477228539905, 18446744069414584065, 68719476720, 4294967296], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
183	if strings.HasPrefix(gateId, "CosetInterpolationGate") {
184		// Has the format CosetInterpolationGate { subgroup_bits: 4, degree: 6, barycentric_weights: [17293822565076172801, 18374686475376656385, 18446744069413535745, 281474976645120, 17592186044416, 18446744069414584577, 18446744000695107601, 18446744065119617025, 1152921504338411520, 72057594037927936, 18446744069415632897, 18446462594437939201, 18446726477228539905, 18446744069414584065, 68719476720, 4294967296], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
185
186		/*
187			regEx := "CosetInterpolationGate { subgroup_bits: (?P<subgroupBits>[0-9]+), degree: (?P<degree>[0-9]+), barycentric_weights: \\[(?P<barycentricWeights>[0-9, ]+)\\], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
188			r, err := regexp.Compile(regEx)
189			if err != nil {
190				panic("Invalid CosetInterpolationGate regular expression")
191			}
192
193			matches := getRegExMatches(r, gateId)
194			subgroupBits, hasSubgroupBits := matches["subgroupBits"]
195			degree, hasDegree := matches["degree"]
196			barycentricWeights, hasBarycentricWeights := matches["barycentricWeights"]
197			if !hasSubgroupBits || !hasDegree || !hasBarycentricWeights {
198				panic("Invalid CosetInterpolationGate ID")
199			}*/
200
201		return NewCosetInterpolationGate(
202			4,
203			6,
204			[]goldilocks.Element{
205				goldilocks.NewElement(17293822565076172801),
206				goldilocks.NewElement(18374686475376656385),
207				goldilocks.NewElement(18446744069413535745),
208				goldilocks.NewElement(281474976645120),
209				goldilocks.NewElement(17592186044416),
210				goldilocks.NewElement(18446744069414584577),
211				goldilocks.NewElement(18446744000695107601),
212				goldilocks.NewElement(18446744065119617025),
213				goldilocks.NewElement(1152921504338411520),
214				goldilocks.NewElement(72057594037927936),
215				goldilocks.NewElement(18446744069415632897),
216				goldilocks.NewElement(18446462594437939201),
217				goldilocks.NewElement(18446726477228539905),
218				goldilocks.NewElement(18446744069414584065),
219				goldilocks.NewElement(68719476720),
220				goldilocks.NewElement(4294967296),
221			},
222		)
223
224	}
225
226	panic(fmt.Sprintf("Unknown gate ID %s", gateId))
227}
228
229func getRegExMatches(r *regexp.Regexp, gateId string) map[string]int {
230	matches := r.FindStringSubmatch(gateId)
231	result := make(map[string]int)
232	for i, name := range r.SubexpNames() {
233		if i != 0 && name != "" {
234			value, err := strconv.Atoi(matches[i])
235			if err != nil {
236				panic("Invalid field value for \"name\": " + err.Error())
237			}
238			result[name] = value
239		}
240	}
241
242	return result
243}
244
245func (p *PlonkChip) computeFilter(
246	row uint64,
247	groupRange Range,
248	s QuadraticExtension,
249	manySelector bool,
250) QuadraticExtension {
251	product := p.qeAPI.ONE_QE
252	for i := groupRange.start; i < groupRange.end; i++ {
253		if i == uint64(row) {
254			continue
255		}
256
257		product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(i)), s))
258	}
259
260	if manySelector {
261		product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(UNUSED_SELECTOR)), s))
262	}
263
264	return product
265}
266
267func (p *PlonkChip) evalFiltered(
268	g gate,
269	vars EvaluationVars,
270	row uint64,
271	selectorIndex uint64,
272	groupRange Range,
273	numSelectors uint64,
274) []QuadraticExtension {
275	filter := p.computeFilter(row, groupRange, vars.localConstants[selectorIndex], numSelectors > 1)
276
277	vars.RemovePrefix(numSelectors)
278
279	unfiltered := g.EvalUnfiltered(p, vars)
280	for i := range unfiltered {
281		unfiltered[i] = p.qeAPI.MulExtension(unfiltered[i], filter)
282	}
283	return unfiltered
284}