From 67692a6646862d6a1e96103a12848eef11c20a69 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Fri, 28 Oct 2022 06:53:48 -0700 Subject: [PATCH] added quadratic extension circuits --- plonky2_verifier/deserialize_test.go | 6 +- plonky2_verifier/quadratic_extension.go | 80 +++++++++++++++++++ plonky2_verifier/quadratic_extension_test.go | 81 ++++++++++++++++++++ 3 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 plonky2_verifier/quadratic_extension.go create mode 100644 plonky2_verifier/quadratic_extension_test.go diff --git a/plonky2_verifier/deserialize_test.go b/plonky2_verifier/deserialize_test.go index d903d95..665e4ca 100644 --- a/plonky2_verifier/deserialize_test.go +++ b/plonky2_verifier/deserialize_test.go @@ -6,19 +6,19 @@ import ( ) func TestDeserializeProofWithPublicInputs(t *testing.T) { - proofWithPis := DeserializeProofWithPublicInputs("./data/proof_with_public_inputs.json") + proofWithPis := DeserializeProofWithPublicInputs("./data/fibonacci/proof_with_public_inputs.json") fmt.Printf("%+v\n", proofWithPis) panic("look at stdout") } func TestDeserializeCommonCircuitData(t *testing.T) { - proofWithPis := DeserializeCommonCircuitData("./data/common_circuit_data.json") + proofWithPis := DeserializeCommonCircuitData("./data/fibonacci/common_circuit_data.json") fmt.Printf("%+v\n", proofWithPis) panic("look at stdout") } func TestDeserializeVerifierOnlyCircuitData(t *testing.T) { - proofWithPis := DeserializeVerifierOnlyCircuitData("./data/verifier_only_circuit_data.json") + proofWithPis := DeserializeVerifierOnlyCircuitData("./data/fibonacci/verifier_only_circuit_data.json") fmt.Printf("%+v\n", proofWithPis) panic("look at stdout") } diff --git a/plonky2_verifier/quadratic_extension.go b/plonky2_verifier/quadratic_extension.go new file mode 100644 index 0000000..19cacea --- /dev/null +++ b/plonky2_verifier/quadratic_extension.go @@ -0,0 +1,80 @@ +package plonky2_verifier + +import ( + . "gnark-ed25519/field" + + "github.com/consensys/gnark/frontend" +) + +type QuadraticExtensionAPI struct { + field frontend.API + + W F + DTH_ROOT F + ZERO_F F + DEGREE_BITS_F F + + ONE QuadraticExtension + DEGREE_BITS_QE QuadraticExtension +} + +func NewQuadraticExtensionAPI(field frontend.API, degreeBits uint64) *QuadraticExtensionAPI { + // TODO: Should degreeBits be verified that it fits within the field? + + return &QuadraticExtensionAPI{ + field: field, + + W: NewFieldElement(7), + DTH_ROOT: NewFieldElement(18446744069414584320), + ZERO_F: NewFieldElement(0), + DEGREE_BITS_F: NewFieldElement(degreeBits), + + ONE: QuadraticExtension{NewFieldElement(1), NewFieldElement(0)}, + DEGREE_BITS_QE: QuadraticExtension{NewFieldElement(degreeBits), NewFieldElement(0)}, + } +} + +func (c *QuadraticExtensionAPI) SquareExtension(a QuadraticExtension) QuadraticExtension { + return c.MulExtension(a, a) +} + +func (c *QuadraticExtensionAPI) MulExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension { + c_0 := c.field.Add(c.field.Mul(a[0], b[0]).(F), c.field.Mul(c.W, a[1], b[1])).(F) + c_1 := c.field.Add(c.field.Mul(a[0], b[1]).(F), c.field.Mul(a[1], b[0])).(F) + return QuadraticExtension{c_0, c_1} +} + +func (c *QuadraticExtensionAPI) AddExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension { + c_0 := c.field.Add(a[0], b[0]).(F) + c_1 := c.field.Add(a[1], b[1]).(F) + return QuadraticExtension{c_0, c_1} +} + +func (c *QuadraticExtensionAPI) SubExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension { + c_0 := c.field.Sub(a[0], b[0]).(F) + c_1 := c.field.Sub(a[1], b[1]).(F) + return QuadraticExtension{c_0, c_1} +} + +func (c *QuadraticExtensionAPI) DivExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension { + return c.MulExtension(a, c.InverseExtension(b)) +} + +// 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 := c.field.IsZero(a[0]) + a1_is_zero := c.field.IsZero(a[1]) + + // assert that a0_is_zero OR a1_is_zero == false + c.field.AssertIsEqual(c.field.Mul(a0_is_zero, a1_is_zero).(F), c.ZERO_F) + + a_pow_r_minus_1 := QuadraticExtension{a[0], c.field.Mul(a[1], c.DTH_ROOT).(F)} + a_pow_r := c.MulExtension(a_pow_r_minus_1, a) + return c.ScalarMulExtension(a_pow_r_minus_1, c.field.Inverse(a_pow_r[0]).(F)) +} + +func (c *QuadraticExtensionAPI) ScalarMulExtension(a QuadraticExtension, scalar F) QuadraticExtension { + return QuadraticExtension{c.field.Mul(a[0], scalar).(F), c.field.Mul(a[1], scalar).(F)} +} diff --git a/plonky2_verifier/quadratic_extension_test.go b/plonky2_verifier/quadratic_extension_test.go new file mode 100644 index 0000000..2fba976 --- /dev/null +++ b/plonky2_verifier/quadratic_extension_test.go @@ -0,0 +1,81 @@ +package plonky2_verifier + +import ( + "gnark-ed25519/field" + . "gnark-ed25519/field" + "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 { + field := field.NewFieldAPI(api) + degreeBits := 3 + c.qeAPI = NewQuadraticExtensionAPI(field, uint64(degreeBits)) + + actualRes := c.qeAPI.MulExtension(c.operand1, c.operand2) + + field.AssertIsEqual(actualRes[0], c.expectedResult[0]) + field.AssertIsEqual(actualRes[1], c.expectedResult[1]) + + return nil +} +func TestQuadraticExtensionMul(t *testing.T) { + assert := test.NewAssert(t) + + operand1 := QuadraticExtension{NewFieldElement(4994088319481652598), NewFieldElement(16489566008211790727)} + operand2 := QuadraticExtension{NewFieldElement(3797605683985595697), NewFieldElement(13424401189265534004)} + expectedResult := QuadraticExtension{NewFieldElement(15052319864161058789), NewFieldElement(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 { + field := field.NewFieldAPI(api) + degreeBits := 3 + c.qeAPI = NewQuadraticExtensionAPI(field, uint64(degreeBits)) + + actualRes := c.qeAPI.DivExtension(c.operand1, c.operand2) + + field.AssertIsEqual(actualRes[0], c.expectedResult[0]) + field.AssertIsEqual(actualRes[1], c.expectedResult[1]) + + return nil +} + +func TestQuadraticExtensionDiv(t *testing.T) { + assert := test.NewAssert(t) + + operand1 := QuadraticExtension{NewFieldElement(4994088319481652598), NewFieldElement(16489566008211790727)} + operand2 := QuadraticExtension{NewFieldElement(7166004739148609569), NewFieldElement(14655965871663555016)} + expectedResult := QuadraticExtension{NewFieldElement(15052319864161058789), NewFieldElement(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) +}