arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/verifier/internal/gates/exponentiation_gate.go
verifier/internal/gates/exponentiation_gate.goRaw
  1package gates
  2
  3import (
  4	"fmt"
  5	"regexp"
  6	"strconv"
  7
  8	"github.com/consensys/gnark/frontend"
  9	"github.com/succinctlabs/gnark-plonky2-verifier/field"
 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(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
 67	base := vars.localWires[g.wireBase()]
 68
 69	var powerBits []field.QuadraticExtension
 70	for i := uint64(0); i < g.numPowerBits; i++ {
 71		powerBits = append(powerBits, vars.localWires[g.wirePowerBit(i)])
 72	}
 73
 74	var intermediateValues []field.QuadraticExtension
 75	for i := uint64(0); i < g.numPowerBits; i++ {
 76		intermediateValues = append(intermediateValues, vars.localWires[g.wireIntermediateValue(i)])
 77	}
 78
 79	output := vars.localWires[g.wireOutput()]
 80
 81	var constraints []field.QuadraticExtension
 82
 83	for i := uint64(0); i < g.numPowerBits; i++ {
 84		var prevIntermediateValue field.QuadraticExtension
 85		if i == 0 {
 86			prevIntermediateValue = qeAPI.ONE_QE
 87		} else {
 88			prevIntermediateValue = qeAPI.SquareExtension(intermediateValues[i-1])
 89		}
 90
 91		// powerBits is in LE order, but we accumulate in BE order.
 92		curBit := powerBits[g.numPowerBits-i-1]
 93
 94		// Do a polynomial representation of generaized select (where the selector variable doesn't have to be binary)
 95		// if b { x } else { y }
 96		// i.e. `bx - (by-y)`.
 97		tmp := qeAPI.MulExtension(curBit, qeAPI.ONE_QE)
 98		tmp = qeAPI.SubExtension(tmp, qeAPI.ONE_QE)
 99		mulBy := qeAPI.MulExtension(curBit, base)
100		mulBy = qeAPI.SubExtension(mulBy, tmp)
101		intermediateValueDiff := qeAPI.MulExtension(prevIntermediateValue, mulBy)
102		intermediateValueDiff = qeAPI.SubExtension(intermediateValueDiff, intermediateValues[i])
103		constraints = append(constraints, intermediateValueDiff)
104	}
105
106	outputDiff := qeAPI.SubExtension(output, intermediateValues[g.numPowerBits-1])
107	constraints = append(constraints, outputDiff)
108
109	return constraints
110}