gnark-plonky2-verifier/plonky2_verifier/gate.go
plonky2_verifier/gate.goRaw
1package plonky2_verifier
2
3import (
4 . "gnark-plonky2-verifier/field"
5 "regexp"
6 "strconv"
7 "strings"
8)
9
10type gate interface {
11 Id() string
12 EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension
13}
14
15func GateInstanceFromId(gateId string) gate {
16 if strings.HasPrefix(gateId, "ArithmeticGate") {
17 numOpsRaw := strings.Split(gateId, ":")[1]
18 numOpsRaw = strings.Split(numOpsRaw, "}")[0]
19 numOpsRaw = strings.TrimSpace(numOpsRaw)
20 numOps, err := strconv.Atoi(numOpsRaw)
21 if err != nil {
22 panic("Invalid gate ID for ArithmeticGate")
23 }
24 return NewArithmeticGate(uint64(numOps))
25 }
26
27 if strings.HasPrefix(gateId, "ConstantGate") {
28 numConstsRaw := strings.Split(gateId, ":")[1]
29 numConstsRaw = strings.Split(numConstsRaw, "}")[0]
30 numConstsRaw = strings.TrimSpace(numConstsRaw)
31 numConsts, err := strconv.Atoi(numConstsRaw)
32 if err != nil {
33 panic("Invalid gate ID")
34 }
35 return NewConstantGate(uint64(numConsts))
36 }
37
38 if gateId == "NoopGate" {
39 return NewNoopGate()
40 }
41
42 if gateId == "PublicInputGate" {
43 return NewPublicInputGate()
44 }
45
46 if strings.HasPrefix(gateId, "PoseidonGate") {
47 return NewPoseidonGate()
48 }
49
50 if strings.HasPrefix(gateId, "BaseSumGate") {
51 // Has the format "BaseSumGate { num_limbs: 32 } + Base: 2"
52
53 regEx := "BaseSumGate { num_limbs: (?P<numLimbs>[0-9]+) } \\+ Base: (?P<base>[0-9]+)"
54 r, err := regexp.Compile(regEx)
55 if err != nil {
56 panic("Invalid BaseSumGate regular expression")
57 }
58
59 matches := getRegExMatches(r, gateId)
60 numLimbs, hasNumLimbs := matches["numLimbs"]
61 base, hasBase := matches["base"]
62 if !hasNumLimbs || !hasBase {
63 panic("Invalid BaseSumGate ID")
64 }
65
66 return NewBaseSumGate(uint64(numLimbs), uint64(base))
67 }
68
69 if strings.HasPrefix(gateId, "RandomAccessGate") {
70 // Has the format "RandomAccessGate { bits: 2, num_copies: 13, num_extra_constants: 2, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
71
72 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]+)>"
73 r, err := regexp.Compile(regEx)
74 if err != nil {
75 panic("Invalid RandomAccessGate regular expression")
76 }
77
78 matches := getRegExMatches(r, gateId)
79 bits, hasBits := matches["bits"]
80 numCopies, hasNumCopies := matches["numCopies"]
81 numExtraConstants, hasNumExtraConstants := matches["numExtraConstants"]
82 if !hasBits || !hasNumCopies || !hasNumExtraConstants {
83 panic("Invalid RandomAccessGate ID")
84 }
85
86 return NewRandomAccessGate(uint64(bits), uint64(numCopies), uint64(numExtraConstants))
87 }
88
89 if strings.HasPrefix(gateId, "ArithmeticExtension") {
90 // Has the format "ArithmeticExtensionGate { num_ops: 10 }"
91
92 regEx := "ArithmeticExtensionGate { num_ops: (?P<numOps>[0-9]+) }"
93 r, err := regexp.Compile(regEx)
94 if err != nil {
95 panic("Invalid ArithmeticExtensionGate regular expression")
96 }
97
98 matches := getRegExMatches(r, gateId)
99 numOps, hasNumOps := matches["numOps"]
100 if !hasNumOps {
101 panic("Invalid ArithmeticExtensionGate ID")
102 }
103
104 return NewArithmeticExtensionGate(uint64(numOps))
105 }
106
107 if strings.HasPrefix(gateId, "MultiplicationExtension") {
108 // Has the format "ArithmeticExtensionGate { num_ops: 10 }"
109
110 regEx := "MultiplicationExtension { num_ops: (?P<numOps>[0-9]+) }"
111 r, err := regexp.Compile(regEx)
112 if err != nil {
113 panic("Invalid MultiplicationExtension regular expression")
114 }
115
116 matches := getRegExMatches(r, gateId)
117 numOps, hasNumOps := matches["numOps"]
118 if !hasNumOps {
119 panic("Invalid MultiplicationExtension ID")
120 }
121
122 return NewMultiplicationExtensionGate(uint64(numOps))
123 }
124
125 if strings.HasPrefix(gateId, "ReducingExtensionGate") {
126 // Has the format "ReducingExtensionGate { num_coeffs: 33 }"
127
128 regEx := "ReducingExtensionGate { num_coeffs: (?P<numCoeffs>[0-9]+) }"
129 r, err := regexp.Compile(regEx)
130 if err != nil {
131 panic("Invalid ReducingExtensionGate regular expression")
132 }
133
134 matches := getRegExMatches(r, gateId)
135 numCoeffs, hasNumCoeffs := matches["numCoeffs"]
136 if !hasNumCoeffs {
137 panic("Invalid ReducingExtensionGate ID")
138 }
139
140 return NewReducingExtensionGate(uint64(numCoeffs))
141 }
142
143 if strings.HasPrefix(gateId, "ReducingGate") {
144 // Has the format "ReducingGate { num_coeffs: 33 }"
145
146 regEx := "ReducingGate { num_coeffs: (?P<numCoeffs>[0-9]+) }"
147 r, err := regexp.Compile(regEx)
148 if err != nil {
149 panic("Invalid ReducingGate regular expression")
150 }
151
152 matches := getRegExMatches(r, gateId)
153 numCoeffs, hasNumCoeffs := matches["numCoeffs"]
154 if !hasNumCoeffs {
155 panic("Invalid ReducingGate ID")
156 }
157
158 return NewReducingGate(uint64(numCoeffs))
159 }
160
161 return nil
162 //panic(fmt.Sprintf("Unknown gate ID %s", gateId))
163}
164
165func getRegExMatches(r *regexp.Regexp, gateId string) map[string]int {
166 matches := r.FindStringSubmatch(gateId)
167 result := make(map[string]int)
168 for i, name := range r.SubexpNames() {
169 if i != 0 && name != "" {
170 value, err := strconv.Atoi(matches[i])
171 if err != nil {
172 panic("Invalid field value for \"name\": " + err.Error())
173 }
174 result[name] = value
175 }
176 }
177
178 return result
179}
180
181func (p *PlonkChip) computeFilter(
182 row uint64,
183 groupRange Range,
184 s QuadraticExtension,
185 manySelector bool,
186) QuadraticExtension {
187 product := p.qeAPI.ONE_QE
188 for i := groupRange.start; i < groupRange.end; i++ {
189 if i == uint64(row) {
190 continue
191 }
192
193 product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(i)), s))
194 }
195
196 if manySelector {
197 product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(UNUSED_SELECTOR)), s))
198 }
199
200 return product
201}
202
203func (p *PlonkChip) evalFiltered(
204 g gate,
205 vars EvaluationVars,
206 row uint64,
207 selectorIndex uint64,
208 groupRange Range,
209 numSelectors uint64,
210) []QuadraticExtension {
211 filter := p.computeFilter(row, groupRange, vars.localConstants[selectorIndex], numSelectors > 1)
212
213 vars.RemovePrefix(numSelectors)
214
215 unfiltered := g.EvalUnfiltered(p, vars)
216 for i := range unfiltered {
217 unfiltered[i] = p.qeAPI.MulExtension(unfiltered[i], filter)
218 }
219 return unfiltered
220}