gnark-plonky2-verifier/plonky2_verifier/exponentiation_gate.go
plonky2_verifier/exponentiation_gate.goRaw
1package plonky2_verifier
2
3import (
4 "fmt"
5 . "gnark-plonky2-verifier/field"
6 "regexp"
7 "strconv"
8)
9
10var exponentiationGateRegex = regexp.MustCompile("ExponentiationGate { num_power_bits: (?P<numPowerBits>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>")
11
12func deserializeExponentiationGate(parameters map[string]string) gate {
13 // Has the format "ExponentiationGate { num_power_bits: 67, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
14 numPowerBits, hasNumPowerBits := parameters["numPowerBits"]
15 if !hasNumPowerBits {
16 panic("Missing field num_power_bits in ExponentiationGate")
17 }
18
19 numPowerBitsInt, err := strconv.Atoi(numPowerBits)
20 if err != nil {
21 panic("Invalid num_power_bits field in ExponentiationGate")
22 }
23
24 return NewExponentiationGate(uint64(numPowerBitsInt))
25}
26
27type ExponentiationGate struct {
28 numPowerBits uint64
29}
30
31func NewExponentiationGate(numPowerBits uint64) *ExponentiationGate {
32 return &ExponentiationGate{
33 numPowerBits: numPowerBits,
34 }
35}
36
37func (g *ExponentiationGate) Id() string {
38 return fmt.Sprintf("ExponentiationGate { num_power_bits: %d }", g.numPowerBits)
39}
40
41func (g *ExponentiationGate) wireBase() uint64 {
42 return 0
43}
44
45// / The `i`th bit of the exponent, in little-endian order.
46func (g *ExponentiationGate) wirePowerBit(i uint64) uint64 {
47 if i >= g.numPowerBits {
48 panic("Invalid power bit index")
49 }
50 return 1 + i
51}
52
53func (g *ExponentiationGate) wireOutput() uint64 {
54 return 1 + g.numPowerBits
55}
56
57func (g *ExponentiationGate) wireIntermediateValue(i uint64) uint64 {
58 if i >= g.numPowerBits {
59 panic("Invalid intermediate value index")
60 }
61 return 2 + g.numPowerBits + i
62}
63
64func (g *ExponentiationGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
65 base := vars.localWires[g.wireBase()]
66
67 var powerBits []QuadraticExtension
68 for i := uint64(0); i < g.numPowerBits; i++ {
69 powerBits = append(powerBits, vars.localWires[g.wirePowerBit(i)])
70 }
71
72 var intermediateValues []QuadraticExtension
73 for i := uint64(0); i < g.numPowerBits; i++ {
74 intermediateValues = append(intermediateValues, vars.localWires[g.wireIntermediateValue(i)])
75 }
76
77 output := vars.localWires[g.wireOutput()]
78
79 var constraints []QuadraticExtension
80
81 for i := uint64(0); i < g.numPowerBits; i++ {
82 var prevIntermediateValue QuadraticExtension
83 if i == 0 {
84 prevIntermediateValue = p.qeAPI.ONE_QE
85 } else {
86 prevIntermediateValue = p.qeAPI.SquareExtension(intermediateValues[i-1])
87 }
88
89 // powerBits is in LE order, but we accumulate in BE order.
90 curBit := powerBits[g.numPowerBits-i-1]
91
92 // Do a polynomial representation of generaized select (where the selector variable doesn't have to be binary)
93 // if b { x } else { y }
94 // i.e. `bx - (by-y)`.
95 tmp := p.qeAPI.MulExtension(curBit, p.qeAPI.ONE_QE)
96 tmp = p.qeAPI.SubExtension(tmp, p.qeAPI.ONE_QE)
97 mulBy := p.qeAPI.MulExtension(curBit, base)
98 mulBy = p.qeAPI.SubExtension(mulBy, tmp)
99 intermediateValueDiff := p.qeAPI.MulExtension(prevIntermediateValue, mulBy)
100 intermediateValueDiff = p.qeAPI.SubExtension(intermediateValueDiff, intermediateValues[i])
101 constraints = append(constraints, intermediateValueDiff)
102 }
103
104 outputDiff := p.qeAPI.SubExtension(output, intermediateValues[g.numPowerBits-1])
105 constraints = append(constraints, outputDiff)
106
107 return constraints
108}