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 numLimbsStr, hasNumLimbs := matches["numLimbs"]
61 baseStr, hasBase := matches["base"]
62 if !hasNumLimbs || !hasBase {
63 panic("Invalid BaseSumGate ID")
64 }
65
66 numLimbs, err := strconv.Atoi(numLimbsStr)
67 if err != nil {
68 panic("Invalid BaseSumGate ID: " + err.Error())
69 }
70
71 base, err := strconv.Atoi(baseStr)
72 if err != nil {
73 panic("Invalid BaseSumGate ID: " + err.Error())
74 }
75
76 return NewBaseSumGate(uint64(numLimbs), uint64(base))
77 }
78
79 if strings.HasPrefix(gateId, "RandomAccessGate") {
80 // Has the format "RandomAccessGate { bits: 2, num_copies: 13, num_extra_constants: 2, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
81
82 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]+)>"
83 r, err := regexp.Compile(regEx)
84 if err != nil {
85 panic("Invalid RandomAccessGate regular expression")
86 }
87
88 matches := getRegExMatches(r, gateId)
89 bitsStr, hasBits := matches["bits"]
90 numCopiesStr, hasNumCopies := matches["numCopies"]
91 numExtraConstantsStr, hasNumExtraConstants := matches["numExtraConstants"]
92 if !hasBits || !hasNumCopies || !hasNumExtraConstants {
93 panic("Invalid RandomAccessGate ID")
94 }
95
96 bits, err := strconv.Atoi(bitsStr)
97 if err != nil {
98 panic("Invalid RandomAccessGate ID: " + err.Error())
99 }
100
101 numCopies, err := strconv.Atoi(numCopiesStr)
102 if err != nil {
103 panic("Invalid RandomAccessGate ID: " + err.Error())
104 }
105
106 numExtraConstants, err := strconv.Atoi(numExtraConstantsStr)
107 if err != nil {
108 panic("Invalid RandomAccessGate ID: " + err.Error())
109 }
110
111 return NewRandomAccessGate(uint64(bits), uint64(numCopies), uint64(numExtraConstants))
112 }
113
114 return nil
115 //panic(fmt.Sprintf("Unknown gate ID %s", gateId))
116}
117
118func getRegExMatches(r *regexp.Regexp, gateId string) map[string]string {
119 matches := r.FindStringSubmatch(gateId)
120 result := make(map[string]string)
121 for i, name := range r.SubexpNames() {
122 if i != 0 && name != "" {
123 result[name] = matches[i]
124 }
125 }
126
127 return result
128}
129
130func (p *PlonkChip) computeFilter(
131 row uint64,
132 groupRange Range,
133 s QuadraticExtension,
134 manySelector bool,
135) QuadraticExtension {
136 product := p.qeAPI.ONE_QE
137 for i := groupRange.start; i < groupRange.end; i++ {
138 if i == uint64(row) {
139 continue
140 }
141
142 product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(i)), s))
143 }
144
145 if manySelector {
146 product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(UNUSED_SELECTOR)), s))
147 }
148
149 return product
150}
151
152func (p *PlonkChip) evalFiltered(
153 g gate,
154 vars EvaluationVars,
155 row uint64,
156 selectorIndex uint64,
157 groupRange Range,
158 numSelectors uint64,
159) []QuadraticExtension {
160 filter := p.computeFilter(row, groupRange, vars.localConstants[selectorIndex], numSelectors > 1)
161
162 vars.RemovePrefix(numSelectors)
163
164 unfiltered := g.EvalUnfiltered(p, vars)
165 for i := range unfiltered {
166 unfiltered[i] = p.qeAPI.MulExtension(unfiltered[i], filter)
167 }
168 return unfiltered
169}