arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
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}