From 67aa8b9d77aef02dd34a44a1b694e3a494ca108e Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Wed, 17 May 2023 18:28:34 -0700 Subject: [PATCH] exponentiation gate (#14) --- plonky2_verifier/exponentiation_gate.go | 89 +++++++++++++++++++++++++ plonky2_verifier/gate.go | 18 +++++ plonky2_verifier/gate_test.go | 1 + 3 files changed, 108 insertions(+) create mode 100644 plonky2_verifier/exponentiation_gate.go diff --git a/plonky2_verifier/exponentiation_gate.go b/plonky2_verifier/exponentiation_gate.go new file mode 100644 index 0000000..f141bb7 --- /dev/null +++ b/plonky2_verifier/exponentiation_gate.go @@ -0,0 +1,89 @@ +package plonky2_verifier + +import ( + "fmt" + . "gnark-plonky2-verifier/field" +) + +type ExponentiationGate struct { + numPowerBits uint64 +} + +func NewExponentiationGate(numPowerBits uint64) *ExponentiationGate { + return &ExponentiationGate{ + numPowerBits: numPowerBits, + } +} + +func (g *ExponentiationGate) Id() string { + return fmt.Sprintf("ExponentiationGate { num_power_bits: %d }", g.numPowerBits) +} + +func (g *ExponentiationGate) wireBase() uint64 { + return 0 +} + +// / The `i`th bit of the exponent, in little-endian order. +func (g *ExponentiationGate) wirePowerBit(i uint64) uint64 { + if i >= g.numPowerBits { + panic("Invalid power bit index") + } + return 1 + i +} + +func (g *ExponentiationGate) wireOutput() uint64 { + return 1 + g.numPowerBits +} + +func (g *ExponentiationGate) wireIntermediateValue(i uint64) uint64 { + if i >= g.numPowerBits { + panic("Invalid intermediate value index") + } + return 2 + g.numPowerBits + i +} + +func (g *ExponentiationGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension { + base := vars.localWires[g.wireBase()] + + var powerBits []QuadraticExtension + for i := uint64(0); i < g.numPowerBits; i++ { + powerBits = append(powerBits, vars.localWires[g.wirePowerBit(i)]) + } + + var intermediateValues []QuadraticExtension + for i := uint64(0); i < g.numPowerBits; i++ { + intermediateValues = append(intermediateValues, vars.localWires[g.wireIntermediateValue(i)]) + } + + output := vars.localWires[g.wireOutput()] + + var constraints []QuadraticExtension + + for i := uint64(0); i < g.numPowerBits; i++ { + var prevIntermediateValue QuadraticExtension + if i == 0 { + prevIntermediateValue = p.qeAPI.ONE_QE + } else { + prevIntermediateValue = p.qeAPI.SquareExtension(intermediateValues[i-1]) + } + + // powerBits is in LE order, but we accumulate in BE order. + curBit := powerBits[g.numPowerBits-i-1] + + // Do a polynomial representation of generaized select (where the selector variable doesn't have to be binary) + // if b { x } else { y } + // i.e. `bx - (by-y)`. + tmp := p.qeAPI.MulExtension(curBit, p.qeAPI.ONE_QE) + tmp = p.qeAPI.SubExtension(tmp, p.qeAPI.ONE_QE) + mulBy := p.qeAPI.MulExtension(curBit, base) + mulBy = p.qeAPI.SubExtension(mulBy, tmp) + intermediateValueDiff := p.qeAPI.MulExtension(prevIntermediateValue, mulBy) + intermediateValueDiff = p.qeAPI.SubExtension(intermediateValueDiff, intermediateValues[i]) + constraints = append(constraints, intermediateValueDiff) + } + + outputDiff := p.qeAPI.SubExtension(output, intermediateValues[g.numPowerBits-1]) + constraints = append(constraints, outputDiff) + + return constraints +} diff --git a/plonky2_verifier/gate.go b/plonky2_verifier/gate.go index c215cd8..ce90ff5 100644 --- a/plonky2_verifier/gate.go +++ b/plonky2_verifier/gate.go @@ -158,6 +158,24 @@ func GateInstanceFromId(gateId string) gate { return NewReducingGate(uint64(numCoeffs)) } + if strings.HasPrefix(gateId, "ExponentiationGate") { + // Has the format "ExponentiationGate { num_power_bits: 67, _phantom: PhantomData }" + + regEx := "ExponentiationGate { num_power_bits: (?P[0-9]+), _phantom: PhantomData }[0-9]+)>" + r, err := regexp.Compile(regEx) + if err != nil { + panic("Invalid ExponentiationGate regular expression") + } + + matches := getRegExMatches(r, gateId) + numPowerBits, hasNumPowerBits := matches["numPowerBits"] + if !hasNumPowerBits { + panic("Invalid ExponentiationGate ID") + } + + return NewExponentiationGate(uint64(numPowerBits)) + } + return nil //panic(fmt.Sprintf("Unknown gate ID %s", gateId)) } diff --git a/plonky2_verifier/gate_test.go b/plonky2_verifier/gate_test.go index 11d9470..0ac2c38 100644 --- a/plonky2_verifier/gate_test.go +++ b/plonky2_verifier/gate_test.go @@ -770,6 +770,7 @@ func TestGates(t *testing.T) { {&MultiplicationExtensionGate{numOps: 13}, mulExtensionGateExpectedConstraints}, {&ReducingExtensionGate{numCoeffs: 33}, reducingExtensionGateExpectedConstraints}, {&ReducingGate{numCoeffs: 44}, reducingGateExpectedConstraints}, + {&ExponentiationGate{numPowerBits: 67}, exponentiationGateExpectedConstraints}, } for _, test := range gateTests {