Browse Source

Use optimized goldilocks in codebase (#26)

* gl

* stage 1 optimizations

* working optimized poseidon

* Fix posedion tests

* in progress gate type refactor

* working gates

* working e2e

* hm'

* hm2

* debug saga continues

* more debugging cry

* more debug

* it finally works

* optimizations

* more optimizations

* new changes

* more optimizations

* more cleanup

* some refactoring

* new files

* flattening of packages

* working commit

* more refactor

* more flattening

* more flattening

* more more refactor

* more optimizations

* more optimizations

* more optimizations

* plonk benchmark

* plonk

* fix r1cs

* resolve kevin's comments

* Update goldilocks/base.go

Co-authored-by: Kevin Jue <kjue235@gmail.com>

* Update goldilocks/base.go

Co-authored-by: Kevin Jue <kjue235@gmail.com>

* Update goldilocks/base.go

Co-authored-by: Kevin Jue <kjue235@gmail.com>

* Update goldilocks/quadratic_extension.go

Co-authored-by: Kevin Jue <kjue235@gmail.com>

* fix: resolve kevin's confusion

---------

Co-authored-by: Kevin Jue <kjue235@gmail.com>
main
John Guibas 2 years ago
committed by GitHub
parent
commit
b670530e7f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 3506 additions and 3211 deletions
  1. +8
    -9
      benchmark.go
  2. +187
    -0
      benchmark_plonk.go
  3. +166
    -0
      challenger/challenger.go
  4. +0
    -183
      field/goldilocks.go
  5. +0
    -289
      field/quadratic_extension.go
  6. +0
    -77
      field/quadratic_extension_test.go
  7. +140
    -140
      fri/fri.go
  8. +126
    -0
      fri/fri_test.go
  9. +44
    -41
      fri/fri_utils.go
  10. +2
    -0
      go.sum
  11. +362
    -0
      goldilocks/base.go
  12. +8
    -7
      goldilocks/base_test.go
  13. +234
    -0
      goldilocks/quadratic_extension.go
  14. +125
    -0
      goldilocks/quadratic_extension_algebra.go
  15. +1
    -0
      goldilocks/quadratic_extension_algebra_test.go
  16. +94
    -0
      goldilocks/quadratic_extension_test.go
  17. +9
    -10
      goldilocks/utils.go
  18. +17
    -13
      plonk/gates/arithmetic_extension_gate.go
  19. +11
    -7
      plonk/gates/arithmetic_gate.go
  20. +15
    -11
      plonk/gates/base_sum_gate.go
  21. +8
    -4
      plonk/gates/constant_gate.go
  22. +36
    -32
      plonk/gates/coset_interpolation_gate.go
  23. +20
    -19
      plonk/gates/evaluate_gates.go
  24. +19
    -15
      plonk/gates/exponentiation_gate.go
  25. +6
    -2
      plonk/gates/gates.go
  26. +768
    -0
      plonk/gates/gates_test.go
  27. +14
    -12
      plonk/gates/multiplication_extension_gate.go
  28. +7
    -3
      plonk/gates/noop_gate.go
  29. +22
    -18
      plonk/gates/poseidon_gate.go
  30. +29
    -18
      plonk/gates/poseidon_mds_gate.go
  31. +9
    -4
      plonk/gates/public_input_gate.go
  32. +21
    -17
      plonk/gates/random_access_gate.go
  33. +20
    -16
      plonk/gates/reducing_extension_gate.go
  34. +21
    -17
      plonk/gates/reducing_gate.go
  35. +0
    -0
      plonk/gates/selectors.go
  36. +10
    -10
      plonk/gates/vars.go
  37. +73
    -62
      plonk/plonk.go
  38. +6
    -10
      plonk/plonk_test.go
  39. +204
    -0
      poseidon/bn254.go
  40. +17
    -18
      poseidon/bn254_test.go
  41. +1
    -1
      poseidon/bn254constants.go
  42. +357
    -0
      poseidon/goldilocks.go
  43. +0
    -0
      poseidon/goldilocks_constants.go
  44. +16
    -17
      poseidon/goldilocks_test.go
  45. +0
    -338
      poseidon/poseidon.go
  46. +0
    -199
      poseidon/poseidon_bn128.go
  47. +11
    -12
      poseidon/public_inputs_hash_test.go
  48. +19
    -25
      types/circuit.go
  49. +99
    -0
      types/fri.go
  50. +33
    -0
      types/plonk.go
  51. +0
    -123
      verifier/common/types.go
  52. +54
    -55
      verifier/deserialize.go
  53. +1
    -1
      verifier/deserialize_test.go
  54. +0
    -124
      verifier/internal/fri/fri_test.go
  55. +0
    -763
      verifier/internal/gates/gate_test.go
  56. +0
    -160
      verifier/internal/plonk/challenger.go
  57. +0
    -227
      verifier/internal/plonk/challenger_test.go
  58. +0
    -13
      verifier/internal/plonk/types.go
  59. +0
    -28
      verifier/types.go
  60. +45
    -49
      verifier/verifier.go
  61. +11
    -12
      verifier/verifier_test.go

+ 8
- 9
benchmark.go

@ -8,10 +8,9 @@ import (
"os" "os"
"time" "time"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier" "github.com/succinctlabs/gnark-plonky2-verifier/verifier"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils"
"github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/groth16"
@ -22,8 +21,8 @@ import (
) )
type BenchmarkPlonky2VerifierCircuit struct { type BenchmarkPlonky2VerifierCircuit struct {
Proof common.Proof
PublicInputs []field.F `gnark:",public"`
Proof types.Proof
PublicInputs []gl.Variable `gnark:",public"`
verifierChip *verifier.VerifierChip `gnark:"-"` verifierChip *verifier.VerifierChip `gnark:"-"`
plonky2CircuitName string `gnark:"-"` plonky2CircuitName string `gnark:"-"`
@ -31,8 +30,8 @@ type BenchmarkPlonky2VerifierCircuit struct {
func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error { func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error {
circuitDirname := "./verifier/data/" + circuit.plonky2CircuitName + "/" circuitDirname := "./verifier/data/" + circuit.plonky2CircuitName + "/"
commonCircuitData := utils.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := utils.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
commonCircuitData := verifier.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
circuit.verifierChip = verifier.NewVerifierChip(api, commonCircuitData) circuit.verifierChip = verifier.NewVerifierChip(api, commonCircuitData)
@ -45,7 +44,7 @@ func compileCircuit(plonky2Circuit string, profileCircuit bool, serialize bool,
circuit := BenchmarkPlonky2VerifierCircuit{ circuit := BenchmarkPlonky2VerifierCircuit{
plonky2CircuitName: plonky2Circuit, plonky2CircuitName: plonky2Circuit,
} }
proofWithPis := utils.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit.Proof = proofWithPis.Proof circuit.Proof = proofWithPis.Proof
circuit.PublicInputs = proofWithPis.PublicInputs circuit.PublicInputs = proofWithPis.PublicInputs
@ -104,7 +103,7 @@ func compileCircuit(plonky2Circuit string, profileCircuit bool, serialize bool,
} }
func createProof(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk groth16.ProvingKey, vk groth16.VerifyingKey, serialize bool) groth16.Proof { func createProof(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk groth16.ProvingKey, vk groth16.VerifyingKey, serialize bool) groth16.Proof {
proofWithPis := utils.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
// Witness // Witness
assignment := &BenchmarkPlonky2VerifierCircuit{ assignment := &BenchmarkPlonky2VerifierCircuit{

+ 187
- 0
benchmark_plonk.go

@ -0,0 +1,187 @@
package main
import (
"bytes"
"flag"
"fmt"
"math/big"
"os"
"time"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/plonk"
"github.com/consensys/gnark/constraint"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/profile"
"github.com/consensys/gnark/test"
)
type BenchmarkPlonky2VerifierCircuitPlonk struct {
Proof types.Proof
PublicInputs []gl.Variable `gnark:",public"`
verifierChip *verifier.VerifierChip `gnark:"-"`
plonky2CircuitName string `gnark:"-"`
}
func (circuit *BenchmarkPlonky2VerifierCircuitPlonk) Define(api frontend.API) error {
circuitDirname := "./verifier/data/" + circuit.plonky2CircuitName + "/"
commonCircuitData := verifier.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
circuit.verifierChip = verifier.NewVerifierChip(api, commonCircuitData)
circuit.verifierChip.Verify(circuit.Proof, circuit.PublicInputs, verifierOnlyCircuitData, commonCircuitData)
return nil
}
func compileCircuitPlonk(plonky2Circuit string, profileCircuit bool, serialize bool, outputSolidity bool) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey) {
circuit := BenchmarkPlonky2VerifierCircuitPlonk{
plonky2CircuitName: plonky2Circuit,
}
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit.Proof = proofWithPis.Proof
circuit.PublicInputs = proofWithPis.PublicInputs
var p *profile.Profile
if profileCircuit {
p = profile.Start()
}
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &circuit)
if err != nil {
fmt.Println("error in building circuit", err)
os.Exit(1)
}
if profileCircuit {
p.Stop()
p.Top()
println("r1cs.GetNbCoefficients(): ", r1cs.GetNbCoefficients())
println("r1cs.GetNbConstraints(): ", r1cs.GetNbConstraints())
println("r1cs.GetNbSecretVariables(): ", r1cs.GetNbSecretVariables())
println("r1cs.GetNbPublicVariables(): ", r1cs.GetNbPublicVariables())
println("r1cs.GetNbInternalVariables(): ", r1cs.GetNbInternalVariables())
}
// Don't serialize the circuit for now, since it takes up too much memory
/*
if serialize {
fR1CS, _ := os.Create("circuit")
r1cs.WriteTo(fR1CS)
fR1CS.Close()
}
*/
srs, err := test.NewKZGSRS(r1cs)
if err != nil {
panic(err)
}
fmt.Println("Running circuit setup", time.Now())
pk, vk, err := plonk.Setup(r1cs, srs)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if serialize {
fPK, _ := os.Create("proving.key")
pk.WriteTo(fPK)
fPK.Close()
fVK, _ := os.Create("verifying.key")
vk.WriteTo(fVK)
fVK.Close()
}
if outputSolidity {
fSolidity, _ := os.Create("proof.sol")
err = vk.ExportSolidity(fSolidity)
}
return r1cs, pk, vk
}
func createProofPlonk(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk plonk.ProvingKey, vk plonk.VerifyingKey, serialize bool) plonk.Proof {
proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
// Witness
assignment := &BenchmarkPlonky2VerifierCircuitPlonk{
Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs,
}
fmt.Println("Generating witness", time.Now())
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
publicWitness, _ := witness.Public()
fmt.Println("Creating proof", time.Now())
proof, err := plonk.Prove(r1cs, pk, witness)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Verifying proof", time.Now())
err = plonk.Verify(proof, vk, publicWitness)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
const fpSize = 4 * 8
var buf bytes.Buffer
proof.WriteRawTo(&buf)
proofBytes := buf.Bytes()
var (
a [2]*big.Int
b [2][2]*big.Int
c [2]*big.Int
)
// proof.Ar, proof.Bs, proof.Krs
a[0] = new(big.Int).SetBytes(proofBytes[fpSize*0 : fpSize*1])
a[1] = new(big.Int).SetBytes(proofBytes[fpSize*1 : fpSize*2])
b[0][0] = new(big.Int).SetBytes(proofBytes[fpSize*2 : fpSize*3])
b[0][1] = new(big.Int).SetBytes(proofBytes[fpSize*3 : fpSize*4])
b[1][0] = new(big.Int).SetBytes(proofBytes[fpSize*4 : fpSize*5])
b[1][1] = new(big.Int).SetBytes(proofBytes[fpSize*5 : fpSize*6])
c[0] = new(big.Int).SetBytes(proofBytes[fpSize*6 : fpSize*7])
c[1] = new(big.Int).SetBytes(proofBytes[fpSize*7 : fpSize*8])
println("a[0] is ", a[0].String())
println("a[1] is ", a[1].String())
println("b[0][0] is ", b[0][0].String())
println("b[0][1] is ", b[0][1].String())
println("b[1][0] is ", b[1][0].String())
println("b[1][1] is ", b[1][1].String())
println("c[0] is ", c[0].String())
println("c[1] is ", c[1].String())
return proof
}
func main() {
plonky2Circuit := flag.String("plonky2-circuit", "", "plonky2 circuit to benchmark")
profileCircuit := flag.Bool("profile", false, "profile the circuit")
serialize := flag.Bool("serialize", false, "serialize the circuit")
outputSolidity := flag.Bool("solidity", false, "output solidity code for the circuit")
flag.Parse()
if plonky2Circuit == nil || *plonky2Circuit == "" {
fmt.Println("Please provide a plonky2 circuit to benchmark")
os.Exit(1)
}
r1cs, pk, vk := compileCircuitPlonk(*plonky2Circuit, *profileCircuit, *serialize, *outputSolidity)
createProofPlonk(*plonky2Circuit, r1cs, pk, vk, *serialize)
}

+ 166
- 0
challenger/challenger.go

@ -0,0 +1,166 @@
package challenger
import (
"fmt"
"github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/fri"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
)
type Chip struct {
api frontend.API `gnark:"-"`
poseidonChip *poseidon.GoldilocksChip
poseidonBN254Chip *poseidon.BN254Chip
spongeState [poseidon.SPONGE_WIDTH]gl.Variable
inputBuffer []gl.Variable
outputBuffer []gl.Variable
}
func NewChip(api frontend.API) *Chip {
var spongeState [poseidon.SPONGE_WIDTH]gl.Variable
var inputBuffer []gl.Variable
var outputBuffer []gl.Variable
for i := 0; i < poseidon.SPONGE_WIDTH; i++ {
spongeState[i] = gl.Zero()
}
poseidonChip := poseidon.NewGoldilocksChip(api)
poseidonBN254Chip := poseidon.NewBN254Chip(api)
return &Chip{
api: api,
poseidonChip: poseidonChip,
poseidonBN254Chip: poseidonBN254Chip,
spongeState: spongeState,
inputBuffer: inputBuffer,
outputBuffer: outputBuffer,
}
}
func (c *Chip) ObserveElement(element gl.Variable) {
c.outputBuffer = clearBuffer(c.outputBuffer)
c.inputBuffer = append(c.inputBuffer, element)
if len(c.inputBuffer) == poseidon.SPONGE_RATE {
c.duplexing()
}
}
func (c *Chip) ObserveElements(elements []gl.Variable) {
for i := 0; i < len(elements); i++ {
c.ObserveElement(elements[i])
}
}
func (c *Chip) ObserveHash(hash poseidon.GoldilocksHashOut) {
elements := c.poseidonChip.ToVec(hash)
c.ObserveElements(elements)
}
func (c *Chip) ObserveBN254Hash(hash poseidon.BN254HashOut) {
elements := c.poseidonBN254Chip.ToVec(hash)
c.ObserveElements(elements)
}
func (c *Chip) ObserveCap(cap []poseidon.BN254HashOut) {
for i := 0; i < len(cap); i++ {
c.ObserveBN254Hash(cap[i])
}
}
func (c *Chip) ObserveExtensionElement(element gl.QuadraticExtensionVariable) {
c.ObserveElements(element[:])
}
func (c *Chip) ObserveExtensionElements(elements []gl.QuadraticExtensionVariable) {
for i := 0; i < len(elements); i++ {
c.ObserveExtensionElement(elements[i])
}
}
func (c *Chip) ObserveOpenings(openings fri.Openings) {
for i := 0; i < len(openings.Batches); i++ {
c.ObserveExtensionElements(openings.Batches[i].Values)
}
}
func (c *Chip) GetChallenge() gl.Variable {
if len(c.inputBuffer) != 0 || len(c.outputBuffer) == 0 {
c.duplexing()
}
challenge := c.outputBuffer[len(c.outputBuffer)-1]
c.outputBuffer = c.outputBuffer[:len(c.outputBuffer)-1]
return challenge
}
func (c *Chip) GetNChallenges(n uint64) []gl.Variable {
challenges := make([]gl.Variable, n)
for i := uint64(0); i < n; i++ {
challenges[i] = c.GetChallenge()
}
return challenges
}
func (c *Chip) GetExtensionChallenge() gl.QuadraticExtensionVariable {
values := c.GetNChallenges(2)
return gl.QuadraticExtensionVariable{values[0], values[1]}
}
func (c *Chip) GetHash() poseidon.GoldilocksHashOut {
return [4]gl.Variable{c.GetChallenge(), c.GetChallenge(), c.GetChallenge(), c.GetChallenge()}
}
func (c *Chip) GetFriChallenges(
commitPhaseMerkleCaps []types.FriMerkleCap,
finalPoly types.PolynomialCoeffs,
powWitness gl.Variable,
degreeBits uint64,
config types.FriConfig,
) types.FriChallenges {
numFriQueries := config.NumQueryRounds
friAlpha := c.GetExtensionChallenge()
var friBetas []gl.QuadraticExtensionVariable
for i := 0; i < len(commitPhaseMerkleCaps); i++ {
c.ObserveCap(commitPhaseMerkleCaps[i])
friBetas = append(friBetas, c.GetExtensionChallenge())
}
c.ObserveExtensionElements(finalPoly.Coeffs)
c.ObserveElement(powWitness)
friPowResponse := c.GetChallenge()
friQueryIndices := c.GetNChallenges(numFriQueries)
return types.FriChallenges{
FriAlpha: friAlpha,
FriBetas: friBetas,
FriPowResponse: friPowResponse,
FriQueryIndices: friQueryIndices,
}
}
func clearBuffer(buffer []gl.Variable) []gl.Variable {
return make([]gl.Variable, 0)
}
func (c *Chip) duplexing() {
if len(c.inputBuffer) > poseidon.SPONGE_RATE {
fmt.Println(len(c.inputBuffer))
panic("something went wrong")
}
glApi := gl.NewChip(c.api)
for i := 0; i < len(c.inputBuffer); i++ {
c.spongeState[i] = glApi.Reduce(c.inputBuffer[i])
}
c.inputBuffer = clearBuffer(c.inputBuffer)
c.spongeState = c.poseidonChip.Poseidon(c.spongeState)
clearBuffer(c.outputBuffer)
for i := 0; i < poseidon.SPONGE_RATE; i++ {
c.outputBuffer = append(c.outputBuffer, c.spongeState[i])
}
}

+ 0
- 183
field/goldilocks.go

@ -1,183 +0,0 @@
package field
import (
"fmt"
"math/big"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/constraint/solver"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/bits"
"github.com/consensys/gnark/std/math/emulated"
)
type EmulatedField = emulated.Goldilocks
type F = *emulated.Element[EmulatedField]
type FieldAPI = *emulated.Field[emulated.Goldilocks]
var TEST_CURVE = ecc.BN254
func NewFieldAPI(api frontend.API) FieldAPI {
fieldAPI, err := emulated.NewField[EmulatedField](api)
if err != nil {
panic(err)
}
return fieldAPI
}
func NewFieldConst(x uint64) F {
val := emulated.ValueOf[EmulatedField](x)
return &val
}
func NewFieldConstFromString(x string) F {
val := emulated.ValueOf[EmulatedField](x)
return &val
}
var ONE_F = NewFieldConst(1)
var ZERO_F = NewFieldConst(0)
var NEG_ONE_F = NewFieldConst(EmulatedField{}.Modulus().Uint64() - 1)
var GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR = goldilocks.NewElement(7)
var GOLDILOCKS_TWO_ADICITY = uint64(32)
var GOLDILOCKS_POWER_OF_TWO_GENERATOR = goldilocks.NewElement(1753635133440165772)
var GOLDILOCKS_MODULUS = EmulatedField{}.Modulus()
func GoldilocksPrimitiveRootOfUnity(nLog uint64) goldilocks.Element {
if nLog > GOLDILOCKS_TWO_ADICITY {
panic("nLog is greater than GOLDILOCKS_TWO_ADICITY")
}
res := goldilocks.NewElement(GOLDILOCKS_POWER_OF_TWO_GENERATOR.Uint64())
for i := 0; i < int(GOLDILOCKS_TWO_ADICITY-nLog); i++ {
res.Square(&res)
}
return res
}
func TwoAdicSubgroup(nLog uint64) []goldilocks.Element {
if nLog > GOLDILOCKS_TWO_ADICITY {
panic("nLog is greater than GOLDILOCKS_TWO_ADICITY")
}
var res []goldilocks.Element
rootOfUnity := GoldilocksPrimitiveRootOfUnity(nLog)
res = append(res, goldilocks.NewElement(1))
for i := 0; i < (1 << nLog); i++ {
lastElement := res[len(res)-1]
res = append(res, *lastElement.Mul(&lastElement, &rootOfUnity))
}
return res
}
func IsZero(api frontend.API, fieldAPI *emulated.Field[emulated.Goldilocks], x F) frontend.Variable {
reduced := fieldAPI.Reduce(x)
limbs := reduced.Limbs
isZero := api.IsZero(limbs[0])
for i := 1; i < len(limbs); i++ {
isZero = api.Mul(isZero, api.IsZero(limbs[i]))
}
return isZero
}
func init() {
// register hints
solver.RegisterHint(GoldilocksMulAddHint)
}
func GoldilocksRangeCheck(api frontend.API, x frontend.Variable) {
// Goldilocks' modulus is 2^64 - 2^32 + 1,
// which is "1111111111111111111111111111111100000000000000000000000000000001' in big endian binary
// This function will first verify that x is at most 64 bits wide.
// Then it checks that if the bits[0:31] (in big-endian) are all 1, then bits[32:64] are all zero
// First decompose x into 64 bits. The bits will be in little-endian order.
bits := bits.ToBinary(api, x, bits.WithNbDigits(64))
// Those bits should compose back to x
reconstructedX := frontend.Variable(0)
c := uint64(1)
for i := 0; i < 64; i++ {
reconstructedX = api.Add(reconstructedX, api.Mul(bits[i], c))
c = c << 1
api.AssertIsBoolean(bits[i])
}
api.AssertIsEqual(x, reconstructedX)
mostSigBits32Sum := frontend.Variable(0)
for i := 32; i < 64; i++ {
mostSigBits32Sum = api.Add(mostSigBits32Sum, bits[i])
}
leastSigBits32Sum := frontend.Variable(0)
for i := 0; i < 32; i++ {
leastSigBits32Sum = api.Add(leastSigBits32Sum, bits[i])
}
// If mostSigBits32Sum < 32, then we know that x < (2^63 + ... + 2^32 + 0 * 2^31 + ... + 0 * 2^0), which equals to 2^64 - 2^32
// So in that case, we don't need to do any more checks.
// If mostSigBits32Sum == 32, then we need to check that x == 2^64 - 2^32 (max GL value)
shouldCheck := api.IsZero(api.Sub(mostSigBits32Sum, 32))
api.AssertIsEqual(
api.Select(
shouldCheck,
leastSigBits32Sum,
frontend.Variable(0),
),
frontend.Variable(0),
)
}
// Calculates operands[0] * operands[1] + operands[2]
// This function assumes that all operands are within goldilocks, and will panic otherwise
// It will ensure that the result is within goldilocks
func GoldilocksMulAdd(api frontend.API, operand1, operand2, operand3 frontend.Variable) frontend.Variable {
result, err := api.Compiler().NewHint(GoldilocksMulAddHint, 2, operand1, operand2, operand3)
if err != nil {
panic(err)
}
quotient := result[0]
remainder := result[1]
// Verify the calculated value
lhs := api.Mul(operand1, operand2)
lhs = api.Add(lhs, operand3)
rhs := api.Add(api.Mul(quotient, GOLDILOCKS_MODULUS), remainder)
api.AssertIsEqual(lhs, rhs)
GoldilocksRangeCheck(api, quotient)
GoldilocksRangeCheck(api, remainder)
return remainder
}
func GoldilocksMulAddHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
if len(inputs) != 3 {
panic("GoldilocksMulAddHint expects 3 input operands")
}
for _, operand := range inputs {
if operand.Cmp(GOLDILOCKS_MODULUS) >= 0 {
panic(fmt.Sprintf("%s is not in the field", operand.String()))
}
}
product := new(big.Int).Mul(inputs[0], inputs[1])
sum := new(big.Int).Add(product, inputs[2])
quotient := new(big.Int).Div(sum, GOLDILOCKS_MODULUS)
remainder := new(big.Int).Rem(sum, GOLDILOCKS_MODULUS)
results[0] = quotient
results[1] = remainder
return nil
}

+ 0
- 289
field/quadratic_extension.go

@ -1,289 +0,0 @@
package field
import (
"math/bits"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend"
)
const D = 2
type QuadraticExtension = [2]F
type QEAlgebra = [D]QuadraticExtension
type QuadraticExtensionAPI struct {
api frontend.API
fieldAPI FieldAPI
W F
DTH_ROOT F
ONE_QE QuadraticExtension
ZERO_QE QuadraticExtension
ZERO_QE_ALGEBRA QEAlgebra
}
func NewQuadraticExtensionAPI(api frontend.API, fieldAPI FieldAPI) *QuadraticExtensionAPI {
var ZERO_QE = QuadraticExtension{ZERO_F, ZERO_F}
var ZERO_QE_ALGEBRA QEAlgebra
for i := 0; i < D; i++ {
ZERO_QE_ALGEBRA[i] = ZERO_QE
}
return &QuadraticExtensionAPI{
api: api,
fieldAPI: fieldAPI,
W: NewFieldConst(7),
DTH_ROOT: NewFieldConst(18446744069414584320),
ONE_QE: QuadraticExtension{ONE_F, ZERO_F},
ZERO_QE: ZERO_QE,
ZERO_QE_ALGEBRA: ZERO_QE_ALGEBRA,
}
}
func (c *QuadraticExtensionAPI) SquareExtension(a QuadraticExtension) QuadraticExtension {
return c.MulExtension(a, a)
}
func (c *QuadraticExtensionAPI) MulExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
c_0 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[0]), c.fieldAPI.Mul(c.fieldAPI.Mul(c.W, a[1]), b[1]))
c_1 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[1]), c.fieldAPI.Mul(a[1], b[0]))
return QuadraticExtension{c_0, c_1}
}
func (c *QuadraticExtensionAPI) AddExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
c_0 := c.fieldAPI.Add(a[0], b[0])
c_1 := c.fieldAPI.Add(a[1], b[1])
return QuadraticExtension{c_0, c_1}
}
func (c *QuadraticExtensionAPI) SubExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
c_0 := c.fieldAPI.Sub(a[0], b[0])
c_1 := c.fieldAPI.Sub(a[1], b[1])
return QuadraticExtension{c_0, c_1}
}
func (c *QuadraticExtensionAPI) DivExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
return c.MulExtension(a, c.InverseExtension(b))
}
func (c *QuadraticExtensionAPI) IsZero(a QuadraticExtension) frontend.Variable {
return c.api.Mul(IsZero(c.api, c.fieldAPI, a[0]), IsZero(c.api, c.fieldAPI, a[1]))
}
// TODO: Instead of calculating the inverse within the circuit, can witness the
// inverse and assert that a_inverse * a = 1. Should reduce # of constraints.
func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension {
// First assert that a doesn't have 0 value coefficients
a0_is_zero := IsZero(c.api, c.fieldAPI, a[0])
a1_is_zero := IsZero(c.api, c.fieldAPI, a[1])
// assert that a0_is_zero OR a1_is_zero == false
c.api.AssertIsEqual(c.api.Mul(a0_is_zero, a1_is_zero), frontend.Variable(0))
a_pow_r_minus_1 := QuadraticExtension{a[0], c.fieldAPI.Mul(a[1], c.DTH_ROOT)}
a_pow_r := c.MulExtension(a_pow_r_minus_1, a)
return c.ScalarMulExtension(a_pow_r_minus_1, c.fieldAPI.Inverse(a_pow_r[0]))
}
func (c *QuadraticExtensionAPI) ScalarMulExtension(a QuadraticExtension, scalar F) QuadraticExtension {
return QuadraticExtension{c.fieldAPI.Mul(a[0], scalar), c.fieldAPI.Mul(a[1], scalar)}
}
func (c *QuadraticExtensionAPI) VarToQE(a frontend.Variable) QuadraticExtension {
return c.FieldToQE(c.fieldAPI.NewElement(a))
}
func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
return QuadraticExtension{a, ZERO_F}
}
// / Exponentiate `base` to the power of a known `exponent`.
func (c *QuadraticExtensionAPI) ExpU64Extension(a QuadraticExtension, exponent uint64) QuadraticExtension {
switch exponent {
case 0:
return c.ONE_QE
case 1:
return a
case 2:
return c.SquareExtension(a)
default:
}
current := a
product := c.ONE_QE
for i := 0; i < bits.Len64(exponent); i++ {
if i != 0 {
current = c.SquareExtension(current)
}
if (exponent >> i & 1) != 0 {
product = c.MulExtension(product, current)
}
}
return product
}
func (c *QuadraticExtensionAPI) ReduceWithPowers(terms []QuadraticExtension, scalar QuadraticExtension) QuadraticExtension {
sum := c.ZERO_QE
for i := len(terms) - 1; i >= 0; i-- {
sum = c.AddExtension(
c.MulExtension(
sum,
scalar,
),
terms[i],
)
}
return sum
}
func (c *QuadraticExtensionAPI) Select(b frontend.Variable, qe0, qe1 QuadraticExtension) QuadraticExtension {
var retQE QuadraticExtension
for i := 0; i < 2; i++ {
retQE[i] = c.fieldAPI.Select(b, qe0[i], qe1[i])
}
return retQE
}
func (c *QuadraticExtensionAPI) Lookup2(b0 frontend.Variable, b1 frontend.Variable, qe0, qe1, qe2, qe3 QuadraticExtension) QuadraticExtension {
var retQE QuadraticExtension
for i := 0; i < 2; i++ {
retQE[i] = c.fieldAPI.Lookup2(b0, b1, qe0[i], qe1[i], qe2[i], qe3[i])
}
return retQE
}
func (c *QuadraticExtensionAPI) AssertIsEqual(a, b QuadraticExtension) {
for i := 0; i < 2; i++ {
c.fieldAPI.AssertIsEqual(a[i], b[i])
}
}
func (c *QuadraticExtensionAPI) InnerProductExtension(constant F, startingAcc QuadraticExtension, pairs [][2]QuadraticExtension) QuadraticExtension {
acc := startingAcc
for i := 0; i < len(pairs); i++ {
a := pairs[i][0]
b := pairs[i][1]
mul := c.ScalarMulExtension(a, constant)
mul = c.MulExtension(mul, b)
acc = c.AddExtension(acc, mul)
}
return acc
}
/*
func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) {
fmt.Print("Degree 0 coefficient")
c.fieldAPI.Println(a[0])
fmt.Print("Degree 1 coefficient")
c.fieldAPI.Println(a[1])
}
*/
func (c *QuadraticExtensionAPI) MulExtensionAlgebra(a, b QEAlgebra) QEAlgebra {
var inner [D][][2]QuadraticExtension
var inner_w [D][][2]QuadraticExtension
for i := 0; i < D; i++ {
for j := 0; j < D-i; j++ {
idx := (i + j) % D
inner[idx] = append(inner[idx], [2]QuadraticExtension{a[i], b[j]})
}
for j := D - i; j < D; j++ {
idx := (i + j) % D
inner_w[idx] = append(inner_w[idx], [2]QuadraticExtension{a[i], b[j]})
}
}
var product QEAlgebra
for i := 0; i < D; i++ {
acc := c.InnerProductExtension(c.W, c.ZERO_QE, inner_w[i])
product[i] = c.InnerProductExtension(ONE_F, acc, inner[i])
}
return product
}
func (c *QuadraticExtensionAPI) ScalarMulExtensionAlgebra(a QuadraticExtension, b QEAlgebra) QEAlgebra {
var product QEAlgebra
for i := 0; i < D; i++ {
product[i] = c.MulExtension(a, b[i])
}
return product
}
func (c *QuadraticExtensionAPI) AddExtensionAlgebra(a, b QEAlgebra) QEAlgebra {
var sum QEAlgebra
for i := 0; i < D; i++ {
sum[i] = c.AddExtension(a[i], b[i])
}
return sum
}
func (c *QuadraticExtensionAPI) SubExtensionAlgebra(a, b QEAlgebra) QEAlgebra {
var diff QEAlgebra
for i := 0; i < D; i++ {
diff[i] = c.SubExtension(a[i], b[i])
}
return diff
}
func (c *QuadraticExtensionAPI) PartialInterpolateExtAlgebra(
domain []goldilocks.Element,
values []QEAlgebra,
barycentricWeights []goldilocks.Element,
point QEAlgebra,
initialEval QEAlgebra,
initialPartialProd QEAlgebra,
) (QEAlgebra, QEAlgebra) {
n := len(values)
if n == 0 {
panic("Cannot interpolate with no values")
}
if n != len(domain) {
panic("Domain and values must have the same length")
}
if n != len(barycentricWeights) {
panic("Domain and barycentric weights must have the same length")
}
newEval := initialEval
newPartialProd := initialPartialProd
for i := 0; i < n; i++ {
val := values[i]
x := domain[i]
xField := NewFieldConst(x.Uint64())
xQE := QuadraticExtension{xField, ZERO_F}
xQEAlgebra := QEAlgebra{xQE, c.ZERO_QE}
weight := QuadraticExtension{NewFieldConst(barycentricWeights[i].Uint64()), ZERO_F}
term := c.SubExtensionAlgebra(point, xQEAlgebra)
weightedVal := c.ScalarMulExtensionAlgebra(weight, val)
newEval = c.MulExtensionAlgebra(newEval, term)
tmp := c.MulExtensionAlgebra(weightedVal, newPartialProd)
newEval = c.AddExtensionAlgebra(newEval, tmp)
newPartialProd = c.MulExtensionAlgebra(newPartialProd, term)
}
return newEval, newPartialProd
}

+ 0
- 77
field/quadratic_extension_test.go

@ -1,77 +0,0 @@
package field
import (
"testing"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
)
// TODO: ADD MORE TEST CASES!!!
// Test for quadratic extension multiplication
type TestQuadraticExtensionMulCircuit struct {
qeAPI *QuadraticExtensionAPI
Operand1 QuadraticExtension
Operand2 QuadraticExtension
ExpectedResult QuadraticExtension
}
func (c *TestQuadraticExtensionMulCircuit) Define(api frontend.API) error {
fieldAPI := NewFieldAPI(api)
c.qeAPI = NewQuadraticExtensionAPI(api, fieldAPI)
actualRes := c.qeAPI.MulExtension(c.Operand1, c.Operand2)
fieldAPI.AssertIsEqual(actualRes[0], c.ExpectedResult[0])
fieldAPI.AssertIsEqual(actualRes[1], c.ExpectedResult[1])
return nil
}
func TestQuadraticExtensionMul(t *testing.T) {
assert := test.NewAssert(t)
operand1 := QuadraticExtension{NewFieldConst(4994088319481652598), NewFieldConst(16489566008211790727)}
operand2 := QuadraticExtension{NewFieldConst(3797605683985595697), NewFieldConst(13424401189265534004)}
expectedResult := QuadraticExtension{NewFieldConst(15052319864161058789), NewFieldConst(16841416332519902625)}
circuit := TestQuadraticExtensionMulCircuit{Operand1: operand1, Operand2: operand2, ExpectedResult: expectedResult}
witness := TestQuadraticExtensionMulCircuit{Operand1: operand1, Operand2: operand2, ExpectedResult: expectedResult}
err := test.IsSolved(&circuit, &witness, TEST_CURVE.ScalarField())
assert.NoError(err)
}
// Test for quadratic extension division
type TestQuadraticExtensionDivCircuit struct {
qeAPI *QuadraticExtensionAPI
Operand1 QuadraticExtension
Operand2 QuadraticExtension
ExpectedResult QuadraticExtension
}
func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error {
fieldAPI := NewFieldAPI(api)
c.qeAPI = NewQuadraticExtensionAPI(api, fieldAPI)
actualRes := c.qeAPI.DivExtension(c.Operand1, c.Operand2)
fieldAPI.AssertIsEqual(actualRes[0], c.ExpectedResult[0])
fieldAPI.AssertIsEqual(actualRes[1], c.ExpectedResult[1])
return nil
}
func TestQuadraticExtensionDiv(t *testing.T) {
assert := test.NewAssert(t)
operand1 := QuadraticExtension{NewFieldConst(4994088319481652598), NewFieldConst(16489566008211790727)}
operand2 := QuadraticExtension{NewFieldConst(7166004739148609569), NewFieldConst(14655965871663555016)}
expectedResult := QuadraticExtension{NewFieldConst(15052319864161058789), NewFieldConst(16841416332519902625)}
circuit := TestQuadraticExtensionDivCircuit{Operand1: operand1, Operand2: operand2, ExpectedResult: expectedResult}
witness := TestQuadraticExtensionDivCircuit{Operand1: operand1, Operand2: operand2, ExpectedResult: expectedResult}
err := test.IsSolved(&circuit, &witness, TEST_CURVE.ScalarField())
assert.NoError(err)
}

verifier/internal/fri/fri.go → fri/fri.go

@ -8,66 +8,69 @@ import (
"github.com/consensys/gnark-crypto/field/goldilocks" "github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
) )
type FriChip struct {
api frontend.API `gnark:"-"`
fieldAPI field.FieldAPI `gnark:"-"`
qeAPI *field.QuadraticExtensionAPI `gnark:"-"`
poseidonBN128Chip *poseidon.PoseidonBN128Chip
friParams *common.FriParams `gnark:"-"`
type Chip struct {
api frontend.API `gnark:"-"`
gl gl.Chip `gnark:"-"`
poseidonBN254Chip *poseidon.BN254Chip
friParams *types.FriParams `gnark:"-"`
} }
func NewFriChip(
func NewChip(
api frontend.API, api frontend.API,
fieldAPI field.FieldAPI,
qeAPI *field.QuadraticExtensionAPI,
poseidonBN128Chip *poseidon.PoseidonBN128Chip,
friParams *common.FriParams,
) *FriChip {
return &FriChip{
friParams *types.FriParams,
) *Chip {
poseidonBN254Chip := poseidon.NewBN254Chip(api)
return &Chip{
api: api, api: api,
fieldAPI: fieldAPI,
qeAPI: qeAPI,
poseidonBN128Chip: poseidonBN128Chip,
poseidonBN254Chip: poseidonBN254Chip,
friParams: friParams, friParams: friParams,
gl: *gl.NewChip(api),
} }
} }
func (f *FriChip) assertLeadingZeros(powWitness field.F, friConfig common.FriConfig) {
func (f *Chip) assertLeadingZeros(powWitness gl.Variable, friConfig types.FriConfig) {
// Asserts that powWitness'es big-endian bit representation has at least `leading_zeros` leading zeros. // Asserts that powWitness'es big-endian bit representation has at least `leading_zeros` leading zeros.
// Note that this is assuming that the Goldilocks field is being used. Specfically that the // Note that this is assuming that the Goldilocks field is being used. Specfically that the
// field is 64 bits long // field is 64 bits long
maxPowWitness := uint64(math.Pow(2, float64(64-friConfig.ProofOfWorkBits))) - 1 maxPowWitness := uint64(math.Pow(2, float64(64-friConfig.ProofOfWorkBits))) - 1
reducedPOWWitness := f.fieldAPI.Reduce(powWitness)
f.fieldAPI.AssertIsLessOrEqual(reducedPOWWitness, field.NewFieldConst(maxPowWitness))
reducedPowWitness := f.gl.Reduce(powWitness)
f.api.AssertIsLessOrEqual(reducedPowWitness.Limb, frontend.Variable(maxPowWitness))
} }
func (f *FriChip) fromOpeningsAndAlpha(openings *FriOpenings, alpha field.QuadraticExtension) []field.QuadraticExtension {
func (f *Chip) fromOpeningsAndAlpha(
openings *Openings,
alpha gl.QuadraticExtensionVariable,
) []gl.QuadraticExtensionVariable {
// One reduced opening for all openings evaluated at point Zeta. // One reduced opening for all openings evaluated at point Zeta.
// Another one for all openings evaluated at point Zeta * Omega (which is only PlonkZsNext polynomial) // Another one for all openings evaluated at point Zeta * Omega (which is only PlonkZsNext polynomial)
reducedOpenings := make([]field.QuadraticExtension, 0, 2)
reducedOpenings := make([]gl.QuadraticExtensionVariable, 0, 2)
for _, batch := range openings.Batches { for _, batch := range openings.Batches {
reducedOpenings = append(reducedOpenings, f.qeAPI.ReduceWithPowers(batch.Values, alpha))
reducedOpenings = append(reducedOpenings, f.gl.ReduceWithPowers(batch.Values, alpha))
} }
return reducedOpenings return reducedOpenings
} }
func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []field.F, leafIndexBits []frontend.Variable, capIndexBits []frontend.Variable, merkleCap common.MerkleCap, proof *common.MerkleProof) {
currentDigest := f.poseidonBN128Chip.HashOrNoop(leafData)
func (f *Chip) verifyMerkleProofToCapWithCapIndex(
leafData []gl.Variable,
leafIndexBits []frontend.Variable,
capIndexBits []frontend.Variable,
merkleCap types.FriMerkleCap,
proof *types.FriMerkleProof,
) {
currentDigest := f.poseidonBN254Chip.HashOrNoop(leafData)
for i, sibling := range proof.Siblings { for i, sibling := range proof.Siblings {
bit := leafIndexBits[i] bit := leafIndexBits[i]
// TODO: Don't need to do two hashes by using a trick that the plonky2 verifier circuit does // TODO: Don't need to do two hashes by using a trick that the plonky2 verifier circuit does
// https://github.com/mir-protocol/plonky2/blob/973624f12d2d12d74422b3ea051358b9eaacb050/plonky2/src/gates/poseidon.rs#L298 // https://github.com/mir-protocol/plonky2/blob/973624f12d2d12d74422b3ea051358b9eaacb050/plonky2/src/gates/poseidon.rs#L298
leftHash := f.poseidonBN128Chip.TwoToOne(sibling, currentDigest)
rightHash := f.poseidonBN128Chip.TwoToOne(currentDigest, sibling)
leftHash := f.poseidonBN254Chip.TwoToOne(sibling, currentDigest)
rightHash := f.poseidonBN254Chip.TwoToOne(currentDigest, sibling)
currentDigest = f.api.Select(bit, leftHash, rightHash) currentDigest = f.api.Select(bit, leftHash, rightHash)
} }
@ -82,7 +85,7 @@ func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []field.F, leafInd
} }
const NUM_LEAF_LOOKUPS = 4 const NUM_LEAF_LOOKUPS = 4
var leafLookups [NUM_LEAF_LOOKUPS]poseidon.PoseidonBN128HashOut
var leafLookups [NUM_LEAF_LOOKUPS]poseidon.BN254HashOut
// First create the "leaf" lookup2 circuits // First create the "leaf" lookup2 circuits
// The will use the least significant bits of the capIndexBits array // The will use the least significant bits of the capIndexBits array
for i := 0; i < NUM_LEAF_LOOKUPS; i++ { for i := 0; i < NUM_LEAF_LOOKUPS; i++ {
@ -97,7 +100,7 @@ func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []field.F, leafInd
f.api.AssertIsEqual(currentDigest, merkleCapEntry) f.api.AssertIsEqual(currentDigest, merkleCapEntry)
} }
func (f *FriChip) verifyInitialProof(xIndexBits []frontend.Variable, proof *common.FriInitialTreeProof, initialMerkleCaps []common.MerkleCap, capIndexBits []frontend.Variable) {
func (f *Chip) verifyInitialProof(xIndexBits []frontend.Variable, proof *types.FriInitialTreeProof, initialMerkleCaps []types.FriMerkleCap, capIndexBits []frontend.Variable) {
if len(proof.EvalsProofs) != len(initialMerkleCaps) { if len(proof.EvalsProofs) != len(initialMerkleCaps) {
panic("length of eval proofs in fri proof should equal length of initial merkle caps") panic("length of eval proofs in fri proof should equal length of initial merkle caps")
} }
@ -122,7 +125,7 @@ func (f *FriChip) verifyInitialProof(xIndexBits []frontend.Variable, proof *comm
// / Thus ambiguous elements contribute a negligible amount to soundness error. // / Thus ambiguous elements contribute a negligible amount to soundness error.
// / // /
// / Here we compare the probabilities as a sanity check, to verify the claim above. // / Here we compare the probabilities as a sanity check, to verify the claim above.
func (f *FriChip) assertNoncanonicalIndicesOK() {
func (f *Chip) assertNoncanonicalIndicesOK() {
numAmbiguousElems := uint64(math.MaxUint64) - goldilocks.Modulus().Uint64() + 1 numAmbiguousElems := uint64(math.MaxUint64) - goldilocks.Modulus().Uint64() + 1
queryError := f.friParams.Config.Rate() queryError := f.friParams.Config.Rate()
pAmbiguous := float64(numAmbiguousElems) / float64(goldilocks.Modulus().Uint64()) pAmbiguous := float64(numAmbiguousElems) / float64(goldilocks.Modulus().Uint64())
@ -133,44 +136,43 @@ func (f *FriChip) assertNoncanonicalIndicesOK() {
} }
} }
func (f *FriChip) expFromBitsConstBase(
func (f *Chip) expFromBitsConstBase(
base goldilocks.Element, base goldilocks.Element,
exponentBits []frontend.Variable, exponentBits []frontend.Variable,
) field.F {
product := field.ONE_F
) gl.Variable {
product := gl.One()
for i, bit := range exponentBits { for i, bit := range exponentBits {
pow := int64(1 << i)
// If the bit is on, we multiply product by base^pow. // If the bit is on, we multiply product by base^pow.
// We can arithmetize this as: // We can arithmetize this as:
// product *= 1 + bit (base^pow - 1) // product *= 1 + bit (base^pow - 1)
// product = (base^pow - 1) product bit + product // product = (base^pow - 1) product bit + product
pow := int64(1 << i)
basePow := goldilocks.NewElement(0) basePow := goldilocks.NewElement(0)
basePow.Exp(base, big.NewInt(pow)) basePow.Exp(base, big.NewInt(pow))
basePowElement := field.NewFieldConst(basePow.Uint64() - 1)
product = f.fieldAPI.Add(
f.fieldAPI.Mul(
f.fieldAPI.Mul(
basePowElement,
product),
f.fieldAPI.NewElement(bit)),
basePowVariable := gl.NewVariable(basePow.Uint64() - 1)
product = f.gl.Add(
f.gl.Mul(
f.gl.Mul(
basePowVariable,
product,
),
gl.NewVariable(bit),
),
product, product,
) )
} }
return product return product
} }
func (f *FriChip) calculateSubgroupX(
func (f *Chip) calculateSubgroupX(
xIndexBits []frontend.Variable, xIndexBits []frontend.Variable,
nLog uint64, nLog uint64,
) field.F {
) gl.Variable {
// Compute x from its index // Compute x from its index
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
// TODO - Make these as global values // TODO - Make these as global values
g := field.NewFieldConst(field.GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR.Uint64())
base := field.GoldilocksPrimitiveRootOfUnity(nLog)
g := gl.NewVariable(gl.MULTIPLICATIVE_GROUP_GENERATOR.Uint64())
base := gl.PrimitiveRootOfUnity(nLog)
// Create a reverse list of xIndexBits // Create a reverse list of xIndexBits
xIndexBitsRev := make([]frontend.Variable, 0) xIndexBitsRev := make([]frontend.Variable, 0)
@ -180,17 +182,17 @@ func (f *FriChip) calculateSubgroupX(
product := f.expFromBitsConstBase(base, xIndexBitsRev) product := f.expFromBitsConstBase(base, xIndexBitsRev)
return f.fieldAPI.Mul(g, product)
return f.gl.Mul(g, product)
} }
func (f *FriChip) friCombineInitial(
instance FriInstanceInfo,
proof common.FriInitialTreeProof,
friAlpha field.QuadraticExtension,
subgroupX_QE field.QuadraticExtension,
precomputedReducedEval []field.QuadraticExtension,
) field.QuadraticExtension {
sum := f.qeAPI.ZERO_QE
func (f *Chip) friCombineInitial(
instance InstanceInfo,
proof types.FriInitialTreeProof,
friAlpha gl.QuadraticExtensionVariable,
subgroupX_QE gl.QuadraticExtensionVariable,
precomputedReducedEval []gl.QuadraticExtensionVariable,
) gl.QuadraticExtensionVariable {
sum := gl.ZeroExtension()
if len(instance.Batches) != len(precomputedReducedEval) { if len(instance.Batches) != len(precomputedReducedEval) {
panic("len(openings) != len(precomputedReducedEval)") panic("len(openings) != len(precomputedReducedEval)")
@ -201,23 +203,24 @@ func (f *FriChip) friCombineInitial(
reducedOpenings := precomputedReducedEval[i] reducedOpenings := precomputedReducedEval[i]
point := batch.Point point := batch.Point
evals := make([]field.QuadraticExtension, 0)
evals := make([]gl.QuadraticExtensionVariable, 0)
for _, polynomial := range batch.Polynomials { for _, polynomial := range batch.Polynomials {
evals = append( evals = append(
evals, evals,
field.QuadraticExtension{proof.EvalsProofs[polynomial.OracleIndex].Elements[polynomial.PolynomialInfo], field.ZERO_F},
gl.QuadraticExtensionVariable{
proof.EvalsProofs[polynomial.OracleIndex].Elements[polynomial.PolynomialInfo],
gl.Zero(),
},
) )
} }
reducedEvals := f.qeAPI.ReduceWithPowers(evals, friAlpha)
numerator := f.qeAPI.SubExtension(reducedEvals, reducedOpenings)
denominator := f.qeAPI.SubExtension(subgroupX_QE, point)
sum = f.qeAPI.MulExtension(f.qeAPI.ExpU64Extension(friAlpha, uint64(len(evals))), sum)
sum = f.qeAPI.AddExtension(
f.qeAPI.DivExtension(
numerator,
denominator,
),
reducedEvals := f.gl.ReduceWithPowers(evals, friAlpha)
numerator := f.gl.SubExtensionNoReduce(reducedEvals, reducedOpenings)
denominator := f.gl.SubExtension(subgroupX_QE, point)
sum = f.gl.MulExtension(f.gl.ExpExtension(friAlpha, uint64(len(evals))), sum)
sum = f.gl.MulAddExtension(
numerator,
f.gl.InverseExtension(denominator),
sum, sum,
) )
} }
@ -225,43 +228,36 @@ func (f *FriChip) friCombineInitial(
return sum return sum
} }
func (f *FriChip) finalPolyEval(finalPoly common.PolynomialCoeffs, point field.QuadraticExtension) field.QuadraticExtension {
ret := f.qeAPI.ZERO_QE
func (f *Chip) finalPolyEval(finalPoly types.PolynomialCoeffs, point gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
ret := gl.ZeroExtension()
for i := len(finalPoly.Coeffs) - 1; i >= 0; i-- { for i := len(finalPoly.Coeffs) - 1; i >= 0; i-- {
ret = f.qeAPI.AddExtension(
f.qeAPI.MulExtension(
ret,
point,
),
finalPoly.Coeffs[i],
)
ret = f.gl.MulAddExtension(ret, point, finalPoly.Coeffs[i])
} }
return ret return ret
} }
func (f *FriChip) interpolate(x field.QuadraticExtension, xPoints []field.QuadraticExtension, yPoints []field.QuadraticExtension, barycentricWeights []field.QuadraticExtension) field.QuadraticExtension {
func (f *Chip) interpolate(
x gl.QuadraticExtensionVariable,
xPoints []gl.QuadraticExtensionVariable,
yPoints []gl.QuadraticExtensionVariable,
barycentricWeights []gl.QuadraticExtensionVariable,
) gl.QuadraticExtensionVariable {
if len(xPoints) != len(yPoints) || len(xPoints) != len(barycentricWeights) { if len(xPoints) != len(yPoints) || len(xPoints) != len(barycentricWeights) {
panic("length of xPoints, yPoints, and barycentricWeights are inconsistent") panic("length of xPoints, yPoints, and barycentricWeights are inconsistent")
} }
lX := f.qeAPI.ONE_QE
lX := gl.OneExtension()
for i := 0; i < len(xPoints); i++ { for i := 0; i < len(xPoints); i++ {
lX = f.qeAPI.MulExtension(
lX,
f.qeAPI.SubExtension(
x,
xPoints[i],
),
)
lX = f.gl.SubMulExtension(x, xPoints[i], lX)
} }
sum := f.qeAPI.ZERO_QE
sum := gl.ZeroExtension()
for i := 0; i < len(xPoints); i++ { for i := 0; i < len(xPoints); i++ {
sum = f.qeAPI.AddExtension(
f.qeAPI.MulExtension(
f.qeAPI.DivExtension(
sum = f.gl.AddExtension(
f.gl.MulExtension(
f.gl.DivExtension(
barycentricWeights[i], barycentricWeights[i],
f.qeAPI.SubExtension(
f.gl.SubExtension(
x, x,
xPoints[i], xPoints[i],
), ),
@ -272,28 +268,28 @@ func (f *FriChip) interpolate(x field.QuadraticExtension, xPoints []field.Quadra
) )
} }
interpolation := f.qeAPI.MulExtension(lX, sum)
interpolation := f.gl.MulExtension(lX, sum)
returnField := interpolation returnField := interpolation
// Now check if x is already within the xPoints // Now check if x is already within the xPoints
for i := 0; i < len(xPoints); i++ { for i := 0; i < len(xPoints); i++ {
returnField = f.qeAPI.Select(
f.qeAPI.IsZero(f.qeAPI.SubExtension(x, xPoints[i])),
yPoints[i],
returnField = f.gl.Lookup(
f.gl.IsZero(f.gl.SubExtension(x, xPoints[i])),
returnField, returnField,
yPoints[i],
) )
} }
return returnField return returnField
} }
func (f *FriChip) computeEvaluation(
x field.F,
func (f *Chip) computeEvaluation(
x gl.Variable,
xIndexWithinCosetBits []frontend.Variable, xIndexWithinCosetBits []frontend.Variable,
arityBits uint64, arityBits uint64,
evals []field.QuadraticExtension,
beta field.QuadraticExtension,
) field.QuadraticExtension {
evals []gl.QuadraticExtensionVariable,
beta gl.QuadraticExtensionVariable,
) gl.QuadraticExtensionVariable {
arity := 1 << arityBits arity := 1 << arityBits
if (len(evals)) != arity { if (len(evals)) != arity {
panic("len(evals) ! arity") panic("len(evals) ! arity")
@ -302,7 +298,7 @@ func (f *FriChip) computeEvaluation(
panic("currently assuming that arityBits is <= 8") panic("currently assuming that arityBits is <= 8")
} }
g := field.GoldilocksPrimitiveRootOfUnity(arityBits)
g := gl.PrimitiveRootOfUnity(arityBits)
gInv := goldilocks.NewElement(0) gInv := goldilocks.NewElement(0)
gInv.Exp(g, big.NewInt(int64(arity-1))) gInv.Exp(g, big.NewInt(int64(arity-1)))
@ -310,7 +306,7 @@ func (f *FriChip) computeEvaluation(
// element's new index is the bit reverse of it's original index. // element's new index is the bit reverse of it's original index.
// TODO: Optimization - Since the size of the evals array should be constant (e.g. 2^arityBits), // TODO: Optimization - Since the size of the evals array should be constant (e.g. 2^arityBits),
// we can just hard code the permutation. // we can just hard code the permutation.
permutedEvals := make([]field.QuadraticExtension, len(evals))
permutedEvals := make([]gl.QuadraticExtensionVariable, len(evals))
for i := uint8(0); i < uint8(len(evals)); i++ { for i := uint8(0); i < uint8(len(evals)); i++ {
newIndex := bits.Reverse8(i) >> arityBits newIndex := bits.Reverse8(i) >> arityBits
permutedEvals[newIndex] = evals[i] permutedEvals[newIndex] = evals[i]
@ -323,53 +319,54 @@ func (f *FriChip) computeEvaluation(
revXIndexWithinCosetBits[len(xIndexWithinCosetBits)-1-i] = xIndexWithinCosetBits[i] revXIndexWithinCosetBits[len(xIndexWithinCosetBits)-1-i] = xIndexWithinCosetBits[i]
} }
start := f.expFromBitsConstBase(gInv, revXIndexWithinCosetBits) start := f.expFromBitsConstBase(gInv, revXIndexWithinCosetBits)
cosetStart := f.fieldAPI.Mul(start, x)
cosetStart := f.gl.Mul(start, x)
xPoints := make([]field.QuadraticExtension, len(evals))
xPoints := make([]gl.QuadraticExtensionVariable, len(evals))
yPoints := permutedEvals yPoints := permutedEvals
// TODO: Make g_F a constant // TODO: Make g_F a constant
g_F := f.qeAPI.FieldToQE(field.NewFieldConst(g.Uint64()))
xPoints[0] = f.qeAPI.FieldToQE(cosetStart)
g_F := gl.NewVariable(g.Uint64()).ToQuadraticExtension()
xPoints[0] = gl.QuadraticExtensionVariable{cosetStart, gl.Zero()}
for i := 1; i < len(evals); i++ { for i := 1; i < len(evals); i++ {
xPoints[i] = f.qeAPI.MulExtension(xPoints[i-1], g_F)
xPoints[i] = f.gl.MulExtension(xPoints[i-1], g_F)
} }
// TODO: This is n^2. Is there a way to do this better? // TODO: This is n^2. Is there a way to do this better?
// Compute the barycentric weights // Compute the barycentric weights
barycentricWeights := make([]field.QuadraticExtension, len(xPoints))
barycentricWeights := make([]gl.QuadraticExtensionVariable, len(xPoints))
for i := 0; i < len(xPoints); i++ { for i := 0; i < len(xPoints); i++ {
barycentricWeights[i] = f.qeAPI.ONE_QE
barycentricWeights[i] = gl.OneExtension()
for j := 0; j < len(xPoints); j++ { for j := 0; j < len(xPoints); j++ {
if i != j { if i != j {
barycentricWeights[i] = f.qeAPI.MulExtension(
f.qeAPI.SubExtension(xPoints[i], xPoints[j]),
barycentricWeights[i] = f.gl.SubMulExtension(
xPoints[i],
xPoints[j],
barycentricWeights[i], barycentricWeights[i],
) )
} }
} }
// Take the inverse of the barycentric weights // Take the inverse of the barycentric weights
// TODO: Can provide a witness to this value // TODO: Can provide a witness to this value
barycentricWeights[i] = f.qeAPI.InverseExtension(barycentricWeights[i])
barycentricWeights[i] = f.gl.InverseExtension(barycentricWeights[i])
} }
return f.interpolate(beta, xPoints, yPoints, barycentricWeights) return f.interpolate(beta, xPoints, yPoints, barycentricWeights)
} }
func (f *FriChip) verifyQueryRound(
instance FriInstanceInfo,
challenges *common.FriChallenges,
precomputedReducedEval []field.QuadraticExtension,
initialMerkleCaps []common.MerkleCap,
proof *common.FriProof,
xIndex field.F,
func (f *Chip) verifyQueryRound(
instance InstanceInfo,
challenges *types.FriChallenges,
precomputedReducedEval []gl.QuadraticExtensionVariable,
initialMerkleCaps []types.FriMerkleCap,
proof *types.FriProof,
xIndex gl.Variable,
n uint64, n uint64,
nLog uint64, nLog uint64,
roundProof *common.FriQueryRound,
roundProof *types.FriQueryRound,
) { ) {
f.assertNoncanonicalIndicesOK() f.assertNoncanonicalIndicesOK()
xIndex = f.fieldAPI.Reduce(xIndex)
xIndexBits := f.fieldAPI.ToBits(xIndex)[0 : f.friParams.DegreeBits+f.friParams.Config.RateBits]
xIndex = f.gl.Reduce(xIndex)
xIndexBits := f.api.ToBinary(xIndex.Limb, 64)[0 : f.friParams.DegreeBits+f.friParams.Config.RateBits]
capIndexBits := xIndexBits[len(xIndexBits)-int(f.friParams.Config.CapHeight):] capIndexBits := xIndexBits[len(xIndexBits)-int(f.friParams.Config.CapHeight):]
f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndexBits) f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndexBits)
@ -379,7 +376,7 @@ func (f *FriChip) verifyQueryRound(
nLog, nLog,
) )
subgroupX_QE := field.QuadraticExtension{subgroupX, field.ZERO_F}
subgroupX_QE := subgroupX.ToQuadraticExtension()
oldEval := f.friCombineInitial( oldEval := f.friCombineInitial(
instance, instance,
@ -404,11 +401,11 @@ func (f *FriChip) verifyQueryRound(
} }
const NUM_LEAF_LOOKUPS = 4 const NUM_LEAF_LOOKUPS = 4
var leafLookups [NUM_LEAF_LOOKUPS]field.QuadraticExtension
var leafLookups [NUM_LEAF_LOOKUPS]gl.QuadraticExtensionVariable
// First create the "leaf" lookup2 circuits // First create the "leaf" lookup2 circuits
// The will use the least significant bits of the xIndexWithCosetBits array // The will use the least significant bits of the xIndexWithCosetBits array
for i := 0; i < NUM_LEAF_LOOKUPS; i++ { for i := 0; i < NUM_LEAF_LOOKUPS; i++ {
leafLookups[i] = f.qeAPI.Lookup2(
leafLookups[i] = f.gl.Lookup2(
xIndexWithinCosetBits[0], xIndexWithinCosetBits[0],
xIndexWithinCosetBits[1], xIndexWithinCosetBits[1],
evals[i*NUM_LEAF_LOOKUPS], evals[i*NUM_LEAF_LOOKUPS],
@ -419,7 +416,7 @@ func (f *FriChip) verifyQueryRound(
} }
// Use the most 2 significant bits of the xIndexWithCosetBits array for the "root" lookup // Use the most 2 significant bits of the xIndexWithCosetBits array for the "root" lookup
newEval := f.qeAPI.Lookup2(
newEval := f.gl.Lookup2(
xIndexWithinCosetBits[2], xIndexWithinCosetBits[2],
xIndexWithinCosetBits[3], xIndexWithinCosetBits[3],
leafLookups[0], leafLookups[0],
@ -428,7 +425,8 @@ func (f *FriChip) verifyQueryRound(
leafLookups[3], leafLookups[3],
) )
f.qeAPI.AssertIsEqual(newEval, oldEval)
f.gl.AssertIsEqual(newEval[0], oldEval[0])
f.gl.AssertIsEqual(newEval[1], oldEval[1])
oldEval = f.computeEvaluation( oldEval = f.computeEvaluation(
subgroupX, subgroupX,
@ -439,7 +437,7 @@ func (f *FriChip) verifyQueryRound(
) )
// Convert evals (array of QE) to fields by taking their 0th degree coefficients // Convert evals (array of QE) to fields by taking their 0th degree coefficients
fieldEvals := make([]field.F, 0, 2*len(evals))
fieldEvals := make([]gl.Variable, 0, 2*len(evals))
for j := 0; j < len(evals); j++ { for j := 0; j < len(evals); j++ {
fieldEvals = append(fieldEvals, evals[j][0]) fieldEvals = append(fieldEvals, evals[j][0])
fieldEvals = append(fieldEvals, evals[j][1]) fieldEvals = append(fieldEvals, evals[j][1])
@ -454,24 +452,25 @@ func (f *FriChip) verifyQueryRound(
// Update the point x to x^arity. // Update the point x to x^arity.
for j := uint64(0); j < arityBits; j++ { for j := uint64(0); j < arityBits; j++ {
subgroupX = f.fieldAPI.Mul(subgroupX, subgroupX)
subgroupX = f.gl.Mul(subgroupX, subgroupX)
} }
xIndexBits = cosetIndexBits xIndexBits = cosetIndexBits
} }
subgroupX_QE = f.qeAPI.FieldToQE(subgroupX)
subgroupX_QE = subgroupX.ToQuadraticExtension()
finalPolyEval := f.finalPolyEval(proof.FinalPoly, subgroupX_QE) finalPolyEval := f.finalPolyEval(proof.FinalPoly, subgroupX_QE)
f.qeAPI.AssertIsEqual(oldEval, finalPolyEval)
f.gl.AssertIsEqual(oldEval[0], finalPolyEval[0])
f.gl.AssertIsEqual(oldEval[1], finalPolyEval[1])
} }
func (f *FriChip) VerifyFriProof(
instance FriInstanceInfo,
openings FriOpenings,
friChallenges *common.FriChallenges,
initialMerkleCaps []common.MerkleCap,
friProof *common.FriProof,
func (f *Chip) VerifyFriProof(
instance InstanceInfo,
openings Openings,
friChallenges *types.FriChallenges,
initialMerkleCaps []types.FriMerkleCap,
friProof *types.FriProof,
) { ) {
// TODO: Check fri config // TODO: Check fri config
/* if let Some(max_arity_bits) = params.max_arity_bits() { /* if let Some(max_arity_bits) = params.max_arity_bits() {
@ -485,6 +484,7 @@ func (f *FriChip) VerifyFriProof(
); */ ); */
// Check POW // Check POW
f.assertLeadingZeros(friChallenges.FriPowResponse, f.friParams.Config) f.assertLeadingZeros(friChallenges.FriPowResponse, f.friParams.Config)
precomputedReducedEvals := f.fromOpeningsAndAlpha(&openings, friChallenges.FriAlpha) precomputedReducedEvals := f.fromOpeningsAndAlpha(&openings, friChallenges.FriAlpha)

+ 126
- 0
fri/fri_test.go

@ -0,0 +1,126 @@
package fri_test
import (
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/challenger"
"github.com/succinctlabs/gnark-plonky2-verifier/fri"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
)
type TestFriCircuit struct {
proofWithPIsFilename string `gnark:"-"`
commonCircuitDataFilename string `gnark:"-"`
verifierOnlyCircuitDataFilename string `gnark:"-"`
}
func (circuit *TestFriCircuit) Define(api frontend.API) error {
proofWithPis := verifier.DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
commonCircuitData := verifier.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
glApi := gl.NewChip(api)
poseidonChip := poseidon.NewGoldilocksChip(api)
friChip := fri.NewChip(api, &commonCircuitData.FriParams)
challengerChip := challenger.NewChip(api)
challengerChip.ObserveBN254Hash(verifierOnlyCircuitData.CircuitDigest)
challengerChip.ObserveHash(poseidonChip.HashNoPad(proofWithPis.PublicInputs))
challengerChip.ObserveCap(proofWithPis.Proof.WiresCap)
plonkBetas := challengerChip.GetNChallenges(commonCircuitData.Config.NumChallenges) // For plonk betas
glApi.AssertIsEqual(plonkBetas[0], gl.NewVariable("17615363392879944733"))
plonkGammas := challengerChip.GetNChallenges(commonCircuitData.Config.NumChallenges) // For plonk gammas
glApi.AssertIsEqual(plonkGammas[0], gl.NewVariable("15174493176564484303"))
challengerChip.ObserveCap(proofWithPis.Proof.PlonkZsPartialProductsCap)
plonkAlphas := challengerChip.GetNChallenges(commonCircuitData.Config.NumChallenges) // For plonk alphas
glApi.AssertIsEqual(plonkAlphas[0], gl.NewVariable("9276470834414745550"))
challengerChip.ObserveCap(proofWithPis.Proof.QuotientPolysCap)
plonkZeta := challengerChip.GetExtensionChallenge()
glApi.AssertIsEqual(plonkZeta[0], gl.NewVariable("3892795992421241388"))
challengerChip.ObserveOpenings(fri.ToOpenings(proofWithPis.Proof.Openings))
friChallenges := challengerChip.GetFriChallenges(
proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
proofWithPis.Proof.OpeningProof.FinalPoly,
proofWithPis.Proof.OpeningProof.PowWitness,
commonCircuitData.DegreeBits,
commonCircuitData.Config.FriConfig,
)
api.AssertIsEqual(friChallenges.FriAlpha[0].Limb, 885535811531859621)
api.AssertIsEqual(friChallenges.FriBetas[0][0].Limb, 5231781384587895507)
api.AssertIsEqual(friChallenges.FriPowResponse.Limb, 70715523064019)
// glApi.AssertIsEqual(friChallenges.FriQueryIndices[0], gl.NewVariableFromConst(11890500485816111017))
var x uint64
x = 11890500485816111017
api.AssertIsEqual(friChallenges.FriQueryIndices[0].Limb, x)
initialMerkleCaps := []types.FriMerkleCap{
verifierOnlyCircuitData.ConstantSigmasCap,
proofWithPis.Proof.WiresCap,
proofWithPis.Proof.PlonkZsPartialProductsCap,
proofWithPis.Proof.QuotientPolysCap,
}
// Seems like there is a bug in the emulated field code.
// Add ZERO to all of the fri challenges values to reduce them.
plonkZeta[0] = glApi.Add(plonkZeta[0], gl.Zero())
plonkZeta[1] = glApi.Add(plonkZeta[1], gl.Zero())
friChallenges.FriAlpha[0] = glApi.Add(friChallenges.FriAlpha[0], gl.Zero())
friChallenges.FriAlpha[1] = glApi.Add(friChallenges.FriAlpha[1], gl.Zero())
for i := 0; i < len(friChallenges.FriBetas); i++ {
friChallenges.FriBetas[i][0] = glApi.Add(friChallenges.FriBetas[i][0], gl.Zero())
friChallenges.FriBetas[i][1] = glApi.Add(friChallenges.FriBetas[i][1], gl.Zero())
}
friChallenges.FriPowResponse = glApi.Add(friChallenges.FriPowResponse, gl.Zero())
for i := 0; i < len(friChallenges.FriQueryIndices); i++ {
friChallenges.FriQueryIndices[i] = glApi.Add(friChallenges.FriQueryIndices[i], gl.Zero())
}
friChip.VerifyFriProof(
fri.GetInstance(&commonCircuitData, glApi, plonkZeta, commonCircuitData.DegreeBits),
fri.ToOpenings(proofWithPis.Proof.Openings),
&friChallenges,
initialMerkleCaps,
&proofWithPis.Proof.OpeningProof,
)
return nil
}
func TestDecodeBlockFriVerification(t *testing.T) {
assert := test.NewAssert(t)
testCase := func() {
circuit := TestFriCircuit{
proofWithPIsFilename: "../../data/decode_block/proof_with_public_inputs.json",
commonCircuitDataFilename: "../../data/decode_block//common_circuit_data.json",
verifierOnlyCircuitDataFilename: "../../data/decode_block//verifier_only_circuit_data.json",
}
witness := TestFriCircuit{
proofWithPIsFilename: "../../data/dummy_2^14_gates/proof_with_public_inputs.json",
commonCircuitDataFilename: "../../data/dummy_2^14_gates/common_circuit_data.json",
verifierOnlyCircuitDataFilename: ".../../data/dummy_2^14_gates/verifier_only_circuit_data.json",
}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}
testCase()
}

verifier/internal/fri/fri_utils.go → fri/fri_utils.go

@ -1,48 +1,48 @@
package fri package fri
import ( import (
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
) )
type FriOpeningBatch struct {
Values []field.QuadraticExtension
type OpeningBatch struct {
Values []gl.QuadraticExtensionVariable
} }
type FriOpenings struct {
Batches []FriOpeningBatch
type Openings struct {
Batches []OpeningBatch
} }
func ToFriOpenings(c common.OpeningSet) FriOpenings {
func ToOpenings(c types.OpeningSet) Openings {
values := c.Constants // num_constants + 1 values := c.Constants // num_constants + 1
values = append(values, c.PlonkSigmas...) // num_routed_wires values = append(values, c.PlonkSigmas...) // num_routed_wires
values = append(values, c.Wires...) // num_wires values = append(values, c.Wires...) // num_wires
values = append(values, c.PlonkZs...) // num_challenges values = append(values, c.PlonkZs...) // num_challenges
values = append(values, c.PartialProducts...) // num_challenges * num_partial_products values = append(values, c.PartialProducts...) // num_challenges * num_partial_products
values = append(values, c.QuotientPolys...) // num_challenges * quotient_degree_factor values = append(values, c.QuotientPolys...) // num_challenges * quotient_degree_factor
zetaBatch := FriOpeningBatch{Values: values}
zetaNextBatch := FriOpeningBatch{Values: c.PlonkZsNext}
return FriOpenings{Batches: []FriOpeningBatch{zetaBatch, zetaNextBatch}}
zetaBatch := OpeningBatch{Values: values}
zetaNextBatch := OpeningBatch{Values: c.PlonkZsNext}
return Openings{Batches: []OpeningBatch{zetaBatch, zetaNextBatch}}
} }
type FriPolynomialInfo struct {
type PolynomialInfo struct {
OracleIndex uint64 OracleIndex uint64
PolynomialInfo uint64 PolynomialInfo uint64
} }
type FriOracleInfo struct {
type OracleInfo struct {
NumPolys uint64 NumPolys uint64
Blinding bool Blinding bool
} }
type FriBatchInfo struct {
Point field.QuadraticExtension
Polynomials []FriPolynomialInfo
type BatchInfo struct {
Point gl.QuadraticExtensionVariable
Polynomials []PolynomialInfo
} }
type FriInstanceInfo struct {
Oracles []FriOracleInfo
Batches []FriBatchInfo
type InstanceInfo struct {
Oracles []OracleInfo
Batches []BatchInfo
} }
type PlonkOracle struct { type PlonkOracle struct {
@ -70,11 +70,11 @@ var QUOTIENT = PlonkOracle{
blinding: true, blinding: true,
} }
func polynomialInfoFromRange(c *common.CommonCircuitData, oracleIdx uint64, startPolyIdx uint64, endPolyIdx uint64) []FriPolynomialInfo {
returnArr := make([]FriPolynomialInfo, 0)
func polynomialInfoFromRange(c *types.CommonCircuitData, oracleIdx uint64, startPolyIdx uint64, endPolyIdx uint64) []PolynomialInfo {
returnArr := make([]PolynomialInfo, 0)
for i := startPolyIdx; i < endPolyIdx; i++ { for i := startPolyIdx; i < endPolyIdx; i++ {
returnArr = append(returnArr, returnArr = append(returnArr,
FriPolynomialInfo{
PolynomialInfo{
OracleIndex: oracleIdx, OracleIndex: oracleIdx,
PolynomialInfo: i, PolynomialInfo: i,
}) })
@ -84,7 +84,7 @@ func polynomialInfoFromRange(c *common.CommonCircuitData, oracleIdx uint64, star
} }
// Range of the sigma polynomials in the `constants_sigmas_commitment`. // Range of the sigma polynomials in the `constants_sigmas_commitment`.
func sigmasRange(c *common.CommonCircuitData) []uint64 {
func sigmasRange(c *types.CommonCircuitData) []uint64 {
returnArr := make([]uint64, 0) returnArr := make([]uint64, 0)
for i := c.NumConstants; i <= c.NumConstants+c.Config.NumRoutedWires; i++ { for i := c.NumConstants; i <= c.NumConstants+c.Config.NumRoutedWires; i++ {
returnArr = append(returnArr, i) returnArr = append(returnArr, i)
@ -93,20 +93,20 @@ func sigmasRange(c *common.CommonCircuitData) []uint64 {
return returnArr return returnArr
} }
func numPreprocessedPolys(c *common.CommonCircuitData) uint64 {
func numPreprocessedPolys(c *types.CommonCircuitData) uint64 {
sigmasRange := sigmasRange(c) sigmasRange := sigmasRange(c)
return sigmasRange[len(sigmasRange)-1] return sigmasRange[len(sigmasRange)-1]
} }
func numZSPartialProductsPolys(c *common.CommonCircuitData) uint64 {
func numZSPartialProductsPolys(c *types.CommonCircuitData) uint64 {
return c.Config.NumChallenges * (1 + c.NumPartialProducts) return c.Config.NumChallenges * (1 + c.NumPartialProducts)
} }
func numQuotientPolys(c *common.CommonCircuitData) uint64 {
func numQuotientPolys(c *types.CommonCircuitData) uint64 {
return c.Config.NumChallenges * c.QuotientDegreeFactor return c.Config.NumChallenges * c.QuotientDegreeFactor
} }
func friPreprocessedPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
func friPreprocessedPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange( return polynomialInfoFromRange(
c, c,
CONSTANTS_SIGMAS.index, CONSTANTS_SIGMAS.index,
@ -115,12 +115,12 @@ func friPreprocessedPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
) )
} }
func friWirePolys(c *common.CommonCircuitData) []FriPolynomialInfo {
func friWirePolys(c *types.CommonCircuitData) []PolynomialInfo {
numWirePolys := c.Config.NumWires numWirePolys := c.Config.NumWires
return polynomialInfoFromRange(c, WIRES.index, 0, numWirePolys) return polynomialInfoFromRange(c, WIRES.index, 0, numWirePolys)
} }
func friZSPartialProductsPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
func friZSPartialProductsPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange( return polynomialInfoFromRange(
c, c,
ZS_PARTIAL_PRODUCTS.index, ZS_PARTIAL_PRODUCTS.index,
@ -129,7 +129,7 @@ func friZSPartialProductsPolys(c *common.CommonCircuitData) []FriPolynomialInfo
) )
} }
func friQuotientPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
func friQuotientPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange( return polynomialInfoFromRange(
c, c,
QUOTIENT.index, QUOTIENT.index,
@ -138,7 +138,7 @@ func friQuotientPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
) )
} }
func friZSPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
func friZSPolys(c *types.CommonCircuitData) []PolynomialInfo {
return polynomialInfoFromRange( return polynomialInfoFromRange(
c, c,
ZS_PARTIAL_PRODUCTS.index, ZS_PARTIAL_PRODUCTS.index,
@ -147,8 +147,8 @@ func friZSPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
) )
} }
func friOracles(c *common.CommonCircuitData) []FriOracleInfo {
return []FriOracleInfo{
func friOracles(c *types.CommonCircuitData) []OracleInfo {
return []OracleInfo{
{ {
NumPolys: numPreprocessedPolys(c), NumPolys: numPreprocessedPolys(c),
Blinding: CONSTANTS_SIGMAS.blinding, Blinding: CONSTANTS_SIGMAS.blinding,
@ -168,8 +168,8 @@ func friOracles(c *common.CommonCircuitData) []FriOracleInfo {
} }
} }
func friAllPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
returnArr := make([]FriPolynomialInfo, 0)
func friAllPolys(c *types.CommonCircuitData) []PolynomialInfo {
returnArr := make([]PolynomialInfo, 0)
returnArr = append(returnArr, friPreprocessedPolys(c)...) returnArr = append(returnArr, friPreprocessedPolys(c)...)
returnArr = append(returnArr, friWirePolys(c)...) returnArr = append(returnArr, friWirePolys(c)...)
returnArr = append(returnArr, friZSPartialProductsPolys(c)...) returnArr = append(returnArr, friZSPartialProductsPolys(c)...)
@ -178,22 +178,25 @@ func friAllPolys(c *common.CommonCircuitData) []FriPolynomialInfo {
return returnArr return returnArr
} }
func GetFriInstance(c *common.CommonCircuitData, qeAPI *field.QuadraticExtensionAPI, zeta field.QuadraticExtension, degreeBits uint64) FriInstanceInfo {
zetaBatch := FriBatchInfo{
func GetInstance(c *types.CommonCircuitData, glApi *gl.Chip, zeta gl.QuadraticExtensionVariable, degreeBits uint64) InstanceInfo {
zetaBatch := BatchInfo{
Point: zeta, Point: zeta,
Polynomials: friAllPolys(c), Polynomials: friAllPolys(c),
} }
g := field.GoldilocksPrimitiveRootOfUnity(degreeBits)
zetaNext := qeAPI.MulExtension(qeAPI.FieldToQE(field.NewFieldConst(g.Uint64())), zeta)
g := gl.PrimitiveRootOfUnity(degreeBits)
zetaNext := glApi.MulExtension(
gl.NewVariable(g.Uint64()).ToQuadraticExtension(),
zeta,
)
zetaNextBath := FriBatchInfo{
zetaNextBath := BatchInfo{
Point: zetaNext, Point: zetaNext,
Polynomials: friZSPolys(c), Polynomials: friZSPolys(c),
} }
return FriInstanceInfo{
return InstanceInfo{
Oracles: friOracles(c), Oracles: friOracles(c),
Batches: []FriBatchInfo{zetaBatch, zetaNextBath},
Batches: []BatchInfo{zetaBatch, zetaNextBath},
} }
} }

+ 2
- 0
go.sum

@ -56,6 +56,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=

+ 362
- 0
goldilocks/base.go

@ -0,0 +1,362 @@
// This package implements efficient Golidlocks arithmetic operations within Gnark. We do not use
// the emulated field arithmetic API, because it is too slow for our purposes. Instead, we use
// an efficient reduction method that leverages the fact that the modulus is a simple
// linear combination of powers of two.
package goldilocks
// In general, methods whose name do not contain `NoReduce` can be used without any extra mental
// overhead. These methods act exactly as you would expect a normal field would operate.
//
// However, if you want to aggressively optimize the number of constraints in your circuit, it can
// be very beneficial to use the no reduction methods and keep track of the maximum number of bits
// your computation uses.
import (
"fmt"
"math/big"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/constraint/solver"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/bits"
"github.com/consensys/gnark/std/math/emulated"
)
// The multiplicative group generator of the field.
var MULTIPLICATIVE_GROUP_GENERATOR goldilocks.Element = goldilocks.NewElement(7)
// The two adicity of the field.
var TWO_ADICITY uint64 = 32
// The power of two generator of the field.
var POWER_OF_TWO_GENERATOR goldilocks.Element = goldilocks.NewElement(1753635133440165772)
// The modulus of the field.
var MODULUS *big.Int = emulated.Goldilocks{}.Modulus()
// The threshold maximum number of bits at which we must reduce the element.
var REDUCE_NB_BITS_THRESHOLD uint8 = 254 - 64
// The number of bits to use for range checks on inner products of field elements.
var RANGE_CHECK_NB_BITS int = 140
// Registers the hint functions with the solver.
func init() {
solver.RegisterHint(MulAddHint)
solver.RegisterHint(ReduceHint)
solver.RegisterHint(InverseHint)
}
// A type alias used to represent Goldilocks field elements.
type Variable struct {
Limb frontend.Variable
}
// Creates a new Goldilocks field element from an existing variable. Assumes that the element is
// already reduced.
func NewVariable(x frontend.Variable) Variable {
return Variable{Limb: x}
}
// The zero element in the Golidlocks field.
func Zero() Variable {
return NewVariable(0)
}
// The one element in the Goldilocks field.
func One() Variable {
return NewVariable(1)
}
// The negative one element in the Goldilocks field.
func NegOne() Variable {
return NewVariable(MODULUS.Uint64() - 1)
}
// The chip used for Goldilocks field operations.
type Chip struct {
api frontend.API
}
// Creates a new Goldilocks chip.
func NewChip(api frontend.API) *Chip {
return &Chip{api: api}
}
// Adds two field elements such that x + y = z within the Golidlocks field.
func (p *Chip) Add(a Variable, b Variable) Variable {
return p.MulAdd(a, NewVariable(1), b)
}
// Adds two field elements such that x + y = z within the Golidlocks field without reducing.
func (p *Chip) AddNoReduce(a Variable, b Variable) Variable {
return NewVariable(p.api.Add(a.Limb, b.Limb))
}
// Subtracts two field elements such that x + y = z within the Golidlocks field.
func (p *Chip) Sub(a Variable, b Variable) Variable {
return p.MulAdd(b, NewVariable(MODULUS.Uint64()-1), a)
}
// Subtracts two field elements such that x + y = z within the Golidlocks field without reducing.
func (p *Chip) SubNoReduce(a Variable, b Variable) Variable {
return NewVariable(p.api.Add(a.Limb, p.api.Mul(b.Limb, MODULUS.Uint64()-1)))
}
// Multiplies two field elements such that x * y = z within the Golidlocks field.
func (p *Chip) Mul(a Variable, b Variable) Variable {
return p.MulAdd(a, b, Zero())
}
// Multiplies two field elements such that x * y = z within the Golidlocks field without reducing.
func (p *Chip) MulNoReduce(a Variable, b Variable) Variable {
return NewVariable(p.api.Mul(a.Limb, b.Limb))
}
// Multiplies two field elements and adds a field element such that x * y + z = c within the
// Golidlocks field.
func (p *Chip) MulAdd(a Variable, b Variable, c Variable) Variable {
result, err := p.api.Compiler().NewHint(MulAddHint, 2, a.Limb, b.Limb, c.Limb)
if err != nil {
panic(err)
}
quotient := NewVariable(result[0])
remainder := NewVariable(result[1])
lhs := p.api.Mul(a.Limb, b.Limb)
lhs = p.api.Add(lhs, c.Limb)
rhs := p.api.Add(p.api.Mul(quotient.Limb, MODULUS), remainder.Limb)
p.api.AssertIsEqual(lhs, rhs)
p.RangeCheck(quotient)
p.RangeCheck(remainder)
return remainder
}
// Multiplies two field elements and adds a field element such that x * y + z = c within the
// Golidlocks field without reducing.
func (p *Chip) MulAddNoReduce(a Variable, b Variable, c Variable) Variable {
return p.AddNoReduce(p.MulNoReduce(a, b), c)
}
// The hint used to compute MulAdd.
func MulAddHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
if len(inputs) != 3 {
panic("MulAddHint expects 3 input operands")
}
for _, operand := range inputs {
if operand.Cmp(MODULUS) >= 0 {
panic(fmt.Sprintf("%s is not in the field", operand.String()))
}
}
product := new(big.Int).Mul(inputs[0], inputs[1])
sum := new(big.Int).Add(product, inputs[2])
quotient := new(big.Int).Div(sum, MODULUS)
remainder := new(big.Int).Rem(sum, MODULUS)
results[0] = quotient
results[1] = remainder
return nil
}
// Reduces a field element x such that x % MODULUS = y.
func (p *Chip) Reduce(x Variable) Variable {
// Witness a `quotient` and `remainder` such that:
//
// MODULUS * quotient + remainder = x
//
// Must check that offset \in [0, MODULUS) and carry \in [0, 2^RANGE_CHECK_NB_BITS) to ensure
// that this computation does not overflow. We use 2^RANGE_CHECK_NB_BITS to reduce the cost of the range check
//
// In other words, we assume that we at most compute a a dot product with dimension at most RANGE_CHECK_NB_BITS - 128.
result, err := p.api.Compiler().NewHint(ReduceHint, 2, x.Limb)
if err != nil {
panic(err)
}
quotient := result[0]
rangeCheckNbBits := RANGE_CHECK_NB_BITS
p.api.ToBinary(quotient, rangeCheckNbBits)
remainder := NewVariable(result[1])
p.RangeCheck(remainder)
return remainder
}
// Reduces a field element x such that x % MODULUS = y.
func (p *Chip) ReduceWithMaxBits(x Variable, maxNbBits uint64) Variable {
// Witness a `quotient` and `remainder` such that:
//
// MODULUS * quotient + remainder = x
//
// Must check that remainder \in [0, MODULUS) and quotient \in [0, 2^maxNbBits) to ensure that this
// computation does not overflow.
result, err := p.api.Compiler().NewHint(ReduceHint, 2, x.Limb)
if err != nil {
panic(err)
}
quotient := result[0]
p.api.ToBinary(quotient, int(maxNbBits))
remainder := NewVariable(result[1])
p.RangeCheck(remainder)
return remainder
}
// The hint used to compute Reduce.
func ReduceHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
if len(inputs) != 1 {
panic("ReduceHint expects 1 input operand")
}
input := inputs[0]
quotient := new(big.Int).Div(input, MODULUS)
remainder := new(big.Int).Rem(input, MODULUS)
results[0] = quotient
results[1] = remainder
return nil
}
// Computes the inverse of a field element x such that x * x^-1 = 1.
func (p *Chip) Inverse(x Variable) Variable {
result, err := p.api.Compiler().NewHint(InverseHint, 1, x.Limb)
if err != nil {
panic(err)
}
inverse := NewVariable(result[0])
product := p.Mul(inverse, x)
p.api.AssertIsEqual(product.Limb, frontend.Variable(1))
return inverse
}
// The hint used to compute Inverse.
func InverseHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
if len(inputs) != 1 {
panic("InverseHint expects 1 input operand")
}
input := inputs[0]
if input.Cmp(MODULUS) == 0 || input.Cmp(MODULUS) == 1 {
panic("Input is not in the field")
}
inputGl := goldilocks.NewElement(input.Uint64())
resultGl := goldilocks.NewElement(0)
resultGl.Inverse(&inputGl)
result := big.NewInt(0)
results[0] = resultGl.BigInt(result)
return nil
}
// Computes a field element raised to some power.
func (p *Chip) Exp(x Variable, k *big.Int) Variable {
if k.IsUint64() && k.Uint64() == 0 {
return One()
}
e := k
if k.Sign() == -1 {
panic("Unsupported negative exponent. Need to implement inversion.")
}
z := x
for i := e.BitLen() - 2; i >= 0; i-- {
z = p.Mul(z, z)
if e.Bit(i) == 1 {
z = p.Mul(z, x)
}
}
return z
}
// Range checks a field element x to be less than the Golidlocks modulus 2 ^ 64 - 2 ^ 32 + 1.
func (p *Chip) RangeCheck(x Variable) {
// The Goldilocks' modulus is 2^64 - 2^32 + 1, which is:
//
// 1111111111111111111111111111111100000000000000000000000000000001
//
// in big endian binary. This function will first verify that x is at most 64 bits wide. Then it
// checks that if the bits[0:31] (in big-endian) are all 1, then bits[32:64] are all zero.
// First decompose x into 64 bits. The bits will be in little-endian order.
bits := bits.ToBinary(p.api, x.Limb, bits.WithNbDigits(64))
// Those bits should compose back to x.
reconstructedX := frontend.Variable(0)
c := uint64(1)
for i := 0; i < 64; i++ {
reconstructedX = p.api.Add(reconstructedX, p.api.Mul(bits[i], c))
c = c << 1
p.api.AssertIsBoolean(bits[i])
}
p.api.AssertIsEqual(x.Limb, reconstructedX)
mostSigBits32Sum := frontend.Variable(0)
for i := 32; i < 64; i++ {
mostSigBits32Sum = p.api.Add(mostSigBits32Sum, bits[i])
}
leastSigBits32Sum := frontend.Variable(0)
for i := 0; i < 32; i++ {
leastSigBits32Sum = p.api.Add(leastSigBits32Sum, bits[i])
}
// If mostSigBits32Sum < 32, then we know that:
//
// x < (2^63 + ... + 2^32 + 0 * 2^31 + ... + 0 * 2^0)
//
// which equals to 2^64 - 2^32. So in that case, we don't need to do any more checks. If
// mostSigBits32Sum == 32, then we need to check that x == 2^64 - 2^32 (max GL value).
shouldCheck := p.api.IsZero(p.api.Sub(mostSigBits32Sum, 32))
p.api.AssertIsEqual(
p.api.Select(
shouldCheck,
leastSigBits32Sum,
frontend.Variable(0),
),
frontend.Variable(0),
)
}
func (p *Chip) AssertIsEqual(x, y Variable) {
p.api.AssertIsEqual(x.Limb, y.Limb)
}
// Computes the n'th primitive root of unity for the Goldilocks field.
func PrimitiveRootOfUnity(nLog uint64) goldilocks.Element {
if nLog > TWO_ADICITY {
panic("nLog is greater than TWO_ADICITY")
}
res := goldilocks.NewElement(POWER_OF_TWO_GENERATOR.Uint64())
for i := 0; i < int(TWO_ADICITY-nLog); i++ {
res.Square(&res)
}
return res
}
func TwoAdicSubgroup(nLog uint64) []goldilocks.Element {
if nLog > TWO_ADICITY {
panic("nLog is greater than GOLDILOCKS_TWO_ADICITY")
}
var res []goldilocks.Element
rootOfUnity := PrimitiveRootOfUnity(nLog)
res = append(res, goldilocks.NewElement(1))
for i := 0; i < (1 << nLog); i++ {
lastElement := res[len(res)-1]
res = append(res, *lastElement.Mul(&lastElement, &rootOfUnity))
}
return res
}

field/goldilocks_test.go → goldilocks/base_test.go

@ -1,4 +1,4 @@
package field
package goldilocks
import ( import (
"math/big" "math/big"
@ -15,7 +15,8 @@ type TestGoldilocksRangeCheckCircuit struct {
} }
func (c *TestGoldilocksRangeCheckCircuit) Define(api frontend.API) error { func (c *TestGoldilocksRangeCheckCircuit) Define(api frontend.API) error {
GoldilocksRangeCheck(api, c.X)
chip := NewChip(api)
chip.RangeCheck(NewVariable(c.X))
return nil return nil
} }
func TestGoldilocksRangeCheck(t *testing.T) { func TestGoldilocksRangeCheck(t *testing.T) {
@ -29,11 +30,11 @@ func TestGoldilocksRangeCheck(t *testing.T) {
witness.X = 0 witness.X = 0
assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization()) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization())
witness.X = EmulatedField{}.Modulus()
witness.X = MODULUS
assert.ProverFailed(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization()) assert.ProverFailed(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization())
one := big.NewInt(1) one := big.NewInt(1)
maxValidVal := new(big.Int).Sub(EmulatedField{}.Modulus(), one)
maxValidVal := new(big.Int).Sub(MODULUS, one)
witness.X = maxValidVal witness.X = maxValidVal
assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16)) assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16))
} }
@ -44,9 +45,9 @@ type TestGoldilocksMulAddCircuit struct {
} }
func (c *TestGoldilocksMulAddCircuit) Define(api frontend.API) error { func (c *TestGoldilocksMulAddCircuit) Define(api frontend.API) error {
calculateValue := GoldilocksMulAdd(api, c.X, c.Y, c.Z)
api.AssertIsEqual(calculateValue, c.ExpectedResult)
chip := NewChip(api)
calculateValue := chip.MulAdd(NewVariable(c.X), NewVariable(c.Y), NewVariable(c.Z))
api.AssertIsEqual(calculateValue.Limb, c.ExpectedResult)
return nil return nil
} }

+ 234
- 0
goldilocks/quadratic_extension.go

@ -0,0 +1,234 @@
package goldilocks
import (
"math/bits"
"github.com/consensys/gnark/frontend"
)
const W uint64 = 7
const DTH_ROOT uint64 = 18446744069414584320
type QuadraticExtensionVariable [2]Variable
func NewQuadraticExtensionVariable(x Variable, y Variable) QuadraticExtensionVariable {
return QuadraticExtensionVariable{x, y}
}
func (p Variable) ToQuadraticExtension() QuadraticExtensionVariable {
return NewQuadraticExtensionVariable(p, Zero())
}
func ZeroExtension() QuadraticExtensionVariable {
return Zero().ToQuadraticExtension()
}
func OneExtension() QuadraticExtensionVariable {
return One().ToQuadraticExtension()
}
// Adds two quadratic extension variables in the Goldilocks field.
func (p *Chip) AddExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
c0 := p.Add(a[0], b[0])
c1 := p.Add(a[1], b[1])
return NewQuadraticExtensionVariable(c0, c1)
}
// Adds two quadratic extension variables in the Goldilocks field without reducing.
func (p *Chip) AddExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
c0 := p.AddNoReduce(a[0], b[0])
c1 := p.AddNoReduce(a[1], b[1])
return NewQuadraticExtensionVariable(c0, c1)
}
// Subtracts two quadratic extension variables in the Goldilocks field.
func (p *Chip) SubExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
c0 := p.Sub(a[0], b[0])
c1 := p.Sub(a[1], b[1])
return NewQuadraticExtensionVariable(c0, c1)
}
// Subtracts two quadratic extension variables in the Goldilocks field without reducing.
func (p *Chip) SubExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
c0 := p.SubNoReduce(a[0], b[0])
c1 := p.SubNoReduce(a[1], b[1])
return NewQuadraticExtensionVariable(c0, c1)
}
// Multiplies quadratic extension variable in the Goldilocks field.
func (p *Chip) MulExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
product := p.MulExtensionNoReduce(a, b)
product[0] = p.Reduce(product[0])
product[1] = p.Reduce(product[1])
return product
}
// Multiplies quadratic extension variable in the Goldilocks field without reducing.
func (p *Chip) MulExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
c0o0 := p.MulNoReduce(a[0], b[0])
c0o1 := p.MulNoReduce(p.MulNoReduce(NewVariable(7), a[1]), b[1])
c0 := p.AddNoReduce(c0o0, c0o1)
c1 := p.AddNoReduce(p.MulNoReduce(a[0], b[1]), p.MulNoReduce(a[1], b[0]))
return NewQuadraticExtensionVariable(c0, c1)
}
// Multiplies two operands a and b and adds to c in the Goldilocks extension field. a * b + c must
// be less than RANGE_CHECK_NB_BITS bits.
func (p *Chip) MulAddExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
product := p.MulExtensionNoReduce(a, b)
sum := p.AddExtensionNoReduce(product, c)
sum[0] = p.Reduce(sum[0])
sum[1] = p.Reduce(sum[1])
return sum
}
func (p *Chip) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
product := p.MulExtensionNoReduce(a, b)
sum := p.AddExtensionNoReduce(product, c)
return sum
}
// Multiplies two operands a and b and subtracts to c in the Goldilocks extension field. a * b - c must
// be less than RANGE_CHECK_NB_BITS bits.
func (p *Chip) SubMulExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
difference := p.SubExtensionNoReduce(a, b)
product := p.MulExtensionNoReduce(difference, c)
product[0] = p.Reduce(product[0])
product[1] = p.Reduce(product[1])
return product
}
// Multiplies quadratic extension variable in the Goldilocks field by a scalar.
func (p *Chip) ScalarMulExtension(
a QuadraticExtensionVariable,
b Variable,
) QuadraticExtensionVariable {
return NewQuadraticExtensionVariable(
p.Mul(a[0], b),
p.Mul(a[1], b),
)
}
// Computes an inner product over quadratic extension variable vectors in the Goldilocks field.
func (p *Chip) InnerProductExtension(
constant Variable,
startingAcc QuadraticExtensionVariable,
pairs [][2]QuadraticExtensionVariable,
) QuadraticExtensionVariable {
acc := startingAcc
for i := 0; i < len(pairs); i++ {
a := pairs[i][0]
b := pairs[i][1]
mul := p.ScalarMulExtension(a, constant)
acc = p.MulAddExtensionNoReduce(mul, b, acc)
}
return p.ReduceExtension(acc)
}
// Computes the inverse of a quadratic extension variable in the Goldilocks field.
func (p *Chip) InverseExtension(a QuadraticExtensionVariable) QuadraticExtensionVariable {
a0IsZero := p.api.IsZero(a[0].Limb)
a1IsZero := p.api.IsZero(a[1].Limb)
p.api.AssertIsEqual(p.api.Mul(a0IsZero, a1IsZero), frontend.Variable(0))
aPowRMinus1 := QuadraticExtensionVariable{
a[0],
p.Mul(a[1], NewVariable(DTH_ROOT)),
}
aPowR := p.MulExtension(aPowRMinus1, a)
return p.ScalarMulExtension(aPowRMinus1, p.Inverse(aPowR[0]))
}
// Divides two quadratic extension variables in the Goldilocks field.
func (p *Chip) DivExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
return p.MulExtension(a, p.InverseExtension(b))
}
// Exponentiates a quadratic extension variable to some exponent in the Golidlocks field.
func (p *Chip) ExpExtension(
a QuadraticExtensionVariable,
exponent uint64,
) QuadraticExtensionVariable {
switch exponent {
case 0:
return OneExtension()
case 1:
return a
case 2:
return p.MulExtension(a, a)
default:
}
current := a
product := OneExtension()
for i := 0; i < bits.Len64(exponent); i++ {
if i != 0 {
current = p.MulExtension(current, current)
}
if (exponent >> i & 1) != 0 {
product = p.MulExtension(product, current)
}
}
return product
}
func (p *Chip) ReduceExtension(x QuadraticExtensionVariable) QuadraticExtensionVariable {
return NewQuadraticExtensionVariable(p.Reduce(x[0]), p.Reduce(x[1]))
}
// Reduces a list of extension field terms with a scalar power in the Goldilocks field.
func (p *Chip) ReduceWithPowers(
terms []QuadraticExtensionVariable,
scalar QuadraticExtensionVariable,
) QuadraticExtensionVariable {
sum := ZeroExtension()
for i := len(terms) - 1; i >= 0; i-- {
sum = p.AddExtensionNoReduce(
p.MulExtensionNoReduce(
sum,
scalar,
),
terms[i],
)
sum = p.ReduceExtension(sum)
}
return sum
}
// Outputs whether the quadratic extension variable is zero.
func (p *Chip) IsZero(x QuadraticExtensionVariable) frontend.Variable {
x0IsZero := p.api.IsZero(x[0].Limb)
x1IsZero := p.api.IsZero(x[1].Limb)
return p.api.Mul(x0IsZero, x1IsZero)
}
// Lookup is similar to select, but returns the first variable if the bit is zero and vice-versa.
func (p *Chip) Lookup(
b frontend.Variable,
x, y QuadraticExtensionVariable,
) QuadraticExtensionVariable {
c0 := p.api.Select(b, y[0].Limb, x[0].Limb)
c1 := p.api.Select(b, y[1].Limb, x[1].Limb)
return NewQuadraticExtensionVariable(NewVariable(c0), NewVariable(c1))
}
// Lookup2 is similar to select2, but returns the first variable if the bit is zero and vice-versa.
func (p *Chip) Lookup2(
b0 frontend.Variable,
b1 frontend.Variable,
qe0, qe1, qe2, qe3 QuadraticExtensionVariable,
) QuadraticExtensionVariable {
c0 := p.Lookup(b0, qe0, qe1)
c1 := p.Lookup(b0, qe2, qe3)
return p.Lookup(b1, c0, c1)
}
// Asserts that two quadratic extension variables are equal.
func (p *Chip) AssertIsEqualExtension(
a QuadraticExtensionVariable,
b QuadraticExtensionVariable,
) {
p.AssertIsEqual(a[0], b[0])
p.AssertIsEqual(a[1], b[1])
}

+ 125
- 0
goldilocks/quadratic_extension_algebra.go

@ -0,0 +1,125 @@
package goldilocks
import "github.com/consensys/gnark-crypto/field/goldilocks"
const D = 2
type QuadraticExtensionAlgebraVariable = [D]QuadraticExtensionVariable
func NewQuadraticExtensionAlgebraVariable(
a QuadraticExtensionVariable,
b QuadraticExtensionVariable,
) QuadraticExtensionAlgebraVariable {
return QuadraticExtensionAlgebraVariable{a, b}
}
func (p QuadraticExtensionVariable) ToQuadraticExtensionAlgebra() QuadraticExtensionAlgebraVariable {
return [2]QuadraticExtensionVariable{p, ZeroExtension()}
}
func ZeroExtensionAlgebra() QuadraticExtensionAlgebraVariable {
return ZeroExtension().ToQuadraticExtensionAlgebra()
}
func OneExtensionAlgebra() QuadraticExtensionAlgebraVariable {
return OneExtension().ToQuadraticExtensionAlgebra()
}
func (p *Chip) AddExtensionAlgebra(
a QuadraticExtensionAlgebraVariable,
b QuadraticExtensionAlgebraVariable,
) QuadraticExtensionAlgebraVariable {
var sum QuadraticExtensionAlgebraVariable
for i := 0; i < D; i++ {
sum[i] = p.AddExtension(a[i], b[i])
}
return sum
}
func (p *Chip) SubExtensionAlgebra(
a QuadraticExtensionAlgebraVariable,
b QuadraticExtensionAlgebraVariable,
) QuadraticExtensionAlgebraVariable {
var diff QuadraticExtensionAlgebraVariable
for i := 0; i < D; i++ {
diff[i] = p.SubExtension(a[i], b[i])
}
return diff
}
func (p Chip) MulExtensionAlgebra(
a QuadraticExtensionAlgebraVariable,
b QuadraticExtensionAlgebraVariable,
) QuadraticExtensionAlgebraVariable {
var inner [D][]QuadraticExtensionAlgebraVariable
var innerW [D][]QuadraticExtensionAlgebraVariable
for i := 0; i < D; i++ {
for j := 0; j < D-i; j++ {
idx := (i + j) % D
inner[idx] = append(inner[idx], QuadraticExtensionAlgebraVariable{a[i], b[j]})
}
for j := D - i; j < D; j++ {
idx := (i + j) % D
innerW[idx] = append(innerW[idx], QuadraticExtensionAlgebraVariable{a[i], b[j]})
}
}
var product QuadraticExtensionAlgebraVariable
for i := 0; i < D; i++ {
acc := p.InnerProductExtension(NewVariable(W), ZeroExtension(), innerW[i])
product[i] = p.InnerProductExtension(One(), acc, inner[i])
}
return product
}
func (p *Chip) ScalarMulExtensionAlgebra(
a QuadraticExtensionVariable,
b QuadraticExtensionAlgebraVariable,
) QuadraticExtensionAlgebraVariable {
var product QuadraticExtensionAlgebraVariable
for i := 0; i < D; i++ {
product[i] = p.MulExtension(a, b[i])
}
return product
}
func (p *Chip) PartialInterpolateExtAlgebra(
domain []goldilocks.Element,
values []QuadraticExtensionAlgebraVariable,
barycentricWeights []goldilocks.Element,
point QuadraticExtensionAlgebraVariable,
initialEval QuadraticExtensionAlgebraVariable,
initialPartialProd QuadraticExtensionAlgebraVariable,
) (QuadraticExtensionAlgebraVariable, QuadraticExtensionAlgebraVariable) {
n := len(values)
if n == 0 {
panic("Cannot interpolate with no values")
}
if n != len(domain) {
panic("Domain and values must have the same length")
}
if n != len(barycentricWeights) {
panic("Domain and barycentric weights must have the same length")
}
newEval := initialEval
newPartialProd := initialPartialProd
for i := 0; i < n; i++ {
val := values[i]
x := domain[i]
xField := NewVariable(x)
xQE := xField.ToQuadraticExtension()
xQEAlgebra := xQE.ToQuadraticExtensionAlgebra()
weight := NewVariable(barycentricWeights[i].Uint64()).ToQuadraticExtension()
term := p.SubExtensionAlgebra(point, xQEAlgebra)
weightedVal := p.ScalarMulExtensionAlgebra(weight, val)
newEval = p.MulExtensionAlgebra(newEval, term)
tmp := p.MulExtensionAlgebra(weightedVal, newPartialProd)
newEval = p.AddExtensionAlgebra(newEval, tmp)
newPartialProd = p.MulExtensionAlgebra(newPartialProd, term)
}
return newEval, newPartialProd
}

+ 1
- 0
goldilocks/quadratic_extension_algebra_test.go

@ -0,0 +1 @@
package goldilocks

+ 94
- 0
goldilocks/quadratic_extension_test.go

@ -0,0 +1,94 @@
package goldilocks
import (
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
)
type TestQuadraticExtensionMulCircuit struct {
Operand1 QuadraticExtensionVariable
Operand2 QuadraticExtensionVariable
ExpectedResult QuadraticExtensionVariable
}
func (c *TestQuadraticExtensionMulCircuit) Define(api frontend.API) error {
glApi := NewChip(api)
actualRes := glApi.MulExtension(c.Operand1, c.Operand2)
glApi.AssertIsEqual(actualRes[0], c.ExpectedResult[0])
glApi.AssertIsEqual(actualRes[1], c.ExpectedResult[1])
return nil
}
func TestQuadraticExtensionMul4(t *testing.T) {
assert := test.NewAssert(t)
operand1 := QuadraticExtensionVariable{
NewVariable("4994088319481652598"),
NewVariable("16489566008211790727"),
}
operand2 := QuadraticExtensionVariable{
NewVariable("3797605683985595697"),
NewVariable("13424401189265534004"),
}
expectedResult := QuadraticExtensionVariable{
NewVariable("15052319864161058789"),
NewVariable("16841416332519902625"),
}
circuit := TestQuadraticExtensionMulCircuit{
Operand1: operand1,
Operand2: operand2,
ExpectedResult: expectedResult,
}
witness := TestQuadraticExtensionMulCircuit{
Operand1: operand1,
Operand2: operand2,
ExpectedResult: expectedResult,
}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}
// Test for quadratic extension division
type TestQuadraticExtensionDivCircuit struct {
Operand1 QuadraticExtensionVariable
Operand2 QuadraticExtensionVariable
ExpectedResult QuadraticExtensionVariable
}
func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error {
glAPI := NewChip(api)
actualRes := glAPI.DivExtension(c.Operand1, c.Operand2)
glAPI.AssertIsEqual(actualRes[0], c.ExpectedResult[0])
glAPI.AssertIsEqual(actualRes[1], c.ExpectedResult[1])
return nil
}
func TestQuadraticExtensionDiv(t *testing.T) {
assert := test.NewAssert(t)
operand1 := QuadraticExtensionVariable{
NewVariable("4994088319481652598"),
NewVariable("16489566008211790727"),
}
operand2 := QuadraticExtensionVariable{
NewVariable("7166004739148609569"),
NewVariable("14655965871663555016"),
}
expectedResult := QuadraticExtensionVariable{
NewVariable("15052319864161058789"),
NewVariable("16841416332519902625"),
}
circuit := TestQuadraticExtensionDivCircuit{
Operand1: operand1,
Operand2: operand2,
ExpectedResult: expectedResult,
}
witness := TestQuadraticExtensionDivCircuit{
Operand1: operand1,
Operand2: operand2,
ExpectedResult: expectedResult,
}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}

utils/utils.go → goldilocks/utils.go

@ -1,10 +1,9 @@
package utils
package goldilocks
import ( import (
"math/big" "math/big"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
) )
func StrArrayToBigIntArray(input []string) []big.Int { func StrArrayToBigIntArray(input []string) []big.Int {
@ -25,22 +24,22 @@ func StrArrayToFrontendVariableArray(input []string) []frontend.Variable {
return output return output
} }
func Uint64ArrayToFArray(input []uint64) []field.F {
var output []field.F
func Uint64ArrayToVariableArray(input []uint64) []Variable {
var output []Variable
for i := 0; i < len(input); i++ { for i := 0; i < len(input); i++ {
output = append(output, field.NewFieldConst(input[i]))
output = append(output, NewVariable(input[i]))
} }
return output return output
} }
func Uint64ArrayToQuadraticExtension(input []uint64) field.QuadraticExtension {
return [2]field.F{field.NewFieldConst(input[0]), field.NewFieldConst(input[1])}
func Uint64ArrayToQuadraticExtension(input []uint64) QuadraticExtensionVariable {
return NewQuadraticExtensionVariable(NewVariable(input[0]), NewVariable(input[1]))
} }
func Uint64ArrayToQuadraticExtensionArray(input [][]uint64) []field.QuadraticExtension {
var output []field.QuadraticExtension
func Uint64ArrayToQuadraticExtensionArray(input [][]uint64) []QuadraticExtensionVariable {
var output []QuadraticExtensionVariable
for i := 0; i < len(input); i++ { for i := 0; i < len(input); i++ {
output = append(output, [2]field.F{field.NewFieldConst(input[i][0]), field.NewFieldConst(input[i][1])})
output = append(output, NewQuadraticExtensionVariable(NewVariable(input[i][0]), NewVariable(input[i][1])))
} }
return output return output
} }

verifier/internal/gates/arithmetic_extension_gate.go → plonk/gates/arithmetic_extension_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var aritheticExtensionGateRegex = regexp.MustCompile("ArithmeticExtensionGate { num_ops: (?P<numOps>[0-9]+) }") var aritheticExtensionGateRegex = regexp.MustCompile("ArithmeticExtensionGate { num_ops: (?P<numOps>[0-9]+) }")
@ -41,39 +41,43 @@ func (g *ArithmeticExtensionGate) Id() string {
} }
func (g *ArithmeticExtensionGate) wiresIthMultiplicand0(i uint64) Range { func (g *ArithmeticExtensionGate) wiresIthMultiplicand0(i uint64) Range {
return Range{4 * field.D * i, 4*field.D*i + field.D}
return Range{4 * gl.D * i, 4*gl.D*i + gl.D}
} }
func (g *ArithmeticExtensionGate) wiresIthMultiplicand1(i uint64) Range { func (g *ArithmeticExtensionGate) wiresIthMultiplicand1(i uint64) Range {
return Range{4*field.D*i + field.D, 4*field.D*i + 2*field.D}
return Range{4*gl.D*i + gl.D, 4*gl.D*i + 2*gl.D}
} }
func (g *ArithmeticExtensionGate) wiresIthAddend(i uint64) Range { func (g *ArithmeticExtensionGate) wiresIthAddend(i uint64) Range {
return Range{4*field.D*i + 2*field.D, 4*field.D*i + 3*field.D}
return Range{4*gl.D*i + 2*gl.D, 4*gl.D*i + 3*gl.D}
} }
func (g *ArithmeticExtensionGate) wiresIthOutput(i uint64) Range { func (g *ArithmeticExtensionGate) wiresIthOutput(i uint64) Range {
return Range{4*field.D*i + 3*field.D, 4*field.D*i + 4*field.D}
return Range{4*gl.D*i + 3*gl.D, 4*gl.D*i + 4*gl.D}
} }
func (g *ArithmeticExtensionGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
func (g *ArithmeticExtensionGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
const0 := vars.localConstants[0] const0 := vars.localConstants[0]
const1 := vars.localConstants[1] const1 := vars.localConstants[1]
constraints := []field.QuadraticExtension{}
constraints := []gl.QuadraticExtensionVariable{}
for i := uint64(0); i < g.numOps; i++ { for i := uint64(0); i < g.numOps; i++ {
multiplicand0 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand0(i)) multiplicand0 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand0(i))
multiplicand1 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand1(i)) multiplicand1 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand1(i))
addend := vars.GetLocalExtAlgebra(g.wiresIthAddend(i)) addend := vars.GetLocalExtAlgebra(g.wiresIthAddend(i))
output := vars.GetLocalExtAlgebra(g.wiresIthOutput(i)) output := vars.GetLocalExtAlgebra(g.wiresIthOutput(i))
mul := qeAPI.MulExtensionAlgebra(multiplicand0, multiplicand1)
scaled_mul := qeAPI.ScalarMulExtensionAlgebra(const0, mul)
computed_output := qeAPI.ScalarMulExtensionAlgebra(const1, addend)
computed_output = qeAPI.AddExtensionAlgebra(computed_output, scaled_mul)
mul := glApi.MulExtensionAlgebra(multiplicand0, multiplicand1)
scaled_mul := glApi.ScalarMulExtensionAlgebra(const0, mul)
computed_output := glApi.ScalarMulExtensionAlgebra(const1, addend)
computed_output = glApi.AddExtensionAlgebra(computed_output, scaled_mul)
diff := qeAPI.SubExtensionAlgebra(output, computed_output)
for j := 0; j < field.D; j++ {
diff := glApi.SubExtensionAlgebra(output, computed_output)
for j := 0; j < gl.D; j++ {
constraints = append(constraints, diff[j]) constraints = append(constraints, diff[j])
} }
} }

verifier/internal/gates/arithmetic_gate.go → plonk/gates/arithmetic_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var aritheticGateRegex = regexp.MustCompile("ArithmeticGate { num_ops: (?P<numOps>[0-9]+) }") var aritheticGateRegex = regexp.MustCompile("ArithmeticGate { num_ops: (?P<numOps>[0-9]+) }")
@ -57,23 +57,27 @@ func (g *ArithmeticGate) WireIthOutput(i uint64) uint64 {
return 4*i + 3 return 4*i + 3
} }
func (g *ArithmeticGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
func (g *ArithmeticGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
const0 := vars.localConstants[0] const0 := vars.localConstants[0]
const1 := vars.localConstants[1] const1 := vars.localConstants[1]
constraints := []field.QuadraticExtension{}
constraints := []gl.QuadraticExtensionVariable{}
for i := uint64(0); i < g.numOps; i++ { for i := uint64(0); i < g.numOps; i++ {
multiplicand0 := vars.localWires[g.WireIthMultiplicand0(i)] multiplicand0 := vars.localWires[g.WireIthMultiplicand0(i)]
multiplicand1 := vars.localWires[g.WireIthMultiplicand1(i)] multiplicand1 := vars.localWires[g.WireIthMultiplicand1(i)]
addend := vars.localWires[g.WireIthAddend(i)] addend := vars.localWires[g.WireIthAddend(i)]
output := vars.localWires[g.WireIthOutput(i)] output := vars.localWires[g.WireIthOutput(i)]
computedOutput := qeAPI.AddExtension(
qeAPI.MulExtension(qeAPI.MulExtension(multiplicand0, multiplicand1), const0),
qeAPI.MulExtension(addend, const1),
computedOutput := glApi.AddExtension(
glApi.MulExtension(glApi.MulExtension(multiplicand0, multiplicand1), const0),
glApi.MulExtension(addend, const1),
) )
constraints = append(constraints, qeAPI.SubExtension(output, computedOutput))
constraints = append(constraints, glApi.SubExtension(output, computedOutput))
} }
return constraints return constraints

verifier/internal/gates/base_sum_gate.go → plonk/gates/base_sum_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var baseSumGateRegex = regexp.MustCompile(`BaseSumGate { num_limbs: (?P<numLimbs>[0-9]+) } \+ Base: (?P<base>[0-9]+)`) var baseSumGateRegex = regexp.MustCompile(`BaseSumGate { num_limbs: (?P<numLimbs>[0-9]+) } \+ Base: (?P<base>[0-9]+)`)
@ -63,27 +63,31 @@ func (g *BaseSumGate) limbs() []uint64 {
return limbIndices return limbIndices
} }
func (g *BaseSumGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
func (g *BaseSumGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
sum := vars.localWires[BASESUM_GATE_WIRE_SUM] sum := vars.localWires[BASESUM_GATE_WIRE_SUM]
limbs := make([]field.QuadraticExtension, g.numLimbs)
limbs := make([]gl.QuadraticExtensionVariable, g.numLimbs)
limbIndices := g.limbs() limbIndices := g.limbs()
for i, limbIdx := range limbIndices { for i, limbIdx := range limbIndices {
limbs[i] = vars.localWires[limbIdx] limbs[i] = vars.localWires[limbIdx]
} }
base_qe := qeAPI.FieldToQE(field.NewFieldConst(g.base))
computedSum := qeAPI.ReduceWithPowers(
baseQe := gl.NewQuadraticExtensionVariable(gl.NewVariable(g.base), gl.Zero())
computedSum := glApi.ReduceWithPowers(
limbs, limbs,
base_qe,
baseQe,
) )
var constraints []field.QuadraticExtension
constraints = append(constraints, qeAPI.SubExtension(computedSum, sum))
var constraints []gl.QuadraticExtensionVariable
constraints = append(constraints, glApi.SubExtension(computedSum, sum))
for _, limb := range limbs { for _, limb := range limbs {
acc := qeAPI.ONE_QE
acc := gl.OneExtension()
for i := uint64(0); i < g.base; i++ { for i := uint64(0); i < g.base; i++ {
difference := qeAPI.SubExtension(limb, qeAPI.FieldToQE(field.NewFieldConst(i)))
acc = qeAPI.MulExtension(acc, difference)
difference := glApi.SubExtension(limb, gl.NewQuadraticExtensionVariable(gl.NewVariable(i), gl.Zero()))
acc = glApi.MulExtension(acc, difference)
} }
constraints = append(constraints, acc) constraints = append(constraints, acc)
} }

verifier/internal/gates/constant_gate.go → plonk/gates/constant_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var constantGateRegex = regexp.MustCompile("ConstantGate { num_consts: (?P<numConsts>[0-9]+) }") var constantGateRegex = regexp.MustCompile("ConstantGate { num_consts: (?P<numConsts>[0-9]+) }")
@ -54,11 +54,15 @@ func (g *ConstantGate) WireOutput(i uint64) uint64 {
return i return i
} }
func (g *ConstantGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
constraints := []field.QuadraticExtension{}
func (g *ConstantGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
constraints := []gl.QuadraticExtensionVariable{}
for i := uint64(0); i < g.numConsts; i++ { for i := uint64(0); i < g.numConsts; i++ {
constraints = append(constraints, qeAPI.SubExtension(vars.localConstants[g.ConstInput(i)], vars.localWires[g.WireOutput(i)]))
constraints = append(constraints, glApi.SubExtension(vars.localConstants[g.ConstInput(i)], vars.localWires[g.WireOutput(i)]))
} }
return constraints return constraints

verifier/internal/gates/coset_interpolation_gate.go → plonk/gates/coset_interpolation_gate.go

@ -8,7 +8,7 @@ import (
"github.com/consensys/gnark-crypto/field/goldilocks" "github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var cosetInterpolationGateRegex = regexp.MustCompile(`CosetInterpolationGate { subgroup_bits: (?P<subgroupBits>[0-9]+), degree: (?P<degree>[0-9]+), barycentric_weights: \[(?P<barycentricWeights>[0-9, ]+)\], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>`) var cosetInterpolationGateRegex = regexp.MustCompile(`CosetInterpolationGate { subgroup_bits: (?P<subgroupBits>[0-9]+), degree: (?P<degree>[0-9]+), barycentric_weights: \[(?P<barycentricWeights>[0-9, ]+)\], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>`)
@ -89,32 +89,32 @@ func (g *CosetInterpolationGate) wiresValue(i uint64) Range {
if i >= g.numPoints() { if i >= g.numPoints() {
panic("Invalid point index") panic("Invalid point index")
} }
start := g.startValues() + i*field.D
return Range{start, start + field.D}
start := g.startValues() + i*gl.D
return Range{start, start + gl.D}
} }
func (g *CosetInterpolationGate) startEvaluationPoint() uint64 { func (g *CosetInterpolationGate) startEvaluationPoint() uint64 {
return g.startValues() + g.numPoints()*field.D
return g.startValues() + g.numPoints()*gl.D
} }
// Wire indices of the point to evaluate the interpolant at. // Wire indices of the point to evaluate the interpolant at.
func (g *CosetInterpolationGate) wiresEvaluationPoint() Range { func (g *CosetInterpolationGate) wiresEvaluationPoint() Range {
start := g.startEvaluationPoint() start := g.startEvaluationPoint()
return Range{start, start + field.D}
return Range{start, start + gl.D}
} }
func (g *CosetInterpolationGate) startEvaluationValue() uint64 { func (g *CosetInterpolationGate) startEvaluationValue() uint64 {
return g.startEvaluationPoint() + field.D
return g.startEvaluationPoint() + gl.D
} }
// Wire indices of the interpolated value. // Wire indices of the interpolated value.
func (g *CosetInterpolationGate) wiresEvaluationValue() Range { func (g *CosetInterpolationGate) wiresEvaluationValue() Range {
start := g.startEvaluationValue() start := g.startEvaluationValue()
return Range{start, start + field.D}
return Range{start, start + gl.D}
} }
func (g *CosetInterpolationGate) startIntermediates() uint64 { func (g *CosetInterpolationGate) startIntermediates() uint64 {
return g.startEvaluationValue() + field.D
return g.startEvaluationValue() + gl.D
} }
func (g *CosetInterpolationGate) numIntermediates() uint64 { func (g *CosetInterpolationGate) numIntermediates() uint64 {
@ -126,8 +126,8 @@ func (g *CosetInterpolationGate) wiresIntermediateEval(i uint64) Range {
if i >= g.numIntermediates() { if i >= g.numIntermediates() {
panic("Invalid intermediate index") panic("Invalid intermediate index")
} }
start := g.startIntermediates() + field.D*i
return Range{start, start + field.D}
start := g.startIntermediates() + gl.D*i
return Range{start, start + gl.D}
} }
// The wires corresponding to the i'th intermediate product. // The wires corresponding to the i'th intermediate product.
@ -135,42 +135,46 @@ func (g *CosetInterpolationGate) wiresIntermediateProd(i uint64) Range {
if i >= g.numIntermediates() { if i >= g.numIntermediates() {
panic("Invalid intermediate index") panic("Invalid intermediate index")
} }
start := g.startIntermediates() + field.D*(g.numIntermediates()+i)
return Range{start, start + field.D}
start := g.startIntermediates() + gl.D*(g.numIntermediates()+i)
return Range{start, start + gl.D}
} }
// Wire indices of the shifted point to evaluate the interpolant at. // Wire indices of the shifted point to evaluate the interpolant at.
func (g *CosetInterpolationGate) wiresShiftedEvaluationPoint() Range { func (g *CosetInterpolationGate) wiresShiftedEvaluationPoint() Range {
start := g.startIntermediates() + field.D*2*g.numIntermediates()
return Range{start, start + field.D}
start := g.startIntermediates() + gl.D*2*g.numIntermediates()
return Range{start, start + gl.D}
} }
func (g *CosetInterpolationGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
constraints := []field.QuadraticExtension{}
func (g *CosetInterpolationGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
constraints := []gl.QuadraticExtensionVariable{}
shift := vars.localWires[g.wireShift()] shift := vars.localWires[g.wireShift()]
evaluationPoint := vars.GetLocalExtAlgebra(g.wiresEvaluationPoint()) evaluationPoint := vars.GetLocalExtAlgebra(g.wiresEvaluationPoint())
shiftedEvaluationPoint := vars.GetLocalExtAlgebra(g.wiresShiftedEvaluationPoint()) shiftedEvaluationPoint := vars.GetLocalExtAlgebra(g.wiresShiftedEvaluationPoint())
negShift := qeAPI.ScalarMulExtension(shift, field.NEG_ONE_F)
negShift := glApi.ScalarMulExtension(shift, gl.NegOne())
tmp := qeAPI.ScalarMulExtensionAlgebra(negShift, shiftedEvaluationPoint)
tmp = qeAPI.AddExtensionAlgebra(tmp, evaluationPoint)
tmp := glApi.ScalarMulExtensionAlgebra(negShift, shiftedEvaluationPoint)
tmp = glApi.AddExtensionAlgebra(tmp, evaluationPoint)
for i := 0; i < field.D; i++ {
for i := 0; i < gl.D; i++ {
constraints = append(constraints, tmp[i]) constraints = append(constraints, tmp[i])
} }
domain := field.TwoAdicSubgroup(g.subgroupBits)
values := []field.QEAlgebra{}
domain := gl.TwoAdicSubgroup(g.subgroupBits)
values := []gl.QuadraticExtensionAlgebraVariable{}
for i := uint64(0); i < g.numPoints(); i++ { for i := uint64(0); i < g.numPoints(); i++ {
values = append(values, vars.GetLocalExtAlgebra(g.wiresValue(i))) values = append(values, vars.GetLocalExtAlgebra(g.wiresValue(i)))
} }
weights := g.barycentricWeights weights := g.barycentricWeights
initialEval := qeAPI.ZERO_QE_ALGEBRA
initialProd := field.QEAlgebra{qeAPI.ONE_QE, qeAPI.ZERO_QE}
computedEval, computedProd := qeAPI.PartialInterpolateExtAlgebra(
initialEval := gl.ZeroExtensionAlgebra()
initialProd := gl.OneExtensionAlgebra()
computedEval, computedProd := glApi.PartialInterpolateExtAlgebra(
domain[:g.degree], domain[:g.degree],
values[:g.degree], values[:g.degree],
weights[:g.degree], weights[:g.degree],
@ -183,19 +187,19 @@ func (g *CosetInterpolationGate) EvalUnfiltered(api frontend.API, qeAPI *field.Q
intermediateEval := vars.GetLocalExtAlgebra(g.wiresIntermediateEval(i)) intermediateEval := vars.GetLocalExtAlgebra(g.wiresIntermediateEval(i))
intermediateProd := vars.GetLocalExtAlgebra(g.wiresIntermediateProd(i)) intermediateProd := vars.GetLocalExtAlgebra(g.wiresIntermediateProd(i))
evalDiff := qeAPI.SubExtensionAlgebra(intermediateEval, computedEval)
for j := 0; j < field.D; j++ {
evalDiff := glApi.SubExtensionAlgebra(intermediateEval, computedEval)
for j := 0; j < gl.D; j++ {
constraints = append(constraints, evalDiff[j]) constraints = append(constraints, evalDiff[j])
} }
prodDiff := qeAPI.SubExtensionAlgebra(intermediateProd, computedProd)
for j := 0; j < field.D; j++ {
prodDiff := glApi.SubExtensionAlgebra(intermediateProd, computedProd)
for j := 0; j < gl.D; j++ {
constraints = append(constraints, prodDiff[j]) constraints = append(constraints, prodDiff[j])
} }
startIndex := 1 + (g.degree-1)*(i+1) startIndex := 1 + (g.degree-1)*(i+1)
endIndex := startIndex + g.degree - 1 endIndex := startIndex + g.degree - 1
computedEval, computedProd = qeAPI.PartialInterpolateExtAlgebra(
computedEval, computedProd = glApi.PartialInterpolateExtAlgebra(
domain[startIndex:endIndex], domain[startIndex:endIndex],
values[startIndex:endIndex], values[startIndex:endIndex],
weights[startIndex:endIndex], weights[startIndex:endIndex],
@ -206,8 +210,8 @@ func (g *CosetInterpolationGate) EvalUnfiltered(api frontend.API, qeAPI *field.Q
} }
evaluationValue := vars.GetLocalExtAlgebra(g.wiresEvaluationValue()) evaluationValue := vars.GetLocalExtAlgebra(g.wiresEvaluationValue())
evalDiff := qeAPI.SubExtensionAlgebra(evaluationValue, computedEval)
for j := 0; j < field.D; j++ {
evalDiff := glApi.SubExtensionAlgebra(evaluationValue, computedEval)
for j := 0; j < gl.D; j++ {
constraints = append(constraints, evalDiff[j]) constraints = append(constraints, evalDiff[j])
} }

verifier/internal/gates/evaluate_gates.go → plonk/gates/evaluate_gates.go

@ -2,12 +2,11 @@ package gates
import ( import (
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
type EvaluateGatesChip struct { type EvaluateGatesChip struct {
api frontend.API
qeAPI *field.QuadraticExtensionAPI
api frontend.API
gates []Gate gates []Gate
numGateConstraints uint64 numGateConstraints uint64
@ -17,14 +16,12 @@ type EvaluateGatesChip struct {
func NewEvaluateGatesChip( func NewEvaluateGatesChip(
api frontend.API, api frontend.API,
qeAPI *field.QuadraticExtensionAPI,
gates []Gate, gates []Gate,
numGateConstraints uint64, numGateConstraints uint64,
selectorsInfo SelectorsInfo, selectorsInfo SelectorsInfo,
) *EvaluateGatesChip { ) *EvaluateGatesChip {
return &EvaluateGatesChip{ return &EvaluateGatesChip{
api: api,
qeAPI: qeAPI,
api: api,
gates: gates, gates: gates,
numGateConstraints: numGateConstraints, numGateConstraints: numGateConstraints,
@ -36,20 +33,22 @@ func NewEvaluateGatesChip(
func (g *EvaluateGatesChip) computeFilter( func (g *EvaluateGatesChip) computeFilter(
row uint64, row uint64,
groupRange Range, groupRange Range,
s field.QuadraticExtension,
s gl.QuadraticExtensionVariable,
manySelector bool, manySelector bool,
) field.QuadraticExtension {
product := g.qeAPI.ONE_QE
) gl.QuadraticExtensionVariable {
glApi := gl.NewChip(g.api)
product := gl.OneExtension()
for i := groupRange.start; i < groupRange.end; i++ { for i := groupRange.start; i < groupRange.end; i++ {
if i == uint64(row) { if i == uint64(row) {
continue continue
} }
product = g.qeAPI.MulExtension(product, g.qeAPI.SubExtension(g.qeAPI.FieldToQE(field.NewFieldConst(i)), s))
tmp := gl.NewQuadraticExtensionVariable(gl.NewVariable(i), gl.Zero())
product = glApi.MulExtension(product, glApi.SubExtension(tmp, s))
} }
if manySelector { if manySelector {
product = g.qeAPI.MulExtension(product, g.qeAPI.SubExtension(g.qeAPI.FieldToQE(field.NewFieldConst(UNUSED_SELECTOR)), s))
tmp := gl.NewQuadraticExtensionVariable(gl.NewVariable(UNUSED_SELECTOR), gl.Zero())
product = glApi.MulExtension(product, glApi.SubExtension(tmp, s))
} }
return product return product
@ -62,22 +61,24 @@ func (g *EvaluateGatesChip) evalFiltered(
selectorIndex uint64, selectorIndex uint64,
groupRange Range, groupRange Range,
numSelectors uint64, numSelectors uint64,
) []field.QuadraticExtension {
) []gl.QuadraticExtensionVariable {
glApi := gl.NewChip(g.api)
filter := g.computeFilter(row, groupRange, vars.localConstants[selectorIndex], numSelectors > 1) filter := g.computeFilter(row, groupRange, vars.localConstants[selectorIndex], numSelectors > 1)
vars.RemovePrefix(numSelectors) vars.RemovePrefix(numSelectors)
unfiltered := gate.EvalUnfiltered(g.api, g.qeAPI, vars)
unfiltered := gate.EvalUnfiltered(g.api, *glApi, vars)
for i := range unfiltered { for i := range unfiltered {
unfiltered[i] = g.qeAPI.MulExtension(unfiltered[i], filter)
unfiltered[i] = glApi.MulExtension(unfiltered[i], filter)
} }
return unfiltered return unfiltered
} }
func (g *EvaluateGatesChip) EvaluateGateConstraints(vars EvaluationVars) []field.QuadraticExtension {
constraints := make([]field.QuadraticExtension, g.numGateConstraints)
func (g *EvaluateGatesChip) EvaluateGateConstraints(vars EvaluationVars) []gl.QuadraticExtensionVariable {
glApi := gl.NewChip(g.api)
constraints := make([]gl.QuadraticExtensionVariable, g.numGateConstraints)
for i := range constraints { for i := range constraints {
constraints[i] = g.qeAPI.ZERO_QE
constraints[i] = gl.ZeroExtension()
} }
for i, gate := range g.gates { for i, gate := range g.gates {
@ -96,7 +97,7 @@ func (g *EvaluateGatesChip) EvaluateGateConstraints(vars EvaluationVars) []field
if uint64(i) >= g.numGateConstraints { if uint64(i) >= g.numGateConstraints {
panic("num_constraints() gave too low of a number") panic("num_constraints() gave too low of a number")
} }
constraints[i] = g.qeAPI.AddExtension(constraints[i], constraint)
constraints[i] = glApi.AddExtension(constraints[i], constraint)
} }
} }

verifier/internal/gates/exponentiation_gate.go → plonk/gates/exponentiation_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var exponentiationGateRegex = regexp.MustCompile("ExponentiationGate { num_power_bits: (?P<numPowerBits>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>") var exponentiationGateRegex = regexp.MustCompile("ExponentiationGate { num_power_bits: (?P<numPowerBits>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>")
@ -63,29 +63,33 @@ func (g *ExponentiationGate) wireIntermediateValue(i uint64) uint64 {
return 2 + g.numPowerBits + i return 2 + g.numPowerBits + i
} }
func (g *ExponentiationGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
func (g *ExponentiationGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
base := vars.localWires[g.wireBase()] base := vars.localWires[g.wireBase()]
var powerBits []field.QuadraticExtension
var powerBits []gl.QuadraticExtensionVariable
for i := uint64(0); i < g.numPowerBits; i++ { for i := uint64(0); i < g.numPowerBits; i++ {
powerBits = append(powerBits, vars.localWires[g.wirePowerBit(i)]) powerBits = append(powerBits, vars.localWires[g.wirePowerBit(i)])
} }
var intermediateValues []field.QuadraticExtension
var intermediateValues []gl.QuadraticExtensionVariable
for i := uint64(0); i < g.numPowerBits; i++ { for i := uint64(0); i < g.numPowerBits; i++ {
intermediateValues = append(intermediateValues, vars.localWires[g.wireIntermediateValue(i)]) intermediateValues = append(intermediateValues, vars.localWires[g.wireIntermediateValue(i)])
} }
output := vars.localWires[g.wireOutput()] output := vars.localWires[g.wireOutput()]
var constraints []field.QuadraticExtension
var constraints []gl.QuadraticExtensionVariable
for i := uint64(0); i < g.numPowerBits; i++ { for i := uint64(0); i < g.numPowerBits; i++ {
var prevIntermediateValue field.QuadraticExtension
var prevIntermediateValue gl.QuadraticExtensionVariable
if i == 0 { if i == 0 {
prevIntermediateValue = qeAPI.ONE_QE
prevIntermediateValue = gl.OneExtension()
} else { } else {
prevIntermediateValue = qeAPI.SquareExtension(intermediateValues[i-1])
prevIntermediateValue = glApi.MulExtension(intermediateValues[i-1], intermediateValues[i-1])
} }
// powerBits is in LE order, but we accumulate in BE order. // powerBits is in LE order, but we accumulate in BE order.
@ -94,16 +98,16 @@ func (g *ExponentiationGate) EvalUnfiltered(api frontend.API, qeAPI *field.Quadr
// Do a polynomial representation of generaized select (where the selector variable doesn't have to be binary) // Do a polynomial representation of generaized select (where the selector variable doesn't have to be binary)
// if b { x } else { y } // if b { x } else { y }
// i.e. `bx - (by-y)`. // i.e. `bx - (by-y)`.
tmp := qeAPI.MulExtension(curBit, qeAPI.ONE_QE)
tmp = qeAPI.SubExtension(tmp, qeAPI.ONE_QE)
mulBy := qeAPI.MulExtension(curBit, base)
mulBy = qeAPI.SubExtension(mulBy, tmp)
intermediateValueDiff := qeAPI.MulExtension(prevIntermediateValue, mulBy)
intermediateValueDiff = qeAPI.SubExtension(intermediateValueDiff, intermediateValues[i])
tmp := glApi.MulExtension(curBit, gl.OneExtension())
tmp = glApi.SubExtension(tmp, gl.OneExtension())
mulBy := glApi.MulExtension(curBit, base)
mulBy = glApi.SubExtension(mulBy, tmp)
intermediateValueDiff := glApi.MulExtension(prevIntermediateValue, mulBy)
intermediateValueDiff = glApi.SubExtension(intermediateValueDiff, intermediateValues[i])
constraints = append(constraints, intermediateValueDiff) constraints = append(constraints, intermediateValueDiff)
} }
outputDiff := qeAPI.SubExtension(output, intermediateValues[g.numPowerBits-1])
outputDiff := glApi.SubExtension(output, intermediateValues[g.numPowerBits-1])
constraints = append(constraints, outputDiff) constraints = append(constraints, outputDiff)
return constraints return constraints

verifier/internal/gates/gate.go → plonk/gates/gates.go

@ -5,12 +5,16 @@ import (
"regexp" "regexp"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
type Gate interface { type Gate interface {
Id() string Id() string
EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension
EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable
} }
var gateRegexHandlers = map[*regexp.Regexp]func(parameters map[string]string) Gate{ var gateRegexHandlers = map[*regexp.Regexp]func(parameters map[string]string) Gate{

+ 768
- 0
plonk/gates/gates_test.go

@ -0,0 +1,768 @@
package gates_test
import (
"errors"
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier"
)
// From recursive_step circuit
var localConstants = []gl.QuadraticExtensionVariable{
{gl.NewVariable("4962976205186800892"), gl.NewVariable("6982360466972099197")},
{gl.NewVariable("3587364333101709084"), gl.NewVariable("17496916837371484700")},
{gl.NewVariable("17287374881609559799"), gl.NewVariable("3152841633956965234")},
{gl.NewVariable("8531030241248616826"), gl.NewVariable("7753678118587211959")},
{gl.NewVariable("7622109056373824903"), gl.NewVariable("6523636236475969621")},
}
var localWires = []gl.QuadraticExtensionVariable{
{gl.NewVariable("5101665081776077058"), gl.NewVariable("13601771238484783081")},
{gl.NewVariable("13763997788502656587"), gl.NewVariable("6068443864169526207")},
{gl.NewVariable("10492880302699453810"), gl.NewVariable("11304418575668616669")},
{gl.NewVariable("2175168501339052813"), gl.NewVariable("3658211467579027796")},
{gl.NewVariable("11342710587435471757"), gl.NewVariable("658078906333318768")},
{gl.NewVariable("16590262768413671742"), gl.NewVariable("4678191900868819358")},
{gl.NewVariable("18412513594273328173"), gl.NewVariable("3981245463942959904")},
{gl.NewVariable("18150166316938544267"), gl.NewVariable("6968565044901838140")},
{gl.NewVariable("1048835939602984673"), gl.NewVariable("3511920575130606798")},
{gl.NewVariable("13693300152826538654"), gl.NewVariable("5872314861500881782")},
{gl.NewVariable("6394696263219721312"), gl.NewVariable("92364988976021720")},
{gl.NewVariable("468193345380249942"), gl.NewVariable("4951036536117371576")},
{gl.NewVariable("9660006729985637684"), gl.NewVariable("14762789799642492635")},
{gl.NewVariable("10091149087332313493"), gl.NewVariable("13279468039286967053")},
{gl.NewVariable("12007469191150580744"), gl.NewVariable("2495445179052731885")},
{gl.NewVariable("14225726459587943147"), gl.NewVariable("13484648741862607201")},
{gl.NewVariable("15365400400136175672"), gl.NewVariable("12227857303059870833")},
{gl.NewVariable("1717742269682481687"), gl.NewVariable("14319701537357602192")},
{gl.NewVariable("2130805637557027375"), gl.NewVariable("9674794597783493233")},
{gl.NewVariable("4200526016516623452"), gl.NewVariable("1757832412907480092")},
{gl.NewVariable("4159226258922372229"), gl.NewVariable("2121976810680943769")},
{gl.NewVariable("2887943290582259162"), gl.NewVariable("10337505797799617185")},
{gl.NewVariable("14760843822980496189"), gl.NewVariable("16331301823872182680")},
{gl.NewVariable("14715580754822129725"), gl.NewVariable("13761736659446638375")},
{gl.NewVariable("6925818640561435525"), gl.NewVariable("14142327999826777974")},
{gl.NewVariable("14048060513252076245"), gl.NewVariable("14860933194240516940")},
{gl.NewVariable("3928889853630846436"), gl.NewVariable("16211791673476822740")},
{gl.NewVariable("15980387576926781891"), gl.NewVariable("6238947314711778055")},
{gl.NewVariable("15694939331980119296"), gl.NewVariable("8708301222382733590")},
{gl.NewVariable("192757930858294268"), gl.NewVariable("5400388905722847256")},
{gl.NewVariable("17614358883814855964"), gl.NewVariable("11499208634388453518")},
{gl.NewVariable("9523994443422431577"), gl.NewVariable("6835394446482946098")},
{gl.NewVariable("10096606893378243201"), gl.NewVariable("8982086840326369907")},
{gl.NewVariable("7328922720001507777"), gl.NewVariable("17298728994563323488")},
{gl.NewVariable("7038859554184407337"), gl.NewVariable("6498153778103681368")},
{gl.NewVariable("10610651604960433540"), gl.NewVariable("18240735600936975661")},
{gl.NewVariable("4310901749476028644"), gl.NewVariable("17813866938235850894")},
{gl.NewVariable("12456949458361594924"), gl.NewVariable("16541357680870686003")},
{gl.NewVariable("13986559680062429806"), gl.NewVariable("14210541290696888125")},
{gl.NewVariable("10299578396192380820"), gl.NewVariable("18011235767871391546")},
{gl.NewVariable("747566550336808782"), gl.NewVariable("5892109075601553099")},
{gl.NewVariable("11613383633841665100"), gl.NewVariable("3562006923196410047")},
{gl.NewVariable("14971867523312360339"), gl.NewVariable("9835080574905235511")},
{gl.NewVariable("5487884847548072736"), gl.NewVariable("17112808386797082519")},
{gl.NewVariable("1687420180518659740"), gl.NewVariable("14003627304711288225")},
{gl.NewVariable("6760442482244819429"), gl.NewVariable("15796493945480647537")},
{gl.NewVariable("2639939427088481105"), gl.NewVariable("16213109089273184951")},
{gl.NewVariable("6186345082501710713"), gl.NewVariable("2529053005908871239")},
{gl.NewVariable("16270115914931256348"), gl.NewVariable("2789355919627681645")},
{gl.NewVariable("4586999018177783314"), gl.NewVariable("2427837399215959725")},
{gl.NewVariable("18143358622388343317"), gl.NewVariable("2145167333845152043")},
{gl.NewVariable("20367062449222124"), gl.NewVariable("14939961527015734373")},
{gl.NewVariable("16851694158642043266"), gl.NewVariable("5250789952541240163")},
{gl.NewVariable("273375074794411822"), gl.NewVariable("16211897175907793903")},
{gl.NewVariable("8905927930385832568"), gl.NewVariable("6540262589846603524")},
{gl.NewVariable("9283781971254844102"), gl.NewVariable("15115068064900745758")},
{gl.NewVariable("16002987404851668189"), gl.NewVariable("15226686847545140008")},
{gl.NewVariable("17201679792194997813"), gl.NewVariable("589849108691638964")},
{gl.NewVariable("13270753269614250355"), gl.NewVariable("13858862497673084592")},
{gl.NewVariable("3679908279346826560"), gl.NewVariable("10125726541855725943")},
{gl.NewVariable("9493227554592600240"), gl.NewVariable("13229107531594530196")},
{gl.NewVariable("10072423214517113799"), gl.NewVariable("1877804054697703518")},
{gl.NewVariable("9351494680554520560"), gl.NewVariable("12930187723253788505")},
{gl.NewVariable("9537056082833040850"), gl.NewVariable("3947445714701039423")},
{gl.NewVariable("978662253133020143"), gl.NewVariable("17432233037279205717")},
{gl.NewVariable("13408331971471826902"), gl.NewVariable("8338873650278204671")},
{gl.NewVariable("10455530172494355126"), gl.NewVariable("14614842120953588617")},
{gl.NewVariable("3066054670984065145"), gl.NewVariable("11061840675948823020")},
{gl.NewVariable("1215442291812236170"), gl.NewVariable("6970679356502977963")},
{gl.NewVariable("16254140688845356393"), gl.NewVariable("16413217415268481315")},
{gl.NewVariable("5571707217813279614"), gl.NewVariable("2506082641312169038")},
{gl.NewVariable("18179591596294163519"), gl.NewVariable("16131760445397495720")},
{gl.NewVariable("9500821197677833979"), gl.NewVariable("14137570623214003877")},
{gl.NewVariable("18159279414894480072"), gl.NewVariable("316120438770524969")},
{gl.NewVariable("18164288455905080997"), gl.NewVariable("12889510574086616078")},
{gl.NewVariable("7158952489901063870"), gl.NewVariable("8855957421923524202")},
{gl.NewVariable("11785615172910130564"), gl.NewVariable("13242859272114186921")},
{gl.NewVariable("7978627011292316159"), gl.NewVariable("12030929068833787030")},
{gl.NewVariable("5676253512795062173"), gl.NewVariable("9401396509276686822")},
{gl.NewVariable("13934555872940874542"), gl.NewVariable("12262482935570269103")},
{gl.NewVariable("17018864997992880664"), gl.NewVariable("8399037137658253821")},
{gl.NewVariable("1846702834278938262"), gl.NewVariable("13210394651984411322")},
{gl.NewVariable("18406563809882201846"), gl.NewVariable("15807625126691296911")},
{gl.NewVariable("16192554501791210701"), gl.NewVariable("15105514277710825451")},
{gl.NewVariable("16115514979166385045"), gl.NewVariable("5618092869410987045")},
{gl.NewVariable("9816852940756124129"), gl.NewVariable("1617435612712694609")},
{gl.NewVariable("15012743324956680415"), gl.NewVariable("11098953448520716956")},
{gl.NewVariable("7370750057902285338"), gl.NewVariable("15456123684241865136")},
{gl.NewVariable("14924801177398773859"), gl.NewVariable("1116868612459919368")},
{gl.NewVariable("509701279674911901"), gl.NewVariable("8606220700917290973")},
{gl.NewVariable("256371784527067555"), gl.NewVariable("18023759020251995084")},
{gl.NewVariable("4027645791496469270"), gl.NewVariable("6446906876250510281")},
{gl.NewVariable("8190141658485644545"), gl.NewVariable("3259909135802998300")},
{gl.NewVariable("11270185749533517292"), gl.NewVariable("7032460358965516338")},
{gl.NewVariable("12112891112487601597"), gl.NewVariable("3686732542066412082")},
{gl.NewVariable("18143522178445971138"), gl.NewVariable("6066438010126851248")},
{gl.NewVariable("16109160830754618815"), gl.NewVariable("2728516440557525242")},
{gl.NewVariable("14634072837475699881"), gl.NewVariable("423778353213757146")},
{gl.NewVariable("10421081673554059162"), gl.NewVariable("10142208889746521219")},
{gl.NewVariable("12957639310809930956"), gl.NewVariable("1709286023553869935")},
{gl.NewVariable("16217923109113456531"), gl.NewVariable("3257438610376598615")},
{gl.NewVariable("14024104132094810570"), gl.NewVariable("6065015478137587430")},
{gl.NewVariable("7972303368219061571"), gl.NewVariable("5413678307283424945")},
{gl.NewVariable("10367882107777269226"), gl.NewVariable("9366367173763419226")},
{gl.NewVariable("11506720810821148150"), gl.NewVariable("15210537421649867625")},
{gl.NewVariable("10979917526797364486"), gl.NewVariable("3365843489182711842")},
{gl.NewVariable("9176981360155624350"), gl.NewVariable("7315956459698675112")},
{gl.NewVariable("3964217770504101577"), gl.NewVariable("9088242192411952739")},
{gl.NewVariable("16243289324567090937"), gl.NewVariable("13379263550784156456")},
{gl.NewVariable("18105277122985331384"), gl.NewVariable("13639149553905751132")},
{gl.NewVariable("11145583988660932112"), gl.NewVariable("16125114195985557867")},
{gl.NewVariable("18437667738670181477"), gl.NewVariable("8593343353929068644")},
{gl.NewVariable("15549894364614350199"), gl.NewVariable("6234736889764963090")},
{gl.NewVariable("17753837009416762390"), gl.NewVariable("15297774054893249240")},
{gl.NewVariable("1465043006528110247"), gl.NewVariable("11029942851654974974")},
{gl.NewVariable("14312704742949520917"), gl.NewVariable("17324353686056674958")},
{gl.NewVariable("8078333430227959261"), gl.NewVariable("14797545414164578336")},
{gl.NewVariable("3544997838139687150"), gl.NewVariable("8846840377946705678")},
{gl.NewVariable("9981846866090807073"), gl.NewVariable("18142560414179130259")},
{gl.NewVariable("1256577435119993994"), gl.NewVariable("155745544208227129")},
{gl.NewVariable("6040293874299819317"), gl.NewVariable("10483265617246740662")},
{gl.NewVariable("976159477616343697"), gl.NewVariable("6356544693059700239")},
{gl.NewVariable("4771747444846377672"), gl.NewVariable("2466985401424965488")},
{gl.NewVariable("9549711421417753693"), gl.NewVariable("9543806479040458857")},
{gl.NewVariable("5277199124405775998"), gl.NewVariable("6251037001966593402")},
{gl.NewVariable("13103543598051591262"), gl.NewVariable("2001921170471454234")},
{gl.NewVariable("1254878001165263070"), gl.NewVariable("17587272030879777460")},
{gl.NewVariable("2300344156307624878"), gl.NewVariable("14356513038946626528")},
{gl.NewVariable("2482567400777596327"), gl.NewVariable("3314129985687795881")},
{gl.NewVariable("16492046206730922155"), gl.NewVariable("1312905854247159931")},
{gl.NewVariable("3061501132630116372"), gl.NewVariable("13315665946615810001")},
{gl.NewVariable("16415932954051444990"), gl.NewVariable("925217124969456536")},
{gl.NewVariable("9764657158286137619"), gl.NewVariable("16039332713210679567")},
{gl.NewVariable("14993545086997628961"), gl.NewVariable("18010329211070748489")},
{gl.NewVariable("17327862012036619887"), gl.NewVariable("16962349802452905993")},
{gl.NewVariable("4826313026336060985"), gl.NewVariable("3597777099127511952")},
}
var publicInputsHash = poseidon.GoldilocksHashOut{
gl.Zero(),
gl.Zero(),
gl.Zero(),
gl.Zero(),
}
var publicInputGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("5101665081776077058"), gl.NewVariable("13601771238484783081")},
{gl.NewVariable("13763997788502656587"), gl.NewVariable("6068443864169526207")},
{gl.NewVariable("10492880302699453810"), gl.NewVariable("11304418575668616669")},
{gl.NewVariable("2175168501339052813"), gl.NewVariable("3658211467579027796")},
}
// BaseSumGate { num_limbs: 63 }), (Base: 2)
var baseSumGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("9928715244459351681"), gl.NewVariable("5344081500364361215")},
{gl.NewVariable("10167164649082076581"), gl.NewVariable("15450889555489725096")},
{gl.NewVariable("3546584706462116594"), gl.NewVariable("1476426705388693036")},
{gl.NewVariable("12648634003162244983"), gl.NewVariable("2239452344495239178")},
{gl.NewVariable("2301087631440580451"), gl.NewVariable("11975672920337250307")},
{gl.NewVariable("14001554463269171732"), gl.NewVariable("6953207277617809048")},
{gl.NewVariable("9895590040747031510"), gl.NewVariable("1356956949635190505")},
{gl.NewVariable("14939964178677988571"), gl.NewVariable("454717738260444218")},
{gl.NewVariable("12201660109699192297"), gl.NewVariable("12502457673278583036")},
{gl.NewVariable("1175543972635147885"), gl.NewVariable("11103026408792334489")},
{gl.NewVariable("3384025741923988904"), gl.NewVariable("2656764746353452717")},
{gl.NewVariable("10849522185534943138"), gl.NewVariable("13172212508084788997")},
{gl.NewVariable("10509522572526523739"), gl.NewVariable("2090707475955491976")},
{gl.NewVariable("13692600715410336206"), gl.NewVariable("7227633217973806771")},
{gl.NewVariable("8471053080480597138"), gl.NewVariable("2646922138422495173")},
{gl.NewVariable("555344530120410083"), gl.NewVariable("13860459564781531385")},
{gl.NewVariable("8748801107049442833"), gl.NewVariable("9263752460533085733")},
{gl.NewVariable("13633964398888639692"), gl.NewVariable("10068133633095351031")},
{gl.NewVariable("6911322073377914708"), gl.NewVariable("17978361073083837803")},
{gl.NewVariable("11223090828346729804"), gl.NewVariable("5006610230932979596")},
{gl.NewVariable("11581626217660221266"), gl.NewVariable("16347470001077006094")},
{gl.NewVariable("2924189901864366701"), gl.NewVariable("4309265474738828848")},
{gl.NewVariable("7275314468944461178"), gl.NewVariable("3109308884739285751")},
{gl.NewVariable("12416988612575693809"), gl.NewVariable("13772367397588066248")},
{gl.NewVariable("15438805794425696237"), gl.NewVariable("5809350894111990599")},
{gl.NewVariable("4275145128501503120"), gl.NewVariable("13230668146909969114")},
{gl.NewVariable("15244699495724739585"), gl.NewVariable("7672322205441472064")},
{gl.NewVariable("5429809680618805220"), gl.NewVariable("3153880467220264060")},
{gl.NewVariable("14715345489518514160"), gl.NewVariable("2246036712337629635")},
{gl.NewVariable("9359342125434211935"), gl.NewVariable("7844760208539761732")},
{gl.NewVariable("17550561700498841003"), gl.NewVariable("10851755490050776878")},
{gl.NewVariable("12192385328855013814"), gl.NewVariable("6629056869404844416")},
{gl.NewVariable("3424745785197724925"), gl.NewVariable("9833599393425172230")},
{gl.NewVariable("8602078107149096927"), gl.NewVariable("6592109323720773368")},
{gl.NewVariable("4109716921881297082"), gl.NewVariable("4396469548700606105")},
{gl.NewVariable("10400304110319417426"), gl.NewVariable("1229823145437740976")},
{gl.NewVariable("14853277673343952974"), gl.NewVariable("7653131044140686982")},
{gl.NewVariable("15831955783787857197"), gl.NewVariable("16541106185743830609")},
{gl.NewVariable("16097830673407036871"), gl.NewVariable("917501749911433098")},
{gl.NewVariable("6819428296662518848"), gl.NewVariable("15325182544903569500")},
{gl.NewVariable("3554857310728040215"), gl.NewVariable("17540168721765377170")},
{gl.NewVariable("7246216899469226885"), gl.NewVariable("3184709231158489554")},
{gl.NewVariable("3462793508732024933"), gl.NewVariable("13410498916934897793")},
{gl.NewVariable("784714181705176804"), gl.NewVariable("8079390288171846846")},
{gl.NewVariable("4592501261546923410"), gl.NewVariable("6046244648190342248")},
{gl.NewVariable("14100558314779073910"), gl.NewVariable("9589305391181830029")},
{gl.NewVariable("7208216654581381179"), gl.NewVariable("16662177305876430630")},
{gl.NewVariable("13442246990998561849"), gl.NewVariable("6359024918649040199")},
{gl.NewVariable("16196376030005699590"), gl.NewVariable("5656446490425854681")},
{gl.NewVariable("16279173216505198700"), gl.NewVariable("6278440230935274234")},
{gl.NewVariable("9299204333782277508"), gl.NewVariable("5539548698065086849")},
{gl.NewVariable("531539748103362347"), gl.NewVariable("17008402782657673980")},
{gl.NewVariable("11956287871118080485"), gl.NewVariable("17776888431041950837")},
{gl.NewVariable("16795401491637949606"), gl.NewVariable("12112971435724505573")},
{gl.NewVariable("10141270150228316653"), gl.NewVariable("8738825159351228227")},
{gl.NewVariable("4249416130151320263"), gl.NewVariable("4171109024390883108")},
{gl.NewVariable("13565954345346642147"), gl.NewVariable("11300077318998472624")},
{gl.NewVariable("6006413348327738680"), gl.NewVariable("17429146764001291339")},
{gl.NewVariable("3009379005164242386"), gl.NewVariable("17911649148503516453")},
{gl.NewVariable("4172202865347441020"), gl.NewVariable("6700979848078030374")},
{gl.NewVariable("9692174554453081047"), gl.NewVariable("16461309050820528716")},
{gl.NewVariable("16012555505188709835"), gl.NewVariable("875036531415994728")},
{gl.NewVariable("14527388813134058525"), gl.NewVariable("13371873777459370318")},
{gl.NewVariable("6493493657980111839"), gl.NewVariable("14874520839734823069")},
}
// ArithmeticGate { num_ops: 20 }
var arithmeticGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("8251494922795803874"), gl.NewVariable("7884328911897949424")},
{gl.NewVariable("17545754596575389449"), gl.NewVariable("15111927979676704385")},
{gl.NewVariable("10052040965126353731"), gl.NewVariable("1448153912054014611")},
{gl.NewVariable("3878848318701063854"), gl.NewVariable("15999854355391952993")},
{gl.NewVariable("2194699804496089007"), gl.NewVariable("7489112350095609056")},
{gl.NewVariable("666656317372820215"), gl.NewVariable("8333111246649438880")},
{gl.NewVariable("15500013716804095980"), gl.NewVariable("7739144386812042617")},
{gl.NewVariable("2815612394018416154"), gl.NewVariable("15839168197108305099")},
{gl.NewVariable("12980309813768330187"), gl.NewVariable("12446111953378048591")},
{gl.NewVariable("1389916348936822477"), gl.NewVariable("2080258147396834809")},
{gl.NewVariable("3676770229830052631"), gl.NewVariable("8984521981419906260")},
{gl.NewVariable("4759606161035299488"), gl.NewVariable("18415228017149216426")},
{gl.NewVariable("6849567585629675684"), gl.NewVariable("15231001333591586187")},
{gl.NewVariable("17831496121270832947"), gl.NewVariable("1868580989876710210")},
{gl.NewVariable("12226832860244216901"), gl.NewVariable("12352098694767236965")},
{gl.NewVariable("9795530155924375772"), gl.NewVariable("4833402654226660686")},
{gl.NewVariable("7421277748600887772"), gl.NewVariable("16979590244320625600")},
{gl.NewVariable("4212532134312824848"), gl.NewVariable("7938725153260099101")},
{gl.NewVariable("17718231164451799422"), gl.NewVariable("13363195988334771788")},
{gl.NewVariable("5414385531680474153"), gl.NewVariable("13600409983387272243")},
}
// RandomAccessGate { bits: 4, num_copies: 4, num_extra_constants: 2, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
var randomAccessGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("18367067186009695282"), gl.NewVariable("6227937229941915629")},
{gl.NewVariable("342627832935644960"), gl.NewVariable("11262336464371657587")},
{gl.NewVariable("7711502047853221895"), gl.NewVariable("9814305320358879113")},
{gl.NewVariable("2436675870898619939"), gl.NewVariable("12171743011114835714")},
{gl.NewVariable("9224796650008092960"), gl.NewVariable("197827193844666436")},
{gl.NewVariable("7661651717350955969"), gl.NewVariable("3929163527437938921")},
{gl.NewVariable("11994613277879586781"), gl.NewVariable("2918199453077793278")},
{gl.NewVariable("2133315582796573410"), gl.NewVariable("9920472598641951727")},
{gl.NewVariable("5763420675219782924"), gl.NewVariable("193200772658790662")},
{gl.NewVariable("14322103909897767697"), gl.NewVariable("2455403487869979318")},
{gl.NewVariable("3583177870835306708"), gl.NewVariable("15956920993825363087")},
{gl.NewVariable("15767764327818217757"), gl.NewVariable("17814936958431909187")},
{gl.NewVariable("7224551806569620055"), gl.NewVariable("1191241782303323453")},
{gl.NewVariable("3994846439282900915"), gl.NewVariable("16007298430807731888")},
{gl.NewVariable("1904864531973789879"), gl.NewVariable("9374437322489636375")},
{gl.NewVariable("17617411600595291430"), gl.NewVariable("11804426503917788826")},
{gl.NewVariable("5010213812557284606"), gl.NewVariable("8276410914978849008")},
{gl.NewVariable("13701536021647106057"), gl.NewVariable("5043776904396037625")},
{gl.NewVariable("4336267979289896624"), gl.NewVariable("8771134635816393433")},
{gl.NewVariable("17885926480537171976"), gl.NewVariable("9644095314646547597")},
{gl.NewVariable("17179233085824331332"), gl.NewVariable("6950525108693323209")},
{gl.NewVariable("9461258042008745175"), gl.NewVariable("6766975264204597922")},
{gl.NewVariable("10838154179711471883"), gl.NewVariable("16554457937262927355")},
{gl.NewVariable("5823858951686479642"), gl.NewVariable("10171201631442530906")},
{gl.NewVariable("17476953112985367168"), gl.NewVariable("12062851564787792403")},
{gl.NewVariable("7909573710893929152"), gl.NewVariable("6207515797705444652")},
}
// PoseidonGate(PhantomData<plonky2_field::goldilocks_field::GoldilocksField>)<WIDTH=12>
var poseidonGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("15438805794425696237"), gl.NewVariable("5809350894111990599")},
{gl.NewVariable("105238306594298866"), gl.NewVariable("6398155585902798861")},
{gl.NewVariable("5256232026568856387"), gl.NewVariable("9253448664982005262")},
{gl.NewVariable("6559974022172208218"), gl.NewVariable("14478753759394222537")},
{gl.NewVariable("7036928093413865537"), gl.NewVariable("895644692646980845")},
{gl.NewVariable("6350074916129003337"), gl.NewVariable("10418298512623677843")},
{gl.NewVariable("6618288817893266284"), gl.NewVariable("17565920952415773065")},
{gl.NewVariable("7214268149308735221"), gl.NewVariable("17797640553663908886")},
{gl.NewVariable("17038147867485750883"), gl.NewVariable("10766691853641769251")},
{gl.NewVariable("1228066111137794024"), gl.NewVariable("1267834319488006514")},
{gl.NewVariable("15317834050441961579"), gl.NewVariable("13280896488837969140")},
{gl.NewVariable("10135227968960430585"), gl.NewVariable("7096433509203324519")},
{gl.NewVariable("10733417635899979276"), gl.NewVariable("16819459255105516700")},
{gl.NewVariable("4231839251429338586"), gl.NewVariable("3213678047797020863")},
{gl.NewVariable("16271445286187692537"), gl.NewVariable("15377656608157234934")},
{gl.NewVariable("9356442829698587975"), gl.NewVariable("14633910545825415036")},
{gl.NewVariable("13952390018297698734"), gl.NewVariable("16325393355066618599")},
{gl.NewVariable("11399251131586292643"), gl.NewVariable("16257107051968717815")},
{gl.NewVariable("4274092107872068929"), gl.NewVariable("15550597684938436610")},
{gl.NewVariable("13076618331457049912"), gl.NewVariable("4958059540220054374")},
{gl.NewVariable("11650097218963026123"), gl.NewVariable("12070947109214611020")},
{gl.NewVariable("2700303408109034014"), gl.NewVariable("5968338348636871194")},
{gl.NewVariable("11508005723655482353"), gl.NewVariable("15224088756564969467")},
{gl.NewVariable("9328231423353697829"), gl.NewVariable("10577349809783627634")},
{gl.NewVariable("556544259468984890"), gl.NewVariable("13376447539117215836")},
{gl.NewVariable("17319865455991589647"), gl.NewVariable("588985536671201497")},
{gl.NewVariable("9528470026616131077"), gl.NewVariable("7257040911301352274")},
{gl.NewVariable("14316182132889623635"), gl.NewVariable("9589165219691594711")},
{gl.NewVariable("10405802815809041956"), gl.NewVariable("13917007789819955074")},
{gl.NewVariable("12560668105252495616"), gl.NewVariable("3591188232548111694")},
{gl.NewVariable("14765117357942682611"), gl.NewVariable("10757853341059462467")},
{gl.NewVariable("6099902163260965551"), gl.NewVariable("11343816861356056114")},
{gl.NewVariable("1083174255539258286"), gl.NewVariable("7587979659522435417")},
{gl.NewVariable("2882552180249608570"), gl.NewVariable("7966658657757662554")},
{gl.NewVariable("13490914415473336227"), gl.NewVariable("63845168436289811")},
{gl.NewVariable("9459794640071212413"), gl.NewVariable("13417331052474309186")},
{gl.NewVariable("18328090807516092318"), gl.NewVariable("11807085063599693782")},
{gl.NewVariable("281059606944328759"), gl.NewVariable("13352248056867426135")},
{gl.NewVariable("10905177588660050370"), gl.NewVariable("6597328385789442670")},
{gl.NewVariable("8426356906491012567"), gl.NewVariable("17214424336396001022")},
{gl.NewVariable("15696035667318839817"), gl.NewVariable("13285870048485492127")},
{gl.NewVariable("6110244444680672193"), gl.NewVariable("17558548349689468031")},
{gl.NewVariable("14614078615782659381"), gl.NewVariable("13184024850613726857")},
{gl.NewVariable("1541592450520953410"), gl.NewVariable("18339388388315914026")},
{gl.NewVariable("8059386643769157052"), gl.NewVariable("10208764910817462305")},
{gl.NewVariable("7612459820354975117"), gl.NewVariable("7582060685277695926")},
{gl.NewVariable("12515587043516861064"), gl.NewVariable("16099239041553682288")},
{gl.NewVariable("14269196473871652102"), gl.NewVariable("1225067220600668761")},
{gl.NewVariable("12691255077510636187"), gl.NewVariable("14147201911063761532")},
{gl.NewVariable("3001134598446056765"), gl.NewVariable("14313090483058155636")},
{gl.NewVariable("13964993951988177315"), gl.NewVariable("17731737838539414275")},
{gl.NewVariable("2686259154263524343"), gl.NewVariable("12198712301337570859")},
{gl.NewVariable("6730431920128908773"), gl.NewVariable("4325394084875720868")},
{gl.NewVariable("988774723104779817"), gl.NewVariable("8388266879854983623")},
{gl.NewVariable("8233087560647959985"), gl.NewVariable("7751837576340060020")},
{gl.NewVariable("9546113779017699592"), gl.NewVariable("4049920632309298778")},
{gl.NewVariable("3283837251411237060"), gl.NewVariable("13560940050752580093")},
{gl.NewVariable("10388838746951897109"), gl.NewVariable("454393475113110282")},
{gl.NewVariable("2208016536897042313"), gl.NewVariable("17105586471193083308")},
{gl.NewVariable("17683990802267567604"), gl.NewVariable("15398473956537380705")},
{gl.NewVariable("70612752050386177"), gl.NewVariable("12349994002954022957")},
{gl.NewVariable("13794244952989612728"), gl.NewVariable("15888581169565306348")},
{gl.NewVariable("8270800566553141412"), gl.NewVariable("1516938823651329185")},
{gl.NewVariable("643507941153616368"), gl.NewVariable("3893451216814345882")},
{gl.NewVariable("16464837166410943694"), gl.NewVariable("11108183142967610977")},
{gl.NewVariable("9748621820629198396"), gl.NewVariable("3766489907402036319")},
{gl.NewVariable("3115179618981245947"), gl.NewVariable("10160994694067456423")},
{gl.NewVariable("4497210741038443097"), gl.NewVariable("6445446770984515259")},
{gl.NewVariable("5470898125882256227"), gl.NewVariable("8249357863801204908")},
{gl.NewVariable("16762380205819269382"), gl.NewVariable("172510727904060494")},
{gl.NewVariable("7920011253931301350"), gl.NewVariable("9681193995678483756")},
{gl.NewVariable("8258951043315574232"), gl.NewVariable("13137471323476190588")},
{gl.NewVariable("4339364527801481944"), gl.NewVariable("16862579756243326257")},
{gl.NewVariable("8980029737458438570"), gl.NewVariable("14651625524257781922")},
{gl.NewVariable("17935993907375677671"), gl.NewVariable("5318319737405476029")},
{gl.NewVariable("716791501623731831"), gl.NewVariable("18425818060734993303")},
{gl.NewVariable("601549076806364660"), gl.NewVariable("12303919727550310013")},
{gl.NewVariable("18026376178895562118"), gl.NewVariable("14687420532194520529")},
{gl.NewVariable("16943892475592026666"), gl.NewVariable("7451688507369746594")},
{gl.NewVariable("8724072308842121373"), gl.NewVariable("11662986251379699921")},
{gl.NewVariable("3201079129905071298"), gl.NewVariable("11542621183935331871")},
{gl.NewVariable("9889739070824270529"), gl.NewVariable("3891825006545095657")},
{gl.NewVariable("15538978715382418651"), gl.NewVariable("2419672705453973015")},
{gl.NewVariable("3001525234835174062"), gl.NewVariable("17115969716224377534")},
{gl.NewVariable("18001237923148428045"), gl.NewVariable("2198015511953873786")},
{gl.NewVariable("14186741561112601666"), gl.NewVariable("13156405199205086627")},
{gl.NewVariable("10166592177477126663"), gl.NewVariable("13586051001537885658")},
{gl.NewVariable("8678352780562557555"), gl.NewVariable("1968366090049630482")},
{gl.NewVariable("5627999915794840395"), gl.NewVariable("13597556392696072088")},
{gl.NewVariable("9291327714650886898"), gl.NewVariable("2411361999629511024")},
{gl.NewVariable("6824943761729555359"), gl.NewVariable("7484507209360908175")},
{gl.NewVariable("6276580084700132178"), gl.NewVariable("6246691657613415035")},
{gl.NewVariable("10736230409698057656"), gl.NewVariable("7306720219045064925")},
{gl.NewVariable("15442170485732017109"), gl.NewVariable("1739984147692575725")},
{gl.NewVariable("4448878124301402845"), gl.NewVariable("18436455114977877323")},
{gl.NewVariable("638012599023653143"), gl.NewVariable("16265955502846626936")},
{gl.NewVariable("6793907577559820653"), gl.NewVariable("15343551069946118619")},
{gl.NewVariable("17903286158968614509"), gl.NewVariable("9559701571149911252")},
{gl.NewVariable("14652006464960400785"), gl.NewVariable("50421020503848143")},
{gl.NewVariable("9452858006432860845"), gl.NewVariable("2625726945677447428")},
{gl.NewVariable("853640589013584892"), gl.NewVariable("14655161412118141649")},
{gl.NewVariable("12863832006745352780"), gl.NewVariable("14564189651136231029")},
{gl.NewVariable("8551517270810530438"), gl.NewVariable("10859465327758962622")},
{gl.NewVariable("10113468436120661191"), gl.NewVariable("16040944006557911589")},
{gl.NewVariable("4921439225277518643"), gl.NewVariable("8399175422965154512")},
{gl.NewVariable("13068240354812957183"), gl.NewVariable("8520393046894990946")},
{gl.NewVariable("1189183420107219532"), gl.NewVariable("18066897627856601789")},
{gl.NewVariable("3997900004790871153"), gl.NewVariable("1269718920871578117")},
{gl.NewVariable("15438784576472256462"), gl.NewVariable("9577304425687441047")},
{gl.NewVariable("17158083218962275971"), gl.NewVariable("17379790274576244684")},
{gl.NewVariable("3470452736936929010"), gl.NewVariable("12769555113044633230")},
{gl.NewVariable("18389243269515626865"), gl.NewVariable("8023737530782576805")},
{gl.NewVariable("3529213023405995549"), gl.NewVariable("8829896701928525938")},
{gl.NewVariable("14072413770981804653"), gl.NewVariable("9660693090213237836")},
{gl.NewVariable("14369435038913678671"), gl.NewVariable("7659129852562422871")},
{gl.NewVariable("6779301728445724040"), gl.NewVariable("18290152515233036523")},
{gl.NewVariable("8113954200727174254"), gl.NewVariable("16490002532983549952")},
{gl.NewVariable("11465655095604389561"), gl.NewVariable("9066100972825318010")},
{gl.NewVariable("15998691377748321442"), gl.NewVariable("16970045124898180365")},
{gl.NewVariable("8424730626816696233"), gl.NewVariable("17168184083072399403")},
{gl.NewVariable("1941959246552302666"), gl.NewVariable("6751013195867127440")},
{gl.NewVariable("1907519456922228224"), gl.NewVariable("689311996911195932")},
{gl.NewVariable("16277197060525435740"), gl.NewVariable("12018417724719716072")},
}
var reducingExtensionGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("12832102811425062912"), gl.NewVariable("2979695993654444095")},
{gl.NewVariable("4822478941232734654"), gl.NewVariable("2600327308894333341")},
{gl.NewVariable("12450653411048814602"), gl.NewVariable("1161667420593062956")},
{gl.NewVariable("3145631295867407955"), gl.NewVariable("1702059944088737075")},
{gl.NewVariable("4597190091407364771"), gl.NewVariable("4257077286672555409")},
{gl.NewVariable("10177664366491925772"), gl.NewVariable("10489575701186298604")},
{gl.NewVariable("2754621968864722399"), gl.NewVariable("12087963411706301871")},
{gl.NewVariable("534408217555793149"), gl.NewVariable("12559345737194357169")},
{gl.NewVariable("9508765820222303634"), gl.NewVariable("14102461861317982082")},
{gl.NewVariable("15070954032232801974"), gl.NewVariable("2078249670161696735")},
{gl.NewVariable("10465809629504954691"), gl.NewVariable("16223748685835312497")},
{gl.NewVariable("10957196413441800202"), gl.NewVariable("3841214025425953691")},
{gl.NewVariable("18438848195188240825"), gl.NewVariable("5697684145424680565")},
{gl.NewVariable("565455534266129104"), gl.NewVariable("12543354947937779806")},
{gl.NewVariable("16376588778962418386"), gl.NewVariable("1273250903423198860")},
{gl.NewVariable("4128104469872810921"), gl.NewVariable("1433037233801071123")},
{gl.NewVariable("6011337242244377340"), gl.NewVariable("16068106780789397185")},
{gl.NewVariable("4741354504248328629"), gl.NewVariable("3000853646720964165")},
{gl.NewVariable("13064594310789140866"), gl.NewVariable("10950406741883971259")},
{gl.NewVariable("17079026691450750925"), gl.NewVariable("6522027970928818261")},
{gl.NewVariable("13158136237489326416"), gl.NewVariable("7677629162183242732")},
{gl.NewVariable("14741398060174921234"), gl.NewVariable("2960243215156352194")},
{gl.NewVariable("9111161782199179468"), gl.NewVariable("8010960876261510099")},
{gl.NewVariable("1404837029582986528"), gl.NewVariable("9377230983302764181")},
{gl.NewVariable("7086781234814455260"), gl.NewVariable("7571558192372650697")},
{gl.NewVariable("5627013434503229817"), gl.NewVariable("14984048934926143304")},
{gl.NewVariable("2115495655441739405"), gl.NewVariable("1656704965110317534")},
{gl.NewVariable("2311846135199651566"), gl.NewVariable("17438437808346967358")},
{gl.NewVariable("8679806319651401773"), gl.NewVariable("3278538718508560579")},
{gl.NewVariable("7897681105604536660"), gl.NewVariable("10966573925848082711")},
{gl.NewVariable("5451958405177630542"), gl.NewVariable("9207735009647199721")},
{gl.NewVariable("8825486358121162697"), gl.NewVariable("15997852519026522914")},
{gl.NewVariable("475225211669491693"), gl.NewVariable("1907827506180042626")},
{gl.NewVariable("16033031089519343732"), gl.NewVariable("15009948832718035672")},
{gl.NewVariable("5048598591200038865"), gl.NewVariable("156574475928756206")},
{gl.NewVariable("3580311624647961767"), gl.NewVariable("6084715537433906996")},
{gl.NewVariable("9121009921295095324"), gl.NewVariable("18407759801432275235")},
{gl.NewVariable("16569013039730214123"), gl.NewVariable("3930908108224055041")},
{gl.NewVariable("13844066138909451365"), gl.NewVariable("6585754647203519368")},
{gl.NewVariable("14133345335167543367"), gl.NewVariable("3946807387480232364")},
{gl.NewVariable("9876285028806980582"), gl.NewVariable("40898067822033734")},
{gl.NewVariable("6293483059765701407"), gl.NewVariable("16009270905706605849")},
{gl.NewVariable("11635947241393753594"), gl.NewVariable("5053395178858294866")},
{gl.NewVariable("16062194595705166277"), gl.NewVariable("752574348595159408")},
{gl.NewVariable("15607597716340375230"), gl.NewVariable("10428583315124220143")},
{gl.NewVariable("6975301479426228318"), gl.NewVariable("16528136630898216147")},
{gl.NewVariable("16312827398430223622"), gl.NewVariable("17909475722464415780")},
{gl.NewVariable("2273087545743905667"), gl.NewVariable("12405446777919046866")},
{gl.NewVariable("14781933506876191161"), gl.NewVariable("4464109151368149713")},
{gl.NewVariable("4226716729950095934"), gl.NewVariable("8908251769229049654")},
{gl.NewVariable("8310476487592089883"), gl.NewVariable("3834672170570438819")},
{gl.NewVariable("4285568636604940795"), gl.NewVariable("7183765355016179794")},
{gl.NewVariable("14300853697824059506"), gl.NewVariable("16287477445929928328")},
{gl.NewVariable("1238186507267033247"), gl.NewVariable("12357102109973664962")},
{gl.NewVariable("15607388919140050768"), gl.NewVariable("15421065238069253306")},
{gl.NewVariable("12418734453826432586"), gl.NewVariable("12072056126139297564")},
{gl.NewVariable("3924467115116313620"), gl.NewVariable("1212362379653628161")},
{gl.NewVariable("8252514850759544679"), gl.NewVariable("7893938436444134034")},
{gl.NewVariable("711675815009325200"), gl.NewVariable("15678724077367989757")},
{gl.NewVariable("10920573406841924033"), gl.NewVariable("8189696933773246220")},
{gl.NewVariable("9737295100232588618"), gl.NewVariable("13383462338120177171")},
{gl.NewVariable("8983013033045953935"), gl.NewVariable("5301160793103788033")},
{gl.NewVariable("2086512740154274197"), gl.NewVariable("9511985884344255651")},
{gl.NewVariable("7404726366142548080"), gl.NewVariable("11257391295697140486")},
{gl.NewVariable("10045968629671906256"), gl.NewVariable("10721172752468420959")},
{gl.NewVariable("9499240237398016191"), gl.NewVariable("17996498955496851489")},
}
// ReducingGate { num_coeffs: 44 }
var reducingGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("4189565386714553574"), gl.NewVariable("14972099283023295929")},
{gl.NewVariable("4811224976739448335"), gl.NewVariable("17901409314576454439")},
{gl.NewVariable("5140059407491502784"), gl.NewVariable("1144330742785924570")},
{gl.NewVariable("7077436393778991453"), gl.NewVariable("13398199711778224412")},
{gl.NewVariable("11213768990622043903"), gl.NewVariable("3886053425349218150")},
{gl.NewVariable("2946099412905029571"), gl.NewVariable("16515307040211357295")},
{gl.NewVariable("11766152895257088950"), gl.NewVariable("12561350435611412995")},
{gl.NewVariable("15559670172179416359"), gl.NewVariable("14246884723129607378")},
{gl.NewVariable("5240707719525548158"), gl.NewVariable("1640773599873992510")},
{gl.NewVariable("14358821079049832289"), gl.NewVariable("2746855687282611080")},
{gl.NewVariable("3214086216088588558"), gl.NewVariable("1520697626094905530")},
{gl.NewVariable("9834748172213967248"), gl.NewVariable("13487010468070558667")},
{gl.NewVariable("1423442768503334248"), gl.NewVariable("10945790255819476518")},
{gl.NewVariable("2308372186436983690"), gl.NewVariable("8803174935784778070")},
{gl.NewVariable("9995833078447025147"), gl.NewVariable("9074310518079663649")},
{gl.NewVariable("14149697874498108875"), gl.NewVariable("15875817120435194028")},
{gl.NewVariable("14564758547073982656"), gl.NewVariable("13386335755835868953")},
{gl.NewVariable("6432745607675418074"), gl.NewVariable("8030247499566565321")},
{gl.NewVariable("17308235779926438117"), gl.NewVariable("16843697410674499818")},
{gl.NewVariable("15507223129386571868"), gl.NewVariable("3935281607585552366")},
{gl.NewVariable("16041402982622709805"), gl.NewVariable("12432717078068957835")},
{gl.NewVariable("6455955094164032063"), gl.NewVariable("2435635342699968412")},
{gl.NewVariable("9814981570869789379"), gl.NewVariable("5009257884262115226")},
{gl.NewVariable("9452031978763862902"), gl.NewVariable("15609083603899848676")},
{gl.NewVariable("13532623109002857304"), gl.NewVariable("7324541443245949391")},
{gl.NewVariable("7899075212455453622"), gl.NewVariable("14276489152002439614")},
{gl.NewVariable("2403019844704266911"), gl.NewVariable("5922544710604013781")},
{gl.NewVariable("9709471021111675830"), gl.NewVariable("5538539165068927028")},
{gl.NewVariable("15700585567216041265"), gl.NewVariable("17893894492159337326")},
{gl.NewVariable("8890003199638063977"), gl.NewVariable("17726621767321974437")},
{gl.NewVariable("389239919653982052"), gl.NewVariable("3497778410650283061")},
{gl.NewVariable("845227572644858827"), gl.NewVariable("7040344997713673855")},
{gl.NewVariable("9861253052349275208"), gl.NewVariable("1880449137233040023")},
{gl.NewVariable("9239454143759318515"), gl.NewVariable("7968256557482935820")},
{gl.NewVariable("12576879243038758854"), gl.NewVariable("9784626207087825707")},
{gl.NewVariable("14811673587164089973"), gl.NewVariable("10785522535030299714")},
{gl.NewVariable("696437091186897361"), gl.NewVariable("13293602092569033065")},
{gl.NewVariable("1240161179290551759"), gl.NewVariable("9542275505416038259")},
{gl.NewVariable("5298553932515957396"), gl.NewVariable("14597738151157731445")},
{gl.NewVariable("8472517818840783225"), gl.NewVariable("7685861056688910111")},
{gl.NewVariable("10067665523858551777"), gl.NewVariable("13019870415534016025")},
{gl.NewVariable("3030966178198674680"), gl.NewVariable("10107838846102885642")},
{gl.NewVariable("6762889891370677550"), gl.NewVariable("16151528872832782368")},
{gl.NewVariable("17207754552662723664"), gl.NewVariable("15168039969859158460")},
{gl.NewVariable("9111161782199179468"), gl.NewVariable("8010960876261510099")},
{gl.NewVariable("1212079098724692260"), gl.NewVariable("3976842077579916925")},
{gl.NewVariable("8111924351272477885"), gl.NewVariable("1472738463707044435")},
{gl.NewVariable("14549763060495382561"), gl.NewVariable("8148654488443197206")},
{gl.NewVariable("9633247645878352168"), gl.NewVariable("4173826759172401145")},
{gl.NewVariable("13429667484612728110"), gl.NewVariable("139708813783643870")},
{gl.NewVariable("11164941208889426013"), gl.NewVariable("3615779386887825309")},
{gl.NewVariable("15733773570058687441"), gl.NewVariable("11172582394325691371")},
{gl.NewVariable("11237663549079845099"), gl.NewVariable("375954911737718734")},
{gl.NewVariable("14815280969174152094"), gl.NewVariable("17903238907570421232")},
{gl.NewVariable("12264332321023153985"), gl.NewVariable("4996015210046477989")},
{gl.NewVariable("5733452693326962912"), gl.NewVariable("15445457134261228447")},
{gl.NewVariable("11339891595047637420"), gl.NewVariable("762619178430884475")},
{gl.NewVariable("10413672060220880988"), gl.NewVariable("2522708614237496949")},
{gl.NewVariable("4759794002943168525"), gl.NewVariable("8366670758049431064")},
{gl.NewVariable("11081128192182141387"), gl.NewVariable("5264843790841556843")},
{gl.NewVariable("16467547707866820269"), gl.NewVariable("10395994280728082037")},
{gl.NewVariable("7372902852922723938"), gl.NewVariable("6597057511414169148")},
{gl.NewVariable("1246550990665510080"), gl.NewVariable("369146659419534786")},
{gl.NewVariable("107137977263990694"), gl.NewVariable("13480217899797734610")},
{gl.NewVariable("9352391006524927052"), gl.NewVariable("16474580549927501346")},
{gl.NewVariable("11475195577527382963"), gl.NewVariable("16771481018793784004")},
{gl.NewVariable("7763817490144412733"), gl.NewVariable("7847907679735875325")},
{gl.NewVariable("6954934416977006194"), gl.NewVariable("1588175103882481774")},
{gl.NewVariable("208699790124989138"), gl.NewVariable("104050776110144395")},
{gl.NewVariable("1999712470949493845"), gl.NewVariable("14640293671425837284")},
{gl.NewVariable("17489389210332023693"), gl.NewVariable("1485853484717956236")},
{gl.NewVariable("13389678828109836153"), gl.NewVariable("12239927773742888217")},
{gl.NewVariable("7279356606052782033"), gl.NewVariable("16889809967345118643")},
{gl.NewVariable("5530632913824527303"), gl.NewVariable("6593916246324540830")},
{gl.NewVariable("6517985275757881887"), gl.NewVariable("1094679265639341934")},
{gl.NewVariable("16005022297334791008"), gl.NewVariable("2231375568117939019")},
{gl.NewVariable("7801581545066110268"), gl.NewVariable("16195585011186011335")},
{gl.NewVariable("2346311239309318787"), gl.NewVariable("10194252071441594046")},
{gl.NewVariable("1333414916806612489"), gl.NewVariable("4078668601880487193")},
{gl.NewVariable("17162202837341088150"), gl.NewVariable("3946492721743094611")},
{gl.NewVariable("2372952988964786162"), gl.NewVariable("14459600129361968991")},
{gl.NewVariable("15958985504784681452"), gl.NewVariable("18297567352909625870")},
{gl.NewVariable("5468110010239944205"), gl.NewVariable("1297673223075459793")},
{gl.NewVariable("5916958362061888790"), gl.NewVariable("12686064186569549334")},
{gl.NewVariable("17141186363273294375"), gl.NewVariable("5330662447468959333")},
{gl.NewVariable("9597329746711776008"), gl.NewVariable("13290917949843243492")},
{gl.NewVariable("9061260430036409956"), gl.NewVariable("10642927510372211646")},
{gl.NewVariable("9766392710518436993"), gl.NewVariable("1864738510099355769")},
}
// ArithmeticExtensionGate { num_ops: 10 }
var arithmeticExtensionGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("14556369430662721230"), gl.NewVariable("4131185000258568561")},
{gl.NewVariable("16378466706564867046"), gl.NewVariable("1439052841211884527")},
{gl.NewVariable("8231479592213172392"), gl.NewVariable("8409169031581010782")},
{gl.NewVariable("5465959779370835700"), gl.NewVariable("17016702720873000919")},
{gl.NewVariable("10611951970626560747"), gl.NewVariable("11015475306668399283")},
{gl.NewVariable("6566683434087540889"), gl.NewVariable("7528162900166069532")},
{gl.NewVariable("13167150559619768862"), gl.NewVariable("15618445283750881414")},
{gl.NewVariable("14768578132422983729"), gl.NewVariable("13938407401080069149")},
{gl.NewVariable("18415232841919605685"), gl.NewVariable("15088528771916927003")},
{gl.NewVariable("1305736199568141897"), gl.NewVariable("16885250849392919438")},
{gl.NewVariable("1425549592953864549"), gl.NewVariable("1074162823816629148")},
{gl.NewVariable("12616210534513128803"), gl.NewVariable("8618852250387339753")},
{gl.NewVariable("16775588216530426832"), gl.NewVariable("16358913853138883160")},
{gl.NewVariable("236831045676808583"), gl.NewVariable("16231688985959438642")},
{gl.NewVariable("264831195814170716"), gl.NewVariable("9852325877887114505")},
{gl.NewVariable("14065541678187010167"), gl.NewVariable("5594602585697559035")},
{gl.NewVariable("2354884863196165822"), gl.NewVariable("12715102096346587892")},
{gl.NewVariable("5881791209743274427"), gl.NewVariable("1913490798645218291")},
{gl.NewVariable("3621056055759314065"), gl.NewVariable("15076066883455218113")},
{gl.NewVariable("15382741815013668685"), gl.NewVariable("5674166256062091576")},
}
// MulExtensionGate { num_ops: 13 }
var mulExtensionGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("14558272317822654580"), gl.NewVariable("833215892324477732")},
{gl.NewVariable("9214806296346539012"), gl.NewVariable("7798842673847612486")},
{gl.NewVariable("4933313819253472884"), gl.NewVariable("17115399133104593821")},
{gl.NewVariable("6382294466663581729"), gl.NewVariable("8863722647290983592")},
{gl.NewVariable("5274430631758054179"), gl.NewVariable("1761561038204031519")},
{gl.NewVariable("6975818216493368257"), gl.NewVariable("3643153118790582585")},
{gl.NewVariable("9382708770545050748"), gl.NewVariable("2040988809014144797")},
{gl.NewVariable("7526300035416853327"), gl.NewVariable("8692405747344509879")},
{gl.NewVariable("6092157877842311771"), gl.NewVariable("5767914690949635280")},
{gl.NewVariable("3636879736078164520"), gl.NewVariable("454792903724498694")},
{gl.NewVariable("5982213211108308130"), gl.NewVariable("3906161453783544349")},
{gl.NewVariable("1353999567434327832"), gl.NewVariable("3912356165392315450")},
{gl.NewVariable("3866250282554618990"), gl.NewVariable("14215790041865539111")},
{gl.NewVariable("16972659905821970574"), gl.NewVariable("2550277288305104044")},
{gl.NewVariable("6739526869755283609"), gl.NewVariable("4676222628249438354")},
{gl.NewVariable("18314541579046409607"), gl.NewVariable("13871312232745645647")},
{gl.NewVariable("13309435341537760906"), gl.NewVariable("10879629980202564460")},
{gl.NewVariable("8149445702527176593"), gl.NewVariable("12079787385488004774")},
{gl.NewVariable("141936326832390573"), gl.NewVariable("9852981409020916366")},
{gl.NewVariable("1174277439708011834"), gl.NewVariable("11084240604056156653")},
{gl.NewVariable("3890191667424476902"), gl.NewVariable("1428130379783403165")},
{gl.NewVariable("18264002552181363059"), gl.NewVariable("17855293364353531924")},
{gl.NewVariable("1657518282890904146"), gl.NewVariable("14874491364689193658")},
{gl.NewVariable("9091236796792826297"), gl.NewVariable("18232800981045995203")},
{gl.NewVariable("7965395014621568897"), gl.NewVariable("15643014489741966811")},
{gl.NewVariable("14048129594584036134"), gl.NewVariable("8880723489474532129")},
}
// CosetInterpolationGate { subgroup_bits: 4, degree: 6, barycentric_weights: [17293822565076172801, 18374686475376656385, 18446744069413535745, 281474976645120, 17592186044416, 18446744069414584577, 18446744000695107601, 18446744065119617025, 1152921504338411520, 72057594037927936, 18446744069415632897, 18446462594437939201, 18446726477228539905, 18446744069414584065, 68719476720, 4294967296], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
var cosetInterpolationGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("4489474937116132272"), gl.NewVariable("17966585078409280607")},
{gl.NewVariable("6284821823752419954"), gl.NewVariable("15732864946173560339")},
{gl.NewVariable("12879723719779486283"), gl.NewVariable("983649133858104142")},
{gl.NewVariable("17293136937393925432"), gl.NewVariable("4033193666483141970")},
{gl.NewVariable("10809912963683055710"), gl.NewVariable("3166226310305151244")},
{gl.NewVariable("13051854837169808452"), gl.NewVariable("12636844243964449888")},
{gl.NewVariable("15180422697988222141"), gl.NewVariable("3172471974421734205")},
{gl.NewVariable("7715327263429433235"), gl.NewVariable("14269461688353925342")},
{gl.NewVariable("7348198793616724228"), gl.NewVariable("11426363269581761252")},
{gl.NewVariable("6529761710182712179"), gl.NewVariable("15370899814178958348")},
{gl.NewVariable("1312640305437468539"), gl.NewVariable("7416725026793550034")},
{gl.NewVariable("7435934314089172319"), gl.NewVariable("8931511780309647479")},
}
// PoseidonMdsGate(PhantomData<plonky2_field::goldilocks_field::GoldilocksField>)<WIDTH=12>"
var poseidonMdsGateExpectedConstraints = []gl.QuadraticExtensionVariable{
{gl.NewVariable("7821764612044984890"), gl.NewVariable("11645399715550800761")},
{gl.NewVariable("7054686226368496581"), gl.NewVariable("3456599659382547499")},
{gl.NewVariable("9932401212201586910"), gl.NewVariable("15935184283784595275")},
{gl.NewVariable("14850232436396031573"), gl.NewVariable("10054869170615550942")},
{gl.NewVariable("17859784214232634920"), gl.NewVariable("3141019307077014353")},
{gl.NewVariable("1316926243065869924"), gl.NewVariable("5447399801288094074")},
{gl.NewVariable("12198784876096903918"), gl.NewVariable("10976551553233951532")},
{gl.NewVariable("3280500541526908156"), gl.NewVariable("1813330468204166522")},
{gl.NewVariable("6788483962196012692"), gl.NewVariable("15983747071745976199")},
{gl.NewVariable("3372073447943379816"), gl.NewVariable("9356836818900551936")},
{gl.NewVariable("13834815153351545489"), gl.NewVariable("1073963211629459057")},
{gl.NewVariable("15376716257200419051"), gl.NewVariable("16044430964768811142")},
{gl.NewVariable("16752138206727891451"), gl.NewVariable("6303059651352280564")},
{gl.NewVariable("17195959285241102556"), gl.NewVariable("10990140109461952122")},
{gl.NewVariable("16812594260057394716"), gl.NewVariable("5841834090350584793")},
{gl.NewVariable("17706037262140285164"), gl.NewVariable("8626184557677598926")},
{gl.NewVariable("6826825357492466350"), gl.NewVariable("17865947929743097490")},
{gl.NewVariable("13679887869755160737"), gl.NewVariable("16481628195512675795")},
{gl.NewVariable("7881296289635150478"), gl.NewVariable("15368930380652981390")},
{gl.NewVariable("12075171536836315078"), gl.NewVariable("12900345753644751245")},
{gl.NewVariable("11461113822534614109"), gl.NewVariable("2937306395206947398")},
{gl.NewVariable("18365572828001780476"), gl.NewVariable("4309067613742479326")},
{gl.NewVariable("9460729461000852035"), gl.NewVariable("9232487430983842586")},
{gl.NewVariable("9920817005263779727"), gl.NewVariable("16326126591726196229")},
}
type TestGateCircuit struct {
testGate gates.Gate
ExpectedConstraints []gl.QuadraticExtensionVariable
}
func (circuit *TestGateCircuit) Define(api frontend.API) error {
commonCircuitData := verifier.DeserializeCommonCircuitData("../../data/decode_block/common_circuit_data.json")
numSelectors := commonCircuitData.SelectorsInfo.NumSelectors()
glApi := gl.NewChip(api)
vars := gates.NewEvaluationVars(localConstants[numSelectors:], localWires, publicInputsHash)
constraints := circuit.testGate.EvalUnfiltered(api, *glApi, *vars)
if len(constraints) != len(circuit.ExpectedConstraints) {
return errors.New("gate constraints length mismatch")
}
for i := 0; i < len(constraints); i++ {
glApi.AssertIsEqualExtension(constraints[i], circuit.ExpectedConstraints[i])
}
return nil
}
func TestGates(t *testing.T) {
assert := test.NewAssert(t)
testCase := func(testGate gates.Gate, expectedConstraints []gl.QuadraticExtensionVariable) {
circuit := &TestGateCircuit{testGate: testGate, ExpectedConstraints: expectedConstraints}
witness := &TestGateCircuit{testGate: testGate, ExpectedConstraints: expectedConstraints}
err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField())
assert.NoError(err)
}
type gateTest struct {
testGate gates.Gate
expectedConstraints []gl.QuadraticExtensionVariable
}
gateTests := []gateTest{
{gates.NewPublicInputGate(), publicInputGateExpectedConstraints},
{gates.NewBaseSumGate(63, 2), baseSumGateExpectedConstraints},
{gates.NewArithmeticGate(20), arithmeticGateExpectedConstraints},
{gates.NewRandomAccessGate(4, 4, 2), randomAccessGateExpectedConstraints},
{gates.NewPoseidonGate(), poseidonGateExpectedConstraints},
{gates.NewArithmeticExtensionGate(10), arithmeticExtensionGateExpectedConstraints},
{gates.NewMultiplicationExtensionGate(13), mulExtensionGateExpectedConstraints},
{gates.NewReducingExtensionGate(33), reducingExtensionGateExpectedConstraints},
{gates.NewReducingGate(44), reducingGateExpectedConstraints},
{gates.NewCosetInterpolationGate(
4,
6,
[]goldilocks.Element{
goldilocks.NewElement(17293822565076172801),
goldilocks.NewElement(18374686475376656385),
goldilocks.NewElement(18446744069413535745),
goldilocks.NewElement(281474976645120),
goldilocks.NewElement(17592186044416),
goldilocks.NewElement(18446744069414584577),
goldilocks.NewElement(18446744000695107601),
goldilocks.NewElement(18446744065119617025),
goldilocks.NewElement(1152921504338411520),
goldilocks.NewElement(72057594037927936),
goldilocks.NewElement(18446744069415632897),
goldilocks.NewElement(18446462594437939201),
goldilocks.NewElement(18446726477228539905),
goldilocks.NewElement(18446744069414584065),
goldilocks.NewElement(68719476720),
goldilocks.NewElement(4294967296),
},
), cosetInterpolationGateExpectedConstraints},
{&gates.PoseidonMdsGate{}, poseidonMdsGateExpectedConstraints},
}
for _, test := range gateTests {
testCase(
test.testGate,
test.expectedConstraints,
)
}
}

verifier/internal/gates/multiplication_extension_gate.go → plonk/gates/multiplication_extension_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var mulExtensionGateRegex = regexp.MustCompile("MulExtensionGate { num_ops: (?P<numOps>[0-9]+) }") var mulExtensionGateRegex = regexp.MustCompile("MulExtensionGate { num_ops: (?P<numOps>[0-9]+) }")
@ -41,34 +41,36 @@ func (g *MultiplicationExtensionGate) Id() string {
} }
func (g *MultiplicationExtensionGate) wiresIthMultiplicand0(i uint64) Range { func (g *MultiplicationExtensionGate) wiresIthMultiplicand0(i uint64) Range {
return Range{3 * field.D * i, 3*field.D*i + field.D}
return Range{3 * gl.D * i, 3*gl.D*i + gl.D}
} }
func (g *MultiplicationExtensionGate) wiresIthMultiplicand1(i uint64) Range { func (g *MultiplicationExtensionGate) wiresIthMultiplicand1(i uint64) Range {
return Range{3*field.D*i + field.D, 3*field.D*i + 2*field.D}
return Range{3*gl.D*i + gl.D, 3*gl.D*i + 2*gl.D}
} }
func (g *MultiplicationExtensionGate) wiresIthOutput(i uint64) Range { func (g *MultiplicationExtensionGate) wiresIthOutput(i uint64) Range {
return Range{3*field.D*i + 2*field.D, 3*field.D*i + 3*field.D}
return Range{3*gl.D*i + 2*gl.D, 3*gl.D*i + 3*gl.D}
} }
func (g *MultiplicationExtensionGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
func (g *MultiplicationExtensionGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
const0 := vars.localConstants[0] const0 := vars.localConstants[0]
constraints := []field.QuadraticExtension{}
constraints := []gl.QuadraticExtensionVariable{}
for i := uint64(0); i < g.numOps; i++ { for i := uint64(0); i < g.numOps; i++ {
multiplicand0 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand0(i)) multiplicand0 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand0(i))
multiplicand1 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand1(i)) multiplicand1 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand1(i))
output := vars.GetLocalExtAlgebra(g.wiresIthOutput(i)) output := vars.GetLocalExtAlgebra(g.wiresIthOutput(i))
mul := qeAPI.MulExtensionAlgebra(multiplicand0, multiplicand1)
computed_output := qeAPI.ScalarMulExtensionAlgebra(const0, mul)
mul := glApi.MulExtensionAlgebra(multiplicand0, multiplicand1)
computed_output := glApi.ScalarMulExtensionAlgebra(const0, mul)
diff := qeAPI.SubExtensionAlgebra(output, computed_output)
for j := 0; j < field.D; j++ {
diff := glApi.SubExtensionAlgebra(output, computed_output)
for j := 0; j < gl.D; j++ {
constraints = append(constraints, diff[j]) constraints = append(constraints, diff[j])
} }
} }
return constraints return constraints
} }

verifier/internal/gates/noop_gate.go → plonk/gates/noop_gate.go

@ -4,7 +4,7 @@ import (
"regexp" "regexp"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var noopGateRegex = regexp.MustCompile("NoopGate") var noopGateRegex = regexp.MustCompile("NoopGate")
@ -25,6 +25,10 @@ func (g *NoopGate) Id() string {
return "NoopGate" return "NoopGate"
} }
func (g *NoopGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
return []field.QuadraticExtension{}
func (g *NoopGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
return []gl.QuadraticExtensionVariable{}
} }

verifier/internal/gates/poseidon_gate.go → plonk/gates/poseidon_gate.go

@ -4,7 +4,7 @@ import (
"regexp" "regexp"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
) )
@ -89,34 +89,38 @@ func (g *PoseidonGate) WiresEnd() uint64 {
return START_FULL_1 + poseidon.HALF_N_FULL_ROUNDS*poseidon.SPONGE_WIDTH return START_FULL_1 + poseidon.HALF_N_FULL_ROUNDS*poseidon.SPONGE_WIDTH
} }
func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
constraints := []field.QuadraticExtension{}
func (g *PoseidonGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
constraints := []gl.QuadraticExtensionVariable{}
poseidonChip := poseidon.NewPoseidonChip(api, field.NewFieldAPI(api), qeAPI)
poseidonChip := poseidon.NewGoldilocksChip(api)
// Assert that `swap` is binary. // Assert that `swap` is binary.
swap := vars.localWires[g.WireSwap()] swap := vars.localWires[g.WireSwap()]
swapMinusOne := qeAPI.SubExtension(swap, qeAPI.FieldToQE(field.ONE_F))
constraints = append(constraints, qeAPI.MulExtension(swap, swapMinusOne))
swapMinusOne := glApi.SubExtension(swap, gl.OneExtension())
constraints = append(constraints, glApi.MulExtension(swap, swapMinusOne))
// Assert that each delta wire is set properly: `delta_i = swap * (rhs - lhs)`. // Assert that each delta wire is set properly: `delta_i = swap * (rhs - lhs)`.
for i := uint64(0); i < 4; i++ { for i := uint64(0); i < 4; i++ {
inputLhs := vars.localWires[g.WireInput(i)] inputLhs := vars.localWires[g.WireInput(i)]
inputRhs := vars.localWires[g.WireInput(i+4)] inputRhs := vars.localWires[g.WireInput(i+4)]
deltaI := vars.localWires[g.WireDelta(i)] deltaI := vars.localWires[g.WireDelta(i)]
diff := qeAPI.SubExtension(inputRhs, inputLhs)
expectedDeltaI := qeAPI.MulExtension(swap, diff)
constraints = append(constraints, qeAPI.SubExtension(expectedDeltaI, deltaI))
diff := glApi.SubExtension(inputRhs, inputLhs)
expectedDeltaI := glApi.MulExtension(swap, diff)
constraints = append(constraints, glApi.SubExtension(expectedDeltaI, deltaI))
} }
// Compute the possibly-swapped input layer. // Compute the possibly-swapped input layer.
var state [poseidon.SPONGE_WIDTH]field.QuadraticExtension
var state [poseidon.SPONGE_WIDTH]gl.QuadraticExtensionVariable
for i := uint64(0); i < 4; i++ { for i := uint64(0); i < 4; i++ {
deltaI := vars.localWires[g.WireDelta(i)] deltaI := vars.localWires[g.WireDelta(i)]
inputLhs := vars.localWires[g.WireInput(i)] inputLhs := vars.localWires[g.WireInput(i)]
inputRhs := vars.localWires[g.WireInput(i+4)] inputRhs := vars.localWires[g.WireInput(i+4)]
state[i] = qeAPI.AddExtension(inputLhs, deltaI)
state[i+4] = qeAPI.SubExtension(inputRhs, deltaI)
state[i] = glApi.AddExtension(inputLhs, deltaI)
state[i+4] = glApi.SubExtension(inputRhs, deltaI)
} }
for i := uint64(8); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(8); i < poseidon.SPONGE_WIDTH; i++ {
state[i] = vars.localWires[g.WireInput(i)] state[i] = vars.localWires[g.WireInput(i)]
@ -130,7 +134,7 @@ func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticEx
if r != 0 { if r != 0 {
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
sBoxIn := vars.localWires[g.WireFullSBox0(r, i)] sBoxIn := vars.localWires[g.WireFullSBox0(r, i)]
constraints = append(constraints, qeAPI.SubExtension(state[i], sBoxIn))
constraints = append(constraints, glApi.SubExtension(state[i], sBoxIn))
state[i] = sBoxIn state[i] = sBoxIn
} }
} }
@ -145,13 +149,13 @@ func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticEx
for r := uint64(0); r < poseidon.N_PARTIAL_ROUNDS-1; r++ { for r := uint64(0); r < poseidon.N_PARTIAL_ROUNDS-1; r++ {
sBoxIn := vars.localWires[g.WirePartialSBox(r)] sBoxIn := vars.localWires[g.WirePartialSBox(r)]
constraints = append(constraints, qeAPI.SubExtension(state[0], sBoxIn))
constraints = append(constraints, glApi.SubExtension(state[0], sBoxIn))
state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn) state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn)
state[0] = qeAPI.AddExtension(state[0], qeAPI.VarToQE(poseidon.FAST_PARTIAL_ROUND_CONSTANTS[r]))
state[0] = glApi.AddExtension(state[0], gl.NewQuadraticExtensionVariable(gl.NewVariable(poseidon.FAST_PARTIAL_ROUND_CONSTANTS[r]), gl.Zero()))
state = poseidonChip.MdsPartialLayerFastExtension(state, int(r)) state = poseidonChip.MdsPartialLayerFastExtension(state, int(r))
} }
sBoxIn := vars.localWires[g.WirePartialSBox(poseidon.N_PARTIAL_ROUNDS-1)] sBoxIn := vars.localWires[g.WirePartialSBox(poseidon.N_PARTIAL_ROUNDS-1)]
constraints = append(constraints, qeAPI.SubExtension(state[0], sBoxIn))
constraints = append(constraints, glApi.SubExtension(state[0], sBoxIn))
state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn) state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn)
state = poseidonChip.MdsPartialLayerFastExtension(state, poseidon.N_PARTIAL_ROUNDS-1) state = poseidonChip.MdsPartialLayerFastExtension(state, poseidon.N_PARTIAL_ROUNDS-1)
roundCounter += poseidon.N_PARTIAL_ROUNDS roundCounter += poseidon.N_PARTIAL_ROUNDS
@ -161,7 +165,7 @@ func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticEx
state = poseidonChip.ConstantLayerExtension(state, &roundCounter) state = poseidonChip.ConstantLayerExtension(state, &roundCounter)
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
sBoxIn := vars.localWires[g.WireFullSBox1(r, i)] sBoxIn := vars.localWires[g.WireFullSBox1(r, i)]
constraints = append(constraints, qeAPI.SubExtension(state[i], sBoxIn))
constraints = append(constraints, glApi.SubExtension(state[i], sBoxIn))
state[i] = sBoxIn state[i] = sBoxIn
} }
state = poseidonChip.SBoxLayerExtension(state) state = poseidonChip.SBoxLayerExtension(state)
@ -170,7 +174,7 @@ func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticEx
} }
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
constraints = append(constraints, qeAPI.SubExtension(state[i], vars.localWires[g.WireOutput(i)]))
constraints = append(constraints, glApi.SubExtension(state[i], vars.localWires[g.WireOutput(i)]))
} }
return constraints return constraints

verifier/internal/gates/poseidon_mds_gate.go → plonk/gates/poseidon_mds_gate.go

@ -4,7 +4,7 @@ import (
"regexp" "regexp"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
) )
@ -30,55 +30,66 @@ func (g *PoseidonMdsGate) WireInput(i uint64) Range {
if i >= poseidon.SPONGE_WIDTH { if i >= poseidon.SPONGE_WIDTH {
panic("Input less than sponge width") panic("Input less than sponge width")
} }
return Range{i * field.D, (i + 1) * field.D}
return Range{i * gl.D, (i + 1) * gl.D}
} }
func (g *PoseidonMdsGate) WireOutput(i uint64) Range { func (g *PoseidonMdsGate) WireOutput(i uint64) Range {
if i >= poseidon.SPONGE_WIDTH { if i >= poseidon.SPONGE_WIDTH {
panic("Input less than sponge width") panic("Input less than sponge width")
} }
return Range{(poseidon.SPONGE_WIDTH + i) * field.D, (poseidon.SPONGE_WIDTH + i + 1) * field.D}
return Range{(poseidon.SPONGE_WIDTH + i) * gl.D, (poseidon.SPONGE_WIDTH + i + 1) * gl.D}
} }
func (g *PoseidonMdsGate) mdsRowShfAlgebra(r uint64, v [poseidon.SPONGE_WIDTH]field.QEAlgebra, qeAPI *field.QuadraticExtensionAPI) field.QEAlgebra {
func (g *PoseidonMdsGate) mdsRowShfAlgebra(
r uint64,
v [poseidon.SPONGE_WIDTH]gl.QuadraticExtensionAlgebraVariable,
api frontend.API,
) gl.QuadraticExtensionAlgebraVariable {
glApi := gl.NewChip(api)
if r >= poseidon.SPONGE_WIDTH { if r >= poseidon.SPONGE_WIDTH {
panic("MDS row index out of range") panic("MDS row index out of range")
} }
res := qeAPI.ZERO_QE_ALGEBRA
res := gl.ZeroExtensionAlgebra()
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
coeff := qeAPI.VarToQE(poseidon.MDS_MATRIX_CIRC[i])
res = qeAPI.AddExtensionAlgebra(res, qeAPI.ScalarMulExtensionAlgebra(coeff, v[(i+r)%poseidon.SPONGE_WIDTH]))
coeff := gl.NewQuadraticExtensionVariable(gl.NewVariable(poseidon.MDS_MATRIX_CIRC[i]), gl.Zero())
res = glApi.AddExtensionAlgebra(res, glApi.ScalarMulExtensionAlgebra(coeff, v[(i+r)%poseidon.SPONGE_WIDTH]))
} }
coeff := qeAPI.VarToQE(poseidon.MDS_MATRIX_DIAG[r])
res = qeAPI.AddExtensionAlgebra(res, qeAPI.ScalarMulExtensionAlgebra(coeff, v[r]))
coeff := gl.NewQuadraticExtensionVariable(gl.NewVariable(poseidon.MDS_MATRIX_DIAG[r]), gl.Zero())
res = glApi.AddExtensionAlgebra(res, glApi.ScalarMulExtensionAlgebra(coeff, v[r]))
return res return res
} }
func (g *PoseidonMdsGate) mdsLayerAlgebra(state [poseidon.SPONGE_WIDTH]field.QEAlgebra, qeAPI *field.QuadraticExtensionAPI) [poseidon.SPONGE_WIDTH]field.QEAlgebra {
var result [poseidon.SPONGE_WIDTH]field.QEAlgebra
func (g *PoseidonMdsGate) mdsLayerAlgebra(
state [poseidon.SPONGE_WIDTH]gl.QuadraticExtensionAlgebraVariable,
api frontend.API,
) [poseidon.SPONGE_WIDTH]gl.QuadraticExtensionAlgebraVariable {
var result [poseidon.SPONGE_WIDTH]gl.QuadraticExtensionAlgebraVariable
for r := uint64(0); r < poseidon.SPONGE_WIDTH; r++ { for r := uint64(0); r < poseidon.SPONGE_WIDTH; r++ {
result[r] = g.mdsRowShfAlgebra(r, state, qeAPI)
result[r] = g.mdsRowShfAlgebra(r, state, api)
} }
return result return result
} }
func (g *PoseidonMdsGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
constraints := []field.QuadraticExtension{}
func (g *PoseidonMdsGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
constraints := []gl.QuadraticExtensionVariable{}
var inputs [poseidon.SPONGE_WIDTH]field.QEAlgebra
var inputs [poseidon.SPONGE_WIDTH]gl.QuadraticExtensionAlgebraVariable
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
inputs[i] = vars.GetLocalExtAlgebra(g.WireInput(i)) inputs[i] = vars.GetLocalExtAlgebra(g.WireInput(i))
} }
computed_outputs := g.mdsLayerAlgebra(inputs, qeAPI)
computed_outputs := g.mdsLayerAlgebra(inputs, api)
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
output := vars.GetLocalExtAlgebra(g.WireOutput(i)) output := vars.GetLocalExtAlgebra(g.WireOutput(i))
diff := qeAPI.SubExtensionAlgebra(output, computed_outputs[i])
diff := glApi.SubExtensionAlgebra(output, computed_outputs[i])
constraints = append(constraints, diff[0], diff[1]) constraints = append(constraints, diff[0], diff[1])
} }

verifier/internal/gates/public_input_gate.go → plonk/gates/public_input_gate.go

@ -4,7 +4,7 @@ import (
"regexp" "regexp"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var publicInputGateRegex = regexp.MustCompile("PublicInputGate") var publicInputGateRegex = regexp.MustCompile("PublicInputGate")
@ -29,8 +29,12 @@ func (g *PublicInputGate) WiresPublicInputsHash() []uint64 {
return []uint64{0, 1, 2, 3} return []uint64{0, 1, 2, 3}
} }
func (g *PublicInputGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
constraints := []field.QuadraticExtension{}
func (g *PublicInputGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
constraints := []gl.QuadraticExtensionVariable{}
wires := g.WiresPublicInputsHash() wires := g.WiresPublicInputsHash()
hash_parts := vars.publicInputsHash hash_parts := vars.publicInputsHash
@ -38,7 +42,8 @@ func (g *PublicInputGate) EvalUnfiltered(api frontend.API, qeAPI *field.Quadrati
wire := wires[i] wire := wires[i]
hash_part := hash_parts[i] hash_part := hash_parts[i]
diff := qeAPI.SubExtension(vars.localWires[wire], qeAPI.FieldToQE(hash_part))
tmp := gl.NewQuadraticExtensionVariable(hash_part, gl.Zero())
diff := glApi.SubExtension(vars.localWires[wire], tmp)
constraints = append(constraints, diff) constraints = append(constraints, diff)
} }

verifier/internal/gates/random_access_gate.go → plonk/gates/random_access_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var randomAccessGateRegex = regexp.MustCompile("RandomAccessGate { bits: (?P<bits>[0-9]+), num_copies: (?P<numCopies>[0-9]+), num_extra_constants: (?P<numExtraConstants>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>") var randomAccessGateRegex = regexp.MustCompile("RandomAccessGate { bits: (?P<bits>[0-9]+), num_copies: (?P<numCopies>[0-9]+), num_extra_constants: (?P<numExtraConstants>[0-9]+), _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=(?P<base>[0-9]+)>")
@ -114,45 +114,49 @@ func (g *RandomAccessGate) WireBit(i uint64, copy uint64) uint64 {
return g.NumRoutedWires() + copy*g.bits + i return g.NumRoutedWires() + copy*g.bits + i
} }
func (g *RandomAccessGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
two := field.QuadraticExtension{field.NewFieldConst(2), field.NewFieldConst(0)}
constraints := []field.QuadraticExtension{}
func (g *RandomAccessGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
two := gl.NewVariable(2).ToQuadraticExtension()
constraints := []gl.QuadraticExtensionVariable{}
for copy := uint64(0); copy < g.numCopies; copy++ { for copy := uint64(0); copy < g.numCopies; copy++ {
accessIndex := vars.localWires[g.WireAccessIndex(copy)] accessIndex := vars.localWires[g.WireAccessIndex(copy)]
listItems := []field.QuadraticExtension{}
listItems := []gl.QuadraticExtensionVariable{}
for i := uint64(0); i < g.vecSize(); i++ { for i := uint64(0); i < g.vecSize(); i++ {
listItems = append(listItems, vars.localWires[g.WireListItem(i, copy)]) listItems = append(listItems, vars.localWires[g.WireListItem(i, copy)])
} }
claimedElement := vars.localWires[g.WireClaimedElement(copy)] claimedElement := vars.localWires[g.WireClaimedElement(copy)]
bits := []field.QuadraticExtension{}
bits := []gl.QuadraticExtensionVariable{}
for i := uint64(0); i < g.bits; i++ { for i := uint64(0); i < g.bits; i++ {
bits = append(bits, vars.localWires[g.WireBit(i, copy)]) bits = append(bits, vars.localWires[g.WireBit(i, copy)])
} }
// Assert that each bit wire value is indeed boolean. // Assert that each bit wire value is indeed boolean.
for _, b := range bits { for _, b := range bits {
bSquared := qeAPI.MulExtension(b, b)
constraints = append(constraints, qeAPI.SubExtension(bSquared, b))
bSquared := glApi.MulExtension(b, b)
constraints = append(constraints, glApi.SubExtension(bSquared, b))
} }
// Assert that the binary decomposition was correct. // Assert that the binary decomposition was correct.
reconstructedIndex := qeAPI.ReduceWithPowers(bits, two)
constraints = append(constraints, qeAPI.SubExtension(reconstructedIndex, accessIndex))
reconstructedIndex := glApi.ReduceWithPowers(bits, two)
constraints = append(constraints, glApi.SubExtension(reconstructedIndex, accessIndex))
for _, b := range bits { for _, b := range bits {
listItemsTmp := []field.QuadraticExtension{}
listItemsTmp := []gl.QuadraticExtensionVariable{}
for i := 0; i < len(listItems); i += 2 { for i := 0; i < len(listItems); i += 2 {
x := listItems[i] x := listItems[i]
y := listItems[i+1] y := listItems[i+1]
// This is computing `if b { x } else { y }` // This is computing `if b { x } else { y }`
// i.e. `bx - (by-y)`. // i.e. `bx - (by-y)`.
mul1 := qeAPI.MulExtension(b, x)
sub1 := qeAPI.SubExtension(mul1, x)
mul1 := glApi.MulExtension(b, x)
sub1 := glApi.SubExtension(mul1, x)
mul2 := qeAPI.MulExtension(b, y)
sub2 := qeAPI.SubExtension(mul2, sub1)
mul2 := glApi.MulExtension(b, y)
sub2 := glApi.SubExtension(mul2, sub1)
listItemsTmp = append(listItemsTmp, sub2) listItemsTmp = append(listItemsTmp, sub2)
} }
@ -163,11 +167,11 @@ func (g *RandomAccessGate) EvalUnfiltered(api frontend.API, qeAPI *field.Quadrat
panic("listItems(len) != 1") panic("listItems(len) != 1")
} }
constraints = append(constraints, qeAPI.SubExtension(listItems[0], claimedElement))
constraints = append(constraints, glApi.SubExtension(listItems[0], claimedElement))
} }
for i := uint64(0); i < g.numExtraConstants; i++ { for i := uint64(0); i < g.numExtraConstants; i++ {
constraints = append(constraints, qeAPI.SubExtension(vars.localConstants[i], vars.localWires[g.wireExtraConstant(i)]))
constraints = append(constraints, glApi.SubExtension(vars.localConstants[i], vars.localWires[g.wireExtraConstant(i)]))
} }
return constraints return constraints

verifier/internal/gates/reducing_extension_gate.go → plonk/gates/reducing_extension_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var reducingExtensionGateRegex = regexp.MustCompile("ReducingExtensionGate { num_coeffs: (?P<numCoeffs>[0-9]+) }") var reducingExtensionGateRegex = regexp.MustCompile("ReducingExtensionGate { num_coeffs: (?P<numCoeffs>[0-9]+) }")
@ -30,7 +30,7 @@ type ReducingExtensionGate struct {
numCoeffs uint64 numCoeffs uint64
} }
const START_COEFFS_REDUCING_EXTENSION_GATE = 3 * field.D
const START_COEFFS_REDUCING_EXTENSION_GATE = 3 * gl.D
func NewReducingExtensionGate(numCoeffs uint64) *ReducingExtensionGate { func NewReducingExtensionGate(numCoeffs uint64) *ReducingExtensionGate {
return &ReducingExtensionGate{ return &ReducingExtensionGate{
@ -43,23 +43,23 @@ func (g *ReducingExtensionGate) Id() string {
} }
func (g *ReducingExtensionGate) wiresOutput() Range { func (g *ReducingExtensionGate) wiresOutput() Range {
return Range{0, field.D}
return Range{0, gl.D}
} }
func (g *ReducingExtensionGate) wiresAlpha() Range { func (g *ReducingExtensionGate) wiresAlpha() Range {
return Range{field.D, 2 * field.D}
return Range{gl.D, 2 * gl.D}
} }
func (g *ReducingExtensionGate) wiresOldAcc() Range { func (g *ReducingExtensionGate) wiresOldAcc() Range {
return Range{2 * field.D, 3 * field.D}
return Range{2 * gl.D, 3 * gl.D}
} }
func (g *ReducingExtensionGate) wiresCoeff(i uint64) Range { func (g *ReducingExtensionGate) wiresCoeff(i uint64) Range {
return Range{START_COEFFS_REDUCING_EXTENSION_GATE + field.D*i, START_COEFFS_REDUCING_EXTENSION_GATE + field.D*(i+1)}
return Range{START_COEFFS_REDUCING_EXTENSION_GATE + gl.D*i, START_COEFFS_REDUCING_EXTENSION_GATE + gl.D*(i+1)}
} }
func (g *ReducingExtensionGate) startAccs() uint64 { func (g *ReducingExtensionGate) startAccs() uint64 {
return START_COEFFS_REDUCING_EXTENSION_GATE + g.numCoeffs*field.D
return START_COEFFS_REDUCING_EXTENSION_GATE + g.numCoeffs*gl.D
} }
func (g *ReducingExtensionGate) wiresAccs(i uint64) Range { func (g *ReducingExtensionGate) wiresAccs(i uint64) Range {
@ -71,31 +71,35 @@ func (g *ReducingExtensionGate) wiresAccs(i uint64) Range {
return g.wiresOutput() return g.wiresOutput()
} }
return Range{g.startAccs() + field.D*i, g.startAccs() + field.D*(i+1)}
return Range{g.startAccs() + gl.D*i, g.startAccs() + gl.D*(i+1)}
} }
func (g *ReducingExtensionGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
func (g *ReducingExtensionGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
alpha := vars.GetLocalExtAlgebra(g.wiresAlpha()) alpha := vars.GetLocalExtAlgebra(g.wiresAlpha())
oldAcc := vars.GetLocalExtAlgebra(g.wiresOldAcc()) oldAcc := vars.GetLocalExtAlgebra(g.wiresOldAcc())
coeffs := []field.QEAlgebra{}
coeffs := []gl.QuadraticExtensionAlgebraVariable{}
for i := uint64(0); i < g.numCoeffs; i++ { for i := uint64(0); i < g.numCoeffs; i++ {
coeffs = append(coeffs, vars.GetLocalExtAlgebra(g.wiresCoeff(i))) coeffs = append(coeffs, vars.GetLocalExtAlgebra(g.wiresCoeff(i)))
} }
accs := []field.QEAlgebra{}
accs := []gl.QuadraticExtensionAlgebraVariable{}
for i := uint64(0); i < g.numCoeffs; i++ { for i := uint64(0); i < g.numCoeffs; i++ {
accs = append(accs, vars.GetLocalExtAlgebra(g.wiresAccs(i))) accs = append(accs, vars.GetLocalExtAlgebra(g.wiresAccs(i)))
} }
constraints := []field.QuadraticExtension{}
constraints := []gl.QuadraticExtensionVariable{}
acc := oldAcc acc := oldAcc
for i := uint64(0); i < g.numCoeffs; i++ { for i := uint64(0); i < g.numCoeffs; i++ {
coeff := coeffs[i] coeff := coeffs[i]
tmp := qeAPI.MulExtensionAlgebra(acc, alpha)
tmp = qeAPI.AddExtensionAlgebra(tmp, coeff)
tmp = qeAPI.SubExtensionAlgebra(tmp, accs[i])
for j := uint64(0); j < field.D; j++ {
tmp := glApi.MulExtensionAlgebra(acc, alpha)
tmp = glApi.AddExtensionAlgebra(tmp, coeff)
tmp = glApi.SubExtensionAlgebra(tmp, accs[i])
for j := uint64(0); j < gl.D; j++ {
constraints = append(constraints, tmp[j]) constraints = append(constraints, tmp[j])
} }
acc = accs[i] acc = accs[i]

verifier/internal/gates/reducing_gate.go → plonk/gates/reducing_gate.go

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var reducingGateRegex = regexp.MustCompile("ReducingGate { num_coeffs: (?P<numCoeffs>[0-9]+) }") var reducingGateRegex = regexp.MustCompile("ReducingGate { num_coeffs: (?P<numCoeffs>[0-9]+) }")
@ -30,7 +30,7 @@ type ReducingGate struct {
numCoeffs uint64 numCoeffs uint64
} }
const START_COEFFS_REDUCING_GATE = 3 * field.D
const START_COEFFS_REDUCING_GATE = 3 * gl.D
func NewReducingGate(numCoeffs uint64) *ReducingGate { func NewReducingGate(numCoeffs uint64) *ReducingGate {
return &ReducingGate{ return &ReducingGate{
@ -43,15 +43,15 @@ func (g *ReducingGate) Id() string {
} }
func (g *ReducingGate) wiresOutput() Range { func (g *ReducingGate) wiresOutput() Range {
return Range{0, field.D}
return Range{0, gl.D}
} }
func (g *ReducingGate) wiresAlpha() Range { func (g *ReducingGate) wiresAlpha() Range {
return Range{field.D, 2 * field.D}
return Range{gl.D, 2 * gl.D}
} }
func (g *ReducingGate) wiresOldAcc() Range { func (g *ReducingGate) wiresOldAcc() Range {
return Range{2 * field.D, 3 * field.D}
return Range{2 * gl.D, 3 * gl.D}
} }
func (g *ReducingGate) wiresCoeff() Range { func (g *ReducingGate) wiresCoeff() Range {
@ -71,36 +71,40 @@ func (g *ReducingGate) wiresAccs(i uint64) Range {
return g.wiresOutput() return g.wiresOutput()
} }
return Range{g.startAccs() + field.D*i, g.startAccs() + field.D*(i+1)}
return Range{g.startAccs() + gl.D*i, g.startAccs() + gl.D*(i+1)}
} }
func (g *ReducingGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticExtensionAPI, vars EvaluationVars) []field.QuadraticExtension {
func (g *ReducingGate) EvalUnfiltered(
api frontend.API,
glApi gl.Chip,
vars EvaluationVars,
) []gl.QuadraticExtensionVariable {
alpha := vars.GetLocalExtAlgebra(g.wiresAlpha()) alpha := vars.GetLocalExtAlgebra(g.wiresAlpha())
oldAcc := vars.GetLocalExtAlgebra(g.wiresOldAcc()) oldAcc := vars.GetLocalExtAlgebra(g.wiresOldAcc())
coeffs := []field.QuadraticExtension{}
coeffs := []gl.QuadraticExtensionVariable{}
coeffsRange := g.wiresCoeff() coeffsRange := g.wiresCoeff()
for i := coeffsRange.start; i < coeffsRange.end; i++ { for i := coeffsRange.start; i < coeffsRange.end; i++ {
coeffs = append(coeffs, vars.localWires[i]) coeffs = append(coeffs, vars.localWires[i])
} }
accs := []field.QEAlgebra{}
accs := []gl.QuadraticExtensionAlgebraVariable{}
for i := uint64(0); i < g.numCoeffs; i++ { for i := uint64(0); i < g.numCoeffs; i++ {
accs = append(accs, vars.GetLocalExtAlgebra(g.wiresAccs(i))) accs = append(accs, vars.GetLocalExtAlgebra(g.wiresAccs(i)))
} }
constraints := []field.QuadraticExtension{}
constraints := []gl.QuadraticExtensionVariable{}
acc := oldAcc acc := oldAcc
for i := uint64(0); i < g.numCoeffs; i++ { for i := uint64(0); i < g.numCoeffs; i++ {
var coeff field.QEAlgebra
for j := 0; j < field.D; j++ {
coeff[j] = qeAPI.ZERO_QE
var coeff gl.QuadraticExtensionAlgebraVariable
for j := 0; j < gl.D; j++ {
coeff[j] = gl.ZeroExtension()
} }
coeff[0] = coeffs[i] coeff[0] = coeffs[i]
tmp := qeAPI.MulExtensionAlgebra(acc, alpha)
tmp = qeAPI.AddExtensionAlgebra(tmp, coeff)
tmp = qeAPI.SubExtensionAlgebra(tmp, accs[i])
for j := 0; j < field.D; j++ {
tmp := glApi.MulExtensionAlgebra(acc, alpha)
tmp = glApi.AddExtensionAlgebra(tmp, coeff)
tmp = glApi.SubExtensionAlgebra(tmp, accs[i])
for j := 0; j < gl.D; j++ {
constraints = append(constraints, tmp[j]) constraints = append(constraints, tmp[j])
} }
acc = accs[i] acc = accs[i]

verifier/internal/gates/selectors.go → plonk/gates/selectors.go


verifier/internal/gates/vars.go → plonk/gates/vars.go

@ -1,20 +1,20 @@
package gates package gates
import ( import (
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
) )
type EvaluationVars struct { type EvaluationVars struct {
localConstants []field.QuadraticExtension
localWires []field.QuadraticExtension
publicInputsHash poseidon.PoseidonHashOut
localConstants []gl.QuadraticExtensionVariable
localWires []gl.QuadraticExtensionVariable
publicInputsHash poseidon.GoldilocksHashOut
} }
func NewEvaluationVars( func NewEvaluationVars(
localConstants []field.QuadraticExtension,
localWires []field.QuadraticExtension,
publicInputsHash poseidon.PoseidonHashOut,
localConstants []gl.QuadraticExtensionVariable,
localWires []gl.QuadraticExtensionVariable,
publicInputsHash poseidon.GoldilocksHashOut,
) *EvaluationVars { ) *EvaluationVars {
return &EvaluationVars{ return &EvaluationVars{
localConstants: localConstants, localConstants: localConstants,
@ -27,13 +27,13 @@ func (e *EvaluationVars) RemovePrefix(numSelectors uint64) {
e.localConstants = e.localConstants[numSelectors:] e.localConstants = e.localConstants[numSelectors:]
} }
func (e *EvaluationVars) GetLocalExtAlgebra(wireRange Range) field.QEAlgebra {
func (e *EvaluationVars) GetLocalExtAlgebra(wireRange Range) gl.QuadraticExtensionAlgebraVariable {
// For now, only support degree 2 // For now, only support degree 2
if wireRange.end-wireRange.start != field.D {
if wireRange.end-wireRange.start != gl.D {
panic("Range must be of size D") panic("Range must be of size D")
} }
var ret field.QEAlgebra
var ret gl.QuadraticExtensionAlgebraVariable
for i := wireRange.start; i < wireRange.end; i++ { for i := wireRange.start; i < wireRange.end; i++ {
ret[i-wireRange.start] = e.localWires[i] ret[i-wireRange.start] = e.localWires[i]
} }

verifier/internal/plonk/plonk.go → plonk/plonk.go

@ -2,102 +2,101 @@ package plonk
import ( import (
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
) )
type PlonkChip struct { type PlonkChip struct {
api frontend.API `gnark:"-"`
qeAPI *field.QuadraticExtensionAPI `gnark:"-"`
api frontend.API `gnark:"-"`
commonData common.CommonCircuitData `gnark:"-"`
commonData types.CommonCircuitData `gnark:"-"`
DEGREE field.F `gnark:"-"`
DEGREE_BITS_F field.F `gnark:"-"`
DEGREE_QE field.QuadraticExtension `gnark:"-"`
DEGREE gl.Variable `gnark:"-"`
DEGREE_BITS_F gl.Variable `gnark:"-"`
DEGREE_QE gl.QuadraticExtensionVariable `gnark:"-"`
evaluateGatesChip *gates.EvaluateGatesChip evaluateGatesChip *gates.EvaluateGatesChip
} }
func NewPlonkChip(api frontend.API, qeAPI *field.QuadraticExtensionAPI, commonData common.CommonCircuitData) *PlonkChip {
func NewPlonkChip(api frontend.API, commonData types.CommonCircuitData) *PlonkChip {
// TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64? // TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64?
evaluateGatesChip := gates.NewEvaluateGatesChip( evaluateGatesChip := gates.NewEvaluateGatesChip(
api, api,
qeAPI,
commonData.Gates, commonData.Gates,
commonData.NumGateConstraints, commonData.NumGateConstraints,
commonData.SelectorsInfo, commonData.SelectorsInfo,
) )
return &PlonkChip{ return &PlonkChip{
api: api,
qeAPI: qeAPI,
api: api,
commonData: commonData, commonData: commonData,
DEGREE: field.NewFieldConst(1 << commonData.DegreeBits),
DEGREE_BITS_F: field.NewFieldConst(commonData.DegreeBits),
DEGREE_QE: field.QuadraticExtension{field.NewFieldConst(1 << commonData.DegreeBits), field.ZERO_F},
DEGREE: gl.NewVariable(1 << commonData.DegreeBits),
DEGREE_BITS_F: gl.NewVariable(commonData.DegreeBits),
DEGREE_QE: gl.NewVariable(1 << commonData.DegreeBits).ToQuadraticExtension(),
evaluateGatesChip: evaluateGatesChip, evaluateGatesChip: evaluateGatesChip,
} }
} }
func (p *PlonkChip) expPowerOf2Extension(x field.QuadraticExtension) field.QuadraticExtension {
func (p *PlonkChip) expPowerOf2Extension(x gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
glApi := gl.NewChip(p.api)
for i := uint64(0); i < p.commonData.DegreeBits; i++ { for i := uint64(0); i < p.commonData.DegreeBits; i++ {
x = p.qeAPI.SquareExtension(x)
x = glApi.MulExtension(x, x)
} }
return x return x
} }
func (p *PlonkChip) evalL0(x field.QuadraticExtension, xPowN field.QuadraticExtension) field.QuadraticExtension {
func (p *PlonkChip) evalL0(x gl.QuadraticExtensionVariable, xPowN gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
// L_0(x) = (x^n - 1) / (n * (x - 1)) // L_0(x) = (x^n - 1) / (n * (x - 1))
evalZeroPoly := p.qeAPI.SubExtension(
glApi := gl.NewChip(p.api)
evalZeroPoly := glApi.SubExtension(
xPowN, xPowN,
p.qeAPI.ONE_QE,
gl.OneExtension(),
) )
denominator := p.qeAPI.SubExtension(
p.qeAPI.ScalarMulExtension(x, p.DEGREE),
denominator := glApi.SubExtension(
glApi.ScalarMulExtension(x, p.DEGREE),
p.DEGREE_QE, p.DEGREE_QE,
) )
return p.qeAPI.DivExtension(
return glApi.DivExtension(
evalZeroPoly, evalZeroPoly,
denominator, denominator,
) )
} }
func (p *PlonkChip) checkPartialProducts( func (p *PlonkChip) checkPartialProducts(
numerators []field.QuadraticExtension,
denominators []field.QuadraticExtension,
numerators []gl.QuadraticExtensionVariable,
denominators []gl.QuadraticExtensionVariable,
challengeNum uint64, challengeNum uint64,
openings common.OpeningSet,
) []field.QuadraticExtension {
openings types.OpeningSet,
) []gl.QuadraticExtensionVariable {
glApi := gl.NewChip(p.api)
numPartProds := p.commonData.NumPartialProducts numPartProds := p.commonData.NumPartialProducts
quotDegreeFactor := p.commonData.QuotientDegreeFactor quotDegreeFactor := p.commonData.QuotientDegreeFactor
productAccs := make([]field.QuadraticExtension, 0, numPartProds+2)
productAccs := make([]gl.QuadraticExtensionVariable, 0, numPartProds+2)
productAccs = append(productAccs, openings.PlonkZs[challengeNum]) productAccs = append(productAccs, openings.PlonkZs[challengeNum])
productAccs = append(productAccs, openings.PartialProducts[challengeNum*numPartProds:(challengeNum+1)*numPartProds]...) productAccs = append(productAccs, openings.PartialProducts[challengeNum*numPartProds:(challengeNum+1)*numPartProds]...)
productAccs = append(productAccs, openings.PlonkZsNext[challengeNum]) productAccs = append(productAccs, openings.PlonkZsNext[challengeNum])
partialProductChecks := make([]field.QuadraticExtension, 0, numPartProds)
partialProductChecks := make([]gl.QuadraticExtensionVariable, 0, numPartProds)
for i := uint64(0); i <= numPartProds; i += 1 { for i := uint64(0); i <= numPartProds; i += 1 {
ppStartIdx := i * quotDegreeFactor ppStartIdx := i * quotDegreeFactor
numeProduct := numerators[ppStartIdx] numeProduct := numerators[ppStartIdx]
denoProduct := denominators[ppStartIdx] denoProduct := denominators[ppStartIdx]
for j := uint64(1); j < quotDegreeFactor; j++ { for j := uint64(1); j < quotDegreeFactor; j++ {
numeProduct = p.qeAPI.MulExtension(numeProduct, numerators[ppStartIdx+j])
denoProduct = p.qeAPI.MulExtension(denoProduct, denominators[ppStartIdx+j])
numeProduct = glApi.MulExtension(numeProduct, numerators[ppStartIdx+j])
denoProduct = glApi.MulExtension(denoProduct, denominators[ppStartIdx+j])
} }
partialProductCheck := p.qeAPI.SubExtension(
p.qeAPI.MulExtension(productAccs[i], numeProduct),
p.qeAPI.MulExtension(productAccs[i+1], denoProduct),
partialProductCheck := glApi.SubExtension(
glApi.MulExtension(productAccs[i], numeProduct),
glApi.MulExtension(productAccs[i+1], denoProduct),
) )
partialProductChecks = append(partialProductChecks, partialProductCheck) partialProductChecks = append(partialProductChecks, partialProductCheck)
@ -105,49 +104,55 @@ func (p *PlonkChip) checkPartialProducts(
return partialProductChecks return partialProductChecks
} }
func (p *PlonkChip) evalVanishingPoly(vars gates.EvaluationVars, proofChallenges common.ProofChallenges, openings common.OpeningSet, zetaPowN field.QuadraticExtension) []field.QuadraticExtension {
func (p *PlonkChip) evalVanishingPoly(
vars gates.EvaluationVars,
proofChallenges types.ProofChallenges,
openings types.OpeningSet,
zetaPowN gl.QuadraticExtensionVariable,
) []gl.QuadraticExtensionVariable {
glApi := gl.NewChip(p.api)
constraintTerms := p.evaluateGatesChip.EvaluateGateConstraints(vars) constraintTerms := p.evaluateGatesChip.EvaluateGateConstraints(vars)
// Calculate the k[i] * x // Calculate the k[i] * x
sIDs := make([]field.QuadraticExtension, p.commonData.Config.NumRoutedWires)
sIDs := make([]gl.QuadraticExtensionVariable, p.commonData.Config.NumRoutedWires)
for i := uint64(0); i < p.commonData.Config.NumRoutedWires; i++ { for i := uint64(0); i < p.commonData.Config.NumRoutedWires; i++ {
sIDs[i] = p.qeAPI.ScalarMulExtension(proofChallenges.PlonkZeta, p.commonData.KIs[i])
sIDs[i] = glApi.ScalarMulExtension(proofChallenges.PlonkZeta, p.commonData.KIs[i])
} }
// Calculate L_0(zeta) // Calculate L_0(zeta)
l0Zeta := p.evalL0(proofChallenges.PlonkZeta, zetaPowN) l0Zeta := p.evalL0(proofChallenges.PlonkZeta, zetaPowN)
vanishingZ1Terms := make([]field.QuadraticExtension, 0, p.commonData.Config.NumChallenges)
vanishingPartialProductsTerms := make([]field.QuadraticExtension, 0, p.commonData.Config.NumChallenges*p.commonData.NumPartialProducts)
vanishingZ1Terms := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumChallenges)
vanishingPartialProductsTerms := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumChallenges*p.commonData.NumPartialProducts)
for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ { for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
// L_0(zeta) (Z(zeta) - 1) = 0 // L_0(zeta) (Z(zeta) - 1) = 0
z1_term := p.qeAPI.MulExtension(
z1_term := glApi.MulExtension(
l0Zeta, l0Zeta,
p.qeAPI.SubExtension(openings.PlonkZs[i], p.qeAPI.ONE_QE))
glApi.SubExtension(openings.PlonkZs[i], gl.OneExtension()))
vanishingZ1Terms = append(vanishingZ1Terms, z1_term) vanishingZ1Terms = append(vanishingZ1Terms, z1_term)
numeratorValues := make([]field.QuadraticExtension, 0, p.commonData.Config.NumRoutedWires)
denominatorValues := make([]field.QuadraticExtension, 0, p.commonData.Config.NumRoutedWires)
numeratorValues := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumRoutedWires)
denominatorValues := make([]gl.QuadraticExtensionVariable, 0, p.commonData.Config.NumRoutedWires)
for j := uint64(0); j < p.commonData.Config.NumRoutedWires; j++ { for j := uint64(0); j < p.commonData.Config.NumRoutedWires; j++ {
// The numerator is `beta * s_id + wire_value + gamma`, and the denominator is // The numerator is `beta * s_id + wire_value + gamma`, and the denominator is
// `beta * s_sigma + wire_value + gamma`. // `beta * s_sigma + wire_value + gamma`.
wireValuePlusGamma := p.qeAPI.AddExtension(
wireValuePlusGamma := glApi.AddExtension(
openings.Wires[j], openings.Wires[j],
p.qeAPI.FieldToQE(proofChallenges.PlonkGammas[i]),
gl.NewQuadraticExtensionVariable(proofChallenges.PlonkGammas[i], gl.Zero()),
) )
numerator := p.qeAPI.AddExtension(
p.qeAPI.MulExtension(
p.qeAPI.FieldToQE(proofChallenges.PlonkBetas[i]),
numerator := glApi.AddExtension(
glApi.MulExtension(
gl.NewQuadraticExtensionVariable(proofChallenges.PlonkBetas[i], gl.Zero()),
sIDs[j], sIDs[j],
), ),
wireValuePlusGamma, wireValuePlusGamma,
) )
denominator := p.qeAPI.AddExtension(
p.qeAPI.MulExtension(
p.qeAPI.FieldToQE(proofChallenges.PlonkBetas[i]),
denominator := glApi.AddExtension(
glApi.MulExtension(
gl.NewQuadraticExtensionVariable(proofChallenges.PlonkBetas[i], gl.Zero()),
openings.PlonkSigmas[j], openings.PlonkSigmas[j],
), ),
wireValuePlusGamma, wireValuePlusGamma,
@ -166,17 +171,17 @@ func (p *PlonkChip) evalVanishingPoly(vars gates.EvaluationVars, proofChallenges
vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...) vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...)
vanishingTerms = append(vanishingTerms, constraintTerms...) vanishingTerms = append(vanishingTerms, constraintTerms...)
reducedValues := make([]field.QuadraticExtension, p.commonData.Config.NumChallenges)
reducedValues := make([]gl.QuadraticExtensionVariable, p.commonData.Config.NumChallenges)
for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ { for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
reducedValues[i] = p.qeAPI.ZERO_QE
reducedValues[i] = gl.ZeroExtension()
} }
// reverse iterate the vanishingPartialProductsTerms array // reverse iterate the vanishingPartialProductsTerms array
for i := len(vanishingTerms) - 1; i >= 0; i-- { for i := len(vanishingTerms) - 1; i >= 0; i-- {
for j := uint64(0); j < p.commonData.Config.NumChallenges; j++ { for j := uint64(0); j < p.commonData.Config.NumChallenges; j++ {
reducedValues[j] = p.qeAPI.AddExtension(
reducedValues[j] = glApi.AddExtension(
vanishingTerms[i], vanishingTerms[i],
p.qeAPI.ScalarMulExtension(
glApi.ScalarMulExtension(
reducedValues[j], reducedValues[j],
proofChallenges.PlonkAlphas[j], proofChallenges.PlonkAlphas[j],
), ),
@ -187,7 +192,13 @@ func (p *PlonkChip) evalVanishingPoly(vars gates.EvaluationVars, proofChallenges
return reducedValues return reducedValues
} }
func (p *PlonkChip) Verify(proofChallenges common.ProofChallenges, openings common.OpeningSet, publicInputsHash poseidon.PoseidonHashOut) {
func (p *PlonkChip) Verify(
proofChallenges types.ProofChallenges,
openings types.OpeningSet,
publicInputsHash poseidon.GoldilocksHashOut,
) {
glApi := gl.NewChip(p.api)
// Calculate zeta^n // Calculate zeta^n
zetaPowN := p.expPowerOf2Extension(proofChallenges.PlonkZeta) zetaPowN := p.expPowerOf2Extension(proofChallenges.PlonkZeta)
@ -202,7 +213,7 @@ func (p *PlonkChip) Verify(proofChallenges common.ProofChallenges, openings comm
vanishingPolysZeta := p.evalVanishingPoly(*vars, proofChallenges, openings, zetaPowN) vanishingPolysZeta := p.evalVanishingPoly(*vars, proofChallenges, openings, zetaPowN)
// Calculate Z(H) // Calculate Z(H)
zHZeta := p.qeAPI.SubExtension(zetaPowN, p.qeAPI.ONE_QE)
zHZeta := glApi.SubExtension(zetaPowN, gl.OneExtension())
// `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations. // `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations.
// Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)` // Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)`
@ -212,14 +223,14 @@ func (p *PlonkChip) Verify(proofChallenges common.ProofChallenges, openings comm
for i := 0; i < len(vanishingPolysZeta); i++ { for i := 0; i < len(vanishingPolysZeta); i++ {
quotientPolysStartIdx := i * int(p.commonData.QuotientDegreeFactor) quotientPolysStartIdx := i * int(p.commonData.QuotientDegreeFactor)
quotientPolysEndIdx := quotientPolysStartIdx + int(p.commonData.QuotientDegreeFactor) quotientPolysEndIdx := quotientPolysStartIdx + int(p.commonData.QuotientDegreeFactor)
prod := p.qeAPI.MulExtension(
prod := glApi.MulExtension(
zHZeta, zHZeta,
p.qeAPI.ReduceWithPowers(
glApi.ReduceWithPowers(
openings.QuotientPolys[quotientPolysStartIdx:quotientPolysEndIdx], openings.QuotientPolys[quotientPolysStartIdx:quotientPolysEndIdx],
zetaPowN, zetaPowN,
), ),
) )
p.qeAPI.AssertIsEqual(vanishingPolysZeta[i], prod)
glApi.AssertIsEqualExtension(vanishingPolysZeta[i], prod)
} }
} }

verifier/internal/plonk/plonk_test.go → plonk/plonk_test.go

@ -3,12 +3,11 @@ package plonk_test
import ( import (
"testing" "testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test" "github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier" "github.com/succinctlabs/gnark-plonky2-verifier/verifier"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/plonk"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils"
) )
type TestPlonkCircuit struct { type TestPlonkCircuit struct {
@ -18,19 +17,16 @@ type TestPlonkCircuit struct {
} }
func (circuit *TestPlonkCircuit) Define(api frontend.API) error { func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
proofWithPis := utils.DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
commonCircuitData := utils.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
verifierOnlyCircuitData := utils.DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
proofWithPis := verifier.DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
commonCircuitData := verifier.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
verifierChip := verifier.NewVerifierChip(api, commonCircuitData) verifierChip := verifier.NewVerifierChip(api, commonCircuitData)
publicInputsHash := verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs) publicInputsHash := verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs)
proofChallenges := verifierChip.GetChallenges(proofWithPis.Proof, publicInputsHash, commonCircuitData, verifierOnlyCircuitData) proofChallenges := verifierChip.GetChallenges(proofWithPis.Proof, publicInputsHash, commonCircuitData, verifierOnlyCircuitData)
fieldAPI := field.NewFieldAPI(api)
qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI)
plonkChip := plonk.NewPlonkChip( plonkChip := plonk.NewPlonkChip(
api, api,
qeAPI,
commonCircuitData, commonCircuitData,
) )
@ -48,7 +44,7 @@ func TestPlonkDecodeBlock(t *testing.T) {
verifierOnlyCircuitDataFilename: "../../data/decode_block/verifier_only_circuit_data.json", verifierOnlyCircuitDataFilename: "../../data/decode_block/verifier_only_circuit_data.json",
} }
witness := TestPlonkCircuit{} witness := TestPlonkCircuit{}
err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField())
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err) assert.NoError(err)
} }

+ 204
- 0
poseidon/bn254.go

@ -0,0 +1,204 @@
package poseidon
// This is a customized implementation of the Poseidon hash function inside the BN254 field.
// This implementation is based on the following implementation:
//
// https://github.com/iden3/go-iden3-crypto/blob/master/poseidon/poseidon.go
//
// The input and output are modified to ingest Goldilocks field elements.
import (
"math/big"
"github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
)
const BN254_FULL_ROUNDS int = 8
const BN254_PARTIAL_ROUNDS int = 56
const BN254_SPONGE_WIDTH int = 4
const BN254_SPONGE_RATE int = 3
type BN254Chip struct {
api frontend.API `gnark:"-"`
gl gl.Chip `gnark:"-"`
}
type BN254State = [BN254_SPONGE_WIDTH]frontend.Variable
type BN254HashOut = frontend.Variable
func NewBN254Chip(api frontend.API) *BN254Chip {
return &BN254Chip{api: api, gl: *gl.NewChip(api)}
}
func (c *BN254Chip) Poseidon(state BN254State) BN254State {
state = c.ark(state, 0)
state = c.fullRounds(state, true)
state = c.partialRounds(state)
state = c.fullRounds(state, false)
return state
}
func (c *BN254Chip) HashNoPad(input []gl.Variable) BN254HashOut {
state := BN254State{
frontend.Variable(0),
frontend.Variable(0),
frontend.Variable(0),
frontend.Variable(0),
}
for i := 0; i < len(input); i += BN254_SPONGE_RATE * 3 {
endI := c.min(len(input), i+BN254_SPONGE_RATE*3)
rateChunk := input[i:endI]
for j, stateIdx := 0, 0; j < len(rateChunk); j, stateIdx = j+3, stateIdx+1 {
endJ := c.min(len(rateChunk), j+3)
bn254Chunk := rateChunk[j:endJ]
bits := []frontend.Variable{}
for k := 0; k < len(bn254Chunk); k++ {
bn254Chunk[k] = c.gl.Reduce(bn254Chunk[k])
bits = append(bits, c.api.ToBinary(bn254Chunk[k].Limb, 64)...)
}
state[stateIdx+1] = c.api.FromBinary(bits...)
}
state = c.Poseidon(state)
}
return BN254HashOut(state[0])
}
func (c *BN254Chip) HashOrNoop(input []gl.Variable) BN254HashOut {
if len(input) <= 3 {
returnVal := frontend.Variable(0)
alpha := new(big.Int).SetInt64(1 << 32)
for i, inputElement := range input {
returnVal = c.api.Add(returnVal, c.api.Mul(inputElement, alpha.Exp(alpha, big.NewInt(int64(i)), nil)))
}
return BN254HashOut(returnVal)
} else {
return c.HashNoPad(input)
}
}
func (c *BN254Chip) TwoToOne(left BN254HashOut, right BN254HashOut) BN254HashOut {
var inputs BN254State
inputs[0] = frontend.Variable(0)
inputs[1] = frontend.Variable(0)
inputs[2] = left
inputs[3] = right
state := c.Poseidon(inputs)
return state[0]
}
func (c *BN254Chip) ToVec(hash BN254HashOut) []gl.Variable {
bits := c.api.ToBinary(hash)
returnElements := []gl.Variable{}
// Split into 7 byte chunks, since 8 byte chunks can result in collisions
chunkSize := 56
for i := 0; i < len(bits); i += chunkSize {
maxIdx := c.min(len(bits), i+chunkSize)
bitChunk := bits[i:maxIdx]
returnElements = append(returnElements, gl.NewVariable(c.api.FromBinary(bitChunk...)))
}
return returnElements
}
func (c *BN254Chip) min(x, y int) int {
if x < y {
return x
}
return y
}
func (c *BN254Chip) fullRounds(state BN254State, isFirst bool) BN254State {
for i := 0; i < BN254_FULL_ROUNDS/2-1; i++ {
state = c.exp5state(state)
if isFirst {
state = c.ark(state, (i+1)*BN254_SPONGE_WIDTH)
} else {
state = c.ark(state, (BN254_FULL_ROUNDS/2+1)*BN254_SPONGE_WIDTH+BN254_PARTIAL_ROUNDS+i*BN254_SPONGE_WIDTH)
}
state = c.mix(state, mMatrix)
}
state = c.exp5state(state)
if isFirst {
state = c.ark(state, (BN254_FULL_ROUNDS/2)*BN254_SPONGE_WIDTH)
state = c.mix(state, pMatrix)
} else {
state = c.mix(state, mMatrix)
}
return state
}
func (c *BN254Chip) partialRounds(state BN254State) BN254State {
for i := 0; i < BN254_PARTIAL_ROUNDS; i++ {
state[0] = c.exp5(state[0])
state[0] = c.api.Add(state[0], cConstants[(BN254_FULL_ROUNDS/2+1)*BN254_SPONGE_WIDTH+i])
var mul frontend.Variable
newState0 := frontend.Variable(0)
for j := 0; j < BN254_SPONGE_WIDTH; j++ {
mul = c.api.Mul(sConstants[(BN254_SPONGE_WIDTH*2-1)*i+j], state[j])
newState0 = c.api.Add(newState0, mul)
}
for k := 1; k < BN254_SPONGE_WIDTH; k++ {
mul = c.api.Mul(state[0], sConstants[(BN254_SPONGE_WIDTH*2-1)*i+BN254_SPONGE_WIDTH+k-1])
state[k] = c.api.Add(state[k], mul)
}
state[0] = newState0
}
return state
}
func (c *BN254Chip) ark(state BN254State, it int) BN254State {
var result BN254State
for i := 0; i < len(state); i++ {
result[i] = c.api.Add(state[i], cConstants[it+i])
}
return result
}
func (c *BN254Chip) exp5(x frontend.Variable) frontend.Variable {
x2 := c.api.Mul(x, x)
x4 := c.api.Mul(x2, x2)
return c.api.Mul(x4, x)
}
func (c *BN254Chip) exp5state(state BN254State) BN254State {
for i := 0; i < BN254_SPONGE_WIDTH; i++ {
state[i] = c.exp5(state[i])
}
return state
}
func (c *BN254Chip) mix(state_ BN254State, constantMatrix [][]*big.Int) BN254State {
var mul frontend.Variable
var result BN254State
for i := 0; i < BN254_SPONGE_WIDTH; i++ {
result[i] = frontend.Variable(0)
}
for i := 0; i < BN254_SPONGE_WIDTH; i++ {
for j := 0; j < BN254_SPONGE_WIDTH; j++ {
mul = c.api.Mul(constantMatrix[j][i], state_[j])
result[i] = c.api.Add(result[i], mul)
}
}
return result
}

poseidon/poseidon_bn128_test.go → poseidon/bn254_test.go

@ -3,23 +3,22 @@ package poseidon
import ( import (
"testing" "testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test" "github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/utils"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
type TestPoseidonBN128Circuit struct {
In [spongeWidth]frontend.Variable
Out [spongeWidth]frontend.Variable
type TestPoseidonBN254Circuit struct {
In [BN254_SPONGE_WIDTH]frontend.Variable
Out [BN254_SPONGE_WIDTH]frontend.Variable
} }
func (circuit *TestPoseidonBN128Circuit) Define(api frontend.API) error {
fieldAPI := field.NewFieldAPI(api)
poseidonChip := NewPoseidonBN128Chip(api, fieldAPI)
func (circuit *TestPoseidonBN254Circuit) Define(api frontend.API) error {
poseidonChip := NewBN254Chip(api)
output := poseidonChip.Poseidon(circuit.In) output := poseidonChip.Poseidon(circuit.In)
for i := 0; i < spongeWidth; i++ {
for i := 0; i < BN254_SPONGE_WIDTH; i++ {
api.AssertIsEqual( api.AssertIsEqual(
output[i], output[i],
circuit.Out[i], circuit.Out[i],
@ -29,13 +28,13 @@ func (circuit *TestPoseidonBN128Circuit) Define(api frontend.API) error {
return nil return nil
} }
func TestPoseidonBN128(t *testing.T) {
func TestPoseidonBN254(t *testing.T) {
assert := test.NewAssert(t) assert := test.NewAssert(t)
testCaseFn := func(in [spongeWidth]frontend.Variable, out [spongeWidth]frontend.Variable) {
circuit := TestPoseidonBN128Circuit{In: in, Out: out}
witness := TestPoseidonBN128Circuit{In: in, Out: out}
err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField())
testCaseFn := func(in [BN254_SPONGE_WIDTH]frontend.Variable, out [BN254_SPONGE_WIDTH]frontend.Variable) {
circuit := TestPoseidonBN254Circuit{In: in, Out: out}
witness := TestPoseidonBN254Circuit{In: in, Out: out}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err) assert.NoError(err)
} }
@ -89,10 +88,10 @@ func TestPoseidonBN128(t *testing.T) {
} }
for _, testCase := range testCases { for _, testCase := range testCases {
var in [spongeWidth]frontend.Variable
var out [spongeWidth]frontend.Variable
copy(in[:], utils.StrArrayToFrontendVariableArray(testCase[0]))
copy(out[:], utils.StrArrayToFrontendVariableArray(testCase[1]))
var in [BN254_SPONGE_WIDTH]frontend.Variable
var out [BN254_SPONGE_WIDTH]frontend.Variable
copy(in[:], gl.StrArrayToFrontendVariableArray(testCase[0]))
copy(out[:], gl.StrArrayToFrontendVariableArray(testCase[1]))
testCaseFn(in, out) testCaseFn(in, out)
} }
} }

poseidon/poseidon_bn128_constants.go → poseidon/bn254constants.go

@ -109,7 +109,7 @@ func init() {
cConstants[85], _ = new(big.Int).SetString("19007581091212404202795325684108744075320879284650517772195719617120941682734", 10) cConstants[85], _ = new(big.Int).SetString("19007581091212404202795325684108744075320879284650517772195719617120941682734", 10)
cConstants[86], _ = new(big.Int).SetString("8172766643075822491744127151779052248074930479661223662192995838879026989201", 10) cConstants[86], _ = new(big.Int).SetString("8172766643075822491744127151779052248074930479661223662192995838879026989201", 10)
cConstants[87], _ = new(big.Int).SetString("1885998770792872998306340529689960371653339961062025442813774917754800650781", 10) cConstants[87], _ = new(big.Int).SetString("1885998770792872998306340529689960371653339961062025442813774917754800650781", 10)
sConstants[0], _ = new(big.Int).SetString("16023668707004248971294664614290028914393192768609916554276071736843535714477", 10) sConstants[0], _ = new(big.Int).SetString("16023668707004248971294664614290028914393192768609916554276071736843535714477", 10)
sConstants[1], _ = new(big.Int).SetString("20198106103550706280267600199190750325504745188750640438654177959939538483777", 10) sConstants[1], _ = new(big.Int).SetString("20198106103550706280267600199190750325504745188750640438654177959939538483777", 10)
sConstants[2], _ = new(big.Int).SetString("20760367756622597472566835313508896628444391801225538453375145392828630013190", 10) sConstants[2], _ = new(big.Int).SetString("20760367756622597472566835313508896628444391801225538453375145392828630013190", 10)

+ 357
- 0
poseidon/goldilocks.go

@ -0,0 +1,357 @@
package poseidon
import (
"github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
)
const HALF_N_FULL_ROUNDS = 4
const N_PARTIAL_ROUNDS = 22
const MAX_WIDTH = 12
const SPONGE_WIDTH = 12
const SPONGE_RATE = 8
type GoldilocksState = [SPONGE_WIDTH]gl.Variable
type GoldilocksStateExtension = [SPONGE_WIDTH]gl.QuadraticExtensionVariable
type GoldilocksHashOut = [4]gl.Variable
type GoldilocksChip struct {
api frontend.API `gnark:"-"`
gl gl.Chip `gnark:"-"`
}
func NewGoldilocksChip(api frontend.API) *GoldilocksChip {
return &GoldilocksChip{api: api, gl: *gl.NewChip(api)}
}
// The permutation function.
// The input state MUST have all it's elements be within Goldilocks field (e.g. this function will not reduce the input elements).
// The returned state's elements will all be within Goldilocks field.
func (c *GoldilocksChip) Poseidon(input GoldilocksState) GoldilocksState {
state := input
roundCounter := 0
state = c.fullRounds(state, &roundCounter)
state = c.partialRounds(state, &roundCounter)
state = c.fullRounds(state, &roundCounter)
return state
}
// The input elements MUST have all it's elements be within Goldilocks field.
// The returned slice's elements will all be within Goldilocks field.
func (c *GoldilocksChip) HashNToMNoPad(input []gl.Variable, nbOutputs int) []gl.Variable {
var state GoldilocksState
for i := 0; i < SPONGE_WIDTH; i++ {
state[i] = gl.NewVariable(0)
}
for i := 0; i < len(input); i += SPONGE_RATE {
for j := 0; j < SPONGE_RATE; j++ {
if i+j < len(input) {
state[j] = input[i+j]
}
}
state = c.Poseidon(state)
}
var outputs []gl.Variable
for {
for i := 0; i < SPONGE_RATE; i++ {
outputs = append(outputs, state[i])
if len(outputs) == nbOutputs {
return outputs
}
}
state = c.Poseidon(state)
}
}
// The input elements can be outside of the Goldilocks field.
// The returned slice's elements will all be within Goldilocks field.
func (c *GoldilocksChip) HashNoPad(input []gl.Variable) GoldilocksHashOut {
var hash GoldilocksHashOut
inputVars := []gl.Variable{}
for i := 0; i < len(input); i++ {
inputVars = append(inputVars, c.gl.Reduce(input[i]))
}
outputVars := c.HashNToMNoPad(inputVars, 4)
for i := 0; i < 4; i++ {
hash[i] = outputVars[i]
}
return hash
}
func (c *GoldilocksChip) ToVec(hash GoldilocksHashOut) []gl.Variable {
return hash[:]
}
func (c *GoldilocksChip) fullRounds(state GoldilocksState, roundCounter *int) GoldilocksState {
for i := 0; i < HALF_N_FULL_ROUNDS; i++ {
state = c.constantLayer(state, roundCounter)
state = c.sBoxLayer(state)
state = c.mdsLayer(state)
*roundCounter += 1
}
return state
}
func (c *GoldilocksChip) partialRounds(state GoldilocksState, roundCounter *int) GoldilocksState {
state = c.partialFirstConstantLayer(state)
state = c.mdsPartialLayerInit(state)
for i := 0; i < N_PARTIAL_ROUNDS; i++ {
state[0] = c.sBoxMonomial(state[0])
state[0] = c.gl.Add(state[0], gl.NewVariable(FAST_PARTIAL_ROUND_CONSTANTS[i]))
state = c.mdsPartialLayerFast(state, i)
}
*roundCounter += N_PARTIAL_ROUNDS
return state
}
func (c *GoldilocksChip) constantLayer(state GoldilocksState, roundCounter *int) GoldilocksState {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
roundConstant := ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)]
state[i] = c.gl.MulAdd(state[i], gl.NewVariable(1), gl.NewVariable(roundConstant))
}
}
return state
}
func (c *GoldilocksChip) ConstantLayerExtension(state GoldilocksStateExtension, roundCounter *int) GoldilocksStateExtension {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
roundConstant := gl.NewVariable(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)])
roundConstantQE := gl.NewQuadraticExtensionVariable(roundConstant, gl.Zero())
state[i] = c.gl.AddExtension(state[i], roundConstantQE)
}
}
return state
}
func (c *GoldilocksChip) sBoxMonomial(x gl.Variable) gl.Variable {
x2 := c.gl.MulNoReduce(x, x)
x3 := c.gl.MulNoReduce(x, x2)
x3 = c.gl.ReduceWithMaxBits(x3, 192)
x6 := c.gl.MulNoReduce(x3, x3)
x7 := c.gl.MulNoReduce(x, x6)
return c.gl.ReduceWithMaxBits(x7, 192)
}
func (c *GoldilocksChip) SBoxMonomialExtension(x gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
x2 := c.gl.MulExtension(x, x)
x4 := c.gl.MulExtension(x2, x2)
x3 := c.gl.MulExtension(x, x2)
return c.gl.MulExtension(x4, x3)
}
func (c *GoldilocksChip) sBoxLayer(state GoldilocksState) GoldilocksState {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
state[i] = c.sBoxMonomial(state[i])
}
}
return state
}
func (c *GoldilocksChip) SBoxLayerExtension(state GoldilocksStateExtension) GoldilocksStateExtension {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
state[i] = c.SBoxMonomialExtension(state[i])
}
}
return state
}
func (c *GoldilocksChip) mdsRowShf(r int, v [SPONGE_WIDTH]gl.Variable) gl.Variable {
res := gl.Zero()
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
res = c.gl.MulAddNoReduce(v[(i+r)%SPONGE_WIDTH], gl.NewVariable(MDS_MATRIX_CIRC_VARS[i]), res)
}
}
res = c.gl.MulAddNoReduce(v[r], gl.NewVariable(MDS_MATRIX_DIAG_VARS[r]), res)
return c.gl.Reduce(res)
}
func (c *GoldilocksChip) MdsRowShfExtension(r int, v [SPONGE_WIDTH]gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable {
res := gl.ZeroExtension()
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
matrixVal := gl.NewVariable(MDS_MATRIX_CIRC[i])
matrixValQE := gl.NewQuadraticExtensionVariable(matrixVal, gl.Zero())
res1 := c.gl.MulExtension(v[(i+r)%SPONGE_WIDTH], matrixValQE)
res = c.gl.AddExtension(res, res1)
}
}
matrixVal := gl.NewVariable(MDS_MATRIX_DIAG[r])
matrixValQE := gl.NewQuadraticExtensionVariable(matrixVal, gl.Zero())
res = c.gl.AddExtension(res, c.gl.MulExtension(v[r], matrixValQE))
return res
}
func (c *GoldilocksChip) mdsLayer(state_ GoldilocksState) GoldilocksState {
var result GoldilocksState
for i := 0; i < SPONGE_WIDTH; i++ {
result[i] = gl.NewVariable(0)
}
for r := 0; r < 12; r++ {
if r < SPONGE_WIDTH {
result[r] = c.mdsRowShf(r, state_)
}
}
return result
}
func (c *GoldilocksChip) MdsLayerExtension(state_ GoldilocksStateExtension) GoldilocksStateExtension {
var result GoldilocksStateExtension
for r := 0; r < 12; r++ {
if r < SPONGE_WIDTH {
sum := c.MdsRowShfExtension(r, state_)
result[r] = sum
}
}
return result
}
func (c *GoldilocksChip) partialFirstConstantLayer(state GoldilocksState) GoldilocksState {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
state[i] = c.gl.Add(state[i], gl.NewVariable(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]))
}
}
return state
}
func (c *GoldilocksChip) PartialFirstConstantLayerExtension(state GoldilocksStateExtension) GoldilocksStateExtension {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
fastPartialRoundConstant := gl.NewVariable(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])
fastPartialRoundConstantQE := gl.NewQuadraticExtensionVariable(fastPartialRoundConstant, gl.Zero())
state[i] = c.gl.AddExtension(state[i], fastPartialRoundConstantQE)
}
}
return state
}
func (c *GoldilocksChip) mdsPartialLayerInit(state GoldilocksState) GoldilocksState {
var result GoldilocksState
for i := 0; i < 12; i++ {
result[i] = gl.NewVariable(0)
}
result[0] = state[0]
for r := 1; r < 12; r++ {
if r < SPONGE_WIDTH {
for d := 1; d < 12; d++ {
if d < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1]
result[d] = c.gl.MulAddNoReduce(state[r], gl.NewVariable(t), result[d])
}
}
}
}
for i := 0; i < 12; i++ {
result[i] = c.gl.Reduce(result[i])
}
return result
}
func (c *GoldilocksChip) MdsPartialLayerInitExtension(state GoldilocksStateExtension) GoldilocksStateExtension {
var result GoldilocksStateExtension
for i := 0; i < 12; i++ {
result[i] = gl.ZeroExtension()
}
result[0] = state[0]
for r := 1; r < 12; r++ {
if r < SPONGE_WIDTH {
for d := 1; d < 12; d++ {
if d < SPONGE_WIDTH {
t := gl.NewVariable(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
tQE := gl.NewQuadraticExtensionVariable(t, gl.Zero())
result[d] = c.gl.AddExtension(result[d], c.gl.MulExtension(state[r], tQE))
}
}
}
}
return result
}
func (c *GoldilocksChip) mdsPartialLayerFast(state GoldilocksState, r int) GoldilocksState {
dSum := gl.Zero()
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_W_HATS_VARS[r][i-1]
dSum = c.gl.MulAddNoReduce(state[i], gl.NewVariable(t), dSum)
}
}
d := c.gl.MulAddNoReduce(state[0], gl.NewVariable(MDS0TO0_VAR), dSum)
d = c.gl.Reduce(d)
var result GoldilocksState
for i := 0; i < SPONGE_WIDTH; i++ {
result[i] = gl.NewVariable(0)
}
result[0] = d
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_VS[r][i-1]
result[i] = c.gl.MulAddNoReduce(state[0], gl.NewVariable(t), state[i])
}
}
for i := 0; i < len(state); i++ {
result[i] = c.gl.Reduce(result[i])
}
return result
}
func (c *GoldilocksChip) MdsPartialLayerFastExtension(state GoldilocksStateExtension, r int) GoldilocksStateExtension {
s0 := state[0]
mds0to0 := gl.NewVariable(MDS0TO0)
mds0to0QE := gl.NewQuadraticExtensionVariable(mds0to0, gl.Zero())
d := c.gl.MulExtension(s0, mds0to0QE)
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := gl.NewVariable(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
tQE := gl.NewQuadraticExtensionVariable(t, gl.Zero())
d = c.gl.AddExtension(d, c.gl.MulExtension(state[i], tQE))
}
}
var result GoldilocksStateExtension
result[0] = d
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := gl.NewVariable(FAST_PARTIAL_ROUND_VS[r][i-1])
tQE := gl.NewQuadraticExtensionVariable(t, gl.Zero())
result[i] = c.gl.AddExtension(c.gl.MulExtension(state[0], tQE), state[i])
}
}
return result
}

poseidon/poseidon_constants.go → poseidon/goldilocks_constants.go


poseidon/poseidon_test.go → poseidon/goldilocks_test.go

@ -3,12 +3,12 @@ package poseidon
import ( import (
"testing" "testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/test" "github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/utils"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
type TestPoseidonCircuit struct { type TestPoseidonCircuit struct {
@ -17,19 +17,18 @@ type TestPoseidonCircuit struct {
} }
func (circuit *TestPoseidonCircuit) Define(api frontend.API) error { func (circuit *TestPoseidonCircuit) Define(api frontend.API) error {
goldilocksApi := field.NewFieldAPI(api)
qeAPI := field.NewQuadraticExtensionAPI(api, goldilocksApi)
var input PoseidonState
var input GoldilocksState
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
input[i] = circuit.In[i]
input[i] = gl.NewVariable(circuit.In[i])
} }
poseidonChip := NewPoseidonChip(api, goldilocksApi, qeAPI)
poseidonChip := NewGoldilocksChip(api)
output := poseidonChip.Poseidon(input) output := poseidonChip.Poseidon(input)
glApi := gl.NewChip(api)
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
api.AssertIsEqual(output[i], circuit.Out[i])
glApi.AssertIsEqual(output[i], gl.NewVariable(circuit.Out[i]))
} }
return nil return nil
@ -41,7 +40,7 @@ func TestPoseidonWitness(t *testing.T) {
testCase := func(in [12]frontend.Variable, out [12]frontend.Variable) { testCase := func(in [12]frontend.Variable, out [12]frontend.Variable) {
circuit := TestPoseidonCircuit{In: in, Out: out} circuit := TestPoseidonCircuit{In: in, Out: out}
witness := TestPoseidonCircuit{In: in, Out: out} witness := TestPoseidonCircuit{In: in, Out: out}
err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField())
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err) assert.NoError(err)
} }
@ -54,8 +53,8 @@ func TestPoseidonWitness(t *testing.T) {
} }
var in [12]frontend.Variable var in [12]frontend.Variable
var out [12]frontend.Variable var out [12]frontend.Variable
copy(in[:], utils.StrArrayToFrontendVariableArray(inStr))
copy(out[:], utils.StrArrayToFrontendVariableArray(outStr))
copy(in[:], gl.StrArrayToFrontendVariableArray(inStr))
copy(out[:], gl.StrArrayToFrontendVariableArray(outStr))
testCase(in, out) testCase(in, out)
} }
@ -69,18 +68,18 @@ func TestPoseidonProof(t *testing.T) {
} }
var in [12]frontend.Variable var in [12]frontend.Variable
var out [12]frontend.Variable var out [12]frontend.Variable
copy(in[:], utils.StrArrayToFrontendVariableArray(inStr))
copy(out[:], utils.StrArrayToFrontendVariableArray(outStr))
copy(in[:], gl.StrArrayToFrontendVariableArray(inStr))
copy(out[:], gl.StrArrayToFrontendVariableArray(outStr))
circuit := TestPoseidonCircuit{In: in, Out: out} circuit := TestPoseidonCircuit{In: in, Out: out}
assignment := TestPoseidonCircuit{In: in, Out: out} assignment := TestPoseidonCircuit{In: in, Out: out}
r1cs, err := frontend.Compile(field.TEST_CURVE.ScalarField(), r1cs.NewBuilder, &circuit)
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil { if err != nil {
panic(err) panic(err)
} }
witness, err := frontend.NewWitness(&assignment, field.TEST_CURVE.ScalarField())
witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -90,7 +89,7 @@ func TestPoseidonProof(t *testing.T) {
panic(err) panic(err)
} }
err = test.IsSolved(&circuit, &assignment, field.TEST_CURVE.ScalarField())
err = test.IsSolved(&circuit, &assignment, ecc.BN254.ScalarField())
if err != nil { if err != nil {
panic(err) panic(err)
} }

+ 0
- 338
poseidon/poseidon.go

@ -1,338 +0,0 @@
package poseidon
import (
"github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
)
const HALF_N_FULL_ROUNDS = 4
const N_PARTIAL_ROUNDS = 22
const MAX_WIDTH = 12
const SPONGE_WIDTH = 12
const SPONGE_RATE = 8
type PoseidonState = [SPONGE_WIDTH]frontend.Variable
type PoseidonStateExtension = [SPONGE_WIDTH]field.QuadraticExtension
type PoseidonHashOut = [4]field.F
type PoseidonChip struct {
api frontend.API `gnark:"-"`
fieldAPI field.FieldAPI `gnark:"-"`
qeAPI *field.QuadraticExtensionAPI `gnark:"-"`
}
func NewPoseidonChip(api frontend.API, fieldAPI field.FieldAPI, qeAPI *field.QuadraticExtensionAPI) *PoseidonChip {
return &PoseidonChip{api: api, fieldAPI: fieldAPI, qeAPI: qeAPI}
}
// The permutation function.
// The input state MUST have all it's elements be within Goldilocks field (e.g. this function will not reduce the input elements).
// The returned state's elements will all be within Goldilocks field.
func (c *PoseidonChip) Poseidon(input PoseidonState) PoseidonState {
state := input
roundCounter := 0
state = c.fullRounds(state, &roundCounter)
state = c.partialRounds(state, &roundCounter)
state = c.fullRounds(state, &roundCounter)
return state
}
// The input elements MUST have all it's elements be within Goldilocks field.
// The returned slice's elements will all be within Goldilocks field.
func (c *PoseidonChip) HashNToMNoPad(input []frontend.Variable, nbOutputs int) []frontend.Variable {
var state PoseidonState
for i := 0; i < SPONGE_WIDTH; i++ {
state[i] = frontend.Variable(0)
}
for i := 0; i < len(input); i += SPONGE_RATE {
for j := 0; j < SPONGE_RATE; j++ {
if i+j < len(input) {
state[j] = input[i+j]
}
}
state = c.Poseidon(state)
}
var outputs []frontend.Variable
for {
for i := 0; i < SPONGE_RATE; i++ {
outputs = append(outputs, state[i])
if len(outputs) == nbOutputs {
return outputs
}
}
state = c.Poseidon(state)
}
}
// The input elements can be outside of the Goldilocks field.
// The returned slice's elements will all be within Goldilocks field.
func (c *PoseidonChip) HashNoPad(input []field.F) PoseidonHashOut {
var hash PoseidonHashOut
inputVars := []frontend.Variable{}
for i := 0; i < len(input); i++ {
inputVars = append(inputVars, c.fieldAPI.Reduce(input[i]).Limbs[0])
}
outputVars := c.HashNToMNoPad(inputVars, 4)
for i := 0; i < 4; i++ {
hash[i] = c.fieldAPI.NewElement(outputVars[i])
}
return hash
}
func (c *PoseidonChip) ToVec(hash PoseidonHashOut) []field.F {
return hash[:]
}
func (c *PoseidonChip) fullRounds(state PoseidonState, roundCounter *int) PoseidonState {
for i := 0; i < HALF_N_FULL_ROUNDS; i++ {
state = c.constantLayer(state, roundCounter)
state = c.sBoxLayer(state)
state = c.mdsLayer(state)
*roundCounter += 1
}
return state
}
func (c *PoseidonChip) partialRounds(state PoseidonState, roundCounter *int) PoseidonState {
state = c.partialFirstConstantLayer(state)
state = c.mdsPartialLayerInit(state)
for i := 0; i < N_PARTIAL_ROUNDS; i++ {
state[0] = c.sBoxMonomial(state[0])
state[0] = field.GoldilocksMulAdd(c.api, frontend.Variable(1), state[0], FAST_PARTIAL_ROUND_CONSTANTS[i])
state = c.mdsPartialLayerFast(state, i)
}
*roundCounter += N_PARTIAL_ROUNDS
return state
}
func (c *PoseidonChip) constantLayer(state PoseidonState, roundCounter *int) PoseidonState {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
roundConstant := ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)]
state[i] = field.GoldilocksMulAdd(c.api, frontend.Variable(1), state[i], roundConstant)
}
}
return state
}
func (c *PoseidonChip) ConstantLayerExtension(state PoseidonStateExtension, roundCounter *int) PoseidonStateExtension {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
roundConstant := c.qeAPI.VarToQE(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)])
state[i] = c.qeAPI.AddExtension(state[i], roundConstant)
}
}
return state
}
func (c *PoseidonChip) sBoxMonomial(x frontend.Variable) frontend.Variable {
x2 := field.GoldilocksMulAdd(c.api, x, x, frontend.Variable(0))
x4 := field.GoldilocksMulAdd(c.api, x2, x2, frontend.Variable(0))
x6 := field.GoldilocksMulAdd(c.api, x4, x2, frontend.Variable(0))
return field.GoldilocksMulAdd(c.api, x6, x, frontend.Variable(0))
}
func (c *PoseidonChip) SBoxMonomialExtension(x field.QuadraticExtension) field.QuadraticExtension {
x2 := c.qeAPI.SquareExtension(x)
x4 := c.qeAPI.SquareExtension(x2)
x3 := c.qeAPI.MulExtension(x, x2)
return c.qeAPI.MulExtension(x3, x4)
}
func (c *PoseidonChip) sBoxLayer(state PoseidonState) PoseidonState {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
state[i] = c.sBoxMonomial(state[i])
}
}
return state
}
func (c *PoseidonChip) SBoxLayerExtension(state PoseidonStateExtension) PoseidonStateExtension {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
state[i] = c.SBoxMonomialExtension(state[i])
}
}
return state
}
func (c *PoseidonChip) mdsRowShf(r int, v [SPONGE_WIDTH]frontend.Variable) frontend.Variable {
res := ZERO_VAR
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
res = field.GoldilocksMulAdd(c.api, v[(i+r)%SPONGE_WIDTH], MDS_MATRIX_CIRC_VARS[i], res)
}
}
res = field.GoldilocksMulAdd(c.api, v[r], MDS_MATRIX_DIAG_VARS[r], res)
return res
}
func (c *PoseidonChip) MdsRowShfExtension(r int, v [SPONGE_WIDTH]field.QuadraticExtension) field.QuadraticExtension {
res := c.qeAPI.FieldToQE(field.ZERO_F)
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
matrixVal := c.qeAPI.VarToQE(MDS_MATRIX_CIRC[i])
res1 := c.qeAPI.MulExtension(v[(i+r)%SPONGE_WIDTH], matrixVal)
res = c.qeAPI.AddExtension(res, res1)
}
}
matrixVal := c.qeAPI.VarToQE(MDS_MATRIX_DIAG[r])
res = c.qeAPI.AddExtension(res, c.qeAPI.MulExtension(v[r], matrixVal))
return res
}
func (c *PoseidonChip) mdsLayer(state_ PoseidonState) PoseidonState {
var result PoseidonState
for i := 0; i < SPONGE_WIDTH; i++ {
result[i] = frontend.Variable(0)
}
for r := 0; r < 12; r++ {
if r < SPONGE_WIDTH {
result[r] = c.mdsRowShf(r, state_)
}
}
return result
}
func (c *PoseidonChip) MdsLayerExtension(state_ PoseidonStateExtension) PoseidonStateExtension {
var result PoseidonStateExtension
for r := 0; r < 12; r++ {
if r < SPONGE_WIDTH {
sum := c.MdsRowShfExtension(r, state_)
result[r] = sum
}
}
return result
}
func (c *PoseidonChip) partialFirstConstantLayer(state PoseidonState) PoseidonState {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
state[i] = field.GoldilocksMulAdd(c.api, frontend.Variable(1), state[i], FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])
}
}
return state
}
func (c *PoseidonChip) PartialFirstConstantLayerExtension(state PoseidonStateExtension) PoseidonStateExtension {
for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH {
state[i] = c.qeAPI.AddExtension(state[i], c.qeAPI.VarToQE((FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])))
}
}
return state
}
func (c *PoseidonChip) mdsPartialLayerInit(state PoseidonState) PoseidonState {
var result PoseidonState
for i := 0; i < 12; i++ {
result[i] = frontend.Variable(0)
}
result[0] = state[0]
for r := 1; r < 12; r++ {
if r < SPONGE_WIDTH {
for d := 1; d < 12; d++ {
if d < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1]
result[d] = field.GoldilocksMulAdd(c.api, state[r], t, result[d])
}
}
}
}
return result
}
func (c *PoseidonChip) MdsPartialLayerInitExtension(state PoseidonStateExtension) PoseidonStateExtension {
var result PoseidonStateExtension
for i := 0; i < 12; i++ {
result[i] = c.qeAPI.FieldToQE(field.ZERO_F)
}
result[0] = state[0]
for r := 1; r < 12; r++ {
if r < SPONGE_WIDTH {
for d := 1; d < 12; d++ {
if d < SPONGE_WIDTH {
t := c.qeAPI.VarToQE(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
result[d] = c.qeAPI.AddExtension(result[d], c.qeAPI.MulExtension(state[r], t))
}
}
}
}
return result
}
func (c *PoseidonChip) mdsPartialLayerFast(state PoseidonState, r int) PoseidonState {
dSum := ZERO_VAR
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_W_HATS_VARS[r][i-1]
dSum = field.GoldilocksMulAdd(c.api, state[i], t, dSum)
}
}
d := field.GoldilocksMulAdd(c.api, state[0], MDS0TO0_VAR, dSum)
var result PoseidonState
for i := 0; i < SPONGE_WIDTH; i++ {
result[i] = frontend.Variable(0)
}
result[0] = d
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_VS[r][i-1]
result[i] = field.GoldilocksMulAdd(c.api, state[0], t, state[i])
}
}
return result
}
func (c *PoseidonChip) MdsPartialLayerFastExtension(state PoseidonStateExtension, r int) PoseidonStateExtension {
s0 := state[0]
mds0to0 := c.qeAPI.VarToQE(MDS0TO0)
d := c.qeAPI.MulExtension(s0, mds0to0)
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := c.qeAPI.VarToQE(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
d = c.qeAPI.AddExtension(d, c.qeAPI.MulExtension(state[i], t))
}
}
var result PoseidonStateExtension
result[0] = d
for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH {
t := c.qeAPI.VarToQE(FAST_PARTIAL_ROUND_VS[r][i-1])
result[i] = c.qeAPI.AddExtension(c.qeAPI.MulExtension(state[0], t), state[i])
}
}
return result
}

+ 0
- 199
poseidon/poseidon_bn128.go

@ -1,199 +0,0 @@
package poseidon
import (
"math/big"
"github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
)
const fullRounds = 8
const partialRounds = 56
const spongeWidth = 4
const spongeRate = 3
type PoseidonBN128Chip struct {
api frontend.API `gnark:"-"`
fieldAPI field.FieldAPI `gnark:"-"`
}
type PoseidonBN128State = [spongeWidth]frontend.Variable
type PoseidonBN128HashOut = frontend.Variable
// This implementation is based on the following implementation:
// https://github.com/iden3/go-iden3-crypto/blob/e5cf066b8be3da9a3df9544c65818df189fdbebe/poseidon/poseidon.go
func NewPoseidonBN128Chip(api frontend.API, fieldAPI field.FieldAPI) *PoseidonBN128Chip {
return &PoseidonBN128Chip{api: api, fieldAPI: fieldAPI}
}
func (c *PoseidonBN128Chip) Poseidon(state PoseidonBN128State) PoseidonBN128State {
state = c.ark(state, 0)
state = c.fullRounds(state, true)
state = c.partialRounds(state)
state = c.fullRounds(state, false)
return state
}
func (c *PoseidonBN128Chip) HashNoPad(input []field.F) PoseidonBN128HashOut {
state := PoseidonBN128State{
frontend.Variable(0),
frontend.Variable(0),
frontend.Variable(0),
frontend.Variable(0),
}
for i := 0; i < len(input); i += spongeRate * 3 {
endI := c.min(len(input), i+spongeRate*3)
rateChunk := input[i:endI]
for j, stateIdx := 0, 0; j < len(rateChunk); j, stateIdx = j+3, stateIdx+1 {
endJ := c.min(len(rateChunk), j+3)
bn128Chunk := rateChunk[j:endJ]
bits := []frontend.Variable{}
for k := 0; k < len(bn128Chunk); k++ {
bn128Chunk[k] = c.fieldAPI.Reduce(bn128Chunk[k])
bits = append(bits, c.fieldAPI.ToBits(bn128Chunk[k])...)
}
state[stateIdx+1] = c.api.FromBinary(bits...)
}
state = c.Poseidon(state)
}
return PoseidonBN128HashOut(state[0])
}
func (c *PoseidonBN128Chip) HashOrNoop(input []field.F) PoseidonBN128HashOut {
if len(input) <= 3 {
returnVal := frontend.Variable(0)
alpha := new(big.Int).SetInt64(1 << 32)
for i, inputElement := range input {
returnVal = c.api.Add(returnVal, c.api.Mul(inputElement, alpha.Exp(alpha, big.NewInt(int64(i)), nil)))
}
return PoseidonBN128HashOut(returnVal)
} else {
return c.HashNoPad(input)
}
}
func (c *PoseidonBN128Chip) TwoToOne(left PoseidonBN128HashOut, right PoseidonBN128HashOut) PoseidonBN128HashOut {
var inputs PoseidonBN128State
inputs[0] = frontend.Variable(0)
inputs[1] = frontend.Variable(0)
inputs[2] = left
inputs[3] = right
state := c.Poseidon(inputs)
return state[0]
}
func (c *PoseidonBN128Chip) ToVec(hash PoseidonBN128HashOut) []field.F {
bits := c.api.ToBinary(hash)
returnElements := []field.F{}
// Split into 7 byte chunks, since 8 byte chunks can result in collisions
chunkSize := 56
for i := 0; i < len(bits); i += chunkSize {
maxIdx := c.min(len(bits), i+chunkSize)
bitChunk := bits[i:maxIdx]
returnElements = append(returnElements, c.fieldAPI.FromBits(bitChunk...))
}
return returnElements
}
func (c *PoseidonBN128Chip) min(x, y int) int {
if x < y {
return x
}
return y
}
func (c *PoseidonBN128Chip) fullRounds(state PoseidonBN128State, isFirst bool) PoseidonBN128State {
for i := 0; i < fullRounds/2-1; i++ {
state = c.exp5state(state)
if isFirst {
state = c.ark(state, (i+1)*spongeWidth)
} else {
state = c.ark(state, (fullRounds/2+1)*spongeWidth+partialRounds+i*spongeWidth)
}
state = c.mix(state, mMatrix)
}
state = c.exp5state(state)
if isFirst {
state = c.ark(state, (fullRounds/2)*spongeWidth)
state = c.mix(state, pMatrix)
} else {
state = c.mix(state, mMatrix)
}
return state
}
func (c *PoseidonBN128Chip) partialRounds(state PoseidonBN128State) PoseidonBN128State {
for i := 0; i < partialRounds; i++ {
state[0] = c.exp5(state[0])
state[0] = c.api.Add(state[0], cConstants[(fullRounds/2+1)*spongeWidth+i])
var mul frontend.Variable
newState0 := frontend.Variable(0)
for j := 0; j < spongeWidth; j++ {
mul = c.api.Mul(sConstants[(spongeWidth*2-1)*i+j], state[j])
newState0 = c.api.Add(newState0, mul)
}
for k := 1; k < spongeWidth; k++ {
mul = c.api.Mul(state[0], sConstants[(spongeWidth*2-1)*i+spongeWidth+k-1])
state[k] = c.api.Add(state[k], mul)
}
state[0] = newState0
}
return state
}
func (c *PoseidonBN128Chip) ark(state PoseidonBN128State, it int) PoseidonBN128State {
var result PoseidonBN128State
for i := 0; i < len(state); i++ {
result[i] = c.api.Add(state[i], cConstants[it+i])
}
return result
}
func (c *PoseidonBN128Chip) exp5(x frontend.Variable) frontend.Variable {
x2 := c.api.Mul(x, x)
x4 := c.api.Mul(x2, x2)
return c.api.Mul(x4, x)
}
func (c *PoseidonBN128Chip) exp5state(state PoseidonBN128State) PoseidonBN128State {
for i := 0; i < spongeWidth; i++ {
state[i] = c.exp5(state[i])
}
return state
}
func (c *PoseidonBN128Chip) mix(state_ PoseidonBN128State, constantMatrix [][]*big.Int) PoseidonBN128State {
var mul frontend.Variable
var result PoseidonBN128State
for i := 0; i < spongeWidth; i++ {
result[i] = frontend.Variable(0)
}
for i := 0; i < spongeWidth; i++ {
for j := 0; j < spongeWidth; j++ {
mul = c.api.Mul(constantMatrix[j][i], state_[j])
result[i] = c.api.Add(result[i], mul)
}
}
return result
}

+ 11
- 12
poseidon/public_inputs_hash_test.go

@ -7,8 +7,7 @@ import (
"github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test" "github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/utils"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
var testCurve = ecc.BN254 var testCurve = ecc.BN254
@ -19,22 +18,22 @@ type TestPublicInputsHashCircuit struct {
} }
func (circuit *TestPublicInputsHashCircuit) Define(api frontend.API) error { func (circuit *TestPublicInputsHashCircuit) Define(api frontend.API) error {
fieldAPI := field.NewFieldAPI(api)
glAPI := gl.NewChip(api)
// BN254 -> Binary(64) -> F // BN254 -> Binary(64) -> F
var input [3]field.F
var input [3]gl.Variable
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
input[i] = fieldAPI.FromBits(api.ToBinary(circuit.In[i], 64)...)
input[i] = gl.NewVariable(api.FromBinary(api.ToBinary(circuit.In[i], 64)...))
} }
poseidonChip := &PoseidonChip{api: api, fieldAPI: fieldAPI}
poseidonChip := &GoldilocksChip{api: api, gl: *glAPI}
output := poseidonChip.HashNoPad(input[:]) output := poseidonChip.HashNoPad(input[:])
// Check that output is correct // Check that output is correct
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
fieldAPI.AssertIsEqual(
glAPI.AssertIsEqual(
output[i], output[i],
fieldAPI.FromBits(api.ToBinary(circuit.Out[i])...),
gl.NewVariable(api.FromBinary(api.ToBinary(circuit.Out[i])...)),
) )
} }
@ -55,8 +54,8 @@ func TestPublicInputsHashWitness(t *testing.T) {
outStr := []string{"8416658900775745054", "12574228347150446423", "9629056739760131473", "3119289788404190010"} outStr := []string{"8416658900775745054", "12574228347150446423", "9629056739760131473", "3119289788404190010"}
var in [3]frontend.Variable var in [3]frontend.Variable
var out [4]frontend.Variable var out [4]frontend.Variable
copy(in[:], utils.StrArrayToFrontendVariableArray(inStr))
copy(out[:], utils.StrArrayToFrontendVariableArray(outStr))
copy(in[:], gl.StrArrayToFrontendVariableArray(inStr))
copy(out[:], gl.StrArrayToFrontendVariableArray(outStr))
testCase(in, out) testCase(in, out)
} }
@ -67,8 +66,8 @@ func TestPublicInputsHashWitness2(t *testing.T) {
outStr := []string{"8416658900775745054", "12574228347150446423", "9629056739760131473", "3119289788404190010"} outStr := []string{"8416658900775745054", "12574228347150446423", "9629056739760131473", "3119289788404190010"}
var in [3]frontend.Variable var in [3]frontend.Variable
var out [4]frontend.Variable var out [4]frontend.Variable
copy(in[:], utils.StrArrayToFrontendVariableArray(inStr))
copy(out[:], utils.StrArrayToFrontendVariableArray(outStr))
copy(in[:], gl.StrArrayToFrontendVariableArray(inStr))
copy(out[:], gl.StrArrayToFrontendVariableArray(outStr))
circuit := TestPublicInputsHashCircuit{In: in, Out: out} circuit := TestPublicInputsHashCircuit{In: in, Out: out}
witness := TestPublicInputsHashCircuit{In: in, Out: out} witness := TestPublicInputsHashCircuit{In: in, Out: out}

verifier/common/config.go → types/circuit.go

@ -1,14 +1,27 @@
package common
package types
import ( import (
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/gates"
) )
type Proof struct {
WiresCap FriMerkleCap // length = 2^CircuitConfig.FriConfig.CapHeight
PlonkZsPartialProductsCap FriMerkleCap // length = 2^CircuitConfig.FriConfig.CapHeight
QuotientPolysCap FriMerkleCap // length = 2^CircuitConfig.FriConfig.CapHeight
Openings OpeningSet
OpeningProof FriProof
}
type ProofWithPublicInputs struct {
Proof Proof
PublicInputs []gl.Variable // Length = CommonCircuitData.NumPublicInputs
}
type VerifierOnlyCircuitData struct { type VerifierOnlyCircuitData struct {
ConstantSigmasCap MerkleCap
CircuitDigest poseidon.PoseidonBN128HashOut
ConstantSigmasCap FriMerkleCap
CircuitDigest poseidon.BN254HashOut
} }
type CircuitConfig struct { type CircuitConfig struct {
@ -33,25 +46,6 @@ type CommonCircuitData struct {
NumGateConstraints uint64 NumGateConstraints uint64
NumConstants uint64 NumConstants uint64
NumPublicInputs uint64 NumPublicInputs uint64
KIs []field.F
KIs []gl.Variable
NumPartialProducts uint64 NumPartialProducts uint64
} }
type FriConfig struct {
RateBits uint64
CapHeight uint64
ProofOfWorkBits uint64
NumQueryRounds uint64
// TODO: add FriReductionStrategy
}
func (fc *FriConfig) Rate() float64 {
return 1.0 / float64((uint64(1) << fc.RateBits))
}
type FriParams struct {
Config FriConfig
Hiding bool
DegreeBits uint64
ReductionArityBits []uint64
}

+ 99
- 0
types/fri.go

@ -0,0 +1,99 @@
package types
import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
)
type PolynomialCoeffs struct {
Coeffs []gl.QuadraticExtensionVariable
}
func NewPolynomialCoeffs(numCoeffs uint64) PolynomialCoeffs {
return PolynomialCoeffs{Coeffs: make([]gl.QuadraticExtensionVariable, numCoeffs)}
}
type FriConfig struct {
RateBits uint64
CapHeight uint64
ProofOfWorkBits uint64
NumQueryRounds uint64
// TODO: add FriReductionStrategy
}
func (fc *FriConfig) Rate() float64 {
return 1.0 / float64((uint64(1) << fc.RateBits))
}
type FriParams struct {
Config FriConfig
Hiding bool
DegreeBits uint64
ReductionArityBits []uint64
}
type FriMerkleCap = []poseidon.BN254HashOut
func NewFriMerkleCap(capHeight uint64) FriMerkleCap {
return make([]poseidon.BN254HashOut, 1<<capHeight)
}
type FriMerkleProof struct {
Siblings []poseidon.BN254HashOut // Length = CircuitConfig.FriConfig.DegreeBits + CircuitConfig.FriConfig.RateBits - CircuitConfig.FriConfig.CapHeight
}
func NewFriMerkleProof(merkleProofLen uint64) FriMerkleProof {
return FriMerkleProof{Siblings: make([]poseidon.BN254HashOut, merkleProofLen)}
}
type FriEvalProof struct {
Elements []gl.Variable // Length = [CommonCircuitData.Constants + CommonCircuitData.NumRoutedWires, CommonCircuitData.NumWires + CommonCircuitData.FriParams.Hiding ? 4 : 0, CommonCircuitData.NumChallenges * (1 + CommonCircuitData.NumPartialProducts) + salt, CommonCircuitData.NumChallenges * CommonCircuitData.QuotientDegreeFactor + salt]
MerkleProof FriMerkleProof
}
func NewFriEvalProof(elements []gl.Variable, merkleProof FriMerkleProof) FriEvalProof {
return FriEvalProof{Elements: elements, MerkleProof: merkleProof}
}
type FriInitialTreeProof struct {
EvalsProofs []FriEvalProof // Length = 4
}
func NewFriInitialTreeProof(evalsProofs []FriEvalProof) FriInitialTreeProof {
return FriInitialTreeProof{EvalsProofs: evalsProofs}
}
type FriQueryStep struct {
Evals []gl.QuadraticExtensionVariable // Length = [2^arityBit for arityBit in CommonCircuitData.FriParams.ReductionArityBits]
MerkleProof FriMerkleProof // Length = [regularSize - arityBit for arityBit in CommonCircuitData.FriParams.ReductionArityBits]
}
func NewFriQueryStep(arityBit uint64, merkleProofLen uint64) FriQueryStep {
return FriQueryStep{
Evals: make([]gl.QuadraticExtensionVariable, 1<<arityBit),
MerkleProof: NewFriMerkleProof(merkleProofLen),
}
}
type FriQueryRound struct {
InitialTreesProof FriInitialTreeProof
Steps []FriQueryStep // Length = Len(CommonCircuitData.FriParams.ReductionArityBits)
}
func NewFriQueryRound(steps []FriQueryStep, initialTreesProof FriInitialTreeProof) FriQueryRound {
return FriQueryRound{InitialTreesProof: initialTreesProof, Steps: steps}
}
type FriProof struct {
CommitPhaseMerkleCaps []FriMerkleCap // Length = Len(CommonCircuitData.FriParams.ReductionArityBits)
QueryRoundProofs []FriQueryRound // Length = CommonCircuitData.FriConfig.FriParams.NumQueryRounds
FinalPoly PolynomialCoeffs
PowWitness gl.Variable
}
type FriChallenges struct {
FriAlpha gl.QuadraticExtensionVariable
FriBetas []gl.QuadraticExtensionVariable
FriPowResponse gl.Variable
FriQueryIndices []gl.Variable
}

+ 33
- 0
types/plonk.go

@ -0,0 +1,33 @@
package types
import gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
type OpeningSet struct {
Constants []gl.QuadraticExtensionVariable // Length = CommonCircuitData.Constants
PlonkSigmas []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumRoutedWires
Wires []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumWires
PlonkZs []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumChallenges
PlonkZsNext []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumChallenges
PartialProducts []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumChallenges * CommonCircuitData.NumPartialProducts
QuotientPolys []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumChallenges * CommonCircuitData.QuotientDegreeFactor
}
func NewOpeningSet(numConstants uint64, numRoutedWires uint64, numWires uint64, numChallenges uint64, numPartialProducts uint64, quotientDegreeFactor uint64) OpeningSet {
return OpeningSet{
Constants: make([]gl.QuadraticExtensionVariable, numConstants),
PlonkSigmas: make([]gl.QuadraticExtensionVariable, numRoutedWires),
Wires: make([]gl.QuadraticExtensionVariable, numWires),
PlonkZs: make([]gl.QuadraticExtensionVariable, numChallenges),
PlonkZsNext: make([]gl.QuadraticExtensionVariable, numChallenges),
PartialProducts: make([]gl.QuadraticExtensionVariable, numChallenges*numPartialProducts),
QuotientPolys: make([]gl.QuadraticExtensionVariable, numChallenges*quotientDegreeFactor),
}
}
type ProofChallenges struct {
PlonkBetas []gl.Variable
PlonkGammas []gl.Variable
PlonkAlphas []gl.Variable
PlonkZeta gl.QuadraticExtensionVariable
FriChallenges FriChallenges
}

+ 0
- 123
verifier/common/types.go

@ -1,123 +0,0 @@
package common
import (
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
)
type MerkleCap = []poseidon.PoseidonBN128HashOut
func NewMerkleCap(capHeight uint64) MerkleCap {
return make([]poseidon.PoseidonBN128HashOut, 1<<capHeight)
}
type MerkleProof struct {
Siblings []poseidon.PoseidonBN128HashOut // Length = CircuitConfig.FriConfig.DegreeBits + CircuitConfig.FriConfig.RateBits - CircuitConfig.FriConfig.CapHeight
}
func NewMerkleProof(merkleProofLen uint64) MerkleProof {
return MerkleProof{Siblings: make([]poseidon.PoseidonBN128HashOut, merkleProofLen)}
}
type EvalProof struct {
Elements []field.F // Length = [CommonCircuitData.Constants + CommonCircuitData.NumRoutedWires, CommonCircuitData.NumWires + CommonCircuitData.FriParams.Hiding ? 4 : 0, CommonCircuitData.NumChallenges * (1 + CommonCircuitData.NumPartialProducts) + salt, CommonCircuitData.NumChallenges * CommonCircuitData.QuotientDegreeFactor + salt]
MerkleProof MerkleProof
}
func NewEvalProof(elements []field.F, merkleProof MerkleProof) EvalProof {
return EvalProof{Elements: elements, MerkleProof: merkleProof}
}
type PolynomialCoeffs struct {
Coeffs []field.QuadraticExtension
}
func NewPolynomialCoeffs(numCoeffs uint64) PolynomialCoeffs {
return PolynomialCoeffs{Coeffs: make([]field.QuadraticExtension, numCoeffs)}
}
type OpeningSet struct {
Constants []field.QuadraticExtension // Length = CommonCircuitData.Constants
PlonkSigmas []field.QuadraticExtension // Length = CommonCircuitData.NumRoutedWires
Wires []field.QuadraticExtension // Length = CommonCircuitData.NumWires
PlonkZs []field.QuadraticExtension // Length = CommonCircuitData.NumChallenges
PlonkZsNext []field.QuadraticExtension // Length = CommonCircuitData.NumChallenges
PartialProducts []field.QuadraticExtension // Length = CommonCircuitData.NumChallenges * CommonCircuitData.NumPartialProducts
QuotientPolys []field.QuadraticExtension // Length = CommonCircuitData.NumChallenges * CommonCircuitData.QuotientDegreeFactor
}
func NewOpeningSet(numConstants uint64, numRoutedWires uint64, numWires uint64, numChallenges uint64, numPartialProducts uint64, quotientDegreeFactor uint64) OpeningSet {
return OpeningSet{
Constants: make([]field.QuadraticExtension, numConstants),
PlonkSigmas: make([]field.QuadraticExtension, numRoutedWires),
Wires: make([]field.QuadraticExtension, numWires),
PlonkZs: make([]field.QuadraticExtension, numChallenges),
PlonkZsNext: make([]field.QuadraticExtension, numChallenges),
PartialProducts: make([]field.QuadraticExtension, numChallenges*numPartialProducts),
QuotientPolys: make([]field.QuadraticExtension, numChallenges*quotientDegreeFactor),
}
}
type Proof struct {
WiresCap MerkleCap // length = 2^CircuitConfig.FriConfig.CapHeight
PlonkZsPartialProductsCap MerkleCap // length = 2^CircuitConfig.FriConfig.CapHeight
QuotientPolysCap MerkleCap // length = 2^CircuitConfig.FriConfig.CapHeight
Openings OpeningSet
OpeningProof FriProof
}
type ProofWithPublicInputs struct {
Proof Proof
PublicInputs []field.F // Length = CommonCircuitData.NumPublicInputs
}
type ProofChallenges struct {
PlonkBetas []field.F
PlonkGammas []field.F
PlonkAlphas []field.F
PlonkZeta field.QuadraticExtension
FriChallenges FriChallenges
}
type FriInitialTreeProof struct {
EvalsProofs []EvalProof // Length = 4
}
func NewFriInitialTreeProof(evalsProofs []EvalProof) FriInitialTreeProof {
return FriInitialTreeProof{EvalsProofs: evalsProofs}
}
type FriQueryStep struct {
Evals []field.QuadraticExtension // Length = [2^arityBit for arityBit in CommonCircuitData.FriParams.ReductionArityBits]
MerkleProof MerkleProof // Length = [regularSize - arityBit for arityBit in CommonCircuitData.FriParams.ReductionArityBits]
}
func NewFriQueryStep(arityBit uint64, merkleProofLen uint64) FriQueryStep {
return FriQueryStep{
Evals: make([]field.QuadraticExtension, 1<<arityBit),
MerkleProof: NewMerkleProof(merkleProofLen),
}
}
type FriQueryRound struct {
InitialTreesProof FriInitialTreeProof
Steps []FriQueryStep // Length = Len(CommonCircuitData.FriParams.ReductionArityBits)
}
func NewFriQueryRound(steps []FriQueryStep, initialTreesProof FriInitialTreeProof) FriQueryRound {
return FriQueryRound{InitialTreesProof: initialTreesProof, Steps: steps}
}
type FriProof struct {
CommitPhaseMerkleCaps []MerkleCap // Length = Len(CommonCircuitData.FriParams.ReductionArityBits)
QueryRoundProofs []FriQueryRound // Length = CommonCircuitData.FriConfig.FriParams.NumQueryRounds
FinalPoly PolynomialCoeffs
PowWitness field.F
}
type FriChallenges struct {
FriAlpha field.QuadraticExtension
FriBetas []field.QuadraticExtension
FriPowResponse field.F
FriQueryIndices []field.F
}

verifier/utils/deserialize.go → verifier/deserialize.go

@ -1,4 +1,4 @@
package utils
package verifier
import ( import (
"encoding/json" "encoding/json"
@ -7,11 +7,10 @@ import (
"os" "os"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/utils"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
) )
type ProofWithPublicInputsRaw struct { type ProofWithPublicInputsRaw struct {
@ -147,9 +146,9 @@ type VerifierOnlyCircuitDataRaw struct {
CircuitDigest string `json:"circuit_digest"` CircuitDigest string `json:"circuit_digest"`
} }
func DeserializeMerkleCap(merkleCapRaw []string) common.MerkleCap {
func DeserializeMerkleCap(merkleCapRaw []string) types.FriMerkleCap {
n := len(merkleCapRaw) n := len(merkleCapRaw)
merkleCap := make([]poseidon.PoseidonBN128HashOut, n)
merkleCap := make([]poseidon.BN254HashOut, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
capBigInt, _ := new(big.Int).SetString(merkleCapRaw[i], 10) capBigInt, _ := new(big.Int).SetString(merkleCapRaw[i], 10)
merkleCap[i] = frontend.Variable(capBigInt) merkleCap[i] = frontend.Variable(capBigInt)
@ -157,13 +156,13 @@ func DeserializeMerkleCap(merkleCapRaw []string) common.MerkleCap {
return merkleCap return merkleCap
} }
func DeserializeMerkleProof(merkleProofRaw struct{ Siblings []interface{} }) common.MerkleProof {
func DeserializeMerkleProof(merkleProofRaw struct{ Siblings []interface{} }) types.FriMerkleProof {
n := len(merkleProofRaw.Siblings) n := len(merkleProofRaw.Siblings)
var mp common.MerkleProof
mp.Siblings = make([]poseidon.PoseidonBN128HashOut, n)
var mp types.FriMerkleProof
mp.Siblings = make([]poseidon.BN254HashOut, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
element := merkleProofRaw.Siblings[i].(struct{ Elements []uint64 }) element := merkleProofRaw.Siblings[i].(struct{ Elements []uint64 })
mp.Siblings[i] = utils.Uint64ArrayToFArray(element.Elements)
mp.Siblings[i] = gl.Uint64ArrayToVariableArray(element.Elements)
} }
return mp return mp
} }
@ -176,25 +175,25 @@ func DeserializeOpeningSet(openingSetRaw struct {
PlonkZsNext [][]uint64 PlonkZsNext [][]uint64
PartialProducts [][]uint64 PartialProducts [][]uint64
QuotientPolys [][]uint64 QuotientPolys [][]uint64
}) common.OpeningSet {
return common.OpeningSet{
Constants: utils.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Constants),
PlonkSigmas: utils.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkSigmas),
Wires: utils.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Wires),
PlonkZs: utils.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZs),
PlonkZsNext: utils.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZsNext),
PartialProducts: utils.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PartialProducts),
QuotientPolys: utils.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.QuotientPolys),
}) types.OpeningSet {
return types.OpeningSet{
Constants: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Constants),
PlonkSigmas: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkSigmas),
Wires: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.Wires),
PlonkZs: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZs),
PlonkZsNext: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PlonkZsNext),
PartialProducts: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.PartialProducts),
QuotientPolys: gl.Uint64ArrayToQuadraticExtensionArray(openingSetRaw.QuotientPolys),
} }
} }
func StringArrayToHashBN128Array(rawHashes []string) []poseidon.PoseidonBN128HashOut {
hashes := []poseidon.PoseidonBN128HashOut{}
func StringArrayToHashBN254Array(rawHashes []string) []poseidon.BN254HashOut {
hashes := []poseidon.BN254HashOut{}
for i := 0; i < len(rawHashes); i++ { for i := 0; i < len(rawHashes); i++ {
hashBigInt, _ := new(big.Int).SetString(rawHashes[i], 10) hashBigInt, _ := new(big.Int).SetString(rawHashes[i], 10)
hashVar := frontend.Variable(hashBigInt) hashVar := frontend.Variable(hashBigInt)
hashes = append(hashes, poseidon.PoseidonBN128HashOut(hashVar))
hashes = append(hashes, poseidon.BN254HashOut(hashVar))
} }
return hashes return hashes
@ -217,39 +216,39 @@ func DeserializeFriProof(openingProofRaw struct {
Coeffs [][]uint64 Coeffs [][]uint64
} }
PowWitness uint64 PowWitness uint64
}) common.FriProof {
var openingProof common.FriProof
openingProof.PowWitness = field.NewFieldConst(openingProofRaw.PowWitness)
openingProof.FinalPoly.Coeffs = utils.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.FinalPoly.Coeffs)
}) types.FriProof {
var openingProof types.FriProof
openingProof.PowWitness = gl.NewVariable(openingProofRaw.PowWitness)
openingProof.FinalPoly.Coeffs = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.FinalPoly.Coeffs)
openingProof.CommitPhaseMerkleCaps = make([]common.MerkleCap, len(openingProofRaw.CommitPhaseMerkleCaps))
openingProof.CommitPhaseMerkleCaps = make([]types.FriMerkleCap, len(openingProofRaw.CommitPhaseMerkleCaps))
for i := 0; i < len(openingProofRaw.CommitPhaseMerkleCaps); i++ { for i := 0; i < len(openingProofRaw.CommitPhaseMerkleCaps); i++ {
openingProof.CommitPhaseMerkleCaps[i] = StringArrayToHashBN128Array(openingProofRaw.CommitPhaseMerkleCaps[i])
openingProof.CommitPhaseMerkleCaps[i] = StringArrayToHashBN254Array(openingProofRaw.CommitPhaseMerkleCaps[i])
} }
numQueryRoundProofs := len(openingProofRaw.QueryRoundProofs) numQueryRoundProofs := len(openingProofRaw.QueryRoundProofs)
openingProof.QueryRoundProofs = make([]common.FriQueryRound, numQueryRoundProofs)
openingProof.QueryRoundProofs = make([]types.FriQueryRound, numQueryRoundProofs)
for i := 0; i < numQueryRoundProofs; i++ { for i := 0; i < numQueryRoundProofs; i++ {
numEvalProofs := len(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs) numEvalProofs := len(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs = make([]common.EvalProof, numEvalProofs)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs = make([]types.FriEvalProof, numEvalProofs)
for j := 0; j < numEvalProofs; j++ { for j := 0; j < numEvalProofs; j++ {
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].Elements = utils.Uint64ArrayToFArray(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].LeafElements)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Siblings = StringArrayToHashBN128Array(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Hash)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].Elements = gl.Uint64ArrayToVariableArray(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].LeafElements)
openingProof.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].InitialTreesProof.EvalsProofs[j].MerkleProof.Hash)
} }
numSteps := len(openingProofRaw.QueryRoundProofs[i].Steps) numSteps := len(openingProofRaw.QueryRoundProofs[i].Steps)
openingProof.QueryRoundProofs[i].Steps = make([]common.FriQueryStep, numSteps)
openingProof.QueryRoundProofs[i].Steps = make([]types.FriQueryStep, numSteps)
for j := 0; j < numSteps; j++ { for j := 0; j < numSteps; j++ {
openingProof.QueryRoundProofs[i].Steps[j].Evals = utils.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.QueryRoundProofs[i].Steps[j].Evals)
openingProof.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings = StringArrayToHashBN128Array(openingProofRaw.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings)
openingProof.QueryRoundProofs[i].Steps[j].Evals = gl.Uint64ArrayToQuadraticExtensionArray(openingProofRaw.QueryRoundProofs[i].Steps[j].Evals)
openingProof.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings = StringArrayToHashBN254Array(openingProofRaw.QueryRoundProofs[i].Steps[j].MerkleProof.Siblings)
} }
} }
return openingProof return openingProof
} }
func DeserializeProofWithPublicInputs(path string) common.ProofWithPublicInputs {
func DeserializeProofWithPublicInputs(path string) types.ProofWithPublicInputs {
jsonFile, err := os.Open(path) jsonFile, err := os.Open(path)
if err != nil { if err != nil {
panic(err) panic(err)
@ -264,7 +263,7 @@ func DeserializeProofWithPublicInputs(path string) common.ProofWithPublicInputs
panic(err) panic(err)
} }
var proofWithPis common.ProofWithPublicInputs
var proofWithPis types.ProofWithPublicInputs
proofWithPis.Proof.WiresCap = DeserializeMerkleCap(raw.Proof.WiresCap) proofWithPis.Proof.WiresCap = DeserializeMerkleCap(raw.Proof.WiresCap)
proofWithPis.Proof.PlonkZsPartialProductsCap = DeserializeMerkleCap(raw.Proof.PlonkZsPartialProductsCap) proofWithPis.Proof.PlonkZsPartialProductsCap = DeserializeMerkleCap(raw.Proof.PlonkZsPartialProductsCap)
proofWithPis.Proof.QuotientPolysCap = DeserializeMerkleCap(raw.Proof.QuotientPolysCap) proofWithPis.Proof.QuotientPolysCap = DeserializeMerkleCap(raw.Proof.QuotientPolysCap)
@ -293,12 +292,12 @@ func DeserializeProofWithPublicInputs(path string) common.ProofWithPublicInputs
FinalPoly struct{ Coeffs [][]uint64 } FinalPoly struct{ Coeffs [][]uint64 }
PowWitness uint64 PowWitness uint64
}(raw.Proof.OpeningProof)) }(raw.Proof.OpeningProof))
proofWithPis.PublicInputs = utils.Uint64ArrayToFArray(raw.PublicInputs)
proofWithPis.PublicInputs = gl.Uint64ArrayToVariableArray(raw.PublicInputs)
return proofWithPis return proofWithPis
} }
func DeserializeProofChallenges(path string) common.ProofChallenges {
func DeserializeProofChallenges(path string) types.ProofChallenges {
jsonFile, err := os.Open(path) jsonFile, err := os.Open(path)
if err != nil { if err != nil {
panic(err) panic(err)
@ -313,15 +312,15 @@ func DeserializeProofChallenges(path string) common.ProofChallenges {
panic(err) panic(err)
} }
var proofChallenges common.ProofChallenges
proofChallenges.PlonkBetas = utils.Uint64ArrayToFArray(raw.PlonkBetas)
proofChallenges.PlonkGammas = utils.Uint64ArrayToFArray(raw.PlonkGammas)
proofChallenges.PlonkAlphas = utils.Uint64ArrayToFArray(raw.PlonkAlphas)
proofChallenges.PlonkZeta = utils.Uint64ArrayToQuadraticExtension(raw.PlonkZeta)
proofChallenges.FriChallenges.FriAlpha = utils.Uint64ArrayToQuadraticExtension(raw.FriChallenges.FriAlpha)
proofChallenges.FriChallenges.FriBetas = utils.Uint64ArrayToQuadraticExtensionArray(raw.FriChallenges.FriBetas)
proofChallenges.FriChallenges.FriPowResponse = field.NewFieldConst(raw.FriChallenges.FriPowResponse)
proofChallenges.FriChallenges.FriQueryIndices = utils.Uint64ArrayToFArray(raw.FriChallenges.FriQueryIndices)
var proofChallenges types.ProofChallenges
proofChallenges.PlonkBetas = gl.Uint64ArrayToVariableArray(raw.PlonkBetas)
proofChallenges.PlonkGammas = gl.Uint64ArrayToVariableArray(raw.PlonkGammas)
proofChallenges.PlonkAlphas = gl.Uint64ArrayToVariableArray(raw.PlonkAlphas)
proofChallenges.PlonkZeta = gl.Uint64ArrayToQuadraticExtension(raw.PlonkZeta)
proofChallenges.FriChallenges.FriAlpha = gl.Uint64ArrayToQuadraticExtension(raw.FriChallenges.FriAlpha)
proofChallenges.FriChallenges.FriBetas = gl.Uint64ArrayToQuadraticExtensionArray(raw.FriChallenges.FriBetas)
proofChallenges.FriChallenges.FriPowResponse = gl.NewVariable(raw.FriChallenges.FriPowResponse)
proofChallenges.FriChallenges.FriQueryIndices = gl.Uint64ArrayToVariableArray(raw.FriChallenges.FriQueryIndices)
return proofChallenges return proofChallenges
} }
@ -346,7 +345,7 @@ func ReductionArityBits(
return returnArr return returnArr
} }
func DeserializeCommonCircuitData(path string) common.CommonCircuitData {
func DeserializeCommonCircuitData(path string) types.CommonCircuitData {
jsonFile, err := os.Open(path) jsonFile, err := os.Open(path)
if err != nil { if err != nil {
panic(err) panic(err)
@ -361,7 +360,7 @@ func DeserializeCommonCircuitData(path string) common.CommonCircuitData {
panic(err) panic(err)
} }
var commonCircuitData common.CommonCircuitData
var commonCircuitData types.CommonCircuitData
commonCircuitData.Config.NumWires = raw.Config.NumWires commonCircuitData.Config.NumWires = raw.Config.NumWires
commonCircuitData.Config.NumRoutedWires = raw.Config.NumRoutedWires commonCircuitData.Config.NumRoutedWires = raw.Config.NumRoutedWires
commonCircuitData.Config.NumConstants = raw.Config.NumConstants commonCircuitData.Config.NumConstants = raw.Config.NumConstants
@ -406,13 +405,13 @@ func DeserializeCommonCircuitData(path string) common.CommonCircuitData {
commonCircuitData.NumGateConstraints = raw.NumGateConstraints commonCircuitData.NumGateConstraints = raw.NumGateConstraints
commonCircuitData.NumConstants = raw.NumConstants commonCircuitData.NumConstants = raw.NumConstants
commonCircuitData.NumPublicInputs = raw.NumPublicInputs commonCircuitData.NumPublicInputs = raw.NumPublicInputs
commonCircuitData.KIs = utils.Uint64ArrayToFArray(raw.KIs)
commonCircuitData.KIs = gl.Uint64ArrayToVariableArray(raw.KIs)
commonCircuitData.NumPartialProducts = raw.NumPartialProducts commonCircuitData.NumPartialProducts = raw.NumPartialProducts
return commonCircuitData return commonCircuitData
} }
func DeserializeVerifierOnlyCircuitData(path string) common.VerifierOnlyCircuitData {
func DeserializeVerifierOnlyCircuitData(path string) types.VerifierOnlyCircuitData {
jsonFile, err := os.Open(path) jsonFile, err := os.Open(path)
if err != nil { if err != nil {
panic(err) panic(err)
@ -427,10 +426,10 @@ func DeserializeVerifierOnlyCircuitData(path string) common.VerifierOnlyCircuitD
panic(err) panic(err)
} }
var verifierOnlyCircuitData common.VerifierOnlyCircuitData
var verifierOnlyCircuitData types.VerifierOnlyCircuitData
verifierOnlyCircuitData.ConstantSigmasCap = DeserializeMerkleCap(raw.ConstantsSigmasCap) verifierOnlyCircuitData.ConstantSigmasCap = DeserializeMerkleCap(raw.ConstantsSigmasCap)
circuitDigestBigInt, _ := new(big.Int).SetString(raw.CircuitDigest, 10) circuitDigestBigInt, _ := new(big.Int).SetString(raw.CircuitDigest, 10)
circuitDigestVar := frontend.Variable(circuitDigestBigInt) circuitDigestVar := frontend.Variable(circuitDigestBigInt)
verifierOnlyCircuitData.CircuitDigest = poseidon.PoseidonBN128HashOut(circuitDigestVar)
verifierOnlyCircuitData.CircuitDigest = poseidon.BN254HashOut(circuitDigestVar)
return verifierOnlyCircuitData return verifierOnlyCircuitData
} }

verifier/utils/deserialize_test.go → verifier/deserialize_test.go

@ -1,4 +1,4 @@
package utils
package verifier
import ( import (
"fmt" "fmt"

+ 0
- 124
verifier/internal/fri/fri_test.go

@ -1,124 +0,0 @@
package fri_test
import (
"testing"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/fri"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/plonk"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils"
)
type TestFriCircuit struct {
proofWithPIsFilename string `gnark:"-"`
commonCircuitDataFilename string `gnark:"-"`
verifierOnlyCircuitDataFilename string `gnark:"-"`
}
func (circuit *TestFriCircuit) Define(api frontend.API) error {
proofWithPis := utils.DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
commonCircuitData := utils.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
verifierOnlyCircuitData := utils.DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
fieldAPI := field.NewFieldAPI(api)
qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI)
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
poseidonBN128Chip := poseidon.NewPoseidonBN128Chip(api, fieldAPI)
friChip := fri.NewFriChip(api, fieldAPI, qeAPI, poseidonBN128Chip, &commonCircuitData.FriParams)
challengerChip := plonk.NewChallengerChip(api, fieldAPI, poseidonChip, poseidonBN128Chip)
challengerChip.ObserveBN128Hash(verifierOnlyCircuitData.CircuitDigest)
challengerChip.ObserveHash(poseidonChip.HashNoPad(proofWithPis.PublicInputs))
challengerChip.ObserveCap(proofWithPis.Proof.WiresCap)
plonkBetas := challengerChip.GetNChallenges(commonCircuitData.Config.NumChallenges) // For plonk betas
fieldAPI.AssertIsEqual(plonkBetas[0], field.NewFieldConst(17615363392879944733))
plonkGammas := challengerChip.GetNChallenges(commonCircuitData.Config.NumChallenges) // For plonk gammas
fieldAPI.AssertIsEqual(plonkGammas[0], field.NewFieldConst(15174493176564484303))
challengerChip.ObserveCap(proofWithPis.Proof.PlonkZsPartialProductsCap)
plonkAlphas := challengerChip.GetNChallenges(commonCircuitData.Config.NumChallenges) // For plonk alphas
fieldAPI.AssertIsEqual(plonkAlphas[0], field.NewFieldConst(9276470834414745550))
challengerChip.ObserveCap(proofWithPis.Proof.QuotientPolysCap)
plonkZeta := challengerChip.GetExtensionChallenge()
fieldAPI.AssertIsEqual(plonkZeta[0], field.NewFieldConst(3892795992421241388))
challengerChip.ObserveOpenings(fri.ToFriOpenings(proofWithPis.Proof.Openings))
friChallenges := challengerChip.GetFriChallenges(
proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
proofWithPis.Proof.OpeningProof.FinalPoly,
proofWithPis.Proof.OpeningProof.PowWitness,
commonCircuitData.DegreeBits,
commonCircuitData.Config.FriConfig,
)
fieldAPI.AssertIsEqual(friChallenges.FriAlpha[0], field.NewFieldConst(885535811531859621))
fieldAPI.AssertIsEqual(friChallenges.FriBetas[0][0], field.NewFieldConst(5231781384587895507))
fieldAPI.AssertIsEqual(friChallenges.FriPowResponse, field.NewFieldConst(70715523064019))
fieldAPI.AssertIsEqual(friChallenges.FriQueryIndices[0], field.NewFieldConst(11890500485816111017))
initialMerkleCaps := []common.MerkleCap{
verifierOnlyCircuitData.ConstantSigmasCap,
proofWithPis.Proof.WiresCap,
proofWithPis.Proof.PlonkZsPartialProductsCap,
proofWithPis.Proof.QuotientPolysCap,
}
// Seems like there is a bug in the emulated field code.
// Add ZERO to all of the fri challenges values to reduce them.
plonkZeta[0] = fieldAPI.Add(plonkZeta[0], field.ZERO_F)
plonkZeta[1] = fieldAPI.Add(plonkZeta[1], field.ZERO_F)
friChallenges.FriAlpha[0] = fieldAPI.Add(friChallenges.FriAlpha[0], field.ZERO_F)
friChallenges.FriAlpha[1] = fieldAPI.Add(friChallenges.FriAlpha[1], field.ZERO_F)
for i := 0; i < len(friChallenges.FriBetas); i++ {
friChallenges.FriBetas[i][0] = fieldAPI.Add(friChallenges.FriBetas[i][0], field.ZERO_F)
friChallenges.FriBetas[i][1] = fieldAPI.Add(friChallenges.FriBetas[i][1], field.ZERO_F)
}
friChallenges.FriPowResponse = fieldAPI.Add(friChallenges.FriPowResponse, field.ZERO_F)
for i := 0; i < len(friChallenges.FriQueryIndices); i++ {
friChallenges.FriQueryIndices[i] = fieldAPI.Add(friChallenges.FriQueryIndices[i], field.ZERO_F)
}
friChip.VerifyFriProof(
fri.GetFriInstance(&commonCircuitData, qeAPI, plonkZeta, commonCircuitData.DegreeBits),
fri.ToFriOpenings(proofWithPis.Proof.Openings),
&friChallenges,
initialMerkleCaps,
&proofWithPis.Proof.OpeningProof,
)
return nil
}
func TestDecodeBlockFriVerification(t *testing.T) {
assert := test.NewAssert(t)
testCase := func() {
circuit := TestFriCircuit{
proofWithPIsFilename: "../../data/decode_block/proof_with_public_inputs.json",
commonCircuitDataFilename: "../../data/decode_block//common_circuit_data.json",
verifierOnlyCircuitDataFilename: "../../data/decode_block//verifier_only_circuit_data.json",
}
witness := TestFriCircuit{
proofWithPIsFilename: "../../data/dummy_2^14_gates/proof_with_public_inputs.json",
commonCircuitDataFilename: "../../data/dummy_2^14_gates/common_circuit_data.json",
verifierOnlyCircuitDataFilename: ".../../data/dummy_2^14_gates/verifier_only_circuit_data.json",
}
err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField())
assert.NoError(err)
}
testCase()
}

+ 0
- 763
verifier/internal/gates/gate_test.go

@ -1,763 +0,0 @@
package gates_test
import (
"errors"
"testing"
"github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/gates"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils"
)
// From recursive_step circuit
var localConstants = []field.QuadraticExtension{
{field.NewFieldConst(4962976205186800892), field.NewFieldConst(6982360466972099197)},
{field.NewFieldConst(3587364333101709084), field.NewFieldConst(17496916837371484700)},
{field.NewFieldConst(17287374881609559799), field.NewFieldConst(3152841633956965234)},
{field.NewFieldConst(8531030241248616826), field.NewFieldConst(7753678118587211959)},
{field.NewFieldConst(7622109056373824903), field.NewFieldConst(6523636236475969621)},
}
var localWires = []field.QuadraticExtension{
{field.NewFieldConst(5101665081776077058), field.NewFieldConst(13601771238484783081)},
{field.NewFieldConst(13763997788502656587), field.NewFieldConst(6068443864169526207)},
{field.NewFieldConst(10492880302699453810), field.NewFieldConst(11304418575668616669)},
{field.NewFieldConst(2175168501339052813), field.NewFieldConst(3658211467579027796)},
{field.NewFieldConst(11342710587435471757), field.NewFieldConst(658078906333318768)},
{field.NewFieldConst(16590262768413671742), field.NewFieldConst(4678191900868819358)},
{field.NewFieldConst(18412513594273328173), field.NewFieldConst(3981245463942959904)},
{field.NewFieldConst(18150166316938544267), field.NewFieldConst(6968565044901838140)},
{field.NewFieldConst(1048835939602984673), field.NewFieldConst(3511920575130606798)},
{field.NewFieldConst(13693300152826538654), field.NewFieldConst(5872314861500881782)},
{field.NewFieldConst(6394696263219721312), field.NewFieldConst(92364988976021720)},
{field.NewFieldConst(468193345380249942), field.NewFieldConst(4951036536117371576)},
{field.NewFieldConst(9660006729985637684), field.NewFieldConst(14762789799642492635)},
{field.NewFieldConst(10091149087332313493), field.NewFieldConst(13279468039286967053)},
{field.NewFieldConst(12007469191150580744), field.NewFieldConst(2495445179052731885)},
{field.NewFieldConst(14225726459587943147), field.NewFieldConst(13484648741862607201)},
{field.NewFieldConst(15365400400136175672), field.NewFieldConst(12227857303059870833)},
{field.NewFieldConst(1717742269682481687), field.NewFieldConst(14319701537357602192)},
{field.NewFieldConst(2130805637557027375), field.NewFieldConst(9674794597783493233)},
{field.NewFieldConst(4200526016516623452), field.NewFieldConst(1757832412907480092)},
{field.NewFieldConst(4159226258922372229), field.NewFieldConst(2121976810680943769)},
{field.NewFieldConst(2887943290582259162), field.NewFieldConst(10337505797799617185)},
{field.NewFieldConst(14760843822980496189), field.NewFieldConst(16331301823872182680)},
{field.NewFieldConst(14715580754822129725), field.NewFieldConst(13761736659446638375)},
{field.NewFieldConst(6925818640561435525), field.NewFieldConst(14142327999826777974)},
{field.NewFieldConst(14048060513252076245), field.NewFieldConst(14860933194240516940)},
{field.NewFieldConst(3928889853630846436), field.NewFieldConst(16211791673476822740)},
{field.NewFieldConst(15980387576926781891), field.NewFieldConst(6238947314711778055)},
{field.NewFieldConst(15694939331980119296), field.NewFieldConst(8708301222382733590)},
{field.NewFieldConst(192757930858294268), field.NewFieldConst(5400388905722847256)},
{field.NewFieldConst(17614358883814855964), field.NewFieldConst(11499208634388453518)},
{field.NewFieldConst(9523994443422431577), field.NewFieldConst(6835394446482946098)},
{field.NewFieldConst(10096606893378243201), field.NewFieldConst(8982086840326369907)},
{field.NewFieldConst(7328922720001507777), field.NewFieldConst(17298728994563323488)},
{field.NewFieldConst(7038859554184407337), field.NewFieldConst(6498153778103681368)},
{field.NewFieldConst(10610651604960433540), field.NewFieldConst(18240735600936975661)},
{field.NewFieldConst(4310901749476028644), field.NewFieldConst(17813866938235850894)},
{field.NewFieldConst(12456949458361594924), field.NewFieldConst(16541357680870686003)},
{field.NewFieldConst(13986559680062429806), field.NewFieldConst(14210541290696888125)},
{field.NewFieldConst(10299578396192380820), field.NewFieldConst(18011235767871391546)},
{field.NewFieldConst(747566550336808782), field.NewFieldConst(5892109075601553099)},
{field.NewFieldConst(11613383633841665100), field.NewFieldConst(3562006923196410047)},
{field.NewFieldConst(14971867523312360339), field.NewFieldConst(9835080574905235511)},
{field.NewFieldConst(5487884847548072736), field.NewFieldConst(17112808386797082519)},
{field.NewFieldConst(1687420180518659740), field.NewFieldConst(14003627304711288225)},
{field.NewFieldConst(6760442482244819429), field.NewFieldConst(15796493945480647537)},
{field.NewFieldConst(2639939427088481105), field.NewFieldConst(16213109089273184951)},
{field.NewFieldConst(6186345082501710713), field.NewFieldConst(2529053005908871239)},
{field.NewFieldConst(16270115914931256348), field.NewFieldConst(2789355919627681645)},
{field.NewFieldConst(4586999018177783314), field.NewFieldConst(2427837399215959725)},
{field.NewFieldConst(18143358622388343317), field.NewFieldConst(2145167333845152043)},
{field.NewFieldConst(20367062449222124), field.NewFieldConst(14939961527015734373)},
{field.NewFieldConst(16851694158642043266), field.NewFieldConst(5250789952541240163)},
{field.NewFieldConst(273375074794411822), field.NewFieldConst(16211897175907793903)},
{field.NewFieldConst(8905927930385832568), field.NewFieldConst(6540262589846603524)},
{field.NewFieldConst(9283781971254844102), field.NewFieldConst(15115068064900745758)},
{field.NewFieldConst(16002987404851668189), field.NewFieldConst(15226686847545140008)},
{field.NewFieldConst(17201679792194997813), field.NewFieldConst(589849108691638964)},
{field.NewFieldConst(13270753269614250355), field.NewFieldConst(13858862497673084592)},
{field.NewFieldConst(3679908279346826560), field.NewFieldConst(10125726541855725943)},
{field.NewFieldConst(9493227554592600240), field.NewFieldConst(13229107531594530196)},
{field.NewFieldConst(10072423214517113799), field.NewFieldConst(1877804054697703518)},
{field.NewFieldConst(9351494680554520560), field.NewFieldConst(12930187723253788505)},
{field.NewFieldConst(9537056082833040850), field.NewFieldConst(3947445714701039423)},
{field.NewFieldConst(978662253133020143), field.NewFieldConst(17432233037279205717)},
{field.NewFieldConst(13408331971471826902), field.NewFieldConst(8338873650278204671)},
{field.NewFieldConst(10455530172494355126), field.NewFieldConst(14614842120953588617)},
{field.NewFieldConst(3066054670984065145), field.NewFieldConst(11061840675948823020)},
{field.NewFieldConst(1215442291812236170), field.NewFieldConst(6970679356502977963)},
{field.NewFieldConst(16254140688845356393), field.NewFieldConst(16413217415268481315)},
{field.NewFieldConst(5571707217813279614), field.NewFieldConst(2506082641312169038)},
{field.NewFieldConst(18179591596294163519), field.NewFieldConst(16131760445397495720)},
{field.NewFieldConst(9500821197677833979), field.NewFieldConst(14137570623214003877)},
{field.NewFieldConst(18159279414894480072), field.NewFieldConst(316120438770524969)},
{field.NewFieldConst(18164288455905080997), field.NewFieldConst(12889510574086616078)},
{field.NewFieldConst(7158952489901063870), field.NewFieldConst(8855957421923524202)},
{field.NewFieldConst(11785615172910130564), field.NewFieldConst(13242859272114186921)},
{field.NewFieldConst(7978627011292316159), field.NewFieldConst(12030929068833787030)},
{field.NewFieldConst(5676253512795062173), field.NewFieldConst(9401396509276686822)},
{field.NewFieldConst(13934555872940874542), field.NewFieldConst(12262482935570269103)},
{field.NewFieldConst(17018864997992880664), field.NewFieldConst(8399037137658253821)},
{field.NewFieldConst(1846702834278938262), field.NewFieldConst(13210394651984411322)},
{field.NewFieldConst(18406563809882201846), field.NewFieldConst(15807625126691296911)},
{field.NewFieldConst(16192554501791210701), field.NewFieldConst(15105514277710825451)},
{field.NewFieldConst(16115514979166385045), field.NewFieldConst(5618092869410987045)},
{field.NewFieldConst(9816852940756124129), field.NewFieldConst(1617435612712694609)},
{field.NewFieldConst(15012743324956680415), field.NewFieldConst(11098953448520716956)},
{field.NewFieldConst(7370750057902285338), field.NewFieldConst(15456123684241865136)},
{field.NewFieldConst(14924801177398773859), field.NewFieldConst(1116868612459919368)},
{field.NewFieldConst(509701279674911901), field.NewFieldConst(8606220700917290973)},
{field.NewFieldConst(256371784527067555), field.NewFieldConst(18023759020251995084)},
{field.NewFieldConst(4027645791496469270), field.NewFieldConst(6446906876250510281)},
{field.NewFieldConst(8190141658485644545), field.NewFieldConst(3259909135802998300)},
{field.NewFieldConst(11270185749533517292), field.NewFieldConst(7032460358965516338)},
{field.NewFieldConst(12112891112487601597), field.NewFieldConst(3686732542066412082)},
{field.NewFieldConst(18143522178445971138), field.NewFieldConst(6066438010126851248)},
{field.NewFieldConst(16109160830754618815), field.NewFieldConst(2728516440557525242)},
{field.NewFieldConst(14634072837475699881), field.NewFieldConst(423778353213757146)},
{field.NewFieldConst(10421081673554059162), field.NewFieldConst(10142208889746521219)},
{field.NewFieldConst(12957639310809930956), field.NewFieldConst(1709286023553869935)},
{field.NewFieldConst(16217923109113456531), field.NewFieldConst(3257438610376598615)},
{field.NewFieldConst(14024104132094810570), field.NewFieldConst(6065015478137587430)},
{field.NewFieldConst(7972303368219061571), field.NewFieldConst(5413678307283424945)},
{field.NewFieldConst(10367882107777269226), field.NewFieldConst(9366367173763419226)},
{field.NewFieldConst(11506720810821148150), field.NewFieldConst(15210537421649867625)},
{field.NewFieldConst(10979917526797364486), field.NewFieldConst(3365843489182711842)},
{field.NewFieldConst(9176981360155624350), field.NewFieldConst(7315956459698675112)},
{field.NewFieldConst(3964217770504101577), field.NewFieldConst(9088242192411952739)},
{field.NewFieldConst(16243289324567090937), field.NewFieldConst(13379263550784156456)},
{field.NewFieldConst(18105277122985331384), field.NewFieldConst(13639149553905751132)},
{field.NewFieldConst(11145583988660932112), field.NewFieldConst(16125114195985557867)},
{field.NewFieldConst(18437667738670181477), field.NewFieldConst(8593343353929068644)},
{field.NewFieldConst(15549894364614350199), field.NewFieldConst(6234736889764963090)},
{field.NewFieldConst(17753837009416762390), field.NewFieldConst(15297774054893249240)},
{field.NewFieldConst(1465043006528110247), field.NewFieldConst(11029942851654974974)},
{field.NewFieldConst(14312704742949520917), field.NewFieldConst(17324353686056674958)},
{field.NewFieldConst(8078333430227959261), field.NewFieldConst(14797545414164578336)},
{field.NewFieldConst(3544997838139687150), field.NewFieldConst(8846840377946705678)},
{field.NewFieldConst(9981846866090807073), field.NewFieldConst(18142560414179130259)},
{field.NewFieldConst(1256577435119993994), field.NewFieldConst(155745544208227129)},
{field.NewFieldConst(6040293874299819317), field.NewFieldConst(10483265617246740662)},
{field.NewFieldConst(976159477616343697), field.NewFieldConst(6356544693059700239)},
{field.NewFieldConst(4771747444846377672), field.NewFieldConst(2466985401424965488)},
{field.NewFieldConst(9549711421417753693), field.NewFieldConst(9543806479040458857)},
{field.NewFieldConst(5277199124405775998), field.NewFieldConst(6251037001966593402)},
{field.NewFieldConst(13103543598051591262), field.NewFieldConst(2001921170471454234)},
{field.NewFieldConst(1254878001165263070), field.NewFieldConst(17587272030879777460)},
{field.NewFieldConst(2300344156307624878), field.NewFieldConst(14356513038946626528)},
{field.NewFieldConst(2482567400777596327), field.NewFieldConst(3314129985687795881)},
{field.NewFieldConst(16492046206730922155), field.NewFieldConst(1312905854247159931)},
{field.NewFieldConst(3061501132630116372), field.NewFieldConst(13315665946615810001)},
{field.NewFieldConst(16415932954051444990), field.NewFieldConst(925217124969456536)},
{field.NewFieldConst(9764657158286137619), field.NewFieldConst(16039332713210679567)},
{field.NewFieldConst(14993545086997628961), field.NewFieldConst(18010329211070748489)},
{field.NewFieldConst(17327862012036619887), field.NewFieldConst(16962349802452905993)},
{field.NewFieldConst(4826313026336060985), field.NewFieldConst(3597777099127511952)},
}
var publicInputsHash = poseidon.PoseidonHashOut{field.ZERO_F, field.ZERO_F, field.ZERO_F, field.ZERO_F}
var publicInputGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(5101665081776077058), field.NewFieldConst(13601771238484783081)},
{field.NewFieldConst(13763997788502656587), field.NewFieldConst(6068443864169526207)},
{field.NewFieldConst(10492880302699453810), field.NewFieldConst(11304418575668616669)},
{field.NewFieldConst(2175168501339052813), field.NewFieldConst(3658211467579027796)},
}
// BaseSumGate { num_limbs: 63 }), (Base: 2)
var baseSumGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(9928715244459351681), field.NewFieldConst(5344081500364361215)},
{field.NewFieldConst(10167164649082076581), field.NewFieldConst(15450889555489725096)},
{field.NewFieldConst(3546584706462116594), field.NewFieldConst(1476426705388693036)},
{field.NewFieldConst(12648634003162244983), field.NewFieldConst(2239452344495239178)},
{field.NewFieldConst(2301087631440580451), field.NewFieldConst(11975672920337250307)},
{field.NewFieldConst(14001554463269171732), field.NewFieldConst(6953207277617809048)},
{field.NewFieldConst(9895590040747031510), field.NewFieldConst(1356956949635190505)},
{field.NewFieldConst(14939964178677988571), field.NewFieldConst(454717738260444218)},
{field.NewFieldConst(12201660109699192297), field.NewFieldConst(12502457673278583036)},
{field.NewFieldConst(1175543972635147885), field.NewFieldConst(11103026408792334489)},
{field.NewFieldConst(3384025741923988904), field.NewFieldConst(2656764746353452717)},
{field.NewFieldConst(10849522185534943138), field.NewFieldConst(13172212508084788997)},
{field.NewFieldConst(10509522572526523739), field.NewFieldConst(2090707475955491976)},
{field.NewFieldConst(13692600715410336206), field.NewFieldConst(7227633217973806771)},
{field.NewFieldConst(8471053080480597138), field.NewFieldConst(2646922138422495173)},
{field.NewFieldConst(555344530120410083), field.NewFieldConst(13860459564781531385)},
{field.NewFieldConst(8748801107049442833), field.NewFieldConst(9263752460533085733)},
{field.NewFieldConst(13633964398888639692), field.NewFieldConst(10068133633095351031)},
{field.NewFieldConst(6911322073377914708), field.NewFieldConst(17978361073083837803)},
{field.NewFieldConst(11223090828346729804), field.NewFieldConst(5006610230932979596)},
{field.NewFieldConst(11581626217660221266), field.NewFieldConst(16347470001077006094)},
{field.NewFieldConst(2924189901864366701), field.NewFieldConst(4309265474738828848)},
{field.NewFieldConst(7275314468944461178), field.NewFieldConst(3109308884739285751)},
{field.NewFieldConst(12416988612575693809), field.NewFieldConst(13772367397588066248)},
{field.NewFieldConst(15438805794425696237), field.NewFieldConst(5809350894111990599)},
{field.NewFieldConst(4275145128501503120), field.NewFieldConst(13230668146909969114)},
{field.NewFieldConst(15244699495724739585), field.NewFieldConst(7672322205441472064)},
{field.NewFieldConst(5429809680618805220), field.NewFieldConst(3153880467220264060)},
{field.NewFieldConst(14715345489518514160), field.NewFieldConst(2246036712337629635)},
{field.NewFieldConst(9359342125434211935), field.NewFieldConst(7844760208539761732)},
{field.NewFieldConst(17550561700498841003), field.NewFieldConst(10851755490050776878)},
{field.NewFieldConst(12192385328855013814), field.NewFieldConst(6629056869404844416)},
{field.NewFieldConst(3424745785197724925), field.NewFieldConst(9833599393425172230)},
{field.NewFieldConst(8602078107149096927), field.NewFieldConst(6592109323720773368)},
{field.NewFieldConst(4109716921881297082), field.NewFieldConst(4396469548700606105)},
{field.NewFieldConst(10400304110319417426), field.NewFieldConst(1229823145437740976)},
{field.NewFieldConst(14853277673343952974), field.NewFieldConst(7653131044140686982)},
{field.NewFieldConst(15831955783787857197), field.NewFieldConst(16541106185743830609)},
{field.NewFieldConst(16097830673407036871), field.NewFieldConst(917501749911433098)},
{field.NewFieldConst(6819428296662518848), field.NewFieldConst(15325182544903569500)},
{field.NewFieldConst(3554857310728040215), field.NewFieldConst(17540168721765377170)},
{field.NewFieldConst(7246216899469226885), field.NewFieldConst(3184709231158489554)},
{field.NewFieldConst(3462793508732024933), field.NewFieldConst(13410498916934897793)},
{field.NewFieldConst(784714181705176804), field.NewFieldConst(8079390288171846846)},
{field.NewFieldConst(4592501261546923410), field.NewFieldConst(6046244648190342248)},
{field.NewFieldConst(14100558314779073910), field.NewFieldConst(9589305391181830029)},
{field.NewFieldConst(7208216654581381179), field.NewFieldConst(16662177305876430630)},
{field.NewFieldConst(13442246990998561849), field.NewFieldConst(6359024918649040199)},
{field.NewFieldConst(16196376030005699590), field.NewFieldConst(5656446490425854681)},
{field.NewFieldConst(16279173216505198700), field.NewFieldConst(6278440230935274234)},
{field.NewFieldConst(9299204333782277508), field.NewFieldConst(5539548698065086849)},
{field.NewFieldConst(531539748103362347), field.NewFieldConst(17008402782657673980)},
{field.NewFieldConst(11956287871118080485), field.NewFieldConst(17776888431041950837)},
{field.NewFieldConst(16795401491637949606), field.NewFieldConst(12112971435724505573)},
{field.NewFieldConst(10141270150228316653), field.NewFieldConst(8738825159351228227)},
{field.NewFieldConst(4249416130151320263), field.NewFieldConst(4171109024390883108)},
{field.NewFieldConst(13565954345346642147), field.NewFieldConst(11300077318998472624)},
{field.NewFieldConst(6006413348327738680), field.NewFieldConst(17429146764001291339)},
{field.NewFieldConst(3009379005164242386), field.NewFieldConst(17911649148503516453)},
{field.NewFieldConst(4172202865347441020), field.NewFieldConst(6700979848078030374)},
{field.NewFieldConst(9692174554453081047), field.NewFieldConst(16461309050820528716)},
{field.NewFieldConst(16012555505188709835), field.NewFieldConst(875036531415994728)},
{field.NewFieldConst(14527388813134058525), field.NewFieldConst(13371873777459370318)},
{field.NewFieldConst(6493493657980111839), field.NewFieldConst(14874520839734823069)},
}
// ArithmeticGate { num_ops: 20 }
var arithmeticGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(8251494922795803874), field.NewFieldConst(7884328911897949424)},
{field.NewFieldConst(17545754596575389449), field.NewFieldConst(15111927979676704385)},
{field.NewFieldConst(10052040965126353731), field.NewFieldConst(1448153912054014611)},
{field.NewFieldConst(3878848318701063854), field.NewFieldConst(15999854355391952993)},
{field.NewFieldConst(2194699804496089007), field.NewFieldConst(7489112350095609056)},
{field.NewFieldConst(666656317372820215), field.NewFieldConst(8333111246649438880)},
{field.NewFieldConst(15500013716804095980), field.NewFieldConst(7739144386812042617)},
{field.NewFieldConst(2815612394018416154), field.NewFieldConst(15839168197108305099)},
{field.NewFieldConst(12980309813768330187), field.NewFieldConst(12446111953378048591)},
{field.NewFieldConst(1389916348936822477), field.NewFieldConst(2080258147396834809)},
{field.NewFieldConst(3676770229830052631), field.NewFieldConst(8984521981419906260)},
{field.NewFieldConst(4759606161035299488), field.NewFieldConst(18415228017149216426)},
{field.NewFieldConst(6849567585629675684), field.NewFieldConst(15231001333591586187)},
{field.NewFieldConst(17831496121270832947), field.NewFieldConst(1868580989876710210)},
{field.NewFieldConst(12226832860244216901), field.NewFieldConst(12352098694767236965)},
{field.NewFieldConst(9795530155924375772), field.NewFieldConst(4833402654226660686)},
{field.NewFieldConst(7421277748600887772), field.NewFieldConst(16979590244320625600)},
{field.NewFieldConst(4212532134312824848), field.NewFieldConst(7938725153260099101)},
{field.NewFieldConst(17718231164451799422), field.NewFieldConst(13363195988334771788)},
{field.NewFieldConst(5414385531680474153), field.NewFieldConst(13600409983387272243)},
}
// RandomAccessGate { bits: 4, num_copies: 4, num_extra_constants: 2, _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
var randomAccessGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(18367067186009695282), field.NewFieldConst(6227937229941915629)},
{field.NewFieldConst(342627832935644960), field.NewFieldConst(11262336464371657587)},
{field.NewFieldConst(7711502047853221895), field.NewFieldConst(9814305320358879113)},
{field.NewFieldConst(2436675870898619939), field.NewFieldConst(12171743011114835714)},
{field.NewFieldConst(9224796650008092960), field.NewFieldConst(197827193844666436)},
{field.NewFieldConst(7661651717350955969), field.NewFieldConst(3929163527437938921)},
{field.NewFieldConst(11994613277879586781), field.NewFieldConst(2918199453077793278)},
{field.NewFieldConst(2133315582796573410), field.NewFieldConst(9920472598641951727)},
{field.NewFieldConst(5763420675219782924), field.NewFieldConst(193200772658790662)},
{field.NewFieldConst(14322103909897767697), field.NewFieldConst(2455403487869979318)},
{field.NewFieldConst(3583177870835306708), field.NewFieldConst(15956920993825363087)},
{field.NewFieldConst(15767764327818217757), field.NewFieldConst(17814936958431909187)},
{field.NewFieldConst(7224551806569620055), field.NewFieldConst(1191241782303323453)},
{field.NewFieldConst(3994846439282900915), field.NewFieldConst(16007298430807731888)},
{field.NewFieldConst(1904864531973789879), field.NewFieldConst(9374437322489636375)},
{field.NewFieldConst(17617411600595291430), field.NewFieldConst(11804426503917788826)},
{field.NewFieldConst(5010213812557284606), field.NewFieldConst(8276410914978849008)},
{field.NewFieldConst(13701536021647106057), field.NewFieldConst(5043776904396037625)},
{field.NewFieldConst(4336267979289896624), field.NewFieldConst(8771134635816393433)},
{field.NewFieldConst(17885926480537171976), field.NewFieldConst(9644095314646547597)},
{field.NewFieldConst(17179233085824331332), field.NewFieldConst(6950525108693323209)},
{field.NewFieldConst(9461258042008745175), field.NewFieldConst(6766975264204597922)},
{field.NewFieldConst(10838154179711471883), field.NewFieldConst(16554457937262927355)},
{field.NewFieldConst(5823858951686479642), field.NewFieldConst(10171201631442530906)},
{field.NewFieldConst(17476953112985367168), field.NewFieldConst(12062851564787792403)},
{field.NewFieldConst(7909573710893929152), field.NewFieldConst(6207515797705444652)},
}
// PoseidonGate(PhantomData<plonky2_field::goldilocks_field::GoldilocksField>)<WIDTH=12>
var poseidonGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(15438805794425696237), field.NewFieldConst(5809350894111990599)},
{field.NewFieldConst(105238306594298866), field.NewFieldConst(6398155585902798861)},
{field.NewFieldConst(5256232026568856387), field.NewFieldConst(9253448664982005262)},
{field.NewFieldConst(6559974022172208218), field.NewFieldConst(14478753759394222537)},
{field.NewFieldConst(7036928093413865537), field.NewFieldConst(895644692646980845)},
{field.NewFieldConst(6350074916129003337), field.NewFieldConst(10418298512623677843)},
{field.NewFieldConst(6618288817893266284), field.NewFieldConst(17565920952415773065)},
{field.NewFieldConst(7214268149308735221), field.NewFieldConst(17797640553663908886)},
{field.NewFieldConst(17038147867485750883), field.NewFieldConst(10766691853641769251)},
{field.NewFieldConst(1228066111137794024), field.NewFieldConst(1267834319488006514)},
{field.NewFieldConst(15317834050441961579), field.NewFieldConst(13280896488837969140)},
{field.NewFieldConst(10135227968960430585), field.NewFieldConst(7096433509203324519)},
{field.NewFieldConst(10733417635899979276), field.NewFieldConst(16819459255105516700)},
{field.NewFieldConst(4231839251429338586), field.NewFieldConst(3213678047797020863)},
{field.NewFieldConst(16271445286187692537), field.NewFieldConst(15377656608157234934)},
{field.NewFieldConst(9356442829698587975), field.NewFieldConst(14633910545825415036)},
{field.NewFieldConst(13952390018297698734), field.NewFieldConst(16325393355066618599)},
{field.NewFieldConst(11399251131586292643), field.NewFieldConst(16257107051968717815)},
{field.NewFieldConst(4274092107872068929), field.NewFieldConst(15550597684938436610)},
{field.NewFieldConst(13076618331457049912), field.NewFieldConst(4958059540220054374)},
{field.NewFieldConst(11650097218963026123), field.NewFieldConst(12070947109214611020)},
{field.NewFieldConst(2700303408109034014), field.NewFieldConst(5968338348636871194)},
{field.NewFieldConst(11508005723655482353), field.NewFieldConst(15224088756564969467)},
{field.NewFieldConst(9328231423353697829), field.NewFieldConst(10577349809783627634)},
{field.NewFieldConst(556544259468984890), field.NewFieldConst(13376447539117215836)},
{field.NewFieldConst(17319865455991589647), field.NewFieldConst(588985536671201497)},
{field.NewFieldConst(9528470026616131077), field.NewFieldConst(7257040911301352274)},
{field.NewFieldConst(14316182132889623635), field.NewFieldConst(9589165219691594711)},
{field.NewFieldConst(10405802815809041956), field.NewFieldConst(13917007789819955074)},
{field.NewFieldConst(12560668105252495616), field.NewFieldConst(3591188232548111694)},
{field.NewFieldConst(14765117357942682611), field.NewFieldConst(10757853341059462467)},
{field.NewFieldConst(6099902163260965551), field.NewFieldConst(11343816861356056114)},
{field.NewFieldConst(1083174255539258286), field.NewFieldConst(7587979659522435417)},
{field.NewFieldConst(2882552180249608570), field.NewFieldConst(7966658657757662554)},
{field.NewFieldConst(13490914415473336227), field.NewFieldConst(63845168436289811)},
{field.NewFieldConst(9459794640071212413), field.NewFieldConst(13417331052474309186)},
{field.NewFieldConst(18328090807516092318), field.NewFieldConst(11807085063599693782)},
{field.NewFieldConst(281059606944328759), field.NewFieldConst(13352248056867426135)},
{field.NewFieldConst(10905177588660050370), field.NewFieldConst(6597328385789442670)},
{field.NewFieldConst(8426356906491012567), field.NewFieldConst(17214424336396001022)},
{field.NewFieldConst(15696035667318839817), field.NewFieldConst(13285870048485492127)},
{field.NewFieldConst(6110244444680672193), field.NewFieldConst(17558548349689468031)},
{field.NewFieldConst(14614078615782659381), field.NewFieldConst(13184024850613726857)},
{field.NewFieldConst(1541592450520953410), field.NewFieldConst(18339388388315914026)},
{field.NewFieldConst(8059386643769157052), field.NewFieldConst(10208764910817462305)},
{field.NewFieldConst(7612459820354975117), field.NewFieldConst(7582060685277695926)},
{field.NewFieldConst(12515587043516861064), field.NewFieldConst(16099239041553682288)},
{field.NewFieldConst(14269196473871652102), field.NewFieldConst(1225067220600668761)},
{field.NewFieldConst(12691255077510636187), field.NewFieldConst(14147201911063761532)},
{field.NewFieldConst(3001134598446056765), field.NewFieldConst(14313090483058155636)},
{field.NewFieldConst(13964993951988177315), field.NewFieldConst(17731737838539414275)},
{field.NewFieldConst(2686259154263524343), field.NewFieldConst(12198712301337570859)},
{field.NewFieldConst(6730431920128908773), field.NewFieldConst(4325394084875720868)},
{field.NewFieldConst(988774723104779817), field.NewFieldConst(8388266879854983623)},
{field.NewFieldConst(8233087560647959985), field.NewFieldConst(7751837576340060020)},
{field.NewFieldConst(9546113779017699592), field.NewFieldConst(4049920632309298778)},
{field.NewFieldConst(3283837251411237060), field.NewFieldConst(13560940050752580093)},
{field.NewFieldConst(10388838746951897109), field.NewFieldConst(454393475113110282)},
{field.NewFieldConst(2208016536897042313), field.NewFieldConst(17105586471193083308)},
{field.NewFieldConst(17683990802267567604), field.NewFieldConst(15398473956537380705)},
{field.NewFieldConst(70612752050386177), field.NewFieldConst(12349994002954022957)},
{field.NewFieldConst(13794244952989612728), field.NewFieldConst(15888581169565306348)},
{field.NewFieldConst(8270800566553141412), field.NewFieldConst(1516938823651329185)},
{field.NewFieldConst(643507941153616368), field.NewFieldConst(3893451216814345882)},
{field.NewFieldConst(16464837166410943694), field.NewFieldConst(11108183142967610977)},
{field.NewFieldConst(9748621820629198396), field.NewFieldConst(3766489907402036319)},
{field.NewFieldConst(3115179618981245947), field.NewFieldConst(10160994694067456423)},
{field.NewFieldConst(4497210741038443097), field.NewFieldConst(6445446770984515259)},
{field.NewFieldConst(5470898125882256227), field.NewFieldConst(8249357863801204908)},
{field.NewFieldConst(16762380205819269382), field.NewFieldConst(172510727904060494)},
{field.NewFieldConst(7920011253931301350), field.NewFieldConst(9681193995678483756)},
{field.NewFieldConst(8258951043315574232), field.NewFieldConst(13137471323476190588)},
{field.NewFieldConst(4339364527801481944), field.NewFieldConst(16862579756243326257)},
{field.NewFieldConst(8980029737458438570), field.NewFieldConst(14651625524257781922)},
{field.NewFieldConst(17935993907375677671), field.NewFieldConst(5318319737405476029)},
{field.NewFieldConst(716791501623731831), field.NewFieldConst(18425818060734993303)},
{field.NewFieldConst(601549076806364660), field.NewFieldConst(12303919727550310013)},
{field.NewFieldConst(18026376178895562118), field.NewFieldConst(14687420532194520529)},
{field.NewFieldConst(16943892475592026666), field.NewFieldConst(7451688507369746594)},
{field.NewFieldConst(8724072308842121373), field.NewFieldConst(11662986251379699921)},
{field.NewFieldConst(3201079129905071298), field.NewFieldConst(11542621183935331871)},
{field.NewFieldConst(9889739070824270529), field.NewFieldConst(3891825006545095657)},
{field.NewFieldConst(15538978715382418651), field.NewFieldConst(2419672705453973015)},
{field.NewFieldConst(3001525234835174062), field.NewFieldConst(17115969716224377534)},
{field.NewFieldConst(18001237923148428045), field.NewFieldConst(2198015511953873786)},
{field.NewFieldConst(14186741561112601666), field.NewFieldConst(13156405199205086627)},
{field.NewFieldConst(10166592177477126663), field.NewFieldConst(13586051001537885658)},
{field.NewFieldConst(8678352780562557555), field.NewFieldConst(1968366090049630482)},
{field.NewFieldConst(5627999915794840395), field.NewFieldConst(13597556392696072088)},
{field.NewFieldConst(9291327714650886898), field.NewFieldConst(2411361999629511024)},
{field.NewFieldConst(6824943761729555359), field.NewFieldConst(7484507209360908175)},
{field.NewFieldConst(6276580084700132178), field.NewFieldConst(6246691657613415035)},
{field.NewFieldConst(10736230409698057656), field.NewFieldConst(7306720219045064925)},
{field.NewFieldConst(15442170485732017109), field.NewFieldConst(1739984147692575725)},
{field.NewFieldConst(4448878124301402845), field.NewFieldConst(18436455114977877323)},
{field.NewFieldConst(638012599023653143), field.NewFieldConst(16265955502846626936)},
{field.NewFieldConst(6793907577559820653), field.NewFieldConst(15343551069946118619)},
{field.NewFieldConst(17903286158968614509), field.NewFieldConst(9559701571149911252)},
{field.NewFieldConst(14652006464960400785), field.NewFieldConst(50421020503848143)},
{field.NewFieldConst(9452858006432860845), field.NewFieldConst(2625726945677447428)},
{field.NewFieldConst(853640589013584892), field.NewFieldConst(14655161412118141649)},
{field.NewFieldConst(12863832006745352780), field.NewFieldConst(14564189651136231029)},
{field.NewFieldConst(8551517270810530438), field.NewFieldConst(10859465327758962622)},
{field.NewFieldConst(10113468436120661191), field.NewFieldConst(16040944006557911589)},
{field.NewFieldConst(4921439225277518643), field.NewFieldConst(8399175422965154512)},
{field.NewFieldConst(13068240354812957183), field.NewFieldConst(8520393046894990946)},
{field.NewFieldConst(1189183420107219532), field.NewFieldConst(18066897627856601789)},
{field.NewFieldConst(3997900004790871153), field.NewFieldConst(1269718920871578117)},
{field.NewFieldConst(15438784576472256462), field.NewFieldConst(9577304425687441047)},
{field.NewFieldConst(17158083218962275971), field.NewFieldConst(17379790274576244684)},
{field.NewFieldConst(3470452736936929010), field.NewFieldConst(12769555113044633230)},
{field.NewFieldConst(18389243269515626865), field.NewFieldConst(8023737530782576805)},
{field.NewFieldConst(3529213023405995549), field.NewFieldConst(8829896701928525938)},
{field.NewFieldConst(14072413770981804653), field.NewFieldConst(9660693090213237836)},
{field.NewFieldConst(14369435038913678671), field.NewFieldConst(7659129852562422871)},
{field.NewFieldConst(6779301728445724040), field.NewFieldConst(18290152515233036523)},
{field.NewFieldConst(8113954200727174254), field.NewFieldConst(16490002532983549952)},
{field.NewFieldConst(11465655095604389561), field.NewFieldConst(9066100972825318010)},
{field.NewFieldConst(15998691377748321442), field.NewFieldConst(16970045124898180365)},
{field.NewFieldConst(8424730626816696233), field.NewFieldConst(17168184083072399403)},
{field.NewFieldConst(1941959246552302666), field.NewFieldConst(6751013195867127440)},
{field.NewFieldConst(1907519456922228224), field.NewFieldConst(689311996911195932)},
{field.NewFieldConst(16277197060525435740), field.NewFieldConst(12018417724719716072)},
}
var reducingExtensionGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(12832102811425062912), field.NewFieldConst(2979695993654444095)},
{field.NewFieldConst(4822478941232734654), field.NewFieldConst(2600327308894333341)},
{field.NewFieldConst(12450653411048814602), field.NewFieldConst(1161667420593062956)},
{field.NewFieldConst(3145631295867407955), field.NewFieldConst(1702059944088737075)},
{field.NewFieldConst(4597190091407364771), field.NewFieldConst(4257077286672555409)},
{field.NewFieldConst(10177664366491925772), field.NewFieldConst(10489575701186298604)},
{field.NewFieldConst(2754621968864722399), field.NewFieldConst(12087963411706301871)},
{field.NewFieldConst(534408217555793149), field.NewFieldConst(12559345737194357169)},
{field.NewFieldConst(9508765820222303634), field.NewFieldConst(14102461861317982082)},
{field.NewFieldConst(15070954032232801974), field.NewFieldConst(2078249670161696735)},
{field.NewFieldConst(10465809629504954691), field.NewFieldConst(16223748685835312497)},
{field.NewFieldConst(10957196413441800202), field.NewFieldConst(3841214025425953691)},
{field.NewFieldConst(18438848195188240825), field.NewFieldConst(5697684145424680565)},
{field.NewFieldConst(565455534266129104), field.NewFieldConst(12543354947937779806)},
{field.NewFieldConst(16376588778962418386), field.NewFieldConst(1273250903423198860)},
{field.NewFieldConst(4128104469872810921), field.NewFieldConst(1433037233801071123)},
{field.NewFieldConst(6011337242244377340), field.NewFieldConst(16068106780789397185)},
{field.NewFieldConst(4741354504248328629), field.NewFieldConst(3000853646720964165)},
{field.NewFieldConst(13064594310789140866), field.NewFieldConst(10950406741883971259)},
{field.NewFieldConst(17079026691450750925), field.NewFieldConst(6522027970928818261)},
{field.NewFieldConst(13158136237489326416), field.NewFieldConst(7677629162183242732)},
{field.NewFieldConst(14741398060174921234), field.NewFieldConst(2960243215156352194)},
{field.NewFieldConst(9111161782199179468), field.NewFieldConst(8010960876261510099)},
{field.NewFieldConst(1404837029582986528), field.NewFieldConst(9377230983302764181)},
{field.NewFieldConst(7086781234814455260), field.NewFieldConst(7571558192372650697)},
{field.NewFieldConst(5627013434503229817), field.NewFieldConst(14984048934926143304)},
{field.NewFieldConst(2115495655441739405), field.NewFieldConst(1656704965110317534)},
{field.NewFieldConst(2311846135199651566), field.NewFieldConst(17438437808346967358)},
{field.NewFieldConst(8679806319651401773), field.NewFieldConst(3278538718508560579)},
{field.NewFieldConst(7897681105604536660), field.NewFieldConst(10966573925848082711)},
{field.NewFieldConst(5451958405177630542), field.NewFieldConst(9207735009647199721)},
{field.NewFieldConst(8825486358121162697), field.NewFieldConst(15997852519026522914)},
{field.NewFieldConst(475225211669491693), field.NewFieldConst(1907827506180042626)},
{field.NewFieldConst(16033031089519343732), field.NewFieldConst(15009948832718035672)},
{field.NewFieldConst(5048598591200038865), field.NewFieldConst(156574475928756206)},
{field.NewFieldConst(3580311624647961767), field.NewFieldConst(6084715537433906996)},
{field.NewFieldConst(9121009921295095324), field.NewFieldConst(18407759801432275235)},
{field.NewFieldConst(16569013039730214123), field.NewFieldConst(3930908108224055041)},
{field.NewFieldConst(13844066138909451365), field.NewFieldConst(6585754647203519368)},
{field.NewFieldConst(14133345335167543367), field.NewFieldConst(3946807387480232364)},
{field.NewFieldConst(9876285028806980582), field.NewFieldConst(40898067822033734)},
{field.NewFieldConst(6293483059765701407), field.NewFieldConst(16009270905706605849)},
{field.NewFieldConst(11635947241393753594), field.NewFieldConst(5053395178858294866)},
{field.NewFieldConst(16062194595705166277), field.NewFieldConst(752574348595159408)},
{field.NewFieldConst(15607597716340375230), field.NewFieldConst(10428583315124220143)},
{field.NewFieldConst(6975301479426228318), field.NewFieldConst(16528136630898216147)},
{field.NewFieldConst(16312827398430223622), field.NewFieldConst(17909475722464415780)},
{field.NewFieldConst(2273087545743905667), field.NewFieldConst(12405446777919046866)},
{field.NewFieldConst(14781933506876191161), field.NewFieldConst(4464109151368149713)},
{field.NewFieldConst(4226716729950095934), field.NewFieldConst(8908251769229049654)},
{field.NewFieldConst(8310476487592089883), field.NewFieldConst(3834672170570438819)},
{field.NewFieldConst(4285568636604940795), field.NewFieldConst(7183765355016179794)},
{field.NewFieldConst(14300853697824059506), field.NewFieldConst(16287477445929928328)},
{field.NewFieldConst(1238186507267033247), field.NewFieldConst(12357102109973664962)},
{field.NewFieldConst(15607388919140050768), field.NewFieldConst(15421065238069253306)},
{field.NewFieldConst(12418734453826432586), field.NewFieldConst(12072056126139297564)},
{field.NewFieldConst(3924467115116313620), field.NewFieldConst(1212362379653628161)},
{field.NewFieldConst(8252514850759544679), field.NewFieldConst(7893938436444134034)},
{field.NewFieldConst(711675815009325200), field.NewFieldConst(15678724077367989757)},
{field.NewFieldConst(10920573406841924033), field.NewFieldConst(8189696933773246220)},
{field.NewFieldConst(9737295100232588618), field.NewFieldConst(13383462338120177171)},
{field.NewFieldConst(8983013033045953935), field.NewFieldConst(5301160793103788033)},
{field.NewFieldConst(2086512740154274197), field.NewFieldConst(9511985884344255651)},
{field.NewFieldConst(7404726366142548080), field.NewFieldConst(11257391295697140486)},
{field.NewFieldConst(10045968629671906256), field.NewFieldConst(10721172752468420959)},
{field.NewFieldConst(9499240237398016191), field.NewFieldConst(17996498955496851489)},
}
// ReducingGate { num_coeffs: 44 }
var reducingGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(4189565386714553574), field.NewFieldConst(14972099283023295929)},
{field.NewFieldConst(4811224976739448335), field.NewFieldConst(17901409314576454439)},
{field.NewFieldConst(5140059407491502784), field.NewFieldConst(1144330742785924570)},
{field.NewFieldConst(7077436393778991453), field.NewFieldConst(13398199711778224412)},
{field.NewFieldConst(11213768990622043903), field.NewFieldConst(3886053425349218150)},
{field.NewFieldConst(2946099412905029571), field.NewFieldConst(16515307040211357295)},
{field.NewFieldConst(11766152895257088950), field.NewFieldConst(12561350435611412995)},
{field.NewFieldConst(15559670172179416359), field.NewFieldConst(14246884723129607378)},
{field.NewFieldConst(5240707719525548158), field.NewFieldConst(1640773599873992510)},
{field.NewFieldConst(14358821079049832289), field.NewFieldConst(2746855687282611080)},
{field.NewFieldConst(3214086216088588558), field.NewFieldConst(1520697626094905530)},
{field.NewFieldConst(9834748172213967248), field.NewFieldConst(13487010468070558667)},
{field.NewFieldConst(1423442768503334248), field.NewFieldConst(10945790255819476518)},
{field.NewFieldConst(2308372186436983690), field.NewFieldConst(8803174935784778070)},
{field.NewFieldConst(9995833078447025147), field.NewFieldConst(9074310518079663649)},
{field.NewFieldConst(14149697874498108875), field.NewFieldConst(15875817120435194028)},
{field.NewFieldConst(14564758547073982656), field.NewFieldConst(13386335755835868953)},
{field.NewFieldConst(6432745607675418074), field.NewFieldConst(8030247499566565321)},
{field.NewFieldConst(17308235779926438117), field.NewFieldConst(16843697410674499818)},
{field.NewFieldConst(15507223129386571868), field.NewFieldConst(3935281607585552366)},
{field.NewFieldConst(16041402982622709805), field.NewFieldConst(12432717078068957835)},
{field.NewFieldConst(6455955094164032063), field.NewFieldConst(2435635342699968412)},
{field.NewFieldConst(9814981570869789379), field.NewFieldConst(5009257884262115226)},
{field.NewFieldConst(9452031978763862902), field.NewFieldConst(15609083603899848676)},
{field.NewFieldConst(13532623109002857304), field.NewFieldConst(7324541443245949391)},
{field.NewFieldConst(7899075212455453622), field.NewFieldConst(14276489152002439614)},
{field.NewFieldConst(2403019844704266911), field.NewFieldConst(5922544710604013781)},
{field.NewFieldConst(9709471021111675830), field.NewFieldConst(5538539165068927028)},
{field.NewFieldConst(15700585567216041265), field.NewFieldConst(17893894492159337326)},
{field.NewFieldConst(8890003199638063977), field.NewFieldConst(17726621767321974437)},
{field.NewFieldConst(389239919653982052), field.NewFieldConst(3497778410650283061)},
{field.NewFieldConst(845227572644858827), field.NewFieldConst(7040344997713673855)},
{field.NewFieldConst(9861253052349275208), field.NewFieldConst(1880449137233040023)},
{field.NewFieldConst(9239454143759318515), field.NewFieldConst(7968256557482935820)},
{field.NewFieldConst(12576879243038758854), field.NewFieldConst(9784626207087825707)},
{field.NewFieldConst(14811673587164089973), field.NewFieldConst(10785522535030299714)},
{field.NewFieldConst(696437091186897361), field.NewFieldConst(13293602092569033065)},
{field.NewFieldConst(1240161179290551759), field.NewFieldConst(9542275505416038259)},
{field.NewFieldConst(5298553932515957396), field.NewFieldConst(14597738151157731445)},
{field.NewFieldConst(8472517818840783225), field.NewFieldConst(7685861056688910111)},
{field.NewFieldConst(10067665523858551777), field.NewFieldConst(13019870415534016025)},
{field.NewFieldConst(3030966178198674680), field.NewFieldConst(10107838846102885642)},
{field.NewFieldConst(6762889891370677550), field.NewFieldConst(16151528872832782368)},
{field.NewFieldConst(17207754552662723664), field.NewFieldConst(15168039969859158460)},
{field.NewFieldConst(9111161782199179468), field.NewFieldConst(8010960876261510099)},
{field.NewFieldConst(1212079098724692260), field.NewFieldConst(3976842077579916925)},
{field.NewFieldConst(8111924351272477885), field.NewFieldConst(1472738463707044435)},
{field.NewFieldConst(14549763060495382561), field.NewFieldConst(8148654488443197206)},
{field.NewFieldConst(9633247645878352168), field.NewFieldConst(4173826759172401145)},
{field.NewFieldConst(13429667484612728110), field.NewFieldConst(139708813783643870)},
{field.NewFieldConst(11164941208889426013), field.NewFieldConst(3615779386887825309)},
{field.NewFieldConst(15733773570058687441), field.NewFieldConst(11172582394325691371)},
{field.NewFieldConst(11237663549079845099), field.NewFieldConst(375954911737718734)},
{field.NewFieldConst(14815280969174152094), field.NewFieldConst(17903238907570421232)},
{field.NewFieldConst(12264332321023153985), field.NewFieldConst(4996015210046477989)},
{field.NewFieldConst(5733452693326962912), field.NewFieldConst(15445457134261228447)},
{field.NewFieldConst(11339891595047637420), field.NewFieldConst(762619178430884475)},
{field.NewFieldConst(10413672060220880988), field.NewFieldConst(2522708614237496949)},
{field.NewFieldConst(4759794002943168525), field.NewFieldConst(8366670758049431064)},
{field.NewFieldConst(11081128192182141387), field.NewFieldConst(5264843790841556843)},
{field.NewFieldConst(16467547707866820269), field.NewFieldConst(10395994280728082037)},
{field.NewFieldConst(7372902852922723938), field.NewFieldConst(6597057511414169148)},
{field.NewFieldConst(1246550990665510080), field.NewFieldConst(369146659419534786)},
{field.NewFieldConst(107137977263990694), field.NewFieldConst(13480217899797734610)},
{field.NewFieldConst(9352391006524927052), field.NewFieldConst(16474580549927501346)},
{field.NewFieldConst(11475195577527382963), field.NewFieldConst(16771481018793784004)},
{field.NewFieldConst(7763817490144412733), field.NewFieldConst(7847907679735875325)},
{field.NewFieldConst(6954934416977006194), field.NewFieldConst(1588175103882481774)},
{field.NewFieldConst(208699790124989138), field.NewFieldConst(104050776110144395)},
{field.NewFieldConst(1999712470949493845), field.NewFieldConst(14640293671425837284)},
{field.NewFieldConst(17489389210332023693), field.NewFieldConst(1485853484717956236)},
{field.NewFieldConst(13389678828109836153), field.NewFieldConst(12239927773742888217)},
{field.NewFieldConst(7279356606052782033), field.NewFieldConst(16889809967345118643)},
{field.NewFieldConst(5530632913824527303), field.NewFieldConst(6593916246324540830)},
{field.NewFieldConst(6517985275757881887), field.NewFieldConst(1094679265639341934)},
{field.NewFieldConst(16005022297334791008), field.NewFieldConst(2231375568117939019)},
{field.NewFieldConst(7801581545066110268), field.NewFieldConst(16195585011186011335)},
{field.NewFieldConst(2346311239309318787), field.NewFieldConst(10194252071441594046)},
{field.NewFieldConst(1333414916806612489), field.NewFieldConst(4078668601880487193)},
{field.NewFieldConst(17162202837341088150), field.NewFieldConst(3946492721743094611)},
{field.NewFieldConst(2372952988964786162), field.NewFieldConst(14459600129361968991)},
{field.NewFieldConst(15958985504784681452), field.NewFieldConst(18297567352909625870)},
{field.NewFieldConst(5468110010239944205), field.NewFieldConst(1297673223075459793)},
{field.NewFieldConst(5916958362061888790), field.NewFieldConst(12686064186569549334)},
{field.NewFieldConst(17141186363273294375), field.NewFieldConst(5330662447468959333)},
{field.NewFieldConst(9597329746711776008), field.NewFieldConst(13290917949843243492)},
{field.NewFieldConst(9061260430036409956), field.NewFieldConst(10642927510372211646)},
{field.NewFieldConst(9766392710518436993), field.NewFieldConst(1864738510099355769)},
}
// ArithmeticExtensionGate { num_ops: 10 }
var arithmeticExtensionGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(14556369430662721230), field.NewFieldConst(4131185000258568561)},
{field.NewFieldConst(16378466706564867046), field.NewFieldConst(1439052841211884527)},
{field.NewFieldConst(8231479592213172392), field.NewFieldConst(8409169031581010782)},
{field.NewFieldConst(5465959779370835700), field.NewFieldConst(17016702720873000919)},
{field.NewFieldConst(10611951970626560747), field.NewFieldConst(11015475306668399283)},
{field.NewFieldConst(6566683434087540889), field.NewFieldConst(7528162900166069532)},
{field.NewFieldConst(13167150559619768862), field.NewFieldConst(15618445283750881414)},
{field.NewFieldConst(14768578132422983729), field.NewFieldConst(13938407401080069149)},
{field.NewFieldConst(18415232841919605685), field.NewFieldConst(15088528771916927003)},
{field.NewFieldConst(1305736199568141897), field.NewFieldConst(16885250849392919438)},
{field.NewFieldConst(1425549592953864549), field.NewFieldConst(1074162823816629148)},
{field.NewFieldConst(12616210534513128803), field.NewFieldConst(8618852250387339753)},
{field.NewFieldConst(16775588216530426832), field.NewFieldConst(16358913853138883160)},
{field.NewFieldConst(236831045676808583), field.NewFieldConst(16231688985959438642)},
{field.NewFieldConst(264831195814170716), field.NewFieldConst(9852325877887114505)},
{field.NewFieldConst(14065541678187010167), field.NewFieldConst(5594602585697559035)},
{field.NewFieldConst(2354884863196165822), field.NewFieldConst(12715102096346587892)},
{field.NewFieldConst(5881791209743274427), field.NewFieldConst(1913490798645218291)},
{field.NewFieldConst(3621056055759314065), field.NewFieldConst(15076066883455218113)},
{field.NewFieldConst(15382741815013668685), field.NewFieldConst(5674166256062091576)},
}
// MulExtensionGate { num_ops: 13 }
var mulExtensionGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(14558272317822654580), field.NewFieldConst(833215892324477732)},
{field.NewFieldConst(9214806296346539012), field.NewFieldConst(7798842673847612486)},
{field.NewFieldConst(4933313819253472884), field.NewFieldConst(17115399133104593821)},
{field.NewFieldConst(6382294466663581729), field.NewFieldConst(8863722647290983592)},
{field.NewFieldConst(5274430631758054179), field.NewFieldConst(1761561038204031519)},
{field.NewFieldConst(6975818216493368257), field.NewFieldConst(3643153118790582585)},
{field.NewFieldConst(9382708770545050748), field.NewFieldConst(2040988809014144797)},
{field.NewFieldConst(7526300035416853327), field.NewFieldConst(8692405747344509879)},
{field.NewFieldConst(6092157877842311771), field.NewFieldConst(5767914690949635280)},
{field.NewFieldConst(3636879736078164520), field.NewFieldConst(454792903724498694)},
{field.NewFieldConst(5982213211108308130), field.NewFieldConst(3906161453783544349)},
{field.NewFieldConst(1353999567434327832), field.NewFieldConst(3912356165392315450)},
{field.NewFieldConst(3866250282554618990), field.NewFieldConst(14215790041865539111)},
{field.NewFieldConst(16972659905821970574), field.NewFieldConst(2550277288305104044)},
{field.NewFieldConst(6739526869755283609), field.NewFieldConst(4676222628249438354)},
{field.NewFieldConst(18314541579046409607), field.NewFieldConst(13871312232745645647)},
{field.NewFieldConst(13309435341537760906), field.NewFieldConst(10879629980202564460)},
{field.NewFieldConst(8149445702527176593), field.NewFieldConst(12079787385488004774)},
{field.NewFieldConst(141936326832390573), field.NewFieldConst(9852981409020916366)},
{field.NewFieldConst(1174277439708011834), field.NewFieldConst(11084240604056156653)},
{field.NewFieldConst(3890191667424476902), field.NewFieldConst(1428130379783403165)},
{field.NewFieldConst(18264002552181363059), field.NewFieldConst(17855293364353531924)},
{field.NewFieldConst(1657518282890904146), field.NewFieldConst(14874491364689193658)},
{field.NewFieldConst(9091236796792826297), field.NewFieldConst(18232800981045995203)},
{field.NewFieldConst(7965395014621568897), field.NewFieldConst(15643014489741966811)},
{field.NewFieldConst(14048129594584036134), field.NewFieldConst(8880723489474532129)},
}
// CosetInterpolationGate { subgroup_bits: 4, degree: 6, barycentric_weights: [17293822565076172801, 18374686475376656385, 18446744069413535745, 281474976645120, 17592186044416, 18446744069414584577, 18446744000695107601, 18446744065119617025, 1152921504338411520, 72057594037927936, 18446744069415632897, 18446462594437939201, 18446726477228539905, 18446744069414584065, 68719476720, 4294967296], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
var cosetInterpolationGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(4489474937116132272), field.NewFieldConst(17966585078409280607)},
{field.NewFieldConst(6284821823752419954), field.NewFieldConst(15732864946173560339)},
{field.NewFieldConst(12879723719779486283), field.NewFieldConst(983649133858104142)},
{field.NewFieldConst(17293136937393925432), field.NewFieldConst(4033193666483141970)},
{field.NewFieldConst(10809912963683055710), field.NewFieldConst(3166226310305151244)},
{field.NewFieldConst(13051854837169808452), field.NewFieldConst(12636844243964449888)},
{field.NewFieldConst(15180422697988222141), field.NewFieldConst(3172471974421734205)},
{field.NewFieldConst(7715327263429433235), field.NewFieldConst(14269461688353925342)},
{field.NewFieldConst(7348198793616724228), field.NewFieldConst(11426363269581761252)},
{field.NewFieldConst(6529761710182712179), field.NewFieldConst(15370899814178958348)},
{field.NewFieldConst(1312640305437468539), field.NewFieldConst(7416725026793550034)},
{field.NewFieldConst(7435934314089172319), field.NewFieldConst(8931511780309647479)},
}
// PoseidonMdsGate(PhantomData<plonky2_field::goldilocks_field::GoldilocksField>)<WIDTH=12>"
var poseidonMdsGateExpectedConstraints = []field.QuadraticExtension{
{field.NewFieldConst(7821764612044984890), field.NewFieldConst(11645399715550800761)},
{field.NewFieldConst(7054686226368496581), field.NewFieldConst(3456599659382547499)},
{field.NewFieldConst(9932401212201586910), field.NewFieldConst(15935184283784595275)},
{field.NewFieldConst(14850232436396031573), field.NewFieldConst(10054869170615550942)},
{field.NewFieldConst(17859784214232634920), field.NewFieldConst(3141019307077014353)},
{field.NewFieldConst(1316926243065869924), field.NewFieldConst(5447399801288094074)},
{field.NewFieldConst(12198784876096903918), field.NewFieldConst(10976551553233951532)},
{field.NewFieldConst(3280500541526908156), field.NewFieldConst(1813330468204166522)},
{field.NewFieldConst(6788483962196012692), field.NewFieldConst(15983747071745976199)},
{field.NewFieldConst(3372073447943379816), field.NewFieldConst(9356836818900551936)},
{field.NewFieldConst(13834815153351545489), field.NewFieldConst(1073963211629459057)},
{field.NewFieldConst(15376716257200419051), field.NewFieldConst(16044430964768811142)},
{field.NewFieldConst(16752138206727891451), field.NewFieldConst(6303059651352280564)},
{field.NewFieldConst(17195959285241102556), field.NewFieldConst(10990140109461952122)},
{field.NewFieldConst(16812594260057394716), field.NewFieldConst(5841834090350584793)},
{field.NewFieldConst(17706037262140285164), field.NewFieldConst(8626184557677598926)},
{field.NewFieldConst(6826825357492466350), field.NewFieldConst(17865947929743097490)},
{field.NewFieldConst(13679887869755160737), field.NewFieldConst(16481628195512675795)},
{field.NewFieldConst(7881296289635150478), field.NewFieldConst(15368930380652981390)},
{field.NewFieldConst(12075171536836315078), field.NewFieldConst(12900345753644751245)},
{field.NewFieldConst(11461113822534614109), field.NewFieldConst(2937306395206947398)},
{field.NewFieldConst(18365572828001780476), field.NewFieldConst(4309067613742479326)},
{field.NewFieldConst(9460729461000852035), field.NewFieldConst(9232487430983842586)},
{field.NewFieldConst(9920817005263779727), field.NewFieldConst(16326126591726196229)},
}
type TestGateCircuit struct {
testGate gates.Gate
ExpectedConstraints []field.QuadraticExtension
}
func (circuit *TestGateCircuit) Define(api frontend.API) error {
commonCircuitData := utils.DeserializeCommonCircuitData("../../data/decode_block/common_circuit_data.json")
numSelectors := commonCircuitData.SelectorsInfo.NumSelectors()
fieldAPI := field.NewFieldAPI(api)
qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI)
vars := gates.NewEvaluationVars(localConstants[numSelectors:], localWires, publicInputsHash)
constraints := circuit.testGate.EvalUnfiltered(api, qeAPI, *vars)
if len(constraints) != len(circuit.ExpectedConstraints) {
return errors.New("gate constraints length mismatch")
}
for i := 0; i < len(constraints); i++ {
qeAPI.AssertIsEqual(constraints[i], circuit.ExpectedConstraints[i])
}
return nil
}
func TestGates(t *testing.T) {
assert := test.NewAssert(t)
testCase := func(testGate gates.Gate, expectedConstraints []field.QuadraticExtension) {
circuit := &TestGateCircuit{testGate: testGate, ExpectedConstraints: expectedConstraints}
witness := &TestGateCircuit{testGate: testGate, ExpectedConstraints: expectedConstraints}
err := test.IsSolved(circuit, witness, field.TEST_CURVE.ScalarField())
assert.NoError(err)
}
type gateTest struct {
testGate gates.Gate
expectedConstraints []field.QuadraticExtension
}
gateTests := []gateTest{
{gates.NewPublicInputGate(), publicInputGateExpectedConstraints},
{gates.NewBaseSumGate(63, 2), baseSumGateExpectedConstraints},
{gates.NewArithmeticGate(20), arithmeticGateExpectedConstraints},
{gates.NewRandomAccessGate(4, 4, 2), randomAccessGateExpectedConstraints},
{gates.NewPoseidonGate(), poseidonGateExpectedConstraints},
{gates.NewArithmeticExtensionGate(10), arithmeticExtensionGateExpectedConstraints},
{gates.NewMultiplicationExtensionGate(13), mulExtensionGateExpectedConstraints},
{gates.NewReducingExtensionGate(33), reducingExtensionGateExpectedConstraints},
{gates.NewReducingGate(44), reducingGateExpectedConstraints},
{gates.NewCosetInterpolationGate(
4,
6,
[]goldilocks.Element{
goldilocks.NewElement(17293822565076172801),
goldilocks.NewElement(18374686475376656385),
goldilocks.NewElement(18446744069413535745),
goldilocks.NewElement(281474976645120),
goldilocks.NewElement(17592186044416),
goldilocks.NewElement(18446744069414584577),
goldilocks.NewElement(18446744000695107601),
goldilocks.NewElement(18446744065119617025),
goldilocks.NewElement(1152921504338411520),
goldilocks.NewElement(72057594037927936),
goldilocks.NewElement(18446744069415632897),
goldilocks.NewElement(18446462594437939201),
goldilocks.NewElement(18446726477228539905),
goldilocks.NewElement(18446744069414584065),
goldilocks.NewElement(68719476720),
goldilocks.NewElement(4294967296),
},
), cosetInterpolationGateExpectedConstraints},
{&gates.PoseidonMdsGate{}, poseidonMdsGateExpectedConstraints},
}
for _, test := range gateTests {
testCase(
test.testGate,
test.expectedConstraints,
)
}
}

+ 0
- 160
verifier/internal/plonk/challenger.go

@ -1,160 +0,0 @@
package plonk
import (
"fmt"
"github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/fri"
)
type ChallengerChip struct {
api frontend.API `gnark:"-"`
field field.FieldAPI `gnark:"-"`
poseidonChip *poseidon.PoseidonChip
poseidonBN128Chip *poseidon.PoseidonBN128Chip
spongeState [poseidon.SPONGE_WIDTH]frontend.Variable
inputBuffer []field.F
outputBuffer []field.F
}
func NewChallengerChip(api frontend.API, fieldAPI field.FieldAPI, poseidonChip *poseidon.PoseidonChip, poseidonBN128Chip *poseidon.PoseidonBN128Chip) *ChallengerChip {
var spongeState [poseidon.SPONGE_WIDTH]frontend.Variable
var inputBuffer []field.F
var outputBuffer []field.F
for i := 0; i < poseidon.SPONGE_WIDTH; i++ {
spongeState[i] = frontend.Variable(0)
}
return &ChallengerChip{
api: api,
field: fieldAPI,
poseidonChip: poseidonChip,
poseidonBN128Chip: poseidonBN128Chip,
spongeState: spongeState,
inputBuffer: inputBuffer,
outputBuffer: outputBuffer,
}
}
func (c *ChallengerChip) ObserveElement(element field.F) {
c.outputBuffer = clearBuffer(c.outputBuffer)
c.inputBuffer = append(c.inputBuffer, element)
if len(c.inputBuffer) == poseidon.SPONGE_RATE {
c.duplexing()
}
}
func (c *ChallengerChip) ObserveElements(elements []field.F) {
for i := 0; i < len(elements); i++ {
c.ObserveElement(elements[i])
}
}
func (c *ChallengerChip) ObserveHash(hash poseidon.PoseidonHashOut) {
elements := c.poseidonChip.ToVec(hash)
c.ObserveElements(elements)
}
func (c *ChallengerChip) ObserveBN128Hash(hash poseidon.PoseidonBN128HashOut) {
elements := c.poseidonBN128Chip.ToVec(hash)
c.ObserveElements(elements)
}
func (c *ChallengerChip) ObserveCap(cap []poseidon.PoseidonBN128HashOut) {
for i := 0; i < len(cap); i++ {
c.ObserveBN128Hash(cap[i])
}
}
func (c *ChallengerChip) ObserveExtensionElement(element field.QuadraticExtension) {
c.ObserveElements(element[:])
}
func (c *ChallengerChip) ObserveExtensionElements(elements []field.QuadraticExtension) {
for i := 0; i < len(elements); i++ {
c.ObserveExtensionElement(elements[i])
}
}
func (c *ChallengerChip) ObserveOpenings(openings fri.FriOpenings) {
for i := 0; i < len(openings.Batches); i++ {
c.ObserveExtensionElements(openings.Batches[i].Values)
}
}
func (c *ChallengerChip) GetChallenge() field.F {
if len(c.inputBuffer) != 0 || len(c.outputBuffer) == 0 {
c.duplexing()
}
challenge := c.outputBuffer[len(c.outputBuffer)-1]
c.outputBuffer = c.outputBuffer[:len(c.outputBuffer)-1]
return challenge
}
func (c *ChallengerChip) GetNChallenges(n uint64) []field.F {
challenges := make([]field.F, n)
for i := uint64(0); i < n; i++ {
challenges[i] = c.GetChallenge()
}
return challenges
}
func (c *ChallengerChip) GetExtensionChallenge() field.QuadraticExtension {
values := c.GetNChallenges(2)
return field.QuadraticExtension{values[0], values[1]}
}
func (c *ChallengerChip) GetHash() poseidon.PoseidonHashOut {
return [4]field.F{c.GetChallenge(), c.GetChallenge(), c.GetChallenge(), c.GetChallenge()}
}
func (c *ChallengerChip) GetFriChallenges(commitPhaseMerkleCaps []common.MerkleCap, finalPoly common.PolynomialCoeffs, powWitness field.F, degreeBits uint64, config common.FriConfig) common.FriChallenges {
numFriQueries := config.NumQueryRounds
friAlpha := c.GetExtensionChallenge()
var friBetas []field.QuadraticExtension
for i := 0; i < len(commitPhaseMerkleCaps); i++ {
c.ObserveCap(commitPhaseMerkleCaps[i])
friBetas = append(friBetas, c.GetExtensionChallenge())
}
c.ObserveExtensionElements(finalPoly.Coeffs)
c.ObserveElement(powWitness)
friPowResponse := c.GetChallenge()
friQueryIndices := c.GetNChallenges(numFriQueries)
return common.FriChallenges{
FriAlpha: friAlpha,
FriBetas: friBetas,
FriPowResponse: friPowResponse,
FriQueryIndices: friQueryIndices,
}
}
func clearBuffer(buffer []field.F) []field.F {
return make([]field.F, 0)
}
func (c *ChallengerChip) duplexing() {
if len(c.inputBuffer) > poseidon.SPONGE_RATE {
fmt.Println(len(c.inputBuffer))
panic("something went wrong")
}
for i := 0; i < len(c.inputBuffer); i++ {
c.spongeState[i] = c.field.Reduce(c.inputBuffer[i]).Limbs[0]
}
c.inputBuffer = clearBuffer(c.inputBuffer)
c.spongeState = c.poseidonChip.Poseidon(c.spongeState)
clearBuffer(c.outputBuffer)
for i := 0; i < poseidon.SPONGE_RATE; i++ {
c.outputBuffer = append(c.outputBuffer, c.field.NewElement(c.spongeState[i]))
}
}

+ 0
- 227
verifier/internal/plonk/challenger_test.go

@ -1,227 +0,0 @@
package plonk
import (
"math/big"
"testing"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/fri"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils"
)
type TestChallengerCircuit struct {
commonCircuitDataFilename string `gnark:"-"`
CircuitDigest frontend.Variable `gnark:",public"`
PublicInputs []field.F `gnark:",public"`
WiresCap []frontend.Variable
PlonkZsPartialProductsCap []frontend.Variable
QuotientPolysCap []frontend.Variable
FriOpenings fri.FriOpenings
CommitPhaseMerkleCaps [][]frontend.Variable
FinalPoly common.PolynomialCoeffs
PowWitness field.F
}
func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
commonCircuitData := utils.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
config := commonCircuitData.Config
numChallenges := config.NumChallenges
fieldAPI := field.NewFieldAPI(api)
qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI)
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
poseidonBN128Chip := poseidon.NewPoseidonBN128Chip(api, fieldAPI)
challenger := NewChallengerChip(api, fieldAPI, poseidonChip, poseidonBN128Chip)
challenger.ObserveBN128Hash(circuit.CircuitDigest)
challenger.ObserveHash(poseidonChip.HashNoPad(circuit.PublicInputs))
challenger.ObserveCap(circuit.WiresCap)
plonkBetas := challenger.GetNChallenges(numChallenges)
plonkGammas := challenger.GetNChallenges(numChallenges)
challenger.ObserveCap(circuit.PlonkZsPartialProductsCap)
plonkAlphas := challenger.GetNChallenges(numChallenges)
challenger.ObserveCap(circuit.QuotientPolysCap)
plonkZeta := challenger.GetExtensionChallenge()
challenger.ObserveOpenings(circuit.FriOpenings)
friChallenges := challenger.GetFriChallenges(
circuit.CommitPhaseMerkleCaps,
circuit.FinalPoly,
circuit.PowWitness,
commonCircuitData.DegreeBits,
config.FriConfig,
)
expectedPlonkBetas := [2]field.F{
field.NewFieldConstFromString("17615363392879944733"),
field.NewFieldConstFromString("9422446877322953047"),
}
expectedPlonkGammas := [2]field.F{
field.NewFieldConstFromString("15174493176564484303"),
field.NewFieldConstFromString("6175150444166239851"),
}
for i := 0; i < 2; i++ {
fieldAPI.AssertIsEqual(plonkBetas[i], expectedPlonkBetas[i])
fieldAPI.AssertIsEqual(plonkGammas[i], expectedPlonkGammas[i])
}
expectedPlonkAlphas := [2]field.F{
field.NewFieldConstFromString("9276470834414745550"),
field.NewFieldConstFromString("5302812342351431915"),
}
for i := 0; i < 2; i++ {
fieldAPI.AssertIsEqual(plonkAlphas[i], expectedPlonkAlphas[i])
}
expectedPlonkZeta := field.QuadraticExtension{
field.NewFieldConstFromString("3892795992421241388"),
field.NewFieldConstFromString("15786647757418200302"),
}
for i := 0; i < 2; i++ {
fieldAPI.AssertIsEqual(plonkZeta[i], expectedPlonkZeta[i])
}
fieldAPI.AssertIsEqual(friChallenges.FriAlpha[0], field.NewFieldConst(885535811531859621))
fieldAPI.AssertIsEqual(friChallenges.FriBetas[0][0], field.NewFieldConst(5231781384587895507))
fieldAPI.AssertIsEqual(friChallenges.FriPowResponse, field.NewFieldConst(70715523064019))
fieldAPI.AssertIsEqual(friChallenges.FriQueryIndices[0], field.NewFieldConst(11890500485816111017))
return nil
}
func StringToBN128Hash(hashStr string) poseidon.PoseidonBN128HashOut {
hashBigInt, ok := new(big.Int).SetString(hashStr, 10)
if !(ok) {
panic("Invalid hash: " + hashStr)
}
hashVar := frontend.Variable(*hashBigInt)
return poseidon.PoseidonBN128HashOut(hashVar)
}
func TestChallengerWitness(t *testing.T) {
assert := test.NewAssert(t)
testCase := func() {
proofWithPis := utils.DeserializeProofWithPublicInputs("../../data/decode_block/proof_with_public_inputs.json")
verifierData := utils.DeserializeVerifierOnlyCircuitData("../../data/decode_block/verifier_only_circuit_data.json")
circuit := TestChallengerCircuit{
commonCircuitDataFilename: "../../data/decode_block/common_circuit_data.json",
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
}
witness := TestChallengerCircuit{
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
}
err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField())
assert.NoError(err)
}
testCase()
}
func TestChallengerProver(t *testing.T) {
proofWithPis := utils.DeserializeProofWithPublicInputs("../../data/decode_block/proof_with_public_inputs.json")
verifierData := utils.DeserializeVerifierOnlyCircuitData("../../data/decode_block/verifier_only_circuit_data.json")
circuit := TestChallengerCircuit{
commonCircuitDataFilename: "../../data/decode_block/common_circuit_data.json",
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
}
proofWithPis = utils.DeserializeProofWithPublicInputs("../../data/decode_block/proof_with_public_inputs.json")
verifierData = utils.DeserializeVerifierOnlyCircuitData("../../data/decode_block/verifier_only_circuit_data.json")
assignment := TestChallengerCircuit{
commonCircuitDataFilename: "../../data/decode_block/common_circuit_data.json",
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
}
r1cs, err := frontend.Compile(field.TEST_CURVE.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
panic(err)
}
println("num constraints is ", r1cs.GetNbConstraints())
assert := test.NewAssert(t)
err = test.IsSolved(&circuit, &assignment, field.TEST_CURVE.ScalarField())
assert.NoError(err)
witness, err := frontend.NewWitness(&assignment, field.TEST_CURVE.ScalarField())
if err != nil {
panic(err)
}
pk, vk, err := groth16.Setup(r1cs)
if err != nil {
panic(err)
}
proof, err := groth16.Prove(r1cs, pk, witness)
if err != nil {
panic(err)
}
publicWitness, err := witness.Public()
if err != nil {
panic(err)
}
err = groth16.Verify(proof, vk, publicWitness)
if err != nil {
panic(err)
}
}

+ 0
- 13
verifier/internal/plonk/types.go

@ -1,13 +0,0 @@
package plonk
import "github.com/succinctlabs/gnark-plonky2-verifier/field"
type OpeningSet struct {
Constants []field.QuadraticExtension
PlonkSigmas []field.QuadraticExtension
Wires []field.QuadraticExtension
PlonkZs []field.QuadraticExtension
PlonkZsNext []field.QuadraticExtension
PartialProducts []field.QuadraticExtension
QuotientPolys []field.QuadraticExtension
}

+ 0
- 28
verifier/types.go

@ -1,28 +0,0 @@
package verifier
import (
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/plonk"
)
type Proof struct {
WiresCap common.MerkleCap
PlonkZsPartialProductsCap common.MerkleCap
QuotientPolysCap common.MerkleCap
Openings plonk.OpeningSet
OpeningProof common.FriProof
}
type ProofWithPublicInputs struct {
Proof Proof
PublicInputs []field.F
}
type ProofChallenges struct {
PlonkBetas []field.F
PlonkGammas []field.F
PlonkAlphas []field.F
PlonkZeta field.QuadraticExtension
FriChallenges common.FriChallenges
}

+ 45
- 49
verifier/verifier.go

@ -2,63 +2,53 @@ package verifier
import ( import (
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/challenger"
"github.com/succinctlabs/gnark-plonky2-verifier/fri"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/plonk"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/fri"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/plonk"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
) )
type VerifierChip struct { type VerifierChip struct {
api frontend.API `gnark:"-"`
fieldAPI field.FieldAPI `gnark:"-"`
qeAPI *field.QuadraticExtensionAPI `gnark:"-"`
poseidonChip *poseidon.PoseidonChip
poseidonBN128Chip *poseidon.PoseidonBN128Chip
api frontend.API `gnark:"-"`
poseidonGlChip *poseidon.GoldilocksChip
poseidonBN254Chip *poseidon.BN254Chip
plonkChip *plonk.PlonkChip plonkChip *plonk.PlonkChip
friChip *fri.FriChip
friChip *fri.Chip
} }
func NewVerifierChip(api frontend.API, commonCircuitData common.CommonCircuitData) *VerifierChip {
fieldAPI := field.NewFieldAPI(api)
qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI)
poseidonBN128Chip := poseidon.NewPoseidonBN128Chip(api, fieldAPI)
friChip := fri.NewFriChip(api, fieldAPI, qeAPI, poseidonBN128Chip, &commonCircuitData.FriParams)
plonkChip := plonk.NewPlonkChip(api, qeAPI, commonCircuitData)
// We are using goldilocks poseidon for the challenge computation
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
func NewVerifierChip(api frontend.API, commonCircuitData types.CommonCircuitData) *VerifierChip {
friChip := fri.NewChip(api, &commonCircuitData.FriParams)
plonkChip := plonk.NewPlonkChip(api, commonCircuitData)
poseidonGlChip := poseidon.NewGoldilocksChip(api)
poseidonBN254Chip := poseidon.NewBN254Chip(api)
return &VerifierChip{ return &VerifierChip{
api: api, api: api,
fieldAPI: fieldAPI,
qeAPI: qeAPI,
poseidonChip: poseidonChip,
poseidonBN128Chip: poseidonBN128Chip,
poseidonGlChip: poseidonGlChip,
poseidonBN254Chip: poseidonBN254Chip,
plonkChip: plonkChip, plonkChip: plonkChip,
friChip: friChip, friChip: friChip,
} }
} }
func (c *VerifierChip) GetPublicInputsHash(publicInputs []field.F) poseidon.PoseidonHashOut {
return c.poseidonChip.HashNoPad(publicInputs)
func (c *VerifierChip) GetPublicInputsHash(publicInputs []gl.Variable) poseidon.GoldilocksHashOut {
return c.poseidonGlChip.HashNoPad(publicInputs)
} }
func (c *VerifierChip) GetChallenges( func (c *VerifierChip) GetChallenges(
proof common.Proof,
publicInputsHash poseidon.PoseidonHashOut,
commonData common.CommonCircuitData,
verifierData common.VerifierOnlyCircuitData,
) common.ProofChallenges {
proof types.Proof,
publicInputsHash poseidon.GoldilocksHashOut,
commonData types.CommonCircuitData,
verifierData types.VerifierOnlyCircuitData,
) types.ProofChallenges {
config := commonData.Config config := commonData.Config
numChallenges := config.NumChallenges numChallenges := config.NumChallenges
challenger := plonk.NewChallengerChip(c.api, c.fieldAPI, c.poseidonChip, c.poseidonBN128Chip)
challenger := challenger.NewChip(c.api)
var circuitDigest = verifierData.CircuitDigest var circuitDigest = verifierData.CircuitDigest
challenger.ObserveBN128Hash(circuitDigest)
challenger.ObserveBN254Hash(circuitDigest)
challenger.ObserveHash(publicInputsHash) challenger.ObserveHash(publicInputsHash)
challenger.ObserveCap(proof.WiresCap) challenger.ObserveCap(proof.WiresCap)
plonkBetas := challenger.GetNChallenges(numChallenges) plonkBetas := challenger.GetNChallenges(numChallenges)
@ -70,9 +60,9 @@ func (c *VerifierChip) GetChallenges(
challenger.ObserveCap(proof.QuotientPolysCap) challenger.ObserveCap(proof.QuotientPolysCap)
plonkZeta := challenger.GetExtensionChallenge() plonkZeta := challenger.GetExtensionChallenge()
challenger.ObserveOpenings(fri.ToFriOpenings(proof.Openings))
challenger.ObserveOpenings(fri.ToOpenings(proof.Openings))
return common.ProofChallenges{
return types.ProofChallenges{
PlonkBetas: plonkBetas, PlonkBetas: plonkBetas,
PlonkGammas: plonkGammas, PlonkGammas: plonkGammas,
PlonkAlphas: plonkAlphas, PlonkAlphas: plonkAlphas,
@ -154,7 +144,13 @@ func (c *VerifierChip) generateProofInput(commonData common.CommonCircuitData) c
} }
*/ */
func (c *VerifierChip) Verify(proof common.Proof, publicInputs []field.F, verifierData common.VerifierOnlyCircuitData, commonData common.CommonCircuitData) {
func (c *VerifierChip) Verify(
proof types.Proof,
publicInputs []gl.Variable,
verifierData types.VerifierOnlyCircuitData,
commonData types.CommonCircuitData,
) {
glApi := gl.NewChip(c.api)
// TODO: Need to range check all the proof and public input elements to make sure they are within goldilocks field // TODO: Need to range check all the proof and public input elements to make sure they are within goldilocks field
// Generate the parts of the witness that is for the plonky2 proof input // Generate the parts of the witness that is for the plonky2 proof input
@ -163,7 +159,7 @@ func (c *VerifierChip) Verify(proof common.Proof, publicInputs []field.F, verifi
c.plonkChip.Verify(proofChallenges, proof.Openings, publicInputsHash) c.plonkChip.Verify(proofChallenges, proof.Openings, publicInputsHash)
initialMerkleCaps := []common.MerkleCap{
initialMerkleCaps := []types.FriMerkleCap{
verifierData.ConstantSigmasCap, verifierData.ConstantSigmasCap,
proof.WiresCap, proof.WiresCap,
proof.PlonkZsPartialProductsCap, proof.PlonkZsPartialProductsCap,
@ -172,26 +168,26 @@ func (c *VerifierChip) Verify(proof common.Proof, publicInputs []field.F, verifi
// Seems like there is a bug in the emulated field code. // Seems like there is a bug in the emulated field code.
// Add ZERO to all of the fri challenges values to reduce them. // Add ZERO to all of the fri challenges values to reduce them.
proofChallenges.PlonkZeta[0] = c.fieldAPI.Add(proofChallenges.PlonkZeta[0], field.ZERO_F)
proofChallenges.PlonkZeta[1] = c.fieldAPI.Add(proofChallenges.PlonkZeta[1], field.ZERO_F)
proofChallenges.PlonkZeta[0] = glApi.Add(proofChallenges.PlonkZeta[0], gl.Zero())
proofChallenges.PlonkZeta[1] = glApi.Add(proofChallenges.PlonkZeta[1], gl.Zero())
proofChallenges.FriChallenges.FriAlpha[0] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriAlpha[0], field.ZERO_F)
proofChallenges.FriChallenges.FriAlpha[1] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriAlpha[1], field.ZERO_F)
proofChallenges.FriChallenges.FriAlpha[0] = glApi.Add(proofChallenges.FriChallenges.FriAlpha[0], gl.Zero())
proofChallenges.FriChallenges.FriAlpha[1] = glApi.Add(proofChallenges.FriChallenges.FriAlpha[1], gl.Zero())
for i := 0; i < len(proofChallenges.FriChallenges.FriBetas); i++ { for i := 0; i < len(proofChallenges.FriChallenges.FriBetas); i++ {
proofChallenges.FriChallenges.FriBetas[i][0] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriBetas[i][0], field.ZERO_F)
proofChallenges.FriChallenges.FriBetas[i][1] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriBetas[i][1], field.ZERO_F)
proofChallenges.FriChallenges.FriBetas[i][0] = glApi.Add(proofChallenges.FriChallenges.FriBetas[i][0], gl.Zero())
proofChallenges.FriChallenges.FriBetas[i][1] = glApi.Add(proofChallenges.FriChallenges.FriBetas[i][1], gl.Zero())
} }
proofChallenges.FriChallenges.FriPowResponse = c.fieldAPI.Add(proofChallenges.FriChallenges.FriPowResponse, field.ZERO_F)
proofChallenges.FriChallenges.FriPowResponse = glApi.Add(proofChallenges.FriChallenges.FriPowResponse, gl.Zero())
for i := 0; i < len(proofChallenges.FriChallenges.FriQueryIndices); i++ { for i := 0; i < len(proofChallenges.FriChallenges.FriQueryIndices); i++ {
proofChallenges.FriChallenges.FriQueryIndices[i] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriQueryIndices[i], field.ZERO_F)
proofChallenges.FriChallenges.FriQueryIndices[i] = glApi.Add(proofChallenges.FriChallenges.FriQueryIndices[i], gl.Zero())
} }
c.friChip.VerifyFriProof( c.friChip.VerifyFriProof(
fri.GetFriInstance(&commonData, c.qeAPI, proofChallenges.PlonkZeta, commonData.DegreeBits),
fri.ToFriOpenings(proof.Openings),
fri.GetInstance(&commonData, glApi, proofChallenges.PlonkZeta, commonData.DegreeBits),
fri.ToOpenings(proof.Openings),
&proofChallenges.FriChallenges, &proofChallenges.FriChallenges,
initialMerkleCaps, initialMerkleCaps,
&proof.OpeningProof, &proof.OpeningProof,

+ 11
- 12
verifier/verifier_test.go

@ -8,15 +8,14 @@ import (
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/math/emulated"
"github.com/consensys/gnark/test" "github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
"github.com/succinctlabs/gnark-plonky2-verifier/types"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier" "github.com/succinctlabs/gnark-plonky2-verifier/verifier"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils"
) )
type TestVerifierCircuit struct { type TestVerifierCircuit struct {
Proof common.Proof
PublicInputs []field.F `gnark:",public"`
Proof types.Proof
PublicInputs []gl.Variable `gnark:",public"`
verifierChip *verifier.VerifierChip `gnark:"-"` verifierChip *verifier.VerifierChip `gnark:"-"`
plonky2CircuitName string `gnark:"-"` plonky2CircuitName string `gnark:"-"`
@ -24,8 +23,8 @@ type TestVerifierCircuit struct {
func (c *TestVerifierCircuit) Define(api frontend.API) error { func (c *TestVerifierCircuit) Define(api frontend.API) error {
circuitDirname := "./data/" + c.plonky2CircuitName + "/" circuitDirname := "./data/" + c.plonky2CircuitName + "/"
commonCircuitData := utils.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := utils.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
commonCircuitData := verifier.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
c.verifierChip = verifier.NewVerifierChip(api, commonCircuitData) c.verifierChip = verifier.NewVerifierChip(api, commonCircuitData)
@ -39,21 +38,21 @@ func TestStepVerifier(t *testing.T) {
testCase := func() { testCase := func() {
plonky2Circuit := "step" plonky2Circuit := "step"
proofWithPis := utils.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
proofWithPis := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit := TestVerifierCircuit{ circuit := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit, plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis.Proof, Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs, PublicInputs: proofWithPis.PublicInputs,
} }
proofWithPis2 := utils.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
proofWithPis2 := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
witness := TestVerifierCircuit{ witness := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit, plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis2.Proof, Proof: proofWithPis2.Proof,
PublicInputs: proofWithPis2.PublicInputs, PublicInputs: proofWithPis2.PublicInputs,
} }
err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField())
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err) assert.NoError(err)
} }
testCase() testCase()
@ -63,14 +62,14 @@ func TestStepVerifier2(t *testing.T) {
assert := test.NewAssert(t) assert := test.NewAssert(t)
plonky2Circuit := "step" plonky2Circuit := "step"
proofWithPis := utils.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
proofWithPis := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
circuit := TestVerifierCircuit{ circuit := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit, plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis.Proof, Proof: proofWithPis.Proof,
PublicInputs: proofWithPis.PublicInputs, PublicInputs: proofWithPis.PublicInputs,
} }
proofWithPis2 := utils.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
proofWithPis2 := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json")
witness := TestVerifierCircuit{ witness := TestVerifierCircuit{
plonky2CircuitName: plonky2Circuit, plonky2CircuitName: plonky2Circuit,
Proof: proofWithPis2.Proof, Proof: proofWithPis2.Proof,

Loading…
Cancel
Save