diff --git a/field/field.go b/field/field.go index b30571d..4bd7ffe 100644 --- a/field/field.go +++ b/field/field.go @@ -13,6 +13,8 @@ type QuadraticExtension = [2]F type QEAlgebra = [2]QuadraticExtension type Hash = [4]F +const D = 2 + var TEST_CURVE = ecc.BN254 func NewFieldElement(x uint64) F { diff --git a/field/quadratic_extension.go b/field/quadratic_extension.go index 8c27212..ca2cb38 100644 --- a/field/quadratic_extension.go +++ b/field/quadratic_extension.go @@ -177,21 +177,21 @@ func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) { } func (c *QuadraticExtensionAPI) MulExtensionAlgebra(a, b QEAlgebra) QEAlgebra { - var inner [2][][2]QuadraticExtension - var inner_w [2][][2]QuadraticExtension - for i := 0; i < 2; i++ { - for j := 0; j < 2-i; j++ { - idx := (i + j) % 2 + 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 := 2 - i; j < 2; j++ { - idx := (i + j) % 2 + 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 < 2; i++ { + for i := 0; i < D; i++ { acc := c.InnerProductExtension(NewFieldElement(7), c.ZERO_QE, inner_w[i]) product[i] = c.InnerProductExtension(ONE_F, acc, inner[i]) } @@ -201,7 +201,7 @@ func (c *QuadraticExtensionAPI) MulExtensionAlgebra(a, b QEAlgebra) QEAlgebra { func (c *QuadraticExtensionAPI) ScalarMulExtensionAlgebra(a QuadraticExtension, b QEAlgebra) QEAlgebra { var product QEAlgebra - for i := 0; i < 2; i++ { + for i := 0; i < D; i++ { product[i] = c.MulExtension(a, b[i]) } @@ -210,7 +210,7 @@ func (c *QuadraticExtensionAPI) ScalarMulExtensionAlgebra(a QuadraticExtension, func (c *QuadraticExtensionAPI) AddExtensionAlgebra(a, b QEAlgebra) QEAlgebra { var sum QEAlgebra - for i := 0; i < 2; i++ { + for i := 0; i < D; i++ { sum[i] = c.AddExtension(a[i], b[i]) } @@ -219,7 +219,7 @@ func (c *QuadraticExtensionAPI) AddExtensionAlgebra(a, b QEAlgebra) QEAlgebra { func (c *QuadraticExtensionAPI) SubExtensionAlgebra(a, b QEAlgebra) QEAlgebra { var diff QEAlgebra - for i := 0; i < 2; i++ { + for i := 0; i < D; i++ { diff[i] = c.SubExtension(a[i], b[i]) } diff --git a/plonky2_verifier/arithmetic_extension_gate.go b/plonky2_verifier/arithmetic_extension_gate.go index 6cb4c2f..25f47d4 100644 --- a/plonky2_verifier/arithmetic_extension_gate.go +++ b/plonky2_verifier/arithmetic_extension_gate.go @@ -5,9 +5,6 @@ import ( . "gnark-plonky2-verifier/field" ) -// Ideally, this should be serialized in the plonky2 repo -const d = 2 - type ArithmeticExtensionGate struct { numOps uint64 } @@ -23,19 +20,19 @@ func (g *ArithmeticExtensionGate) Id() string { } func (g *ArithmeticExtensionGate) wiresIthMultiplicand0(i uint64) Range { - return Range{4 * d * i, 4*d*i + d} + return Range{4 * D * i, 4*D*i + D} } func (g *ArithmeticExtensionGate) wiresIthMultiplicand1(i uint64) Range { - return Range{4*d*i + d, 4*d*i + 2*d} + return Range{4*D*i + D, 4*D*i + 2*D} } func (g *ArithmeticExtensionGate) wiresIthAddend(i uint64) Range { - return Range{4*d*i + 2*d, 4*d*i + 3*d} + return Range{4*D*i + 2*D, 4*D*i + 3*D} } func (g *ArithmeticExtensionGate) wiresIthOutput(i uint64) Range { - return Range{4*d*i + 3*d, 4*d*i + 4*d} + return Range{4*D*i + 3*D, 4*D*i + 4*D} } func (g *ArithmeticExtensionGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension { diff --git a/plonky2_verifier/gate.go b/plonky2_verifier/gate.go index 5332634..7a92d79 100644 --- a/plonky2_verifier/gate.go +++ b/plonky2_verifier/gate.go @@ -104,6 +104,24 @@ func GateInstanceFromId(gateId string) gate { return NewArithmeticExtensionGate(uint64(numOps)) } + if strings.HasPrefix(gateId, "MultiplicationExtension") { + // Has the format "ArithmeticExtensionGate { num_ops: 10 }" + + regEx := "MultiplicationExtension { num_ops: (?P[0-9]+) }" + r, err := regexp.Compile(regEx) + if err != nil { + panic("Invalid MultiplicationExtension regular expression") + } + + matches := getRegExMatches(r, gateId) + numOps, hasNumOps := matches["numOps"] + if !hasNumOps { + panic("Invalid MultiplicationExtension ID") + } + + return NewMultiplicationExtensionGate(uint64(numOps)) + } + return nil //panic(fmt.Sprintf("Unknown gate ID %s", gateId)) } diff --git a/plonky2_verifier/gate_test.go b/plonky2_verifier/gate_test.go index 1c31b10..8efd21c 100644 --- a/plonky2_verifier/gate_test.go +++ b/plonky2_verifier/gate_test.go @@ -768,6 +768,7 @@ func TestGates(t *testing.T) { {&RandomAccessGate{bits: 4, numCopies: 4, numExtraConstants: 2}, randomAccessGateExpectedConstraints}, {&PoseidonGate{}, poseidonGateExpectedConstraints}, {&ArithmeticExtensionGate{numOps: 10}, arithmeticExtensionGateExpectedConstraints}, + {&MultiplicationExtensionGate{numOps: 13}, mulExtensionGateExpectedConstraints}, } for _, test := range gateTests { diff --git a/plonky2_verifier/multiplication_extension_gate.go b/plonky2_verifier/multiplication_extension_gate.go new file mode 100644 index 0000000..2ac82da --- /dev/null +++ b/plonky2_verifier/multiplication_extension_gate.go @@ -0,0 +1,51 @@ +package plonky2_verifier + +import ( + "fmt" + . "gnark-plonky2-verifier/field" +) + +type MultiplicationExtensionGate struct { + numOps uint64 +} + +func NewMultiplicationExtensionGate(numOps uint64) *MultiplicationExtensionGate { + return &MultiplicationExtensionGate{ + numOps: numOps, + } +} + +func (g *MultiplicationExtensionGate) Id() string { + return fmt.Sprintf("ArithmeticExtensionGate { num_ops: %d }", g.numOps) +} + +func (g *MultiplicationExtensionGate) wiresIthMultiplicand0(i uint64) Range { + return Range{3 * D * i, 3*D*i + D} +} + +func (g *MultiplicationExtensionGate) wiresIthMultiplicand1(i uint64) Range { + return Range{3*D*i + D, 3*D*i + 2*D} +} + +func (g *MultiplicationExtensionGate) wiresIthOutput(i uint64) Range { + return Range{3*D*i + 2*D, 3*D*i + 3*D} +} + +func (g *MultiplicationExtensionGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension { + const0 := vars.localConstants[0] + + constraints := []QuadraticExtension{} + 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 := p.qeAPI.MulExtensionAlgebra(multiplicand0, multiplicand1) + computed_output := p.qeAPI.ScalarMulExtensionAlgebra(const0, mul) + + diff := p.qeAPI.SubExtensionAlgebra(output, computed_output) + constraints = append(constraints, diff[0], diff[1]) + } + + return constraints +}