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}