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