diff --git a/benchmark.go b/benchmark.go index 7cb6b31..9b60a3b 100644 --- a/benchmark.go +++ b/benchmark.go @@ -8,10 +8,9 @@ import ( "os" "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/common" - "github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" @@ -22,8 +21,8 @@ import ( ) type BenchmarkPlonky2VerifierCircuit struct { - Proof common.Proof - PublicInputs []field.F `gnark:",public"` + Proof types.Proof + PublicInputs []gl.Variable `gnark:",public"` verifierChip *verifier.VerifierChip `gnark:"-"` plonky2CircuitName string `gnark:"-"` @@ -31,8 +30,8 @@ type BenchmarkPlonky2VerifierCircuit struct { func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error { 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) @@ -45,7 +44,7 @@ func compileCircuit(plonky2Circuit string, profileCircuit bool, serialize bool, circuit := BenchmarkPlonky2VerifierCircuit{ 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.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 { - proofWithPis := utils.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json") + proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json") // Witness assignment := &BenchmarkPlonky2VerifierCircuit{ diff --git a/benchmark_plonk.go b/benchmark_plonk.go new file mode 100644 index 0000000..6f7df12 --- /dev/null +++ b/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) +} diff --git a/challenger/challenger.go b/challenger/challenger.go new file mode 100644 index 0000000..b1af60b --- /dev/null +++ b/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]) + } +} diff --git a/field/goldilocks.go b/field/goldilocks.go deleted file mode 100644 index 214fd63..0000000 --- a/field/goldilocks.go +++ /dev/null @@ -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 -} diff --git a/field/quadratic_extension.go b/field/quadratic_extension.go deleted file mode 100644 index 852176e..0000000 --- a/field/quadratic_extension.go +++ /dev/null @@ -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 -} diff --git a/field/quadratic_extension_test.go b/field/quadratic_extension_test.go deleted file mode 100644 index 5f10b1d..0000000 --- a/field/quadratic_extension_test.go +++ /dev/null @@ -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) -} diff --git a/verifier/internal/fri/fri.go b/fri/fri.go similarity index 65% rename from verifier/internal/fri/fri.go rename to fri/fri.go index 9a1bc2f..373fe01 100644 --- a/verifier/internal/fri/fri.go +++ b/fri/fri.go @@ -8,66 +8,69 @@ import ( "github.com/consensys/gnark-crypto/field/goldilocks" "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/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, - 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, - fieldAPI: fieldAPI, - qeAPI: qeAPI, - poseidonBN128Chip: poseidonBN128Chip, + poseidonBN254Chip: poseidonBN254Chip, 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. // Note that this is assuming that the Goldilocks field is being used. Specfically that the // field is 64 bits long 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. // 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 { - reducedOpenings = append(reducedOpenings, f.qeAPI.ReduceWithPowers(batch.Values, alpha)) + reducedOpenings = append(reducedOpenings, f.gl.ReduceWithPowers(batch.Values, alpha)) } 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 { bit := leafIndexBits[i] // 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 - 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) } @@ -82,7 +85,7 @@ func (f *FriChip) verifyMerkleProofToCapWithCapIndex(leafData []field.F, leafInd } 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 // The will use the least significant bits of the capIndexBits array 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) } -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) { 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. // / // / 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 queryError := f.friParams.Config.Rate() 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, exponentBits []frontend.Variable, -) field.F { - product := field.ONE_F +) gl.Variable { + product := gl.One() for i, bit := range exponentBits { - pow := int64(1 << i) // If the bit is on, we multiply product by base^pow. // We can arithmetize this as: // product *= 1 + bit (base^pow - 1) // product = (base^pow - 1) product bit + product + pow := int64(1 << i) basePow := goldilocks.NewElement(0) 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, ) } - return product } -func (f *FriChip) calculateSubgroupX( +func (f *Chip) calculateSubgroupX( xIndexBits []frontend.Variable, nLog uint64, -) field.F { +) gl.Variable { // Compute x from its index // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. // 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 xIndexBitsRev := make([]frontend.Variable, 0) @@ -180,17 +182,17 @@ func (f *FriChip) calculateSubgroupX( 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) { panic("len(openings) != len(precomputedReducedEval)") @@ -201,23 +203,24 @@ func (f *FriChip) friCombineInitial( reducedOpenings := precomputedReducedEval[i] point := batch.Point - evals := make([]field.QuadraticExtension, 0) + evals := make([]gl.QuadraticExtensionVariable, 0) for _, polynomial := range batch.Polynomials { evals = append( 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, ) } @@ -225,43 +228,36 @@ func (f *FriChip) friCombineInitial( 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-- { - ret = f.qeAPI.AddExtension( - f.qeAPI.MulExtension( - ret, - point, - ), - finalPoly.Coeffs[i], - ) + ret = f.gl.MulAddExtension(ret, point, finalPoly.Coeffs[i]) } 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) { panic("length of xPoints, yPoints, and barycentricWeights are inconsistent") } - lX := f.qeAPI.ONE_QE + lX := gl.OneExtension() 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++ { - sum = f.qeAPI.AddExtension( - f.qeAPI.MulExtension( - f.qeAPI.DivExtension( + sum = f.gl.AddExtension( + f.gl.MulExtension( + f.gl.DivExtension( barycentricWeights[i], - f.qeAPI.SubExtension( + f.gl.SubExtension( x, 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 // Now check if x is already within the xPoints 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, + yPoints[i], ) } return returnField } -func (f *FriChip) computeEvaluation( - x field.F, +func (f *Chip) computeEvaluation( + x gl.Variable, xIndexWithinCosetBits []frontend.Variable, arityBits uint64, - evals []field.QuadraticExtension, - beta field.QuadraticExtension, -) field.QuadraticExtension { + evals []gl.QuadraticExtensionVariable, + beta gl.QuadraticExtensionVariable, +) gl.QuadraticExtensionVariable { arity := 1 << arityBits if (len(evals)) != arity { panic("len(evals) ! arity") @@ -302,7 +298,7 @@ func (f *FriChip) computeEvaluation( panic("currently assuming that arityBits is <= 8") } - g := field.GoldilocksPrimitiveRootOfUnity(arityBits) + g := gl.PrimitiveRootOfUnity(arityBits) gInv := goldilocks.NewElement(0) 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. // TODO: Optimization - Since the size of the evals array should be constant (e.g. 2^arityBits), // 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++ { newIndex := bits.Reverse8(i) >> arityBits permutedEvals[newIndex] = evals[i] @@ -323,53 +319,54 @@ func (f *FriChip) computeEvaluation( revXIndexWithinCosetBits[len(xIndexWithinCosetBits)-1-i] = xIndexWithinCosetBits[i] } 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 // 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++ { - 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? // Compute the barycentric weights - barycentricWeights := make([]field.QuadraticExtension, len(xPoints)) + barycentricWeights := make([]gl.QuadraticExtensionVariable, len(xPoints)) for i := 0; i < len(xPoints); i++ { - barycentricWeights[i] = f.qeAPI.ONE_QE + barycentricWeights[i] = gl.OneExtension() for j := 0; j < len(xPoints); 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], ) } } // Take the inverse of the barycentric weights // 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) } -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, nLog uint64, - roundProof *common.FriQueryRound, + roundProof *types.FriQueryRound, ) { 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):] f.verifyInitialProof(xIndexBits, &roundProof.InitialTreesProof, initialMerkleCaps, capIndexBits) @@ -379,7 +376,7 @@ func (f *FriChip) verifyQueryRound( nLog, ) - subgroupX_QE := field.QuadraticExtension{subgroupX, field.ZERO_F} + subgroupX_QE := subgroupX.ToQuadraticExtension() oldEval := f.friCombineInitial( instance, @@ -404,11 +401,11 @@ func (f *FriChip) verifyQueryRound( } 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 // The will use the least significant bits of the xIndexWithCosetBits array for i := 0; i < NUM_LEAF_LOOKUPS; i++ { - leafLookups[i] = f.qeAPI.Lookup2( + leafLookups[i] = f.gl.Lookup2( xIndexWithinCosetBits[0], xIndexWithinCosetBits[1], 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 - newEval := f.qeAPI.Lookup2( + newEval := f.gl.Lookup2( xIndexWithinCosetBits[2], xIndexWithinCosetBits[3], leafLookups[0], @@ -428,7 +425,8 @@ func (f *FriChip) verifyQueryRound( leafLookups[3], ) - f.qeAPI.AssertIsEqual(newEval, oldEval) + f.gl.AssertIsEqual(newEval[0], oldEval[0]) + f.gl.AssertIsEqual(newEval[1], oldEval[1]) oldEval = f.computeEvaluation( subgroupX, @@ -439,7 +437,7 @@ func (f *FriChip) verifyQueryRound( ) // 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++ { fieldEvals = append(fieldEvals, evals[j][0]) fieldEvals = append(fieldEvals, evals[j][1]) @@ -454,24 +452,25 @@ func (f *FriChip) verifyQueryRound( // Update the point x to x^arity. for j := uint64(0); j < arityBits; j++ { - subgroupX = f.fieldAPI.Mul(subgroupX, subgroupX) + subgroupX = f.gl.Mul(subgroupX, subgroupX) } xIndexBits = cosetIndexBits } - subgroupX_QE = f.qeAPI.FieldToQE(subgroupX) + subgroupX_QE = subgroupX.ToQuadraticExtension() 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 /* if let Some(max_arity_bits) = params.max_arity_bits() { @@ -485,6 +484,7 @@ func (f *FriChip) VerifyFriProof( ); */ // Check POW + f.assertLeadingZeros(friChallenges.FriPowResponse, f.friParams.Config) precomputedReducedEvals := f.fromOpeningsAndAlpha(&openings, friChallenges.FriAlpha) diff --git a/fri/fri_test.go b/fri/fri_test.go new file mode 100644 index 0000000..d5c0033 --- /dev/null +++ b/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() +} diff --git a/verifier/internal/fri/fri_utils.go b/fri/fri_utils.go similarity index 56% rename from verifier/internal/fri/fri_utils.go rename to fri/fri_utils.go index 9df6994..962a36b 100644 --- a/verifier/internal/fri/fri_utils.go +++ b/fri/fri_utils.go @@ -1,48 +1,48 @@ package fri 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 = append(values, c.PlonkSigmas...) // num_routed_wires values = append(values, c.Wires...) // num_wires values = append(values, c.PlonkZs...) // num_challenges values = append(values, c.PartialProducts...) // num_challenges * num_partial_products 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 PolynomialInfo uint64 } -type FriOracleInfo struct { +type OracleInfo struct { NumPolys uint64 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 { @@ -70,11 +70,11 @@ var QUOTIENT = PlonkOracle{ 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++ { returnArr = append(returnArr, - FriPolynomialInfo{ + PolynomialInfo{ OracleIndex: oracleIdx, PolynomialInfo: i, }) @@ -84,7 +84,7 @@ func polynomialInfoFromRange(c *common.CommonCircuitData, oracleIdx uint64, star } // 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) for i := c.NumConstants; i <= c.NumConstants+c.Config.NumRoutedWires; i++ { returnArr = append(returnArr, i) @@ -93,20 +93,20 @@ func sigmasRange(c *common.CommonCircuitData) []uint64 { return returnArr } -func numPreprocessedPolys(c *common.CommonCircuitData) uint64 { +func numPreprocessedPolys(c *types.CommonCircuitData) uint64 { sigmasRange := sigmasRange(c) return sigmasRange[len(sigmasRange)-1] } -func numZSPartialProductsPolys(c *common.CommonCircuitData) uint64 { +func numZSPartialProductsPolys(c *types.CommonCircuitData) uint64 { 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 } -func friPreprocessedPolys(c *common.CommonCircuitData) []FriPolynomialInfo { +func friPreprocessedPolys(c *types.CommonCircuitData) []PolynomialInfo { return polynomialInfoFromRange( c, 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 return polynomialInfoFromRange(c, WIRES.index, 0, numWirePolys) } -func friZSPartialProductsPolys(c *common.CommonCircuitData) []FriPolynomialInfo { +func friZSPartialProductsPolys(c *types.CommonCircuitData) []PolynomialInfo { return polynomialInfoFromRange( c, 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( c, 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( c, 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), 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, friWirePolys(c)...) returnArr = append(returnArr, friZSPartialProductsPolys(c)...) @@ -178,22 +178,25 @@ func friAllPolys(c *common.CommonCircuitData) []FriPolynomialInfo { 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, 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, Polynomials: friZSPolys(c), } - return FriInstanceInfo{ + return InstanceInfo{ Oracles: friOracles(c), - Batches: []FriBatchInfo{zetaBatch, zetaNextBath}, + Batches: []BatchInfo{zetaBatch, zetaNextBath}, } } diff --git a/go.sum b/go.sum index 4d58fd0..9e3d146 100644 --- a/go.sum +++ b/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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 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/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= diff --git a/goldilocks/base.go b/goldilocks/base.go new file mode 100644 index 0000000..ad7b0c6 --- /dev/null +++ b/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 +} diff --git a/field/goldilocks_test.go b/goldilocks/base_test.go similarity index 86% rename from field/goldilocks_test.go rename to goldilocks/base_test.go index 8e1673d..3a5f490 100644 --- a/field/goldilocks_test.go +++ b/goldilocks/base_test.go @@ -1,4 +1,4 @@ -package field +package goldilocks import ( "math/big" @@ -15,7 +15,8 @@ type TestGoldilocksRangeCheckCircuit struct { } func (c *TestGoldilocksRangeCheckCircuit) Define(api frontend.API) error { - GoldilocksRangeCheck(api, c.X) + chip := NewChip(api) + chip.RangeCheck(NewVariable(c.X)) return nil } func TestGoldilocksRangeCheck(t *testing.T) { @@ -29,11 +30,11 @@ func TestGoldilocksRangeCheck(t *testing.T) { witness.X = 0 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()) one := big.NewInt(1) - maxValidVal := new(big.Int).Sub(EmulatedField{}.Modulus(), one) + maxValidVal := new(big.Int).Sub(MODULUS, one) witness.X = maxValidVal 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 { - 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 } diff --git a/goldilocks/quadratic_extension.go b/goldilocks/quadratic_extension.go new file mode 100644 index 0000000..92be086 --- /dev/null +++ b/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]) +} diff --git a/goldilocks/quadratic_extension_algebra.go b/goldilocks/quadratic_extension_algebra.go new file mode 100644 index 0000000..9ce1028 --- /dev/null +++ b/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 +} diff --git a/goldilocks/quadratic_extension_algebra_test.go b/goldilocks/quadratic_extension_algebra_test.go new file mode 100644 index 0000000..fa9934d --- /dev/null +++ b/goldilocks/quadratic_extension_algebra_test.go @@ -0,0 +1 @@ +package goldilocks diff --git a/goldilocks/quadratic_extension_test.go b/goldilocks/quadratic_extension_test.go new file mode 100644 index 0000000..0087ab6 --- /dev/null +++ b/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) +} diff --git a/utils/utils.go b/goldilocks/utils.go similarity index 50% rename from utils/utils.go rename to goldilocks/utils.go index 26b0e60..654230f 100644 --- a/utils/utils.go +++ b/goldilocks/utils.go @@ -1,10 +1,9 @@ -package utils +package goldilocks import ( "math/big" "github.com/consensys/gnark/frontend" - "github.com/succinctlabs/gnark-plonky2-verifier/field" ) func StrArrayToBigIntArray(input []string) []big.Int { @@ -25,22 +24,22 @@ func StrArrayToFrontendVariableArray(input []string) []frontend.Variable { 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++ { - output = append(output, field.NewFieldConst(input[i])) + output = append(output, NewVariable(input[i])) } 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++ { - 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 } diff --git a/verifier/internal/gates/arithmetic_extension_gate.go b/plonk/gates/arithmetic_extension_gate.go similarity index 66% rename from verifier/internal/gates/arithmetic_extension_gate.go rename to plonk/gates/arithmetic_extension_gate.go index 8040d48..e09ed2a 100644 --- a/verifier/internal/gates/arithmetic_extension_gate.go +++ b/plonk/gates/arithmetic_extension_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+) }") @@ -41,39 +41,43 @@ func (g *ArithmeticExtensionGate) Id() string { } 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 { - 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 { - 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 { - 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] const1 := vars.localConstants[1] - constraints := []field.QuadraticExtension{} + constraints := []gl.QuadraticExtensionVariable{} for i := uint64(0); i < g.numOps; i++ { multiplicand0 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand0(i)) multiplicand1 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand1(i)) addend := vars.GetLocalExtAlgebra(g.wiresIthAddend(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]) } } diff --git a/verifier/internal/gates/arithmetic_gate.go b/plonk/gates/arithmetic_gate.go similarity index 77% rename from verifier/internal/gates/arithmetic_gate.go rename to plonk/gates/arithmetic_gate.go index 237a9c8..7867cb0 100644 --- a/verifier/internal/gates/arithmetic_gate.go +++ b/plonk/gates/arithmetic_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+) }") @@ -57,23 +57,27 @@ func (g *ArithmeticGate) WireIthOutput(i uint64) uint64 { 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] const1 := vars.localConstants[1] - constraints := []field.QuadraticExtension{} + constraints := []gl.QuadraticExtensionVariable{} for i := uint64(0); i < g.numOps; i++ { multiplicand0 := vars.localWires[g.WireIthMultiplicand0(i)] multiplicand1 := vars.localWires[g.WireIthMultiplicand1(i)] addend := vars.localWires[g.WireIthAddend(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 diff --git a/verifier/internal/gates/base_sum_gate.go b/plonk/gates/base_sum_gate.go similarity index 71% rename from verifier/internal/gates/base_sum_gate.go rename to plonk/gates/base_sum_gate.go index ef503ce..aff6db6 100644 --- a/verifier/internal/gates/base_sum_gate.go +++ b/plonk/gates/base_sum_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+) } \+ Base: (?P[0-9]+)`) @@ -63,27 +63,31 @@ func (g *BaseSumGate) limbs() []uint64 { 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] - limbs := make([]field.QuadraticExtension, g.numLimbs) + limbs := make([]gl.QuadraticExtensionVariable, g.numLimbs) limbIndices := g.limbs() for i, limbIdx := range limbIndices { 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, - 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 { - acc := qeAPI.ONE_QE + acc := gl.OneExtension() 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) } diff --git a/verifier/internal/gates/constant_gate.go b/plonk/gates/constant_gate.go similarity index 80% rename from verifier/internal/gates/constant_gate.go rename to plonk/gates/constant_gate.go index 3bf227c..e263139 100644 --- a/verifier/internal/gates/constant_gate.go +++ b/plonk/gates/constant_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+) }") @@ -54,11 +54,15 @@ func (g *ConstantGate) WireOutput(i uint64) uint64 { 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++ { - 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 diff --git a/verifier/internal/gates/coset_interpolation_gate.go b/plonk/gates/coset_interpolation_gate.go similarity index 77% rename from verifier/internal/gates/coset_interpolation_gate.go rename to plonk/gates/coset_interpolation_gate.go index fa0fcce..58e53da 100644 --- a/verifier/internal/gates/coset_interpolation_gate.go +++ b/plonk/gates/coset_interpolation_gate.go @@ -8,7 +8,7 @@ import ( "github.com/consensys/gnark-crypto/field/goldilocks" "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[0-9]+), degree: (?P[0-9]+), barycentric_weights: \[(?P[0-9, ]+)\], _phantom: PhantomData }`) @@ -89,32 +89,32 @@ func (g *CosetInterpolationGate) wiresValue(i uint64) Range { if i >= g.numPoints() { 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 { - return g.startValues() + g.numPoints()*field.D + return g.startValues() + g.numPoints()*gl.D } // Wire indices of the point to evaluate the interpolant at. func (g *CosetInterpolationGate) wiresEvaluationPoint() Range { start := g.startEvaluationPoint() - return Range{start, start + field.D} + return Range{start, start + gl.D} } func (g *CosetInterpolationGate) startEvaluationValue() uint64 { - return g.startEvaluationPoint() + field.D + return g.startEvaluationPoint() + gl.D } // Wire indices of the interpolated value. func (g *CosetInterpolationGate) wiresEvaluationValue() Range { start := g.startEvaluationValue() - return Range{start, start + field.D} + return Range{start, start + gl.D} } func (g *CosetInterpolationGate) startIntermediates() uint64 { - return g.startEvaluationValue() + field.D + return g.startEvaluationValue() + gl.D } func (g *CosetInterpolationGate) numIntermediates() uint64 { @@ -126,8 +126,8 @@ func (g *CosetInterpolationGate) wiresIntermediateEval(i uint64) Range { if i >= g.numIntermediates() { 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. @@ -135,42 +135,46 @@ func (g *CosetInterpolationGate) wiresIntermediateProd(i uint64) Range { if i >= g.numIntermediates() { 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. 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()] evaluationPoint := vars.GetLocalExtAlgebra(g.wiresEvaluationPoint()) 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]) } - domain := field.TwoAdicSubgroup(g.subgroupBits) - values := []field.QEAlgebra{} + domain := gl.TwoAdicSubgroup(g.subgroupBits) + values := []gl.QuadraticExtensionAlgebraVariable{} for i := uint64(0); i < g.numPoints(); i++ { values = append(values, vars.GetLocalExtAlgebra(g.wiresValue(i))) } 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], values[: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)) 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]) } - 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]) } startIndex := 1 + (g.degree-1)*(i+1) endIndex := startIndex + g.degree - 1 - computedEval, computedProd = qeAPI.PartialInterpolateExtAlgebra( + computedEval, computedProd = glApi.PartialInterpolateExtAlgebra( domain[startIndex:endIndex], values[startIndex:endIndex], weights[startIndex:endIndex], @@ -206,8 +210,8 @@ func (g *CosetInterpolationGate) EvalUnfiltered(api frontend.API, qeAPI *field.Q } 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]) } diff --git a/verifier/internal/gates/evaluate_gates.go b/plonk/gates/evaluate_gates.go similarity index 62% rename from verifier/internal/gates/evaluate_gates.go rename to plonk/gates/evaluate_gates.go index 44b17a2..8823cc9 100644 --- a/verifier/internal/gates/evaluate_gates.go +++ b/plonk/gates/evaluate_gates.go @@ -2,12 +2,11 @@ package gates import ( "github.com/consensys/gnark/frontend" - "github.com/succinctlabs/gnark-plonky2-verifier/field" + gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" ) type EvaluateGatesChip struct { - api frontend.API - qeAPI *field.QuadraticExtensionAPI + api frontend.API gates []Gate numGateConstraints uint64 @@ -17,14 +16,12 @@ type EvaluateGatesChip struct { func NewEvaluateGatesChip( api frontend.API, - qeAPI *field.QuadraticExtensionAPI, gates []Gate, numGateConstraints uint64, selectorsInfo SelectorsInfo, ) *EvaluateGatesChip { return &EvaluateGatesChip{ - api: api, - qeAPI: qeAPI, + api: api, gates: gates, numGateConstraints: numGateConstraints, @@ -36,20 +33,22 @@ func NewEvaluateGatesChip( func (g *EvaluateGatesChip) computeFilter( row uint64, groupRange Range, - s field.QuadraticExtension, + s gl.QuadraticExtensionVariable, 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++ { if i == uint64(row) { 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 { - 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 @@ -62,22 +61,24 @@ func (g *EvaluateGatesChip) evalFiltered( selectorIndex uint64, groupRange Range, numSelectors uint64, -) []field.QuadraticExtension { +) []gl.QuadraticExtensionVariable { + glApi := gl.NewChip(g.api) filter := g.computeFilter(row, groupRange, vars.localConstants[selectorIndex], numSelectors > 1) vars.RemovePrefix(numSelectors) - unfiltered := gate.EvalUnfiltered(g.api, g.qeAPI, vars) + unfiltered := gate.EvalUnfiltered(g.api, *glApi, vars) for i := range unfiltered { - unfiltered[i] = g.qeAPI.MulExtension(unfiltered[i], filter) + unfiltered[i] = glApi.MulExtension(unfiltered[i], filter) } 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 { - constraints[i] = g.qeAPI.ZERO_QE + constraints[i] = gl.ZeroExtension() } for i, gate := range g.gates { @@ -96,7 +97,7 @@ func (g *EvaluateGatesChip) EvaluateGateConstraints(vars EvaluationVars) []field if uint64(i) >= g.numGateConstraints { panic("num_constraints() gave too low of a number") } - constraints[i] = g.qeAPI.AddExtension(constraints[i], constraint) + constraints[i] = glApi.AddExtension(constraints[i], constraint) } } diff --git a/verifier/internal/gates/exponentiation_gate.go b/plonk/gates/exponentiation_gate.go similarity index 73% rename from verifier/internal/gates/exponentiation_gate.go rename to plonk/gates/exponentiation_gate.go index 3a3ae08..ccf02e6 100644 --- a/verifier/internal/gates/exponentiation_gate.go +++ b/plonk/gates/exponentiation_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+), _phantom: PhantomData }[0-9]+)>") @@ -63,29 +63,33 @@ func (g *ExponentiationGate) wireIntermediateValue(i uint64) uint64 { 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()] - var powerBits []field.QuadraticExtension + var powerBits []gl.QuadraticExtensionVariable for i := uint64(0); i < g.numPowerBits; 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++ { intermediateValues = append(intermediateValues, vars.localWires[g.wireIntermediateValue(i)]) } output := vars.localWires[g.wireOutput()] - var constraints []field.QuadraticExtension + var constraints []gl.QuadraticExtensionVariable for i := uint64(0); i < g.numPowerBits; i++ { - var prevIntermediateValue field.QuadraticExtension + var prevIntermediateValue gl.QuadraticExtensionVariable if i == 0 { - prevIntermediateValue = qeAPI.ONE_QE + prevIntermediateValue = gl.OneExtension() } 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. @@ -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) // if b { x } else { 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) } - outputDiff := qeAPI.SubExtension(output, intermediateValues[g.numPowerBits-1]) + outputDiff := glApi.SubExtension(output, intermediateValues[g.numPowerBits-1]) constraints = append(constraints, outputDiff) return constraints diff --git a/verifier/internal/gates/gate.go b/plonk/gates/gates.go similarity index 89% rename from verifier/internal/gates/gate.go rename to plonk/gates/gates.go index 5310f5a..edd98d4 100644 --- a/verifier/internal/gates/gate.go +++ b/plonk/gates/gates.go @@ -5,12 +5,16 @@ import ( "regexp" "github.com/consensys/gnark/frontend" - "github.com/succinctlabs/gnark-plonky2-verifier/field" + gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" ) type Gate interface { 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{ diff --git a/plonk/gates/gates_test.go b/plonk/gates/gates_test.go new file mode 100644 index 0000000..8bf99ba --- /dev/null +++ b/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 } +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) +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 } +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)" +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, + ) + } +} diff --git a/verifier/internal/gates/multiplication_extension_gate.go b/plonk/gates/multiplication_extension_gate.go similarity index 69% rename from verifier/internal/gates/multiplication_extension_gate.go rename to plonk/gates/multiplication_extension_gate.go index 0ed4cd4..37cec16 100644 --- a/verifier/internal/gates/multiplication_extension_gate.go +++ b/plonk/gates/multiplication_extension_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+) }") @@ -41,34 +41,36 @@ func (g *MultiplicationExtensionGate) Id() string { } 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 { - 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 { - 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] - - constraints := []field.QuadraticExtension{} + constraints := []gl.QuadraticExtensionVariable{} for i := uint64(0); i < g.numOps; i++ { multiplicand0 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand0(i)) multiplicand1 := vars.GetLocalExtAlgebra(g.wiresIthMultiplicand1(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]) } } - return constraints } diff --git a/verifier/internal/gates/noop_gate.go b/plonk/gates/noop_gate.go similarity index 62% rename from verifier/internal/gates/noop_gate.go rename to plonk/gates/noop_gate.go index 662a3ae..f7c67e0 100644 --- a/verifier/internal/gates/noop_gate.go +++ b/plonk/gates/noop_gate.go @@ -4,7 +4,7 @@ import ( "regexp" "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") @@ -25,6 +25,10 @@ func (g *NoopGate) Id() string { 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{} } diff --git a/verifier/internal/gates/poseidon_gate.go b/plonk/gates/poseidon_gate.go similarity index 78% rename from verifier/internal/gates/poseidon_gate.go rename to plonk/gates/poseidon_gate.go index 9238c4e..4576b2f 100644 --- a/verifier/internal/gates/poseidon_gate.go +++ b/plonk/gates/poseidon_gate.go @@ -4,7 +4,7 @@ import ( "regexp" "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" ) @@ -89,34 +89,38 @@ func (g *PoseidonGate) WiresEnd() uint64 { 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. 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)`. for i := uint64(0); i < 4; i++ { inputLhs := vars.localWires[g.WireInput(i)] inputRhs := vars.localWires[g.WireInput(i+4)] 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. - var state [poseidon.SPONGE_WIDTH]field.QuadraticExtension + var state [poseidon.SPONGE_WIDTH]gl.QuadraticExtensionVariable for i := uint64(0); i < 4; i++ { deltaI := vars.localWires[g.WireDelta(i)] inputLhs := vars.localWires[g.WireInput(i)] 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++ { state[i] = vars.localWires[g.WireInput(i)] @@ -130,7 +134,7 @@ func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticEx if r != 0 { for i := uint64(0); i < poseidon.SPONGE_WIDTH; 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 } } @@ -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++ { 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] = 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)) } 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 = poseidonChip.MdsPartialLayerFastExtension(state, poseidon.N_PARTIAL_ROUNDS-1) roundCounter += poseidon.N_PARTIAL_ROUNDS @@ -161,7 +165,7 @@ func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticEx state = poseidonChip.ConstantLayerExtension(state, &roundCounter) for i := uint64(0); i < poseidon.SPONGE_WIDTH; 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 = 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++ { - 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 diff --git a/verifier/internal/gates/poseidon_mds_gate.go b/plonk/gates/poseidon_mds_gate.go similarity index 50% rename from verifier/internal/gates/poseidon_mds_gate.go rename to plonk/gates/poseidon_mds_gate.go index 39ab230..9efb2ef 100644 --- a/verifier/internal/gates/poseidon_mds_gate.go +++ b/plonk/gates/poseidon_mds_gate.go @@ -4,7 +4,7 @@ import ( "regexp" "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" ) @@ -30,55 +30,66 @@ func (g *PoseidonMdsGate) WireInput(i uint64) Range { if i >= poseidon.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 { if i >= poseidon.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 { panic("MDS row index out of range") } - res := qeAPI.ZERO_QE_ALGEBRA + res := gl.ZeroExtensionAlgebra() 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 } -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++ { - result[r] = g.mdsRowShfAlgebra(r, state, qeAPI) + result[r] = g.mdsRowShfAlgebra(r, state, api) } - 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++ { 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++ { 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]) } diff --git a/verifier/internal/gates/public_input_gate.go b/plonk/gates/public_input_gate.go similarity index 67% rename from verifier/internal/gates/public_input_gate.go rename to plonk/gates/public_input_gate.go index 3f2ac35..9fad5e7 100644 --- a/verifier/internal/gates/public_input_gate.go +++ b/plonk/gates/public_input_gate.go @@ -4,7 +4,7 @@ import ( "regexp" "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") @@ -29,8 +29,12 @@ func (g *PublicInputGate) WiresPublicInputsHash() []uint64 { 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() hash_parts := vars.publicInputsHash @@ -38,7 +42,8 @@ func (g *PublicInputGate) EvalUnfiltered(api frontend.API, qeAPI *field.Quadrati wire := wires[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) } diff --git a/verifier/internal/gates/random_access_gate.go b/plonk/gates/random_access_gate.go similarity index 82% rename from verifier/internal/gates/random_access_gate.go rename to plonk/gates/random_access_gate.go index 214b7cd..5d1e0a8 100644 --- a/verifier/internal/gates/random_access_gate.go +++ b/plonk/gates/random_access_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+), num_copies: (?P[0-9]+), num_extra_constants: (?P[0-9]+), _phantom: PhantomData }[0-9]+)>") @@ -114,45 +114,49 @@ func (g *RandomAccessGate) WireBit(i uint64, copy uint64) uint64 { 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++ { accessIndex := vars.localWires[g.WireAccessIndex(copy)] - listItems := []field.QuadraticExtension{} + listItems := []gl.QuadraticExtensionVariable{} for i := uint64(0); i < g.vecSize(); i++ { listItems = append(listItems, vars.localWires[g.WireListItem(i, copy)]) } claimedElement := vars.localWires[g.WireClaimedElement(copy)] - bits := []field.QuadraticExtension{} + bits := []gl.QuadraticExtensionVariable{} for i := uint64(0); i < g.bits; i++ { bits = append(bits, vars.localWires[g.WireBit(i, copy)]) } // Assert that each bit wire value is indeed boolean. 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. - 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 { - listItemsTmp := []field.QuadraticExtension{} + listItemsTmp := []gl.QuadraticExtensionVariable{} for i := 0; i < len(listItems); i += 2 { x := listItems[i] y := listItems[i+1] // This is computing `if b { x } else { 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) } @@ -163,11 +167,11 @@ func (g *RandomAccessGate) EvalUnfiltered(api frontend.API, qeAPI *field.Quadrat 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++ { - 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 diff --git a/verifier/internal/gates/reducing_extension_gate.go b/plonk/gates/reducing_extension_gate.go similarity index 68% rename from verifier/internal/gates/reducing_extension_gate.go rename to plonk/gates/reducing_extension_gate.go index 2f9d2b9..2d71c07 100644 --- a/verifier/internal/gates/reducing_extension_gate.go +++ b/plonk/gates/reducing_extension_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+) }") @@ -30,7 +30,7 @@ type ReducingExtensionGate struct { 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 { return &ReducingExtensionGate{ @@ -43,23 +43,23 @@ func (g *ReducingExtensionGate) Id() string { } func (g *ReducingExtensionGate) wiresOutput() Range { - return Range{0, field.D} + return Range{0, gl.D} } func (g *ReducingExtensionGate) wiresAlpha() Range { - return Range{field.D, 2 * field.D} + return Range{gl.D, 2 * gl.D} } 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 { - 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 { - 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 { @@ -71,31 +71,35 @@ func (g *ReducingExtensionGate) wiresAccs(i uint64) Range { 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()) oldAcc := vars.GetLocalExtAlgebra(g.wiresOldAcc()) - coeffs := []field.QEAlgebra{} + coeffs := []gl.QuadraticExtensionAlgebraVariable{} for i := uint64(0); i < g.numCoeffs; i++ { coeffs = append(coeffs, vars.GetLocalExtAlgebra(g.wiresCoeff(i))) } - accs := []field.QEAlgebra{} + accs := []gl.QuadraticExtensionAlgebraVariable{} for i := uint64(0); i < g.numCoeffs; i++ { accs = append(accs, vars.GetLocalExtAlgebra(g.wiresAccs(i))) } - constraints := []field.QuadraticExtension{} + constraints := []gl.QuadraticExtensionVariable{} acc := oldAcc for i := uint64(0); i < g.numCoeffs; 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]) } acc = accs[i] diff --git a/verifier/internal/gates/reducing_gate.go b/plonk/gates/reducing_gate.go similarity index 70% rename from verifier/internal/gates/reducing_gate.go rename to plonk/gates/reducing_gate.go index 139f56c..2212f2b 100644 --- a/verifier/internal/gates/reducing_gate.go +++ b/plonk/gates/reducing_gate.go @@ -6,7 +6,7 @@ import ( "strconv" "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[0-9]+) }") @@ -30,7 +30,7 @@ type ReducingGate struct { numCoeffs uint64 } -const START_COEFFS_REDUCING_GATE = 3 * field.D +const START_COEFFS_REDUCING_GATE = 3 * gl.D func NewReducingGate(numCoeffs uint64) *ReducingGate { return &ReducingGate{ @@ -43,15 +43,15 @@ func (g *ReducingGate) Id() string { } func (g *ReducingGate) wiresOutput() Range { - return Range{0, field.D} + return Range{0, gl.D} } func (g *ReducingGate) wiresAlpha() Range { - return Range{field.D, 2 * field.D} + return Range{gl.D, 2 * gl.D} } 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 { @@ -71,36 +71,40 @@ func (g *ReducingGate) wiresAccs(i uint64) Range { 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()) oldAcc := vars.GetLocalExtAlgebra(g.wiresOldAcc()) - coeffs := []field.QuadraticExtension{} + coeffs := []gl.QuadraticExtensionVariable{} coeffsRange := g.wiresCoeff() for i := coeffsRange.start; i < coeffsRange.end; i++ { coeffs = append(coeffs, vars.localWires[i]) } - accs := []field.QEAlgebra{} + accs := []gl.QuadraticExtensionAlgebraVariable{} for i := uint64(0); i < g.numCoeffs; i++ { accs = append(accs, vars.GetLocalExtAlgebra(g.wiresAccs(i))) } - constraints := []field.QuadraticExtension{} + constraints := []gl.QuadraticExtensionVariable{} acc := oldAcc 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] - 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]) } acc = accs[i] diff --git a/verifier/internal/gates/selectors.go b/plonk/gates/selectors.go similarity index 100% rename from verifier/internal/gates/selectors.go rename to plonk/gates/selectors.go diff --git a/verifier/internal/gates/vars.go b/plonk/gates/vars.go similarity index 52% rename from verifier/internal/gates/vars.go rename to plonk/gates/vars.go index 2d28eca..c18663a 100644 --- a/verifier/internal/gates/vars.go +++ b/plonk/gates/vars.go @@ -1,20 +1,20 @@ package gates import ( - "github.com/succinctlabs/gnark-plonky2-verifier/field" + gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon" ) type EvaluationVars struct { - localConstants []field.QuadraticExtension - localWires []field.QuadraticExtension - publicInputsHash poseidon.PoseidonHashOut + localConstants []gl.QuadraticExtensionVariable + localWires []gl.QuadraticExtensionVariable + publicInputsHash poseidon.GoldilocksHashOut } func NewEvaluationVars( - localConstants []field.QuadraticExtension, - localWires []field.QuadraticExtension, - publicInputsHash poseidon.PoseidonHashOut, + localConstants []gl.QuadraticExtensionVariable, + localWires []gl.QuadraticExtensionVariable, + publicInputsHash poseidon.GoldilocksHashOut, ) *EvaluationVars { return &EvaluationVars{ localConstants: localConstants, @@ -27,13 +27,13 @@ func (e *EvaluationVars) RemovePrefix(numSelectors uint64) { 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 - if wireRange.end-wireRange.start != field.D { + if wireRange.end-wireRange.start != gl.D { panic("Range must be of size D") } - var ret field.QEAlgebra + var ret gl.QuadraticExtensionAlgebraVariable for i := wireRange.start; i < wireRange.end; i++ { ret[i-wireRange.start] = e.localWires[i] } diff --git a/verifier/internal/plonk/plonk.go b/plonk/plonk.go similarity index 52% rename from verifier/internal/plonk/plonk.go rename to plonk/plonk.go index d27a736..47494dd 100644 --- a/verifier/internal/plonk/plonk.go +++ b/plonk/plonk.go @@ -2,102 +2,101 @@ package plonk import ( "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/verifier/common" - "github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/gates" + "github.com/succinctlabs/gnark-plonky2-verifier/types" ) 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 } -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? evaluateGatesChip := gates.NewEvaluateGatesChip( api, - qeAPI, commonData.Gates, commonData.NumGateConstraints, commonData.SelectorsInfo, ) return &PlonkChip{ - api: api, - qeAPI: qeAPI, + api: api, 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, } } -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++ { - x = p.qeAPI.SquareExtension(x) + x = glApi.MulExtension(x, 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)) - evalZeroPoly := p.qeAPI.SubExtension( + glApi := gl.NewChip(p.api) + evalZeroPoly := glApi.SubExtension( 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, ) - return p.qeAPI.DivExtension( + return glApi.DivExtension( evalZeroPoly, denominator, ) } func (p *PlonkChip) checkPartialProducts( - numerators []field.QuadraticExtension, - denominators []field.QuadraticExtension, + numerators []gl.QuadraticExtensionVariable, + denominators []gl.QuadraticExtensionVariable, challengeNum uint64, - openings common.OpeningSet, -) []field.QuadraticExtension { + openings types.OpeningSet, +) []gl.QuadraticExtensionVariable { + glApi := gl.NewChip(p.api) numPartProds := p.commonData.NumPartialProducts 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.PartialProducts[challengeNum*numPartProds:(challengeNum+1)*numPartProds]...) 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 { ppStartIdx := i * quotDegreeFactor numeProduct := numerators[ppStartIdx] denoProduct := denominators[ppStartIdx] 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) @@ -105,49 +104,55 @@ func (p *PlonkChip) checkPartialProducts( 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) // 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++ { - 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) 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++ { // L_0(zeta) (Z(zeta) - 1) = 0 - z1_term := p.qeAPI.MulExtension( + z1_term := glApi.MulExtension( l0Zeta, - p.qeAPI.SubExtension(openings.PlonkZs[i], p.qeAPI.ONE_QE)) + glApi.SubExtension(openings.PlonkZs[i], gl.OneExtension())) 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++ { // The numerator is `beta * s_id + wire_value + gamma`, and the denominator is // `beta * s_sigma + wire_value + gamma`. - wireValuePlusGamma := p.qeAPI.AddExtension( + wireValuePlusGamma := glApi.AddExtension( 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], ), 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], ), wireValuePlusGamma, @@ -166,17 +171,17 @@ func (p *PlonkChip) evalVanishingPoly(vars gates.EvaluationVars, proofChallenges vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...) 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++ { - reducedValues[i] = p.qeAPI.ZERO_QE + reducedValues[i] = gl.ZeroExtension() } // reverse iterate the vanishingPartialProductsTerms array for i := len(vanishingTerms) - 1; i >= 0; i-- { for j := uint64(0); j < p.commonData.Config.NumChallenges; j++ { - reducedValues[j] = p.qeAPI.AddExtension( + reducedValues[j] = glApi.AddExtension( vanishingTerms[i], - p.qeAPI.ScalarMulExtension( + glApi.ScalarMulExtension( reducedValues[j], proofChallenges.PlonkAlphas[j], ), @@ -187,7 +192,13 @@ func (p *PlonkChip) evalVanishingPoly(vars gates.EvaluationVars, proofChallenges 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 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) // 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. // 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++ { quotientPolysStartIdx := i * int(p.commonData.QuotientDegreeFactor) quotientPolysEndIdx := quotientPolysStartIdx + int(p.commonData.QuotientDegreeFactor) - prod := p.qeAPI.MulExtension( + prod := glApi.MulExtension( zHZeta, - p.qeAPI.ReduceWithPowers( + glApi.ReduceWithPowers( openings.QuotientPolys[quotientPolysStartIdx:quotientPolysEndIdx], zetaPowN, ), ) - p.qeAPI.AssertIsEqual(vanishingPolysZeta[i], prod) + glApi.AssertIsEqualExtension(vanishingPolysZeta[i], prod) } } diff --git a/verifier/internal/plonk/plonk_test.go b/plonk/plonk_test.go similarity index 67% rename from verifier/internal/plonk/plonk_test.go rename to plonk/plonk_test.go index 92ff1b1..5cb00dc 100644 --- a/verifier/internal/plonk/plonk_test.go +++ b/plonk/plonk_test.go @@ -3,12 +3,11 @@ package plonk_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/field" + "github.com/succinctlabs/gnark-plonky2-verifier/plonk" "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 { @@ -18,19 +17,16 @@ type TestPlonkCircuit struct { } 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) publicInputsHash := verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs) proofChallenges := verifierChip.GetChallenges(proofWithPis.Proof, publicInputsHash, commonCircuitData, verifierOnlyCircuitData) - fieldAPI := field.NewFieldAPI(api) - qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI) plonkChip := plonk.NewPlonkChip( api, - qeAPI, commonCircuitData, ) @@ -48,7 +44,7 @@ func TestPlonkDecodeBlock(t *testing.T) { verifierOnlyCircuitDataFilename: "../../data/decode_block/verifier_only_circuit_data.json", } witness := TestPlonkCircuit{} - err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField()) + err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } diff --git a/poseidon/bn254.go b/poseidon/bn254.go new file mode 100644 index 0000000..d28b7b6 --- /dev/null +++ b/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 +} diff --git a/poseidon/poseidon_bn128_test.go b/poseidon/bn254_test.go similarity index 73% rename from poseidon/poseidon_bn128_test.go rename to poseidon/bn254_test.go index ca23023..8df999c 100644 --- a/poseidon/poseidon_bn128_test.go +++ b/poseidon/bn254_test.go @@ -3,23 +3,22 @@ package poseidon import ( "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" "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) - for i := 0; i < spongeWidth; i++ { + for i := 0; i < BN254_SPONGE_WIDTH; i++ { api.AssertIsEqual( output[i], circuit.Out[i], @@ -29,13 +28,13 @@ func (circuit *TestPoseidonBN128Circuit) Define(api frontend.API) error { return nil } -func TestPoseidonBN128(t *testing.T) { +func TestPoseidonBN254(t *testing.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) } @@ -89,10 +88,10 @@ func TestPoseidonBN128(t *testing.T) { } 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) } } diff --git a/poseidon/poseidon_bn128_constants.go b/poseidon/bn254constants.go similarity index 99% rename from poseidon/poseidon_bn128_constants.go rename to poseidon/bn254constants.go index 0359154..bfea7b0 100644 --- a/poseidon/poseidon_bn128_constants.go +++ b/poseidon/bn254constants.go @@ -109,7 +109,7 @@ func init() { cConstants[85], _ = new(big.Int).SetString("19007581091212404202795325684108744075320879284650517772195719617120941682734", 10) cConstants[86], _ = new(big.Int).SetString("8172766643075822491744127151779052248074930479661223662192995838879026989201", 10) cConstants[87], _ = new(big.Int).SetString("1885998770792872998306340529689960371653339961062025442813774917754800650781", 10) - + sConstants[0], _ = new(big.Int).SetString("16023668707004248971294664614290028914393192768609916554276071736843535714477", 10) sConstants[1], _ = new(big.Int).SetString("20198106103550706280267600199190750325504745188750640438654177959939538483777", 10) sConstants[2], _ = new(big.Int).SetString("20760367756622597472566835313508896628444391801225538453375145392828630013190", 10) diff --git a/poseidon/goldilocks.go b/poseidon/goldilocks.go new file mode 100644 index 0000000..ee27bcd --- /dev/null +++ b/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 +} diff --git a/poseidon/poseidon_constants.go b/poseidon/goldilocks_constants.go similarity index 100% rename from poseidon/poseidon_constants.go rename to poseidon/goldilocks_constants.go diff --git a/poseidon/poseidon_test.go b/poseidon/goldilocks_test.go similarity index 70% rename from poseidon/poseidon_test.go rename to poseidon/goldilocks_test.go index 3825f7e..32be542 100644 --- a/poseidon/poseidon_test.go +++ b/poseidon/goldilocks_test.go @@ -3,12 +3,12 @@ package poseidon import ( "testing" + "github.com/consensys/gnark-crypto/ecc" "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/utils" + gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" ) type TestPoseidonCircuit struct { @@ -17,19 +17,18 @@ type TestPoseidonCircuit struct { } 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++ { - input[i] = circuit.In[i] + input[i] = gl.NewVariable(circuit.In[i]) } - poseidonChip := NewPoseidonChip(api, goldilocksApi, qeAPI) + poseidonChip := NewGoldilocksChip(api) output := poseidonChip.Poseidon(input) + glApi := gl.NewChip(api) + for i := 0; i < 12; i++ { - api.AssertIsEqual(output[i], circuit.Out[i]) + glApi.AssertIsEqual(output[i], gl.NewVariable(circuit.Out[i])) } return nil @@ -41,7 +40,7 @@ func TestPoseidonWitness(t *testing.T) { testCase := func(in [12]frontend.Variable, out [12]frontend.Variable) { circuit := 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) } @@ -54,8 +53,8 @@ func TestPoseidonWitness(t *testing.T) { } var in [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) } @@ -69,18 +68,18 @@ func TestPoseidonProof(t *testing.T) { } var in [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} 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 { panic(err) } - witness, err := frontend.NewWitness(&assignment, field.TEST_CURVE.ScalarField()) + witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) if err != nil { panic(err) } @@ -90,7 +89,7 @@ func TestPoseidonProof(t *testing.T) { panic(err) } - err = test.IsSolved(&circuit, &assignment, field.TEST_CURVE.ScalarField()) + err = test.IsSolved(&circuit, &assignment, ecc.BN254.ScalarField()) if err != nil { panic(err) } diff --git a/poseidon/poseidon.go b/poseidon/poseidon.go deleted file mode 100644 index ad4ef69..0000000 --- a/poseidon/poseidon.go +++ /dev/null @@ -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 -} diff --git a/poseidon/poseidon_bn128.go b/poseidon/poseidon_bn128.go deleted file mode 100644 index a939604..0000000 --- a/poseidon/poseidon_bn128.go +++ /dev/null @@ -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 -} diff --git a/poseidon/public_inputs_hash_test.go b/poseidon/public_inputs_hash_test.go index 354965e..5ff7251 100644 --- a/poseidon/public_inputs_hash_test.go +++ b/poseidon/public_inputs_hash_test.go @@ -7,8 +7,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" "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 @@ -19,22 +18,22 @@ type TestPublicInputsHashCircuit struct { } func (circuit *TestPublicInputsHashCircuit) Define(api frontend.API) error { - fieldAPI := field.NewFieldAPI(api) + glAPI := gl.NewChip(api) // BN254 -> Binary(64) -> F - var input [3]field.F + var input [3]gl.Variable 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[:]) // Check that output is correct for i := 0; i < 4; i++ { - fieldAPI.AssertIsEqual( + glAPI.AssertIsEqual( 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"} var in [3]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) } @@ -67,8 +66,8 @@ func TestPublicInputsHashWitness2(t *testing.T) { outStr := []string{"8416658900775745054", "12574228347150446423", "9629056739760131473", "3119289788404190010"} var in [3]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} witness := TestPublicInputsHashCircuit{In: in, Out: out} diff --git a/verifier/common/config.go b/types/circuit.go similarity index 51% rename from verifier/common/config.go rename to types/circuit.go index 1bc31a8..9e46d30 100644 --- a/verifier/common/config.go +++ b/types/circuit.go @@ -1,14 +1,27 @@ -package common +package types 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/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 { - ConstantSigmasCap MerkleCap - CircuitDigest poseidon.PoseidonBN128HashOut + ConstantSigmasCap FriMerkleCap + CircuitDigest poseidon.BN254HashOut } type CircuitConfig struct { @@ -33,25 +46,6 @@ type CommonCircuitData struct { NumGateConstraints uint64 NumConstants uint64 NumPublicInputs uint64 - KIs []field.F + KIs []gl.Variable 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 -} diff --git a/types/fri.go b/types/fri.go new file mode 100644 index 0000000..aaea0f3 --- /dev/null +++ b/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< } -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) -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 } -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)" -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, - ) - } -} diff --git a/verifier/internal/plonk/challenger.go b/verifier/internal/plonk/challenger.go deleted file mode 100644 index 23461b8..0000000 --- a/verifier/internal/plonk/challenger.go +++ /dev/null @@ -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])) - } -} diff --git a/verifier/internal/plonk/challenger_test.go b/verifier/internal/plonk/challenger_test.go deleted file mode 100644 index f7796d2..0000000 --- a/verifier/internal/plonk/challenger_test.go +++ /dev/null @@ -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) - } -} diff --git a/verifier/internal/plonk/types.go b/verifier/internal/plonk/types.go deleted file mode 100644 index e78ea36..0000000 --- a/verifier/internal/plonk/types.go +++ /dev/null @@ -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 -} diff --git a/verifier/types.go b/verifier/types.go deleted file mode 100644 index 61a59fa..0000000 --- a/verifier/types.go +++ /dev/null @@ -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 -} diff --git a/verifier/verifier.go b/verifier/verifier.go index 16dd985..0b35c46 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -2,63 +2,53 @@ package verifier import ( "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/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 { - 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 - 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{ api: api, - fieldAPI: fieldAPI, - qeAPI: qeAPI, - poseidonChip: poseidonChip, - poseidonBN128Chip: poseidonBN128Chip, + poseidonGlChip: poseidonGlChip, + poseidonBN254Chip: poseidonBN254Chip, plonkChip: plonkChip, 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( - 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 numChallenges := config.NumChallenges - challenger := plonk.NewChallengerChip(c.api, c.fieldAPI, c.poseidonChip, c.poseidonBN128Chip) + challenger := challenger.NewChip(c.api) var circuitDigest = verifierData.CircuitDigest - challenger.ObserveBN128Hash(circuitDigest) + challenger.ObserveBN254Hash(circuitDigest) challenger.ObserveHash(publicInputsHash) challenger.ObserveCap(proof.WiresCap) plonkBetas := challenger.GetNChallenges(numChallenges) @@ -70,9 +60,9 @@ func (c *VerifierChip) GetChallenges( challenger.ObserveCap(proof.QuotientPolysCap) plonkZeta := challenger.GetExtensionChallenge() - challenger.ObserveOpenings(fri.ToFriOpenings(proof.Openings)) + challenger.ObserveOpenings(fri.ToOpenings(proof.Openings)) - return common.ProofChallenges{ + return types.ProofChallenges{ PlonkBetas: plonkBetas, PlonkGammas: plonkGammas, 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 // 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) - initialMerkleCaps := []common.MerkleCap{ + initialMerkleCaps := []types.FriMerkleCap{ verifierData.ConstantSigmasCap, proof.WiresCap, 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. // 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++ { - 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++ { - 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( - 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, initialMerkleCaps, &proof.OpeningProof, diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index a98cadd..10d1790 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -8,15 +8,14 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" "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/common" - "github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils" ) type TestVerifierCircuit struct { - Proof common.Proof - PublicInputs []field.F `gnark:",public"` + Proof types.Proof + PublicInputs []gl.Variable `gnark:",public"` verifierChip *verifier.VerifierChip `gnark:"-"` plonky2CircuitName string `gnark:"-"` @@ -24,8 +23,8 @@ type TestVerifierCircuit struct { func (c *TestVerifierCircuit) Define(api frontend.API) error { 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) @@ -39,21 +38,21 @@ func TestStepVerifier(t *testing.T) { testCase := func() { plonky2Circuit := "step" - proofWithPis := utils.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json") + proofWithPis := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json") circuit := TestVerifierCircuit{ plonky2CircuitName: plonky2Circuit, Proof: proofWithPis.Proof, 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{ plonky2CircuitName: plonky2Circuit, Proof: proofWithPis2.Proof, PublicInputs: proofWithPis2.PublicInputs, } - err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField()) + err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } testCase() @@ -63,14 +62,14 @@ func TestStepVerifier2(t *testing.T) { assert := test.NewAssert(t) plonky2Circuit := "step" - proofWithPis := utils.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json") + proofWithPis := verifier.DeserializeProofWithPublicInputs("./data/" + plonky2Circuit + "/proof_with_public_inputs.json") circuit := TestVerifierCircuit{ plonky2CircuitName: plonky2Circuit, Proof: proofWithPis.Proof, 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{ plonky2CircuitName: plonky2Circuit, Proof: proofWithPis2.Proof,