From 89d3b8418cf8e09b624455da772e072b513500b3 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 13 Dec 2024 10:20:14 +0000 Subject: [PATCH 1/8] feat: add G2, Gt mux --- std/algebra/interfaces.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/algebra/interfaces.go b/std/algebra/interfaces.go index 3775d0f922..6815e31016 100644 --- a/std/algebra/interfaces.go +++ b/std/algebra/interfaces.go @@ -105,4 +105,7 @@ type Pairing[G1El G1ElementT, G2El G2ElementT, GtEl GtElementT] interface { // AssertIsOnG2 asserts that the input is on the G2 curve. AssertIsOnG2(*G2El) + + MuxG2(sel frontend.Variable, inputs ...*G2El) *G2El + MuxGt(sel frontend.Variable, inputs ...*GtEl) *GtEl } From ab335b02268543e258a8a2fc6e7f0a1fd6a901b4 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 13 Dec 2024 10:20:30 +0000 Subject: [PATCH 2/8] feat: implement muxes --- std/algebra/emulated/sw_bls12381/pairing.go | 8 ++ std/algebra/emulated/sw_bn254/pairing.go | 114 ++++++++++++++++++++ std/algebra/emulated/sw_bw6761/pairing.go | 8 ++ std/algebra/native/sw_bls12377/pairing2.go | 114 ++++++++++++++++++++ std/algebra/native/sw_bls24315/pairing2.go | 8 ++ 5 files changed, 252 insertions(+) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index b46a3d2c22..bf3a9f9d34 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -266,6 +266,14 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } +func (pr Pairing) MuxG2(sel frontend.Variable, inputs ...*G2Affine) *G2Affine { + panic("not implemented") +} + +func (pr Pairing) MuxGt(sel frontend.Variable, inputs ...*GTEl) *GTEl { + panic("not implemented") +} + func (pr Pairing) AssertIsOnCurve(P *G1Affine) { pr.curve.AssertIsOnCurve(P) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index def19d2654..ba1cddf204 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -274,6 +274,120 @@ func (pr Pairing) AssertIsOnCurve(P *G1Affine) { pr.curve.AssertIsOnCurve(P) } +func (pr Pairing) MuxG2(sel frontend.Variable, inputs ...*G2Affine) *G2Affine { + if len(inputs) == 0 { + return nil + } + if len(inputs) == 1 { + pr.api.AssertIsEqual(sel, 0) + return inputs[0] + } + for i := 1; i < len(inputs); i++ { + if (inputs[0].Lines == nil) != (inputs[i].Lines == nil) { + panic("muxing points with and without precomputed lines") + } + } + var ret G2Affine + XA0 := make([]*emulated.Element[BaseField], len(inputs)) + XA1 := make([]*emulated.Element[BaseField], len(inputs)) + YA0 := make([]*emulated.Element[BaseField], len(inputs)) + YA1 := make([]*emulated.Element[BaseField], len(inputs)) + for i := range inputs { + XA0[i] = &inputs[i].P.X.A0 + XA1[i] = &inputs[i].P.X.A1 + YA0[i] = &inputs[i].P.Y.A0 + YA1[i] = &inputs[i].P.Y.A1 + } + ret.P.X.A0 = *pr.curveF.Mux(sel, XA0...) + ret.P.X.A1 = *pr.curveF.Mux(sel, XA1...) + ret.P.Y.A0 = *pr.curveF.Mux(sel, YA0...) + ret.P.Y.A1 = *pr.curveF.Mux(sel, YA1...) + + if inputs[0].Lines == nil { + return &ret + } + + // switch precomputed lines + ret.Lines = new(lineEvaluations) + for j := range inputs[0].Lines[0] { + lineR0A0 := make([]*emulated.Element[BaseField], len(inputs)) + lineR0A1 := make([]*emulated.Element[BaseField], len(inputs)) + lineR1A0 := make([]*emulated.Element[BaseField], len(inputs)) + lineR1A1 := make([]*emulated.Element[BaseField], len(inputs)) + for k := 0; k < 2; k++ { + for i := range inputs { + lineR0A0[i] = &inputs[i].Lines[k][j].R0.A0 + lineR0A1[i] = &inputs[i].Lines[k][j].R0.A1 + lineR1A0[i] = &inputs[i].Lines[k][j].R1.A0 + lineR1A1[i] = &inputs[i].Lines[k][j].R1.A1 + } + le := &lineEvaluation{ + R0: fields_bn254.E2{ + A0: *pr.curveF.Mux(sel, lineR0A0...), + A1: *pr.curveF.Mux(sel, lineR0A1...), + }, + R1: fields_bn254.E2{ + A0: *pr.curveF.Mux(sel, lineR1A0...), + A1: *pr.curveF.Mux(sel, lineR1A1...), + }, + } + ret.Lines[k][j] = le + } + } + + return &ret +} + +func (pr Pairing) MuxGt(sel frontend.Variable, inputs ...*GTEl) *GTEl { + if len(inputs) == 0 { + return nil + } + if len(inputs) == 1 { + pr.api.AssertIsEqual(sel, 0) + return inputs[0] + } + var ret GTEl + C0B0A0s := make([]*emulated.Element[BaseField], len(inputs)) + C0B0A1s := make([]*emulated.Element[BaseField], len(inputs)) + C0B1A0s := make([]*emulated.Element[BaseField], len(inputs)) + C0B1A1s := make([]*emulated.Element[BaseField], len(inputs)) + C0B2A0s := make([]*emulated.Element[BaseField], len(inputs)) + C0B2A1s := make([]*emulated.Element[BaseField], len(inputs)) + C1B0A0s := make([]*emulated.Element[BaseField], len(inputs)) + C1B0A1s := make([]*emulated.Element[BaseField], len(inputs)) + C1B1A0s := make([]*emulated.Element[BaseField], len(inputs)) + C1B1A1s := make([]*emulated.Element[BaseField], len(inputs)) + C1B2A0s := make([]*emulated.Element[BaseField], len(inputs)) + C1B2A1s := make([]*emulated.Element[BaseField], len(inputs)) + for i := range inputs { + C0B0A0s[i] = &inputs[i].C0.B0.A0 + C0B0A1s[i] = &inputs[i].C0.B0.A1 + C0B1A0s[i] = &inputs[i].C0.B1.A0 + C0B1A1s[i] = &inputs[i].C0.B1.A1 + C0B2A0s[i] = &inputs[i].C0.B2.A0 + C0B2A1s[i] = &inputs[i].C0.B2.A1 + C1B0A0s[i] = &inputs[i].C1.B0.A0 + C1B0A1s[i] = &inputs[i].C1.B0.A1 + C1B1A0s[i] = &inputs[i].C1.B1.A0 + C1B1A1s[i] = &inputs[i].C1.B1.A1 + C1B2A0s[i] = &inputs[i].C1.B2.A0 + C1B2A1s[i] = &inputs[i].C1.B2.A1 + } + ret.C0.B0.A0 = *pr.curveF.Mux(sel, C0B0A0s...) + ret.C0.B0.A1 = *pr.curveF.Mux(sel, C0B0A1s...) + ret.C0.B1.A0 = *pr.curveF.Mux(sel, C0B1A0s...) + ret.C0.B1.A1 = *pr.curveF.Mux(sel, C0B1A1s...) + ret.C0.B2.A0 = *pr.curveF.Mux(sel, C0B2A0s...) + ret.C0.B2.A1 = *pr.curveF.Mux(sel, C0B2A1s...) + ret.C1.B0.A0 = *pr.curveF.Mux(sel, C1B0A0s...) + ret.C1.B0.A1 = *pr.curveF.Mux(sel, C1B0A1s...) + ret.C1.B1.A0 = *pr.curveF.Mux(sel, C1B1A0s...) + ret.C1.B1.A1 = *pr.curveF.Mux(sel, C1B1A1s...) + ret.C1.B2.A0 = *pr.curveF.Mux(sel, C1B2A0s...) + ret.C1.B2.A1 = *pr.curveF.Mux(sel, C1B2A1s...) + return &ret +} + func (pr Pairing) computeTwistEquation(Q *G2Affine) (left, right *fields_bn254.E2) { // Twist: Y² == X³ + aX + b, where a=0 and b=3/(9+u) // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) diff --git a/std/algebra/emulated/sw_bw6761/pairing.go b/std/algebra/emulated/sw_bw6761/pairing.go index 3b690be6fa..c841701170 100644 --- a/std/algebra/emulated/sw_bw6761/pairing.go +++ b/std/algebra/emulated/sw_bw6761/pairing.go @@ -156,6 +156,14 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext6.AssertIsEqual(x, y) } +func (pr Pairing) MuxG2(sel frontend.Variable, inputs ...*G2Affine) *G2Affine { + panic("not implemented") +} + +func (pr Pairing) MuxGt(sel frontend.Variable, inputs ...*GTEl) *GTEl { + panic("not implemented") +} + func (pr Pairing) AssertIsOnCurve(P *G1Affine) { pr.curve.AssertIsOnCurve(P) } diff --git a/std/algebra/native/sw_bls12377/pairing2.go b/std/algebra/native/sw_bls12377/pairing2.go index 945b732209..67989e5dfd 100644 --- a/std/algebra/native/sw_bls12377/pairing2.go +++ b/std/algebra/native/sw_bls12377/pairing2.go @@ -335,6 +335,120 @@ func (p *Pairing) AssertIsEqual(e1, e2 *GT) { e1.AssertIsEqual(p.api, *e2) } +func (pr Pairing) MuxG2(sel frontend.Variable, inputs ...*G2Affine) *G2Affine { + if len(inputs) == 0 { + return nil + } + if len(inputs) == 1 { + pr.api.AssertIsEqual(sel, 0) + return inputs[0] + } + for i := 1; i < len(inputs); i++ { + if (inputs[0].Lines == nil) != (inputs[i].Lines == nil) { + panic("muxing points with and without precomputed lines") + } + } + var ret G2Affine + XA0 := make([]frontend.Variable, len(inputs)) + XA1 := make([]frontend.Variable, len(inputs)) + YA0 := make([]frontend.Variable, len(inputs)) + YA1 := make([]frontend.Variable, len(inputs)) + for i := range inputs { + XA0[i] = inputs[i].P.X.A0 + XA1[i] = inputs[i].P.X.A1 + YA0[i] = inputs[i].P.Y.A0 + YA1[i] = inputs[i].P.Y.A1 + } + ret.P.X.A0 = selector.Mux(pr.api, sel, XA0...) + ret.P.X.A1 = selector.Mux(pr.api, sel, XA1...) + ret.P.Y.A0 = selector.Mux(pr.api, sel, YA0...) + ret.P.Y.A1 = selector.Mux(pr.api, sel, YA1...) + + if inputs[0].Lines == nil { + return &ret + } + + // switch precomputed lines + ret.Lines = new(lineEvaluations) + for j := range inputs[0].Lines[0] { + lineR0A0 := make([]frontend.Variable, len(inputs)) + lineR0A1 := make([]frontend.Variable, len(inputs)) + lineR1A0 := make([]frontend.Variable, len(inputs)) + lineR1A1 := make([]frontend.Variable, len(inputs)) + for k := 0; k < 2; k++ { + for i := range inputs { + lineR0A0[i] = inputs[i].Lines[k][j].R0.A0 + lineR0A1[i] = inputs[i].Lines[k][j].R0.A1 + lineR1A0[i] = inputs[i].Lines[k][j].R1.A0 + lineR1A1[i] = inputs[i].Lines[k][j].R1.A1 + } + le := &lineEvaluation{ + R0: fields_bls12377.E2{ + A0: selector.Mux(pr.api, sel, lineR0A0...), + A1: selector.Mux(pr.api, sel, lineR0A1...), + }, + R1: fields_bls12377.E2{ + A0: selector.Mux(pr.api, sel, lineR1A0...), + A1: selector.Mux(pr.api, sel, lineR1A1...), + }, + } + ret.Lines[k][j] = le + } + } + + return &ret +} + +func (pr Pairing) MuxGt(sel frontend.Variable, inputs ...*GT) *GT { + if len(inputs) == 0 { + return nil + } + if len(inputs) == 1 { + pr.api.AssertIsEqual(sel, 0) + return inputs[0] + } + var ret GT + C0B0A0s := make([]frontend.Variable, len(inputs)) + C0B0A1s := make([]frontend.Variable, len(inputs)) + C0B1A0s := make([]frontend.Variable, len(inputs)) + C0B1A1s := make([]frontend.Variable, len(inputs)) + C0B2A0s := make([]frontend.Variable, len(inputs)) + C0B2A1s := make([]frontend.Variable, len(inputs)) + C1B0A0s := make([]frontend.Variable, len(inputs)) + C1B0A1s := make([]frontend.Variable, len(inputs)) + C1B1A0s := make([]frontend.Variable, len(inputs)) + C1B1A1s := make([]frontend.Variable, len(inputs)) + C1B2A0s := make([]frontend.Variable, len(inputs)) + C1B2A1s := make([]frontend.Variable, len(inputs)) + for i := range inputs { + C0B0A0s[i] = inputs[i].C0.B0.A0 + C0B0A1s[i] = inputs[i].C0.B0.A1 + C0B1A0s[i] = inputs[i].C0.B1.A0 + C0B1A1s[i] = inputs[i].C0.B1.A1 + C0B2A0s[i] = inputs[i].C0.B2.A0 + C0B2A1s[i] = inputs[i].C0.B2.A1 + C1B0A0s[i] = inputs[i].C1.B0.A0 + C1B0A1s[i] = inputs[i].C1.B0.A1 + C1B1A0s[i] = inputs[i].C1.B1.A0 + C1B1A1s[i] = inputs[i].C1.B1.A1 + C1B2A0s[i] = inputs[i].C1.B2.A0 + C1B2A1s[i] = inputs[i].C1.B2.A1 + } + ret.C0.B0.A0 = selector.Mux(pr.api, sel, C0B0A0s...) + ret.C0.B0.A1 = selector.Mux(pr.api, sel, C0B0A1s...) + ret.C0.B1.A0 = selector.Mux(pr.api, sel, C0B1A0s...) + ret.C0.B1.A1 = selector.Mux(pr.api, sel, C0B1A1s...) + ret.C0.B2.A0 = selector.Mux(pr.api, sel, C0B2A0s...) + ret.C0.B2.A1 = selector.Mux(pr.api, sel, C0B2A1s...) + ret.C1.B0.A0 = selector.Mux(pr.api, sel, C1B0A0s...) + ret.C1.B0.A1 = selector.Mux(pr.api, sel, C1B0A1s...) + ret.C1.B1.A0 = selector.Mux(pr.api, sel, C1B1A0s...) + ret.C1.B1.A1 = selector.Mux(pr.api, sel, C1B1A1s...) + ret.C1.B2.A0 = selector.Mux(pr.api, sel, C1B2A0s...) + ret.C1.B2.A1 = selector.Mux(pr.api, sel, C1B2A1s...) + return &ret +} + // AssertIsOnCurve asserts if p belongs to the curve. It doesn't modify p. func (c *Pairing) AssertIsOnCurve(p *G1Affine) { // (X,Y) ∈ {Y² == X³ + 1} U (0,0) diff --git a/std/algebra/native/sw_bls24315/pairing2.go b/std/algebra/native/sw_bls24315/pairing2.go index 405d53b2b3..295845eab8 100644 --- a/std/algebra/native/sw_bls24315/pairing2.go +++ b/std/algebra/native/sw_bls24315/pairing2.go @@ -318,6 +318,14 @@ func (p *Pairing) AssertIsEqual(e1, e2 *GT) { e1.AssertIsEqual(p.api, *e2) } +func (pr Pairing) MuxG2(sel frontend.Variable, inputs ...*G2Affine) *G2Affine { + panic("not implemented") +} + +func (pr Pairing) MuxGt(sel frontend.Variable, inputs ...*GT) *GT { + panic("not implemented") +} + func (p *Pairing) AssertIsOnG1(P *G1Affine) { panic("not implemented") } From 69ae44b184b2ab9275afe9f3a95ee078f8b7d7b8 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 13 Dec 2024 10:21:35 +0000 Subject: [PATCH 3/8] feat: implement Groth16 key switch --- std/recursion/groth16/verifier.go | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/std/recursion/groth16/verifier.go b/std/recursion/groth16/verifier.go index 067158b441..a1318f51a4 100644 --- a/std/recursion/groth16/verifier.go +++ b/std/recursion/groth16/verifier.go @@ -688,3 +688,82 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[G1El, G2El, v.pairing.AssertIsEqual(pairing, &vk.E) return nil } + +func (v *Verifier[FR, G1El, G2El, GtEl]) SwitchVerificationKey(idx frontend.Variable, vks []VerifyingKey[G1El, G2El, GtEl]) (VerifyingKey[G1El, G2El, GtEl], error) { + var ret VerifyingKey[G1El, G2El, GtEl] + if len(vks) == 0 { + return ret, fmt.Errorf("no verifying keys provided") + } + if len(vks) == 1 { + v.api.AssertIsEqual(idx, 0) + return vks[0], nil + } + // commitment info + for i := 1; i < len(vks); i++ { + if len(vks[i].PublicAndCommitmentCommitted) != len(vks[0].PublicAndCommitmentCommitted) { + return ret, fmt.Errorf("invalid number of commitments") + } + for j := range vks[i].PublicAndCommitmentCommitted { + if len(vks[i].PublicAndCommitmentCommitted[j]) != len(vks[0].PublicAndCommitmentCommitted[j]) { + return ret, fmt.Errorf("invalid number of public committed variables") + } + for k := range vks[i].PublicAndCommitmentCommitted[j] { + if vks[i].PublicAndCommitmentCommitted[j][k] != vks[0].PublicAndCommitmentCommitted[j][k] { + return ret, fmt.Errorf("invalid public committed variable index") + } + } + } + if len(vks[i].CommitmentKeys) != len(vks[0].CommitmentKeys) { + return ret, fmt.Errorf("invalid number of commitment keys") + } + } + ret.PublicAndCommitmentCommitted = make([][]int, len(vks[0].PublicAndCommitmentCommitted)) + for i := range vks[0].PublicAndCommitmentCommitted { + ret.PublicAndCommitmentCommitted[i] = make([]int, len(vks[0].PublicAndCommitmentCommitted[i])) + copy(ret.PublicAndCommitmentCommitted[i], vks[0].PublicAndCommitmentCommitted[i]) + } + + ret.CommitmentKeys = make([]pedersen.VerifyingKey[G2El], len(vks[0].CommitmentKeys)) + for i := range ret.CommitmentKeys { + cmtBss := make([]*G2El, len(vks)) + cmtBexs := make([]*G2El, len(vks)) + for j := range vks { + cmtBss[j] = &vks[j].CommitmentKeys[i].G + cmtBexs[j] = &vks[j].CommitmentKeys[i].GSigmaNeg + } + ret.CommitmentKeys[i].G = *v.pairing.MuxG2(idx, cmtBss...) + } + // switch E + Es := make([]*GtEl, len(vks)) + for i := range vks { + Es[i] = &vks[i].E + } + ret.E = *v.pairing.MuxGt(idx, Es...) + + // Switch K + for i := 1; i < len(vks); i++ { + if len(vks[i].G1.K) != len(vks[0].G1.K) { + return ret, fmt.Errorf("invalid number of K elements") + } + } + ret.G1.K = make([]G1El, len(vks[0].G1.K)) + for i := range ret.G1.K { + Ks := make([]*G1El, len(vks)) + for j := range vks { + Ks[j] = &vks[j].G1.K[i] + } + ret.G1.K[i] = *v.curve.Mux(idx, Ks...) + } + + // Switch G2 + gammaNegs := make([]*G2El, len(vks)) + deltaNegs := make([]*G2El, len(vks)) + for i := range vks { + gammaNegs[i] = &vks[i].G2.GammaNeg + deltaNegs[i] = &vks[i].G2.DeltaNeg + } + ret.G2.GammaNeg = *v.pairing.MuxG2(idx, gammaNegs...) + ret.G2.DeltaNeg = *v.pairing.MuxG2(idx, deltaNegs...) + + return ret, nil +} From ffa7b6480c9bb611027117089ab54fa1c9f7dbe7 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 13 Dec 2024 10:21:56 +0000 Subject: [PATCH 4/8] fix: assert index is 0 when 1 key --- std/recursion/plonk/verifier.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index cec5b15e06..688866cb4b 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -1221,6 +1221,8 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) SwitchVerificationKey(bvk BaseVerifying return ret, fmt.Errorf("no circuit verification keys given") } if len(cvks) == 1 { + // we don't need to switch. But the index needs to be 0. + v.api.AssertIsEqual(idx, 0) return VerifyingKey[FR, G1El, G2El]{ BaseVerifyingKey: bvk, CircuitVerifyingKey: cvks[0], From aa28939ae3c634a2b56ce76e40429af6f0bf166a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Mon, 16 Dec 2024 14:38:00 +0100 Subject: [PATCH 5/8] missing GSigmaNeg --- std/recursion/groth16/verifier.go | 1 + 1 file changed, 1 insertion(+) diff --git a/std/recursion/groth16/verifier.go b/std/recursion/groth16/verifier.go index a1318f51a4..0a73f5e8bb 100644 --- a/std/recursion/groth16/verifier.go +++ b/std/recursion/groth16/verifier.go @@ -732,6 +732,7 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) SwitchVerificationKey(idx frontend.Vari cmtBexs[j] = &vks[j].CommitmentKeys[i].GSigmaNeg } ret.CommitmentKeys[i].G = *v.pairing.MuxG2(idx, cmtBss...) + ret.CommitmentKeys[i].GSigmaNeg = *v.pairing.MuxG2(idx, cmtBexs...) } // switch E Es := make([]*GtEl, len(vks)) From becbd0e43531ea2cd0c4b23d0da60f4852db5398 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Tue, 17 Dec 2024 11:27:37 +0100 Subject: [PATCH 6/8] initial tests --- std/recursion/groth16/verifier_test.go | 228 +++++++++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/std/recursion/groth16/verifier_test.go b/std/recursion/groth16/verifier_test.go index 3a4f40ac32..7c834c2680 100644 --- a/std/recursion/groth16/verifier_test.go +++ b/std/recursion/groth16/verifier_test.go @@ -453,3 +453,231 @@ func TestBW6InBN254Commitment(t *testing.T) { err = test.IsSolved(outerCircuit, outerAssignment, ecc.BN254.ScalarField()) assert.NoError(err) } + +type innerDummyCircuit struct { + nbConstraints int + SecretInput frontend.Variable `gnark:",secret"` + PublicInputs frontend.Variable `gnark:",public"` +} + +func (c *innerDummyCircuit) Define(api frontend.API) error { + res := api.Mul(c.SecretInput, c.SecretInput) + for i := 2; i < c.nbConstraints; i++ { + res = api.Mul(res, c.SecretInput) + } + api.AssertIsEqual(c.PublicInputs, res) + return nil +} + +func getInnerDummy(assert *test.Assert, main constraint.ConstraintSystem, field *big.Int) ( + constraint.ConstraintSystem, groth16.VerifyingKey, witness.Witness, groth16.Proof, +) { + dummyCcs, err := frontend.Compile(field, r1cs.NewBuilder, &innerDummyCircuit{ + nbConstraints: main.GetNbConstraints(), + }) + assert.NoError(err) + dummyPK, dummyVK, err := groth16.Setup(dummyCcs) + assert.NoError(err) + + // dummy proof + dummyAssignment := &innerDummyCircuit{ + SecretInput: 1, + PublicInputs: 1, + } + dummyWitness, err := frontend.NewWitness(dummyAssignment, field) + assert.NoError(err) + dummyProof, err := groth16.Prove(dummyCcs, dummyPK, dummyWitness) + assert.NoError(err) + dummyPubWitness, err := dummyWitness.Public() + assert.NoError(err) + err = groth16.Verify(dummyProof, dummyVK, dummyPubWitness) + assert.NoError(err) + return dummyCcs, dummyVK, dummyPubWitness, dummyProof +} + +func getInnersWithDummies(assert *test.Assert, main constraint.ConstraintSystem, selectors []int, field *big.Int) ( + []constraint.ConstraintSystem, []groth16.VerifyingKey, []witness.Witness, []groth16.Proof, +) { + innerCcs, innerVK, innerWitness, innerProof := getInner(assert, field) + dummyCcs, dummyVK, dummyWitness, dummyProof := getInnerDummy(assert, main, field) + var ( + ccss []constraint.ConstraintSystem + witnesses []witness.Witness + proofs []groth16.Proof + ) + for _, selector := range selectors { + if selector == 1 { + ccss = append(ccss, innerCcs) + witnesses = append(witnesses, innerWitness) + proofs = append(proofs, innerProof) + } else { + ccss = append(ccss, dummyCcs) + witnesses = append(witnesses, dummyWitness) + proofs = append(proofs, dummyProof) + } + } + return ccss, []groth16.VerifyingKey{dummyVK, innerVK}, witnesses, proofs +} + +type OuterCircuitMulti[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { + Selectors []frontend.Variable + Proofs []Proof[G1El, G2El] + vks []VerifyingKey[G1El, G2El, GtEl] `gnark:"-"` + InnerWitnesses []Witness[FR] +} + +func (c *OuterCircuitMulti[FR, G1El, G2El, GtEl]) Define(api frontend.API) error { + verifier, err := NewVerifier[FR, G1El, G2El, GtEl](api) + if err != nil { + return fmt.Errorf("new verifier: %w", err) + } + for i, selector := range c.Selectors { + vk, err := verifier.SwitchVerificationKey(selector, c.vks) + if err != nil { + return fmt.Errorf("switch vk: %w", err) + } + if err := verifier.AssertProof(vk, c.Proofs[i], c.InnerWitnesses[i]); err != nil { + return err + } + } + return nil +} + +func TestMultipleBN254InBN254(t *testing.T) { + assert := test.NewAssert(t) + innerCcs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &InnerCircuit{}) + assert.NoError(err) + // generate four circuits with two inner and two dummy (1 = inner, 0 = dummy) + selector := []int{1, 0, 0, 1} + innerCcss, innerVks, innerWitnesses, innerProofs := getInnersWithDummies(assert, innerCcs, selector, ecc.BN254.ScalarField()) + // generate outer and dummy vks + circuitVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl](innerVks[1]) + assert.NoError(err) + circuitDummyVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl](innerVks[0]) + assert.NoError(err) + // parse the placeholders, witnesses and proofs + var ( + placeholders []Witness[sw_bn254.ScalarField] + witnesses []Witness[sw_bn254.ScalarField] + proofs []Proof[sw_bn254.G1Affine, sw_bn254.G2Affine] + ) + for i, ccs := range innerCcss { + placeholders = append(placeholders, PlaceholderWitness[sw_bn254.ScalarField](ccs)) + circuiWitness, err := ValueOfWitness[sw_bn254.ScalarField](innerWitnesses[i]) + assert.NoError(err) + witnesses = append(witnesses, circuiWitness) + proof, err := ValueOfProof[sw_bn254.G1Affine, sw_bn254.G2Affine](innerProofs[i]) + assert.NoError(err) + proofs = append(proofs, proof) + } + // construct the outer circuit with the placeholders and fixed vks + outerCircuit := &OuterCircuitMulti[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + InnerWitnesses: placeholders, + vks: []VerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + circuitDummyVk, + circuitVk, + }, + } + // construct the outer assignment with the witnesses, proofs and circuit selectors + outerAssignment := &OuterCircuitMulti[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Selectors: []frontend.Variable{1, 0, 0, 1}, + InnerWitnesses: witnesses, + Proofs: proofs, + } + err = test.IsSolved(outerCircuit, outerAssignment, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +func TestMultipleBLS12InBW6(t *testing.T) { + assert := test.NewAssert(t) + innerCcs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &InnerCircuit{}) + assert.NoError(err) + // generate four circuits with two inner and two dummy (1 = inner, 0 = dummy) + selector := []int{1, 0, 0, 1} + innerCcss, innerVks, innerWitnesses, innerProofs := getInnersWithDummies(assert, innerCcs, selector, ecc.BLS12_377.ScalarField()) + // generate outer and dummy vks + circuitVk, err := ValueOfVerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](innerVks[1]) + assert.NoError(err) + circuitDummyVk, err := ValueOfVerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](innerVks[0]) + assert.NoError(err) + // parse the placeholders, witnesses and proofs + var ( + placeholders []Witness[sw_bls12377.ScalarField] + witnesses []Witness[sw_bls12377.ScalarField] + proofs []Proof[sw_bls12377.G1Affine, sw_bls12377.G2Affine] + ) + for i, ccs := range innerCcss { + placeholders = append(placeholders, PlaceholderWitness[sw_bls12377.ScalarField](ccs)) + circuiWitness, err := ValueOfWitness[sw_bls12377.ScalarField](innerWitnesses[i]) + assert.NoError(err) + witnesses = append(witnesses, circuiWitness) + proof, err := ValueOfProof[sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProofs[i]) + assert.NoError(err) + proofs = append(proofs, proof) + } + // construct the outer circuit with the placeholders and fixed vks + outerCircuit := &OuterCircuitMulti[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + InnerWitnesses: placeholders, + vks: []VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + circuitDummyVk, + circuitVk, + }, + } + // construct the outer assignment with the witnesses, proofs and circuit selectors + outerAssignment := &OuterCircuitMulti[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + Selectors: []frontend.Variable{1, 0, 0, 1}, + InnerWitnesses: witnesses, + Proofs: proofs, + } + err = test.IsSolved(outerCircuit, outerAssignment, ecc.BW6_761.ScalarField()) + assert.NoError(err) + +} + +func TestMultipleBW6InBN254(t *testing.T) { + assert := test.NewAssert(t) + innerCcs, err := frontend.Compile(ecc.BW6_761.ScalarField(), r1cs.NewBuilder, &InnerCircuit{}) + assert.NoError(err) + + // generate four circuits with two inner and two dummy (1 = inner, 0 = dummy) + selector := []int{1, 0, 0, 1} + innerCcss, innerVks, innerWitnesses, innerProofs := getInnersWithDummies(assert, innerCcs, selector, ecc.BW6_761.ScalarField()) + + // generate outer and dummy vks + circuitVk, err := ValueOfVerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl](innerVks[1]) + assert.NoError(err) + circuitDummyVk, err := ValueOfVerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl](innerVks[0]) + assert.NoError(err) + + // parse the placeholders, witnesses and proofs + var ( + placeholders []Witness[sw_bw6761.ScalarField] + witnesses []Witness[sw_bw6761.ScalarField] + proofs []Proof[sw_bw6761.G1Affine, sw_bw6761.G2Affine] + ) + for i, ccs := range innerCcss { + placeholders = append(placeholders, PlaceholderWitness[sw_bw6761.ScalarField](ccs)) + circuiWitness, err := ValueOfWitness[sw_bw6761.ScalarField](innerWitnesses[i]) + assert.NoError(err) + witnesses = append(witnesses, circuiWitness) + proof, err := ValueOfProof[sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProofs[i]) + assert.NoError(err) + proofs = append(proofs, proof) + } + // construct the outer circuit with the placeholders and fixed vks + outerCircuit := &OuterCircuitMulti[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + InnerWitnesses: placeholders, + vks: []VerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + circuitDummyVk, + circuitVk, + }, + } + // construct the outer assignment with the witnesses, proofs and circuit selectors + outerAssignment := &OuterCircuitMulti[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + Selectors: []frontend.Variable{1, 0, 0, 1}, + InnerWitnesses: witnesses, + Proofs: proofs, + } + err = test.IsSolved(outerCircuit, outerAssignment, ecc.BN254.ScalarField()) + assert.NoError(err) +} From b7c9c2fcbe8c16af46292c5974aa78ec332f4170 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Tue, 17 Dec 2024 11:48:36 +0100 Subject: [PATCH 7/8] more comments --- std/recursion/groth16/verifier_test.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/std/recursion/groth16/verifier_test.go b/std/recursion/groth16/verifier_test.go index 7c834c2680..b80b080fd3 100644 --- a/std/recursion/groth16/verifier_test.go +++ b/std/recursion/groth16/verifier_test.go @@ -469,6 +469,10 @@ func (c *innerDummyCircuit) Define(api frontend.API) error { return nil } +// getInnerDummy method returns a dummy circuit with the number of constraints +// of the main one provided as argument, it also generates a proof for this +// circuit and verifies it. It returns the circuit, the verifying key, the +// public witness and the proof. func getInnerDummy(assert *test.Assert, main constraint.ConstraintSystem, field *big.Int) ( constraint.ConstraintSystem, groth16.VerifyingKey, witness.Witness, groth16.Proof, ) { @@ -495,6 +499,13 @@ func getInnerDummy(assert *test.Assert, main constraint.ConstraintSystem, field return dummyCcs, dummyVK, dummyPubWitness, dummyProof } +// getInnersWithDummies method returns a list of constraint systems, verifying +// keys, witnesses and proofs based on the selectors provided. It generates +// the lists based on the selectors provided, where it includes a 1, it will +// generate an inner circuit, where it includes a 0, it will generate a dummy +// circuit. It returns the resulting lists of assests in the same way as the +// selectors, unless the verification keys, which include in the first place +// the dummy vk and in the second place the inner vk. func getInnersWithDummies(assert *test.Assert, main constraint.ConstraintSystem, selectors []int, field *big.Int) ( []constraint.ConstraintSystem, []groth16.VerifyingKey, []witness.Witness, []groth16.Proof, ) { @@ -520,17 +531,24 @@ func getInnersWithDummies(assert *test.Assert, main constraint.ConstraintSystem, } type OuterCircuitMulti[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { - Selectors []frontend.Variable - Proofs []Proof[G1El, G2El] + // selectors include a 1 for inner and 0 for dummy verification keys + // it allows to switch between the two vks to use the right one for each + // proof and witness + Selectors []frontend.Variable + Proofs []Proof[G1El, G2El] + // vks includes the dummy vk in the first place and the inner vk in the + // second place vks []VerifyingKey[G1El, G2El, GtEl] `gnark:"-"` InnerWitnesses []Witness[FR] } func (c *OuterCircuitMulti[FR, G1El, G2El, GtEl]) Define(api frontend.API) error { + // init the verifier verifier, err := NewVerifier[FR, G1El, G2El, GtEl](api) if err != nil { return fmt.Errorf("new verifier: %w", err) } + // switch between vkeys based on each selector for i, selector := range c.Selectors { vk, err := verifier.SwitchVerificationKey(selector, c.vks) if err != nil { From dc185485fe9ab360268c5e7ed7387c8335ce20b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Wed, 8 Jan 2025 13:14:59 +0100 Subject: [PATCH 8/8] Revert "Merge branch 'master' into feat/switch-groth16-key" This reverts commit 41479641c3d8cc20b8cb185c932a2bc7e3667d6a, reversing changes made to b7c9c2fcbe8c16af46292c5974aa78ec332f4170. --- CODE_OF_CONDUCT.md | 4 +- README.md | 14 +- SECURITY.md | 4 +- backend/groth16/bls12-377/commitment_test.go | 2 +- backend/groth16/bls12-377/marshal.go | 2 +- backend/groth16/bls12-377/marshal_test.go | 2 +- .../groth16/bls12-377/mpcsetup/lagrange.go | 2 +- backend/groth16/bls12-377/mpcsetup/marshal.go | 2 +- .../bls12-377/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls12-377/mpcsetup/phase1.go | 2 +- backend/groth16/bls12-377/mpcsetup/phase2.go | 2 +- backend/groth16/bls12-377/mpcsetup/setup.go | 2 +- .../groth16/bls12-377/mpcsetup/setup_test.go | 2 +- backend/groth16/bls12-377/mpcsetup/utils.go | 2 +- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-377/verify.go | 2 +- backend/groth16/bls12-381/commitment_test.go | 2 +- backend/groth16/bls12-381/marshal.go | 2 +- backend/groth16/bls12-381/marshal_test.go | 2 +- .../groth16/bls12-381/mpcsetup/lagrange.go | 2 +- backend/groth16/bls12-381/mpcsetup/marshal.go | 2 +- .../bls12-381/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls12-381/mpcsetup/phase1.go | 2 +- backend/groth16/bls12-381/mpcsetup/phase2.go | 2 +- backend/groth16/bls12-381/mpcsetup/setup.go | 2 +- .../groth16/bls12-381/mpcsetup/setup_test.go | 2 +- backend/groth16/bls12-381/mpcsetup/utils.go | 2 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls12-381/verify.go | 2 +- backend/groth16/bls24-315/commitment_test.go | 2 +- backend/groth16/bls24-315/marshal.go | 2 +- backend/groth16/bls24-315/marshal_test.go | 2 +- .../groth16/bls24-315/mpcsetup/lagrange.go | 2 +- backend/groth16/bls24-315/mpcsetup/marshal.go | 2 +- .../bls24-315/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls24-315/mpcsetup/phase1.go | 2 +- backend/groth16/bls24-315/mpcsetup/phase2.go | 2 +- backend/groth16/bls24-315/mpcsetup/setup.go | 2 +- .../groth16/bls24-315/mpcsetup/setup_test.go | 2 +- backend/groth16/bls24-315/mpcsetup/utils.go | 2 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-315/verify.go | 2 +- backend/groth16/bls24-317/commitment_test.go | 2 +- backend/groth16/bls24-317/marshal.go | 2 +- backend/groth16/bls24-317/marshal_test.go | 2 +- .../groth16/bls24-317/mpcsetup/lagrange.go | 2 +- backend/groth16/bls24-317/mpcsetup/marshal.go | 2 +- .../bls24-317/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls24-317/mpcsetup/phase1.go | 2 +- backend/groth16/bls24-317/mpcsetup/phase2.go | 2 +- backend/groth16/bls24-317/mpcsetup/setup.go | 2 +- .../groth16/bls24-317/mpcsetup/setup_test.go | 2 +- backend/groth16/bls24-317/mpcsetup/utils.go | 2 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bls24-317/verify.go | 2 +- backend/groth16/bn254/commitment_test.go | 2 +- backend/groth16/bn254/icicle/device.go | 31 - backend/groth16/bn254/icicle/doc.go | 2 +- backend/groth16/bn254/icicle/icicle.go | 677 +++++--------- backend/groth16/bn254/icicle/marshal_test.go | 33 +- backend/groth16/bn254/icicle/noicicle.go | 22 +- backend/groth16/bn254/icicle/provingkey.go | 34 +- backend/groth16/bn254/marshal.go | 2 +- backend/groth16/bn254/marshal_test.go | 2 +- backend/groth16/bn254/mpcsetup/lagrange.go | 2 +- backend/groth16/bn254/mpcsetup/marshal.go | 2 +- .../groth16/bn254/mpcsetup/marshal_test.go | 2 +- backend/groth16/bn254/mpcsetup/phase1.go | 2 +- backend/groth16/bn254/mpcsetup/phase2.go | 2 +- backend/groth16/bn254/mpcsetup/setup.go | 2 +- backend/groth16/bn254/mpcsetup/setup_test.go | 2 +- backend/groth16/bn254/mpcsetup/utils.go | 2 +- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bn254/setup.go | 2 +- backend/groth16/bn254/solidity.go | 2 +- backend/groth16/bn254/verify.go | 2 +- backend/groth16/bw6-633/commitment_test.go | 2 +- backend/groth16/bw6-633/marshal.go | 2 +- backend/groth16/bw6-633/marshal_test.go | 2 +- backend/groth16/bw6-633/mpcsetup/lagrange.go | 2 +- backend/groth16/bw6-633/mpcsetup/marshal.go | 2 +- .../groth16/bw6-633/mpcsetup/marshal_test.go | 2 +- backend/groth16/bw6-633/mpcsetup/phase1.go | 2 +- backend/groth16/bw6-633/mpcsetup/phase2.go | 2 +- backend/groth16/bw6-633/mpcsetup/setup.go | 2 +- .../groth16/bw6-633/mpcsetup/setup_test.go | 2 +- backend/groth16/bw6-633/mpcsetup/utils.go | 2 +- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-633/verify.go | 2 +- backend/groth16/bw6-761/commitment_test.go | 2 +- backend/groth16/bw6-761/marshal.go | 2 +- backend/groth16/bw6-761/marshal_test.go | 2 +- backend/groth16/bw6-761/mpcsetup/lagrange.go | 2 +- backend/groth16/bw6-761/mpcsetup/marshal.go | 2 +- .../groth16/bw6-761/mpcsetup/marshal_test.go | 2 +- backend/groth16/bw6-761/mpcsetup/phase1.go | 2 +- backend/groth16/bw6-761/mpcsetup/phase2.go | 2 +- backend/groth16/bw6-761/mpcsetup/setup.go | 2 +- .../groth16/bw6-761/mpcsetup/setup_test.go | 2 +- backend/groth16/bw6-761/mpcsetup/utils.go | 2 +- backend/groth16/bw6-761/prove.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- backend/groth16/bw6-761/verify.go | 2 +- backend/groth16/groth16.go | 2 +- backend/plonk/bls12-377/marshal.go | 2 +- backend/plonk/bls12-377/marshal_test.go | 2 +- backend/plonk/bls12-377/prove.go | 2 +- backend/plonk/bls12-377/setup.go | 2 +- backend/plonk/bls12-377/verify.go | 2 +- backend/plonk/bls12-381/marshal.go | 2 +- backend/plonk/bls12-381/marshal_test.go | 2 +- backend/plonk/bls12-381/prove.go | 2 +- backend/plonk/bls12-381/setup.go | 2 +- backend/plonk/bls12-381/verify.go | 2 +- backend/plonk/bls24-315/marshal.go | 2 +- backend/plonk/bls24-315/marshal_test.go | 2 +- backend/plonk/bls24-315/prove.go | 2 +- backend/plonk/bls24-315/setup.go | 2 +- backend/plonk/bls24-315/verify.go | 2 +- backend/plonk/bls24-317/marshal.go | 2 +- backend/plonk/bls24-317/marshal_test.go | 2 +- backend/plonk/bls24-317/prove.go | 2 +- backend/plonk/bls24-317/setup.go | 2 +- backend/plonk/bls24-317/verify.go | 2 +- backend/plonk/bn254/marshal.go | 2 +- backend/plonk/bn254/marshal_test.go | 2 +- backend/plonk/bn254/prove.go | 2 +- backend/plonk/bn254/setup.go | 2 +- backend/plonk/bn254/verify.go | 2 +- backend/plonk/bw6-633/marshal.go | 2 +- backend/plonk/bw6-633/marshal_test.go | 2 +- backend/plonk/bw6-633/prove.go | 2 +- backend/plonk/bw6-633/setup.go | 2 +- backend/plonk/bw6-633/verify.go | 2 +- backend/plonk/bw6-761/marshal.go | 2 +- backend/plonk/bw6-761/marshal_test.go | 2 +- backend/plonk/bw6-761/prove.go | 2 +- backend/plonk/bw6-761/setup.go | 2 +- backend/plonk/bw6-761/verify.go | 2 +- constraint/bls12-377/coeff.go | 2 +- constraint/bls12-377/gkr.go | 2 +- constraint/bls12-377/marshal.go | 2 +- constraint/bls12-377/r1cs_test.go | 2 +- constraint/bls12-377/solver.go | 2 +- constraint/bls12-377/system.go | 2 +- constraint/bls12-381/coeff.go | 2 +- constraint/bls12-381/gkr.go | 2 +- constraint/bls12-381/marshal.go | 2 +- constraint/bls12-381/r1cs_test.go | 2 +- constraint/bls12-381/solver.go | 2 +- constraint/bls12-381/system.go | 2 +- constraint/bls24-315/coeff.go | 2 +- constraint/bls24-315/gkr.go | 2 +- constraint/bls24-315/marshal.go | 2 +- constraint/bls24-315/r1cs_test.go | 2 +- constraint/bls24-315/solver.go | 2 +- constraint/bls24-315/system.go | 2 +- constraint/bls24-317/coeff.go | 2 +- constraint/bls24-317/gkr.go | 2 +- constraint/bls24-317/marshal.go | 2 +- constraint/bls24-317/r1cs_test.go | 2 +- constraint/bls24-317/solver.go | 2 +- constraint/bls24-317/system.go | 2 +- constraint/bn254/coeff.go | 2 +- constraint/bn254/gkr.go | 2 +- constraint/bn254/marshal.go | 2 +- constraint/bn254/r1cs_test.go | 2 +- constraint/bn254/solver.go | 2 +- constraint/bn254/system.go | 2 +- constraint/bw6-633/coeff.go | 2 +- constraint/bw6-633/gkr.go | 2 +- constraint/bw6-633/marshal.go | 2 +- constraint/bw6-633/r1cs_test.go | 2 +- constraint/bw6-633/solver.go | 2 +- constraint/bw6-633/system.go | 2 +- constraint/bw6-761/coeff.go | 2 +- constraint/bw6-761/gkr.go | 2 +- constraint/bw6-761/marshal.go | 2 +- constraint/bw6-761/r1cs_test.go | 2 +- constraint/bw6-761/solver.go | 2 +- constraint/bw6-761/system.go | 2 +- constraint/tinyfield/coeff.go | 2 +- constraint/tinyfield/marshal.go | 2 +- constraint/tinyfield/r1cs_test.go | 2 +- constraint/tinyfield/solver.go | 2 +- constraint/tinyfield/system.go | 2 +- frontend/api.go | 4 +- frontend/builder.go | 2 +- frontend/variable.go | 2 +- go.mod | 6 +- go.sum | 10 +- internal/generator/backend/main.go | 2 +- internal/stats/latest_stats.csv | 16 +- internal/tinyfield/arith.go | 2 +- internal/tinyfield/doc.go | 10 +- internal/tinyfield/element.go | 60 +- ...lement_purego.go => element_ops_purego.go} | 22 +- internal/tinyfield/element_test.go | 28 +- internal/tinyfield/vector.go | 39 +- internal/tinyfield/vector_purego.go | 43 - internal/tinyfield/vector_test.go | 2 +- logger/logger.go | 2 +- profile/profile.go | 2 +- std/algebra/algopts/algopts.go | 12 +- std/algebra/defaults.go | 5 +- std/algebra/emulated/fields_bls12381/doc.go | 6 +- std/algebra/emulated/fields_bls12381/e12.go | 791 ++++------------ .../emulated/fields_bls12381/e12_pairing.go | 496 +++++++++-- .../emulated/fields_bls12381/e12_test.go | 387 +++++--- std/algebra/emulated/fields_bls12381/e2.go | 34 +- std/algebra/emulated/fields_bls12381/e6.go | 465 ++++++++++ .../emulated/fields_bls12381/e6_test.go | 360 ++++++++ std/algebra/emulated/fields_bls12381/hints.go | 395 +++++--- std/algebra/emulated/fields_bn254/doc.go | 6 +- std/algebra/emulated/fields_bn254/e12.go | 843 ++++-------------- .../emulated/fields_bn254/e12_pairing.go | 714 +++++++++------ std/algebra/emulated/fields_bn254/e12_test.go | 440 +++++---- std/algebra/emulated/fields_bn254/e2.go | 35 +- std/algebra/emulated/fields_bn254/e6.go | 495 ++++++++++ std/algebra/emulated/fields_bn254/e6_test.go | 444 +++++++++ std/algebra/emulated/fields_bn254/hints.go | 441 ++++++--- std/algebra/emulated/sw_bls12381/g1.go | 49 +- std/algebra/emulated/sw_bls12381/g2.go | 94 +- std/algebra/emulated/sw_bls12381/hints.go | 128 --- std/algebra/emulated/sw_bls12381/pairing.go | 431 +++++---- .../emulated/sw_bls12381/pairing_test.go | 101 ++- std/algebra/emulated/sw_bn254/g2.go | 64 +- std/algebra/emulated/sw_bn254/hints.go | 124 --- std/algebra/emulated/sw_bn254/pairing.go | 671 +++++++------- std/algebra/emulated/sw_bn254/pairing_test.go | 162 +++- std/algebra/emulated/sw_bw6761/g1.go | 9 +- std/algebra/emulated/sw_emulated/hints.go | 44 +- std/algebra/emulated/sw_emulated/point.go | 32 +- std/algebra/native/sw_bls12377/hints.go | 26 +- std/algebra/native/sw_bls12377/pairing2.go | 7 +- std/algebra/native/sw_bls24315/hints.go | 12 +- std/algebra/native/sw_bls24315/pairing2.go | 7 +- std/algebra/native/twistededwards/hints.go | 11 +- std/commitments/fri/fri.go | 2 +- std/evmprecompiles/08-bnpairing.go | 2 +- std/evmprecompiles/hints.go | 2 +- std/gkr/compile.go | 6 +- std/gkr/gkr.go | 5 +- std/hash/hash.go | 15 - std/hash/mimc/mimc.go | 25 - std/hash/mimc/mimc_test.go | 128 --- .../poseidon2/poseidon2.go | 2 +- .../poseidon2/poseidon2_test.go | 0 std/hash/ripemd160/ripemd160_test.go | 2 +- std/internal/limbcomposition/composition.go | 8 +- std/internal/logderivarg/logderivarg.go | 7 +- .../logderivprecomp/logderivprecomp.go | 4 +- std/math/bitslice/hints.go | 8 +- std/math/bitslice/partition.go | 2 +- std/math/emulated/element_test.go | 2 +- std/math/emulated/emparams/emparams.go | 2 +- std/math/emulated/field.go | 13 +- std/math/emulated/field_assert.go | 2 +- std/math/emulated/field_hint.go | 11 +- std/math/emulated/field_mul.go | 9 +- std/math/emulated/hints.go | 23 +- std/math/emulated/subtraction_padding.go | 7 +- std/math/polynomial/polynomial.go | 7 +- std/math/uints/hints.go | 10 +- std/multicommit/doc_test.go | 2 +- std/signature/ecdsa/ecdsa.go | 5 +- std/signature/ecdsa/ecdsa_secpr_test.go | 27 - std/sumcheck/sumcheck.go | 4 +- test/unsafekzg/options.go | 2 +- 274 files changed, 5780 insertions(+), 4342 deletions(-) delete mode 100644 backend/groth16/bn254/icicle/device.go rename internal/tinyfield/{element_purego.go => element_ops_purego.go} (97%) delete mode 100644 internal/tinyfield/vector_purego.go create mode 100644 std/algebra/emulated/fields_bls12381/e6.go create mode 100644 std/algebra/emulated/fields_bls12381/e6_test.go create mode 100644 std/algebra/emulated/fields_bn254/e6.go create mode 100644 std/algebra/emulated/fields_bn254/e6_test.go delete mode 100644 std/algebra/emulated/sw_bls12381/hints.go rename std/{permutation => hash}/poseidon2/poseidon2.go (99%) rename std/{permutation => hash}/poseidon2/poseidon2_test.go (100%) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a591c5fbac..9579bd2200 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -26,7 +26,7 @@ Examples of unacceptable behavior by participants include: advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as physical or electronic +* Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting @@ -70,4 +70,4 @@ members of the project's leadership. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html -[homepage]: https://www.contributor-covenant.org +[homepage]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/README.md b/README.md index 61c9c71c14..229630ff94 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/consensys/gnark)](https://pkg.go.dev/mod/github.com/consensys/gnark) [![Documentation Status](https://readthedocs.com/projects/pegasys-gnark/badge/)][`gnark` User Documentation] [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5819104.svg)](https://doi.org/10.5281/zenodo.5819104) -`gnark` is a fast zk-SNARK library that offers a high-level API to design circuits. The library is open-source and developed under the Apache 2.0 license. +`gnark` is a fast zk-SNARK library that offers a high-level API to design circuits. The library is open source and developed under the Apache 2.0 license. `gnark` uses [`gnark-crypto`] for the finite-field arithmetic and out-circuit implementation of cryptographic algorithms. @@ -29,7 +29,7 @@ Checkout the [online playground][`gnark` Playground] to compile circuits and vis ## Security -**`gnark` and [`gnark-crypto`] have been [extensively audited](#audits), but are provided as-is, we make no guarantees or warranties to their safety and reliability. In particular, `gnark` makes no security guarantees such as constant time implementation or side-channel attack resistance.** +**`gnark` and [`gnark-crypto`] have been [extensively audited](#audits), but are provided as-is, we make no guarantees or warranties to its safety and reliability. In particular, `gnark` makes no security guarantees such as constant time implementation or side-channel attack resistance.** **To report a security bug, please refer to [`gnark` Security Policy](SECURITY.md).** @@ -56,7 +56,7 @@ The tests are automatically run during every PR and merge commit. We run full te ## Performance -`gnark` and `gnark-crypto` packages are optimized for 64bits architectures (x86 `amd64`) using assembly operations. We have a generic implementation of the same arithmetic algorithms for ARM backends (`arm64`). We do not implement vector operations. +`gnark` and `gnark-crypto` packages are optimized for 64bits architectures (x86 `amd64`) using assembly operations. We have generic implementation of the same arithmetic algorithms for ARM backends (`arm64`). We do not implement vector operations. ## Backwards compatibility @@ -162,9 +162,9 @@ func main() { ### GPU Support -#### ICICLE Library +#### Icicle Library -The following schemes and curves support experimental use of Ingonyama's ICICLE GPU library for low level zk-SNARK primitives such as MSM, NTT, and polynomial operations: +The following schemes and curves support experimental use of Ingonyama's Icicle GPU library for low level zk-SNARK primitives such as MSM, NTT, and polynomial operations: - [x] [Groth16](https://eprint.iacr.org/2016/260) @@ -184,7 +184,7 @@ You can then toggle on or off icicle acceleration by providing the `WithIcicleAc proof, err := groth16.Prove(ccs, pk, secretWitness) ``` -For more information about prerequisites see the [ICICLE repo](https://github.com/ingonyama-zk/icicle). **NB! ICICLE CUDA kernels are covered by a special license for now. Follow the instructions to download and set up the kernels.** +For more information about prerequisites see the [Icicle repo](https://github.com/ingonyama-zk/icicle). ## Citing @@ -228,4 +228,4 @@ This project is licensed under the Apache 2 License - see the [LICENSE](LICENSE) [`gnark-announce`]: https://groups.google.com/g/gnark-announce [@gnark_team]: https://twitter.com/gnark_team [`gnark-crypto`]: https://github.com/Consensys/gnark-crypto -[`gnark-solidity-checker`]: https://github.com/Consensys/gnark-solidity-checker +[`gnark-solidity-checker`]: https://github.com/Consensys/gnark-solidity-checker \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index 215f8ca6bc..39db02c5e7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -28,7 +28,7 @@ Issues in the **PUBLIC** track affect niche configurations, have very limited im Issues in the **PRIVATE** track are violations of committed security properties. -**PRIVATE** track issues are fixed in the next scheduled minor releases, and are kept private until then. +**PRIVATE** track issues are fixed in the next scheduled minor releases , and are kept private until then. Three to seven days before the release, a pre-announcement is sent to [`gnark-announce`] and [@gnark_team], announcing the presence of a security fix in the upcoming releases, and which component in gnark is affected; compiler, constraint system or proof system (but not disclosing any more details). @@ -59,4 +59,4 @@ This process can take some time, especially when coordination is required with m The best way to receive security announcements is to subscribe to the [`gnark-announce`] mailing list. Any messages pertaining to a security issue will be prefixed with \[security\]. [`gnark-announce`]: https://groups.google.com/g/gnark-announce -[@gnark_team]: https://twitter.com/gnark_team +[@gnark_team]: https://twitter.com/gnark_team \ No newline at end of file diff --git a/backend/groth16/bls12-377/commitment_test.go b/backend/groth16/bls12-377/commitment_test.go index 2b11523888..cf4a19931e 100644 --- a/backend/groth16/bls12-377/commitment_test.go +++ b/backend/groth16/bls12-377/commitment_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index 2614fe1912..e5072c7baf 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/marshal_test.go b/backend/groth16/bls12-377/marshal_test.go index 7cb6646736..70a39cfeab 100644 --- a/backend/groth16/bls12-377/marshal_test.go +++ b/backend/groth16/bls12-377/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/lagrange.go b/backend/groth16/bls12-377/mpcsetup/lagrange.go index b7cc5535a3..b240155f12 100644 --- a/backend/groth16/bls12-377/mpcsetup/lagrange.go +++ b/backend/groth16/bls12-377/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/marshal.go b/backend/groth16/bls12-377/mpcsetup/marshal.go index ed7e699339..aab5af4057 100644 --- a/backend/groth16/bls12-377/mpcsetup/marshal.go +++ b/backend/groth16/bls12-377/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/marshal_test.go b/backend/groth16/bls12-377/mpcsetup/marshal_test.go index 5fcd3594d3..af045351c1 100644 --- a/backend/groth16/bls12-377/mpcsetup/marshal_test.go +++ b/backend/groth16/bls12-377/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/phase1.go b/backend/groth16/bls12-377/mpcsetup/phase1.go index ab471c2ab6..724ac887b6 100644 --- a/backend/groth16/bls12-377/mpcsetup/phase1.go +++ b/backend/groth16/bls12-377/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/phase2.go b/backend/groth16/bls12-377/mpcsetup/phase2.go index 48e05fbc60..bb4ab9a05e 100644 --- a/backend/groth16/bls12-377/mpcsetup/phase2.go +++ b/backend/groth16/bls12-377/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/setup.go b/backend/groth16/bls12-377/mpcsetup/setup.go index 34b1c0e0fb..1796c00203 100644 --- a/backend/groth16/bls12-377/mpcsetup/setup.go +++ b/backend/groth16/bls12-377/mpcsetup/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/setup_test.go b/backend/groth16/bls12-377/mpcsetup/setup_test.go index c31ff4bf17..24204f31ca 100644 --- a/backend/groth16/bls12-377/mpcsetup/setup_test.go +++ b/backend/groth16/bls12-377/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/mpcsetup/utils.go b/backend/groth16/bls12-377/mpcsetup/utils.go index fe56aaf198..a0757bc065 100644 --- a/backend/groth16/bls12-377/mpcsetup/utils.go +++ b/backend/groth16/bls12-377/mpcsetup/utils.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 6ee0df5ec3..282b7da3d0 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index d4f023fc52..8b599d571e 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 3c36f182d2..ff95c7ec6b 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/commitment_test.go b/backend/groth16/bls12-381/commitment_test.go index ad5a2a6c99..087f68a6ff 100644 --- a/backend/groth16/bls12-381/commitment_test.go +++ b/backend/groth16/bls12-381/commitment_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 5f8a5fe325..9fbb9273cd 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/marshal_test.go b/backend/groth16/bls12-381/marshal_test.go index fb7f728696..6156c5c2a1 100644 --- a/backend/groth16/bls12-381/marshal_test.go +++ b/backend/groth16/bls12-381/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/lagrange.go b/backend/groth16/bls12-381/mpcsetup/lagrange.go index da31e2a6ca..34d3b1d040 100644 --- a/backend/groth16/bls12-381/mpcsetup/lagrange.go +++ b/backend/groth16/bls12-381/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/marshal.go b/backend/groth16/bls12-381/mpcsetup/marshal.go index 4d4994d9a6..47c750583c 100644 --- a/backend/groth16/bls12-381/mpcsetup/marshal.go +++ b/backend/groth16/bls12-381/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/marshal_test.go b/backend/groth16/bls12-381/mpcsetup/marshal_test.go index ae297dbf39..7104c8eac5 100644 --- a/backend/groth16/bls12-381/mpcsetup/marshal_test.go +++ b/backend/groth16/bls12-381/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/phase1.go b/backend/groth16/bls12-381/mpcsetup/phase1.go index e476f527ab..be297e477f 100644 --- a/backend/groth16/bls12-381/mpcsetup/phase1.go +++ b/backend/groth16/bls12-381/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/phase2.go b/backend/groth16/bls12-381/mpcsetup/phase2.go index dbb525181c..09610500c6 100644 --- a/backend/groth16/bls12-381/mpcsetup/phase2.go +++ b/backend/groth16/bls12-381/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/setup.go b/backend/groth16/bls12-381/mpcsetup/setup.go index d6a2608417..64e42f4889 100644 --- a/backend/groth16/bls12-381/mpcsetup/setup.go +++ b/backend/groth16/bls12-381/mpcsetup/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/setup_test.go b/backend/groth16/bls12-381/mpcsetup/setup_test.go index 3757ee19d2..37a20a1d8f 100644 --- a/backend/groth16/bls12-381/mpcsetup/setup_test.go +++ b/backend/groth16/bls12-381/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/mpcsetup/utils.go b/backend/groth16/bls12-381/mpcsetup/utils.go index a87234cf37..6868c0278f 100644 --- a/backend/groth16/bls12-381/mpcsetup/utils.go +++ b/backend/groth16/bls12-381/mpcsetup/utils.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 497de249b8..fd3a54981b 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 4500f36c27..9c4eb95927 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index baf4163d16..798c093bde 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/commitment_test.go b/backend/groth16/bls24-315/commitment_test.go index d39b6376a7..c8a3f1180c 100644 --- a/backend/groth16/bls24-315/commitment_test.go +++ b/backend/groth16/bls24-315/commitment_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index f330c626ca..72591f46cf 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/marshal_test.go b/backend/groth16/bls24-315/marshal_test.go index 04a4f5119c..ce91212511 100644 --- a/backend/groth16/bls24-315/marshal_test.go +++ b/backend/groth16/bls24-315/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/lagrange.go b/backend/groth16/bls24-315/mpcsetup/lagrange.go index 156d3a08e4..68a642863b 100644 --- a/backend/groth16/bls24-315/mpcsetup/lagrange.go +++ b/backend/groth16/bls24-315/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/marshal.go b/backend/groth16/bls24-315/mpcsetup/marshal.go index 62d1470077..7c994e08fe 100644 --- a/backend/groth16/bls24-315/mpcsetup/marshal.go +++ b/backend/groth16/bls24-315/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/marshal_test.go b/backend/groth16/bls24-315/mpcsetup/marshal_test.go index cc7e19ed8c..ffd1631d71 100644 --- a/backend/groth16/bls24-315/mpcsetup/marshal_test.go +++ b/backend/groth16/bls24-315/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/phase1.go b/backend/groth16/bls24-315/mpcsetup/phase1.go index e98b00ddcc..c61a807625 100644 --- a/backend/groth16/bls24-315/mpcsetup/phase1.go +++ b/backend/groth16/bls24-315/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/phase2.go b/backend/groth16/bls24-315/mpcsetup/phase2.go index 9c1c74e359..8d11d19a06 100644 --- a/backend/groth16/bls24-315/mpcsetup/phase2.go +++ b/backend/groth16/bls24-315/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/setup.go b/backend/groth16/bls24-315/mpcsetup/setup.go index df3abc91bb..26ca9fcc78 100644 --- a/backend/groth16/bls24-315/mpcsetup/setup.go +++ b/backend/groth16/bls24-315/mpcsetup/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/setup_test.go b/backend/groth16/bls24-315/mpcsetup/setup_test.go index 786bcbdfe0..5a8b6d63de 100644 --- a/backend/groth16/bls24-315/mpcsetup/setup_test.go +++ b/backend/groth16/bls24-315/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/mpcsetup/utils.go b/backend/groth16/bls24-315/mpcsetup/utils.go index 95e43b8c5a..0bd4cdd3cb 100644 --- a/backend/groth16/bls24-315/mpcsetup/utils.go +++ b/backend/groth16/bls24-315/mpcsetup/utils.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index f610b94624..5c81871287 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index fcd392fcc6..bb126cc3ed 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index 8a4d1f6755..580ae2031f 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/commitment_test.go b/backend/groth16/bls24-317/commitment_test.go index 5682bba631..d08a909c76 100644 --- a/backend/groth16/bls24-317/commitment_test.go +++ b/backend/groth16/bls24-317/commitment_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index f2f0a45040..e42d864ef3 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/marshal_test.go b/backend/groth16/bls24-317/marshal_test.go index e472051fb1..5803cfe5f6 100644 --- a/backend/groth16/bls24-317/marshal_test.go +++ b/backend/groth16/bls24-317/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/lagrange.go b/backend/groth16/bls24-317/mpcsetup/lagrange.go index e8b45d396e..ad78a233ad 100644 --- a/backend/groth16/bls24-317/mpcsetup/lagrange.go +++ b/backend/groth16/bls24-317/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/marshal.go b/backend/groth16/bls24-317/mpcsetup/marshal.go index b087846391..19706282c7 100644 --- a/backend/groth16/bls24-317/mpcsetup/marshal.go +++ b/backend/groth16/bls24-317/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/marshal_test.go b/backend/groth16/bls24-317/mpcsetup/marshal_test.go index a6905524b3..15c39e9e1d 100644 --- a/backend/groth16/bls24-317/mpcsetup/marshal_test.go +++ b/backend/groth16/bls24-317/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/phase1.go b/backend/groth16/bls24-317/mpcsetup/phase1.go index 0004ef4909..774f1a6aa8 100644 --- a/backend/groth16/bls24-317/mpcsetup/phase1.go +++ b/backend/groth16/bls24-317/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/phase2.go b/backend/groth16/bls24-317/mpcsetup/phase2.go index 6f7a2bf8dd..5521eadb9b 100644 --- a/backend/groth16/bls24-317/mpcsetup/phase2.go +++ b/backend/groth16/bls24-317/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/setup.go b/backend/groth16/bls24-317/mpcsetup/setup.go index e01ada3991..c4620fb3c8 100644 --- a/backend/groth16/bls24-317/mpcsetup/setup.go +++ b/backend/groth16/bls24-317/mpcsetup/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/setup_test.go b/backend/groth16/bls24-317/mpcsetup/setup_test.go index 80cf432635..98e466aa90 100644 --- a/backend/groth16/bls24-317/mpcsetup/setup_test.go +++ b/backend/groth16/bls24-317/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/mpcsetup/utils.go b/backend/groth16/bls24-317/mpcsetup/utils.go index 51d4583a4a..69dbbdefac 100644 --- a/backend/groth16/bls24-317/mpcsetup/utils.go +++ b/backend/groth16/bls24-317/mpcsetup/utils.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 41f858d9eb..d0e4c44adc 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index f1962d9b38..9b42e4e305 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index e1fafd4549..75ab20a555 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/commitment_test.go b/backend/groth16/bn254/commitment_test.go index fb821dfe64..62054a12ad 100644 --- a/backend/groth16/bn254/commitment_test.go +++ b/backend/groth16/bn254/commitment_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/icicle/device.go b/backend/groth16/bn254/icicle/device.go deleted file mode 100644 index d00fd1cd4b..0000000000 --- a/backend/groth16/bn254/icicle/device.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build icicle - -package icicle - -import ( - "fmt" - "sync" - - "github.com/consensys/gnark/logger" - icicle_runtime "github.com/ingonyama-zk/icicle/v3/wrappers/golang/runtime" -) - -var onceWarmUpDevice sync.Once - -func warmUpDevice() { - onceWarmUpDevice.Do(func() { - log := logger.Logger() - err := icicle_runtime.LoadBackendFromEnvOrDefault() - if err != icicle_runtime.Success { - panic(fmt.Sprintf("ICICLE backend loading error: %s", err.AsString())) - } - device := icicle_runtime.CreateDevice("CUDA", 0) - log.Debug().Int32("id", device.Id).Str("type", device.GetDeviceType()).Msg("ICICLE device created") - icicle_runtime.RunOnDevice(&device, func(args ...any) { - err := icicle_runtime.WarmUpDevice() - if err != icicle_runtime.Success { - panic(fmt.Sprintf("ICICLE device warmup error: %s", err.AsString())) - } - }) - }) -} diff --git a/backend/groth16/bn254/icicle/doc.go b/backend/groth16/bn254/icicle/doc.go index 3a662b35da..a77a7fbde9 100644 --- a/backend/groth16/bn254/icicle/doc.go +++ b/backend/groth16/bn254/icicle/doc.go @@ -1,2 +1,2 @@ // Package icicle_bn254 implements ICICLE acceleration for BN254 Groth16 backend. -package icicle +package icicle_bn254 diff --git a/backend/groth16/bn254/icicle/icicle.go b/backend/groth16/bn254/icicle/icicle.go index 49133cd8b1..5b1b235d33 100644 --- a/backend/groth16/bn254/icicle/icicle.go +++ b/backend/groth16/bn254/icicle/icicle.go @@ -1,20 +1,19 @@ //go:build icicle -package icicle +package icicle_bn254 import ( "fmt" "math/big" "math/bits" - "os" "time" + "unsafe" - "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/hash_to_field" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend" groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" "github.com/consensys/gnark/backend/groth16/internal" @@ -24,40 +23,33 @@ import ( "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" - - icicle_core "github.com/ingonyama-zk/icicle/v3/wrappers/golang/core" - icicle_bn254 "github.com/ingonyama-zk/icicle/v3/wrappers/golang/curves/bn254" - icicle_g2 "github.com/ingonyama-zk/icicle/v3/wrappers/golang/curves/bn254/g2" - icicle_msm "github.com/ingonyama-zk/icicle/v3/wrappers/golang/curves/bn254/msm" - icicle_ntt "github.com/ingonyama-zk/icicle/v3/wrappers/golang/curves/bn254/ntt" - icicle_vecops "github.com/ingonyama-zk/icicle/v3/wrappers/golang/curves/bn254/vecOps" - icicle_runtime "github.com/ingonyama-zk/icicle/v3/wrappers/golang/runtime" - - fcs "github.com/consensys/gnark/frontend/cs" + iciclegnark "github.com/ingonyama-zk/iciclegnark/curves/bn254" ) const HasIcicle = true -var isProfileMode bool - -func init() { - _, isProfileMode = os.LookupEnv("ICICLE_STEP_PROFILE") -} - -func (pk *ProvingKey) setupDevicePointers(device *icicle_runtime.Device) error { +func (pk *ProvingKey) setupDevicePointers() error { if pk.deviceInfo != nil { return nil } pk.deviceInfo = &deviceInfo{} - gen, err := fft.Generator(2 * pk.Domain.Cardinality) - if err != nil { - return fmt.Errorf("get fft generator: %w", err) - } - /************************* Den ***************************/ n := int(pk.Domain.Cardinality) + sizeBytes := n * fr.Bytes + + /************************* Start Domain Device Setup ***************************/ + copyCosetInvDone := make(chan unsafe.Pointer, 1) + copyCosetDone := make(chan unsafe.Pointer, 1) + copyDenDone := make(chan unsafe.Pointer, 1) + /************************* CosetTableInv ***************************/ + go iciclegnark.CopyToDevice(pk.Domain.CosetTableInv, sizeBytes, copyCosetInvDone) + + /************************* CosetTable ***************************/ + go iciclegnark.CopyToDevice(pk.Domain.CosetTable, sizeBytes, copyCosetDone) + + /************************* Den ***************************/ var denI, oneI fr.Element oneI.SetOne() - denI.Exp(gen, big.NewInt(int64(pk.Domain.Cardinality))) + denI.Exp(pk.Domain.FrMultiplicativeGen, big.NewInt(int64(pk.Domain.Cardinality))) denI.Sub(&denI, &oneI).Inverse(&denI) log2SizeFloor := bits.Len(uint(n)) - 1 @@ -70,165 +62,71 @@ func (pk *ProvingKey) setupDevicePointers(device *icicle_runtime.Device) error { denIcicleArr = append(denIcicleArr, denI) } - copyDenDone := make(chan struct{}) - icicle_runtime.RunOnDevice(device, func(args ...any) { - denIcicleArrHost := (icicle_core.HostSlice[fr.Element])(denIcicleArr) - denIcicleArrHost.CopyToDevice(&pk.DenDevice, true) - if err := icicle_bn254.FromMontgomery(pk.DenDevice); err != icicle_runtime.Success { - panic(fmt.Sprintf("copy den to device: %s", err.AsString())) - } - close(copyDenDone) - }) - - /************************* Init Domain Device ***************************/ - genBits := gen.Bits() - limbs := icicle_core.ConvertUint64ArrToUint32Arr(genBits[:]) - copy(pk.CosetGenerator[:], limbs[:fr.Limbs*2]) - var rouIcicle icicle_bn254.ScalarField - rouIcicle.FromLimbs(limbs) - - initDomain := make(chan struct{}) - icicle_runtime.RunOnDevice(device, func(args ...any) { - if e := icicle_ntt.InitDomain(rouIcicle, icicle_core.GetDefaultNTTInitDomainConfig()); e != icicle_runtime.Success { - panic(fmt.Sprintf("couldn't initialize domain: %s", e.AsString())) // TODO - } - close(initDomain) - }) - - /************************* End Init Domain Device ***************************/ - /************************* Start G1 Device Setup ***************************/ - /************************* A ***************************/ - copyADone := make(chan struct{}) - icicle_runtime.RunOnDevice(device, func(args ...any) { - g1AHost := (icicle_core.HostSlice[curve.G1Affine])(pk.G1.A) - g1AHost.CopyToDevice(&pk.G1Device.A, true) - if err := icicle_bn254.AffineFromMontgomery(pk.G1Device.A); err != icicle_runtime.Success { - panic(fmt.Sprintf("copy A to device: %s", err.AsString())) - } - close(copyADone) - }) - /************************* B ***************************/ - copyBDone := make(chan struct{}) - icicle_runtime.RunOnDevice(device, func(args ...any) { - g1BHost := (icicle_core.HostSlice[curve.G1Affine])(pk.G1.B) - g1BHost.CopyToDevice(&pk.G1Device.B, true) - if err := icicle_bn254.AffineFromMontgomery(pk.G1Device.B); err != icicle_runtime.Success { - panic(fmt.Sprintf("copy B to device: %s", err.AsString())) - } - close(copyBDone) - }) - /************************* K ***************************/ - copyKDone := make(chan struct{}) - icicle_runtime.RunOnDevice(device, func(args ...any) { - g1KHost := (icicle_core.HostSlice[curve.G1Affine])(pk.G1.K) - g1KHost.CopyToDevice(&pk.G1Device.K, true) - if err := icicle_bn254.AffineFromMontgomery(pk.G1Device.K); err != icicle_runtime.Success { - panic(fmt.Sprintf("copy K to device: %s", err.AsString())) - } - close(copyKDone) - }) - /************************* Z ***************************/ - copyZDone := make(chan struct{}) - icicle_runtime.RunOnDevice(device, func(args ...any) { - g1ZHost := (icicle_core.HostSlice[curve.G1Affine])(pk.G1.Z) - g1ZHost.CopyToDevice(&pk.G1Device.Z, true) - err := icicle_bn254.AffineFromMontgomery(pk.G1Device.Z) - if err != icicle_runtime.Success { - panic(fmt.Sprintf("copy Z to device: %s", err.AsString())) - } - close(copyZDone) - }) - /************************* End G1 Device Setup ***************************/ - /************************* Start G2 Device Setup ***************************/ - copyG2BDone := make(chan struct{}) - icicle_runtime.RunOnDevice(device, func(args ...any) { - g2BHost := (icicle_core.HostSlice[curve.G2Affine])(pk.G2.B) - g2BHost.CopyToDevice(&pk.G2Device.B, true) - if err := icicle_g2.G2AffineFromMontgomery(pk.G2Device.B); err != icicle_runtime.Success { - panic(fmt.Sprintf("copy G2 B to device: %s", err.AsString())) - } - close(copyG2BDone) - }) - /************************* End G2 Device Setup ***************************/ - - /************************* Commitment Keys Device Setup ***************************/ - - commitmentKeysDeviceDone := make(chan struct{}) - pk.CommitmentKeysDevice.Basis = make([]icicle_core.DeviceSlice, len(pk.CommitmentKeys)) - pk.CommitmentKeysDevice.BasisExpSigma = make([]icicle_core.DeviceSlice, len(pk.CommitmentKeys)) - icicle_runtime.RunOnDevice(device, func(args ...any) { - for i := range pk.CommitmentKeys { - commitmentKeyBasisHost := icicle_core.HostSliceFromElements(pk.CommitmentKeys[i].Basis) - commitmentKeyBasisExpSigmaHost := icicle_core.HostSliceFromElements(pk.CommitmentKeys[i].BasisExpSigma) - commitmentKeyBasisHost.CopyToDevice(&pk.CommitmentKeysDevice.Basis[i], true) - commitmentKeyBasisExpSigmaHost.CopyToDevice(&pk.CommitmentKeysDevice.BasisExpSigma[i], true) - } - close(commitmentKeysDeviceDone) - }) - /************************* End Commitment Keys Device Setup ***************************/ - - /************************* Wait for all data tranfsers ***************************/ - <-initDomain - <-copyDenDone - <-copyADone - <-copyBDone - <-copyKDone - <-copyZDone - <-copyG2BDone - <-commitmentKeysDeviceDone - - return nil -} + go iciclegnark.CopyToDevice(denIcicleArr, sizeBytes, copyDenDone) -func projectiveToGnarkAffine(p icicle_bn254.Projective) *curve.G1Affine { - px, _ := fp.LittleEndian.Element((*[fp.Bytes]byte)(p.X.ToBytesLittleEndian())) - py, _ := fp.LittleEndian.Element((*[fp.Bytes]byte)(p.Y.ToBytesLittleEndian())) - pz, _ := fp.LittleEndian.Element((*[fp.Bytes]byte)(p.Z.ToBytesLittleEndian())) + /************************* Twiddles and Twiddles Inv ***************************/ + twiddlesInv_d_gen, twddles_err := iciclegnark.GenerateTwiddleFactors(n, true) + if twddles_err != nil { + return twddles_err + } - var x, y, zInv fp.Element + twiddles_d_gen, twddles_err := iciclegnark.GenerateTwiddleFactors(n, false) + if twddles_err != nil { + return twddles_err + } - zInv.Inverse(&pz) - x.Mul(&px, &zInv) - y.Mul(&py, &zInv) + /************************* End Domain Device Setup ***************************/ + pk.DomainDevice.Twiddles = twiddles_d_gen + pk.DomainDevice.TwiddlesInv = twiddlesInv_d_gen - return &curve.G1Affine{X: x, Y: y} -} + pk.DomainDevice.CosetTableInv = <-copyCosetInvDone + pk.DomainDevice.CosetTable = <-copyCosetDone + pk.DenDevice = <-copyDenDone -func g1ProjectiveToG1Jac(p icicle_bn254.Projective) curve.G1Jac { - var p1 curve.G1Jac - p1.FromAffine(projectiveToGnarkAffine(p)) + /************************* Start G1 Device Setup ***************************/ + /************************* A ***************************/ + pointsBytesA := len(pk.G1.A) * fp.Bytes * 2 + copyADone := make(chan unsafe.Pointer, 1) + go iciclegnark.CopyPointsToDevice(pk.G1.A, pointsBytesA, copyADone) // Make a function for points - return p1 -} + /************************* B ***************************/ + pointsBytesB := len(pk.G1.B) * fp.Bytes * 2 + copyBDone := make(chan unsafe.Pointer, 1) + go iciclegnark.CopyPointsToDevice(pk.G1.B, pointsBytesB, copyBDone) // Make a function for points -func toGnarkE2(f icicle_g2.G2BaseField) curve.E2 { - bytes := f.ToBytesLittleEndian() - a0, _ := fp.LittleEndian.Element((*[fp.Bytes]byte)(bytes[:fp.Bytes])) - a1, _ := fp.LittleEndian.Element((*[fp.Bytes]byte)(bytes[fp.Bytes:])) - return curve.E2{ - A0: a0, - A1: a1, + /************************* K ***************************/ + var pointsNoInfinity []curve.G1Affine + for i, gnarkPoint := range pk.G1.K { + if gnarkPoint.IsInfinity() { + pk.InfinityPointIndicesK = append(pk.InfinityPointIndicesK, i) + } else { + pointsNoInfinity = append(pointsNoInfinity, gnarkPoint) + } } -} -func g2ProjectiveToG2Jac(p *icicle_g2.G2Projective) curve.G2Jac { - x := toGnarkE2(p.X) - y := toGnarkE2(p.Y) - z := toGnarkE2(p.Z) - var zSquared curve.E2 - zSquared.Mul(&z, &z) + pointsBytesK := len(pointsNoInfinity) * fp.Bytes * 2 + copyKDone := make(chan unsafe.Pointer, 1) + go iciclegnark.CopyPointsToDevice(pointsNoInfinity, pointsBytesK, copyKDone) // Make a function for points - var X curve.E2 - X.Mul(&x, &z) + /************************* Z ***************************/ + pointsBytesZ := len(pk.G1.Z) * fp.Bytes * 2 + copyZDone := make(chan unsafe.Pointer, 1) + go iciclegnark.CopyPointsToDevice(pk.G1.Z, pointsBytesZ, copyZDone) // Make a function for points - var Y curve.E2 - Y.Mul(&y, &zSquared) + /************************* End G1 Device Setup ***************************/ + pk.G1Device.A = <-copyADone + pk.G1Device.B = <-copyBDone + pk.G1Device.K = <-copyKDone + pk.G1Device.Z = <-copyZDone - return curve.G2Jac{ - X: X, - Y: Y, - Z: z, - } + /************************* Start G2 Device Setup ***************************/ + pointsBytesB2 := len(pk.G2.B) * fp.Bytes * 4 + copyG2BDone := make(chan unsafe.Pointer, 1) + go iciclegnark.CopyG2PointsToDevice(pk.G2.B, pointsBytesB2, copyG2BDone) // Make a function for points + pk.G2Device.B = <-copyG2BDone + + /************************* End G2 Device Setup ***************************/ + return nil } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). @@ -244,13 +142,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return groth16_bn254.Prove(r1cs, &pk.ProvingKey, fullWitness, opts...) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Str("acceleration", "icicle").Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - - device := icicle_runtime.CreateDevice("CUDA", 0) - if pk.deviceInfo == nil { log.Debug().Msg("precomputing proving key in GPU") - - if err := pk.setupDevicePointers(&device); err != nil { + if err := pk.setupDevicePointers(); err != nil { return nil, fmt.Errorf("setup device pointers: %w", err) } } @@ -262,48 +156,42 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) - privateCommittedValuesDevice := make([]icicle_core.DeviceSlice, len(commitmentInfo)) - - // override hints - bsb22ID := solver.GetHintID(fcs.Bsb22CommitmentComputePlaceholder) - solverOpts = append(solverOpts, solver.OverrideHint(bsb22ID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - i := int(in[0].Int64()) - in = in[1:] - privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) - hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] - committed := in[+len(hashed):] - for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) - } + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) + } + + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } - proofCommitmentIcicle := make(icicle_core.HostSlice[icicle_bn254.Projective], 1) - ckBasisMsmDone := make(chan struct{}) - icicle_runtime.RunOnDevice(&device, func(args ...any) { - cfg := icicle_msm.GetDefaultMSMConfig() - cfg.AreBasesMontgomeryForm = true - cfg.AreScalarsMontgomeryForm = true - privateCommittedValuesHost := icicle_core.HostSliceFromElements(privateCommittedValues[i]) - privateCommittedValuesHost.CopyToDevice(&privateCommittedValuesDevice[i], true) - if err := icicle_msm.Msm(privateCommittedValuesDevice[i], pk.CommitmentKeysDevice.Basis[i], &cfg, proofCommitmentIcicle); err != icicle_runtime.Success { - panic(fmt.Sprintf("commitment: %s", err.AsString())) + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + res.BigInt(out[0]) + return err } - close(ckBasisMsmDone) - }) - <-ckBasisMsmDone - proof.Commitments[i] = *projectiveToGnarkAffine(proofCommitmentIcicle[0]) - - opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) - hashBts := opt.HashToFieldFn.Sum(nil) - opt.HashToFieldFn.Reset() - nbBuf := fr.Bytes - if opt.HashToFieldFn.Size() < fr.Bytes { - nbBuf = opt.HashToFieldFn.Size() - } - var res fr.Element - res.SetBytes(hashBts[:nbBuf]) - res.BigInt(out[0]) - return nil - })) + }(i))) + } + + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { @@ -314,66 +202,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b wireValues := []fr.Element(solution.W) start := time.Now() - numCommitmentKeys := len(pk.CommitmentKeys) - poks := make([]curve.G1Affine, numCommitmentKeys) - - // if there are CommitmentKeys, run a batch MSM for pederson Proof of Knowledge - if numCommitmentKeys > 0 { - startPoKBatch := time.Now() - poksIcicle := make([]icicle_core.HostSlice[icicle_bn254.Projective], numCommitmentKeys) - for i := range poksIcicle { - poksIcicle[i] = make(icicle_core.HostSlice[icicle_bn254.Projective], 1) - } - ckBasisExpSigmaMsmBatchDone := make(chan struct{}) - icicle_runtime.RunOnDevice(&device, func(args ...any) { - cfg := icicle_msm.GetDefaultMSMConfig() - cfg.AreBasesMontgomeryForm = true - cfg.AreScalarsMontgomeryForm = true - for i := range pk.CommitmentKeysDevice.BasisExpSigma { - if err := icicle_msm.Msm(privateCommittedValuesDevice[i], pk.CommitmentKeysDevice.BasisExpSigma[i], &cfg, poksIcicle[i]); err != icicle_runtime.Success { - panic(fmt.Sprintf("commitment POK: %s", err.AsString())) - } - } - close(ckBasisExpSigmaMsmBatchDone) - }) - <-ckBasisExpSigmaMsmBatchDone - for i := range pk.CommitmentKeys { - poks[i] = *projectiveToGnarkAffine(poksIcicle[i][0]) - } - if isProfileMode { - log.Debug().Dur("took", time.Since(startPoKBatch)).Msg("ICICLE Batch Proof of Knowledge") - } - } - // compute challenge for folding the PoKs from the commitments + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) for i := range commitmentInfo { copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } - challenge, err := fr.Hash(commitmentsSerialized, []byte("G16-BSB22"), 1) - if err != nil { - return nil, err - } - if _, err = proof.CommitmentPok.Fold(poks, challenge[0], ecc.MultiExpConfig{NbTasks: 1}); err != nil { + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } - // H (witness reduction / FFT part) - var h icicle_core.DeviceSlice - chHDone := make(chan struct{}) - icicle_runtime.RunOnDevice(&device, func(args ...any) { - h = computeH(solution.A, solution.B, solution.C, pk, &device) + // H (witness reduction / FFT part) + var h unsafe.Pointer + chHDone := make(chan struct{}, 1) + go func() { + h = computeH(solution.A, solution.B, solution.C, pk) solution.A = nil solution.B = nil solution.C = nil - close(chHDone) - }) + chHDone <- struct{}{} + }() // we need to copy and filter the wireValues for each multi exp // as pk.G1.A, pk.G1.B and pk.G2.B may have (a significant) number of point at infinity - var wireValuesADevice, wireValuesBDevice icicle_core.DeviceSlice - chWireValuesA, chWireValuesB := make(chan struct{}), make(chan struct{}) + var wireValuesADevice, wireValuesBDevice iciclegnark.OnDeviceData + chWireValuesA, chWireValuesB := make(chan struct{}, 1), make(chan struct{}, 1) - icicle_runtime.RunOnDevice(&device, func(args ...any) { + go func() { wireValuesA := make([]fr.Element, len(wireValues)-int(pk.NbInfinityA)) for i, j := 0, 0; j < len(wireValuesA); i++ { if pk.InfinityA[i] { @@ -382,18 +237,22 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b wireValuesA[j] = wireValues[i] j++ } + wireValuesASize := len(wireValuesA) + scalarBytes := wireValuesASize * fr.Bytes // Copy scalars to the device and retain ptr to them - wireValuesAHost := (icicle_core.HostSlice[fr.Element])(wireValuesA) - wireValuesAHost.CopyToDevice(&wireValuesADevice, true) - if err := icicle_bn254.FromMontgomery(wireValuesADevice); err != icicle_runtime.Success { - panic(fmt.Sprintf("copy A to device: %s", err.AsString())) + copyDone := make(chan unsafe.Pointer, 1) + iciclegnark.CopyToDevice(wireValuesA, scalarBytes, copyDone) + wireValuesADevicePtr := <-copyDone + + wireValuesADevice = iciclegnark.OnDeviceData{ + P: wireValuesADevicePtr, + Size: wireValuesASize, } close(chWireValuesA) - }) - - icicle_runtime.RunOnDevice(&device, func(args ...any) { + }() + go func() { wireValuesB := make([]fr.Element, len(wireValues)-int(pk.NbInfinityB)) for i, j := 0, 0; j < len(wireValuesB); i++ { if pk.InfinityB[i] { @@ -402,16 +261,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b wireValuesB[j] = wireValues[i] j++ } + wireValuesBSize := len(wireValuesB) + scalarBytes := wireValuesBSize * fr.Bytes // Copy scalars to the device and retain ptr to them - wireValuesBHost := (icicle_core.HostSlice[fr.Element])(wireValuesB) - wireValuesBHost.CopyToDevice(&wireValuesBDevice, true) - if err := icicle_bn254.FromMontgomery(wireValuesBDevice); err != icicle_runtime.Success { - panic(fmt.Sprintf("copy B to device: %s", err.AsString())) + copyDone := make(chan unsafe.Pointer, 1) + iciclegnark.CopyToDevice(wireValuesB, scalarBytes, copyDone) + wireValuesBDevicePtr := <-copyDone + + wireValuesBDevice = iciclegnark.OnDeviceData{ + P: wireValuesBDevicePtr, + Size: wireValuesBSize, } close(chWireValuesB) - }) + }() // sample random r and s var r, s big.Int @@ -431,91 +295,74 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) var bs1, ar curve.G1Jac - chArDone, chBs1Done := make(chan struct{}), make(chan struct{}) computeBS1 := func() error { <-chWireValuesB - cfg := icicle_msm.GetDefaultMSMConfig() - res := make(icicle_core.HostSlice[icicle_bn254.Projective], 1) - start := time.Now() - if err := icicle_msm.Msm(wireValuesBDevice, pk.G1Device.B, &cfg, res); err != icicle_runtime.Success { - panic(fmt.Sprintf("msm Bs1: %s", err.AsString())) - } - - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("MSM Bs1") + if bs1, _, err = iciclegnark.MsmOnDevice(wireValuesBDevice.P, pk.G1Device.B, wireValuesBDevice.Size, true); err != nil { + return err } - bs1 = g1ProjectiveToG1Jac(res[0]) bs1.AddMixed(&pk.G1.Beta) bs1.AddMixed(&deltas[1]) - close(chBs1Done) return nil } computeAR1 := func() error { <-chWireValuesA - cfg := icicle_msm.GetDefaultMSMConfig() - res := make(icicle_core.HostSlice[icicle_bn254.Projective], 1) - start := time.Now() - if err := icicle_msm.Msm(wireValuesADevice, pk.G1Device.A, &cfg, res); err != icicle_runtime.Success { - panic(fmt.Sprintf("msm Ar1: %s", err.AsString())) - } - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("MSM Ar1") + if ar, _, err = iciclegnark.MsmOnDevice(wireValuesADevice.P, pk.G1Device.A, wireValuesADevice.Size, true); err != nil { + return err } - ar = g1ProjectiveToG1Jac(res[0]) ar.AddMixed(&pk.G1.Alpha) ar.AddMixed(&deltas[0]) proof.Ar.FromJacobian(&ar) - close(chArDone) return nil } computeKRS := func() error { var krs, krs2, p1 curve.G1Jac - sizeH := int(pk.Domain.Cardinality - 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 - cfg := icicle_msm.GetDefaultMSMConfig() - resKrs2 := make(icicle_core.HostSlice[icicle_bn254.Projective], 1) - start := time.Now() - if err := icicle_msm.Msm(h.RangeTo(sizeH, false), pk.G1Device.Z, &cfg, resKrs2); err != icicle_runtime.Success { - panic(fmt.Sprintf("msm Krs2: %s", err.AsString())) - } - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("MSM Krs2") + // check for small circuits as iciclegnark doesn't handle zero sizes well + if len(pk.G1.Z) > 0 { + if krs2, _, err = iciclegnark.MsmOnDevice(h, pk.G1Device.Z, sizeH, true); err != nil { + return err + } } - krs2 = g1ProjectiveToG1Jac(resKrs2[0]) // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) - _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - _wireValuesHost := (icicle_core.HostSlice[fr.Element])(_wireValues) - resKrs := make(icicle_core.HostSlice[icicle_bn254.Projective], 1) - cfg.AreScalarsMontgomeryForm = true - start = time.Now() - if err := icicle_msm.Msm(_wireValuesHost, pk.G1Device.K, &cfg, resKrs); err != icicle_runtime.Success { - panic(fmt.Sprintf("msm Krs: %s", err.AsString())) + scalars := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) + + // filter zero/infinity points since icicle doesn't handle them + // See https://github.com/ingonyama-zk/icicle/issues/169 for more info + for _, indexToRemove := range pk.InfinityPointIndicesK { + scalars = append(scalars[:indexToRemove], scalars[indexToRemove+1:]...) } - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("MSM Krs") + + scalarBytes := len(scalars) * fr.Bytes + + copyDone := make(chan unsafe.Pointer, 1) + iciclegnark.CopyToDevice(scalars, scalarBytes, copyDone) + scalars_d := <-copyDone + + krs, _, err = iciclegnark.MsmOnDevice(scalars_d, pk.G1Device.K, len(scalars), true) + iciclegnark.FreeDevicePointer(scalars_d) + + if err != nil { + return err } - krs = g1ProjectiveToG1Jac(resKrs[0]) krs.AddMixed(&deltas[2]) krs.AddAssign(&krs2) - <-chArDone - <-chBs1Done - p1.ScalarMultiplication(&ar, &s) krs.AddAssign(&p1) @@ -532,17 +379,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b var Bs, deltaS curve.G2Jac <-chWireValuesB - - cfg := icicle_g2.G2GetDefaultMSMConfig() - res := make(icicle_core.HostSlice[icicle_g2.G2Projective], 1) - start := time.Now() - if err := icicle_g2.G2Msm(wireValuesBDevice, pk.G2Device.B, &cfg, res); err != icicle_runtime.Success { - panic(fmt.Sprintf("msm Bs2: %s", err.AsString())) - } - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("MSM Bs2 G2") + if Bs, _, err = iciclegnark.MsmG2OnDevice(wireValuesBDevice.P, pk.G2Device.B, wireValuesBDevice.Size, true); err != nil { + return err } - Bs = g2ProjectiveToG2Jac(&res[0]) deltaS.FromAffine(&pk.G2.Delta) deltaS.ScalarMultiplication(&deltaS, &s) @@ -553,51 +392,31 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil } - // schedule our proof part computations - icicle_runtime.RunOnDevice(&device, func(args ...any) { - if err := computeAR1(); err != nil { - panic(fmt.Sprintf("compute AR1: %v", err)) - } - }) - - icicle_runtime.RunOnDevice(&device, func(args ...any) { - if err := computeBS1(); err != nil { - panic(fmt.Sprintf("compute BS1: %v", err)) - } - }) - - icicle_runtime.RunOnDevice(&device, func(args ...any) { - if err := computeBS2(); err != nil { - panic(fmt.Sprintf("compute BS2: %v", err)) - } - }) - // wait for FFT to end <-chHDone - computeKrsDone := make(chan struct{}) - icicle_runtime.RunOnDevice(&device, func(args ...any) { - if err := computeKRS(); err != nil { - panic(fmt.Sprintf("compute KRS: %v", err)) - } - close(computeKrsDone) - }) - <-computeKrsDone + // schedule our proof part computations + if err := computeAR1(); err != nil { + return nil, err + } + if err := computeBS1(); err != nil { + return nil, err + } + if err := computeKRS(); err != nil { + return nil, err + } + if err := computeBS2(); err != nil { + return nil, err + } log.Debug().Dur("took", time.Since(start)).Msg("prover done") // free device/GPU memory that is not needed for future proofs (scalars/hpoly) - icicle_runtime.RunOnDevice(&device, func(args ...any) { - if err := wireValuesADevice.Free(); err != icicle_runtime.Success { - log.Error().Msgf("free wireValuesADevice failed: %s", err.AsString()) - } - if err := wireValuesBDevice.Free(); err != icicle_runtime.Success { - log.Error().Msgf("free wireValuesBDevice failed: %s", err.AsString()) - } - if err := h.Free(); err != icicle_runtime.Success { - log.Error().Msgf("free h failed: %s", err.AsString()) - } - }) + go func() { + iciclegnark.FreeDevicePointer(wireValuesADevice.P) + iciclegnark.FreeDevicePointer(wireValuesBDevice.P) + iciclegnark.FreeDevicePointer(h) + }() return proof, nil } @@ -631,14 +450,13 @@ func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr return } -func computeH(a, b, c []fr.Element, pk *ProvingKey, device *icicle_runtime.Device) icicle_core.DeviceSlice { +func computeH(a, b, c []fr.Element, pk *ProvingKey) unsafe.Pointer { // H part of Krs // Compute H (hz=ab-c, where z=-2 on ker X^n+1 (z(x)=x^n-1)) // 1 - _a = ifft(a), _b = ifft(b), _c = ifft(c) // 2 - ca = fft_coset(_a), ba = fft_coset(_b), cc = fft_coset(_c) // 3 - h = ifft_coset(ca o cb - cc) - log := logger.Logger() - startTotal := time.Now() + n := len(a) // add padding to ensure input length is domain cardinality @@ -648,83 +466,48 @@ func computeH(a, b, c []fr.Element, pk *ProvingKey, device *icicle_runtime.Devic c = append(c, padding...) n = len(a) - computeADone := make(chan icicle_core.DeviceSlice) - computeBDone := make(chan icicle_core.DeviceSlice) - computeCDone := make(chan icicle_core.DeviceSlice) - - computeInttNttOnDevice := func(args ...any) { - var scalars []fr.Element = args[0].([]fr.Element) - var channel chan icicle_core.DeviceSlice = args[1].(chan icicle_core.DeviceSlice) - - cfg := icicle_ntt.GetDefaultNttConfig() - scalarsStream, _ := icicle_runtime.CreateStream() - cfg.StreamHandle = scalarsStream - cfg.Ordering = icicle_core.KNM - cfg.IsAsync = true - scalarsHost := icicle_core.HostSliceFromElements(scalars) - var scalarsDevice icicle_core.DeviceSlice - scalarsHost.CopyToDeviceAsync(&scalarsDevice, scalarsStream, true) - start := time.Now() - icicle_ntt.Ntt(scalarsDevice, icicle_core.KInverse, &cfg, scalarsDevice) - cfg.Ordering = icicle_core.KMN - cfg.CosetGen = pk.CosetGenerator - icicle_ntt.Ntt(scalarsDevice, icicle_core.KForward, &cfg, scalarsDevice) - icicle_runtime.SynchronizeStream(scalarsStream) - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("computeH: NTT + INTT") - } - channel <- scalarsDevice - close(channel) - } + sizeBytes := n * fr.Bytes - icicle_runtime.RunOnDevice(device, computeInttNttOnDevice, a, computeADone) - icicle_runtime.RunOnDevice(device, computeInttNttOnDevice, b, computeBDone) - icicle_runtime.RunOnDevice(device, computeInttNttOnDevice, c, computeCDone) + /*********** Copy a,b,c to Device Start ************/ + // Individual channels are necessary to know which device pointers + // point to which vector + copyADone := make(chan unsafe.Pointer, 1) + copyBDone := make(chan unsafe.Pointer, 1) + copyCDone := make(chan unsafe.Pointer, 1) - aDevice := <-computeADone - bDevice := <-computeBDone - cDevice := <-computeCDone + go iciclegnark.CopyToDevice(a, sizeBytes, copyADone) + go iciclegnark.CopyToDevice(b, sizeBytes, copyBDone) + go iciclegnark.CopyToDevice(c, sizeBytes, copyCDone) - // The following does not need to be run in a RunOnDevice call because - // computeH is being run inside a RunOnDevice call and the following is not - // being run in a different goroutine unlike the calls above to - // computeInttNttOnDevice which are running in different goroutines - vecCfg := icicle_core.DefaultVecOpsConfig() - start := time.Now() - if err := icicle_bn254.FromMontgomery(aDevice); err != icicle_runtime.Success { - panic(fmt.Sprintf("fromMontgomery a in computeH: %s", err.AsString())) - } - if err := icicle_vecops.VecOp(aDevice, bDevice, aDevice, vecCfg, icicle_core.Mul); err != icicle_runtime.Success { - panic(fmt.Sprintf("mul a b in computeH: %s", err.AsString())) - } - if err := icicle_vecops.VecOp(aDevice, cDevice, aDevice, vecCfg, icicle_core.Sub); err != icicle_runtime.Success { - panic(fmt.Sprintf("sub a c in computeH: %s", err.AsString())) - } - if err := icicle_vecops.VecOp(aDevice, pk.DenDevice, aDevice, vecCfg, icicle_core.Mul); err != icicle_runtime.Success { - panic(fmt.Sprintf("mul a den in computeH: %s", err.AsString())) - } - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("computeH: vecOps") - } - defer bDevice.Free() - defer cDevice.Free() - - cfg := icicle_ntt.GetDefaultNttConfig() - cfg.CosetGen = pk.CosetGenerator - cfg.Ordering = icicle_core.KNR - start = time.Now() - if err := icicle_ntt.Ntt(aDevice, icicle_core.KInverse, &cfg, aDevice); err != icicle_runtime.Success { - panic(fmt.Sprintf("ntt a in computeH: %s", err.AsString())) - } - if isProfileMode { - log.Debug().Dur("took", time.Since(start)).Msg("computeH: INTT final") - } - if err := icicle_bn254.FromMontgomery(aDevice); err != icicle_runtime.Success { - panic(fmt.Sprintf("fromMontgomery a in computeH: %s", err.AsString())) - } + a_device := <-copyADone + b_device := <-copyBDone + c_device := <-copyCDone + /*********** Copy a,b,c to Device End ************/ - if isProfileMode { - log.Debug().Dur("took", time.Since(startTotal)).Msg("computeH: Total") + computeInttNttDone := make(chan error, 1) + computeInttNttOnDevice := func(devicePointer unsafe.Pointer) { + a_intt_d := iciclegnark.INttOnDevice(devicePointer, pk.DomainDevice.TwiddlesInv, nil, n, sizeBytes, false) + iciclegnark.NttOnDevice(devicePointer, a_intt_d, pk.DomainDevice.Twiddles, pk.DomainDevice.CosetTable, n, n, sizeBytes, true) + computeInttNttDone <- nil + iciclegnark.FreeDevicePointer(a_intt_d) } - return aDevice + + go computeInttNttOnDevice(a_device) + go computeInttNttOnDevice(b_device) + go computeInttNttOnDevice(c_device) + _, _, _ = <-computeInttNttDone, <-computeInttNttDone, <-computeInttNttDone + + iciclegnark.PolyOps(a_device, b_device, c_device, pk.DenDevice, n) + + h := iciclegnark.INttOnDevice(a_device, pk.DomainDevice.TwiddlesInv, pk.DomainDevice.CosetTableInv, n, sizeBytes, true) + + go func() { + iciclegnark.FreeDevicePointer(a_device) + iciclegnark.FreeDevicePointer(b_device) + iciclegnark.FreeDevicePointer(c_device) + }() + + iciclegnark.ReverseScalars(h, n) + + return h } diff --git a/backend/groth16/bn254/icicle/marshal_test.go b/backend/groth16/bn254/icicle/marshal_test.go index 114765dafe..75c5a2b57e 100644 --- a/backend/groth16/bn254/icicle/marshal_test.go +++ b/backend/groth16/bn254/icicle/marshal_test.go @@ -1,13 +1,10 @@ -//go:build icicle - -package icicle_test +package icicle_bn254_test import ( "bytes" "testing" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" icicle_bn254 "github.com/consensys/gnark/backend/groth16/bn254/icicle" @@ -46,20 +43,6 @@ func TestMarshal(t *testing.T) { if pk.IsDifferent(&nativePK) { t.Error("marshal output difference") } - - assignment := circuit{A: 3, B: 5, Res: 15} - w, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) - assert.NoError(err) - pw, err := w.Public() - assert.NoError(err) - proofNative, err := groth16_bn254.Prove(tCcs, &nativePK, w) - assert.NoError(err) - proofIcicle, err := groth16.Prove(tCcs, pk, w, backend.WithIcicleAcceleration()) - assert.NoError(err) - err = groth16.Verify(proofNative, &nativeVK, pw) - assert.NoError(err) - err = groth16.Verify(proofIcicle, &nativeVK, pw) - assert.NoError(err) } func TestMarshal2(t *testing.T) { @@ -81,18 +64,4 @@ func TestMarshal2(t *testing.T) { if iciPK.IsDifferent(&nativePK) { t.Error("marshal output difference") } - - assignment := circuit{A: 3, B: 5, Res: 15} - w, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) - assert.NoError(err) - pw, err := w.Public() - assert.NoError(err) - proofNative, err := groth16_bn254.Prove(tCcs, &nativePK, w) - assert.NoError(err) - proofIcicle, err := groth16.Prove(tCcs, &iciPK, w, backend.WithIcicleAcceleration()) - assert.NoError(err) - err = groth16.Verify(proofNative, &iciVK, pw) - assert.NoError(err) - err = groth16.Verify(proofIcicle, &iciVK, pw) - assert.NoError(err) } diff --git a/backend/groth16/bn254/icicle/noicicle.go b/backend/groth16/bn254/icicle/noicicle.go index 0fa0a656bb..87703339ce 100644 --- a/backend/groth16/bn254/icicle/noicicle.go +++ b/backend/groth16/bn254/icicle/noicicle.go @@ -1,8 +1,10 @@ //go:build !icicle -package icicle +package icicle_bn254 import ( + "fmt" + "github.com/consensys/gnark/backend" groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" "github.com/consensys/gnark/backend/witness" @@ -11,22 +13,6 @@ import ( const HasIcicle = false -type ProvingKey struct { - groth16_bn254.ProvingKey -} - func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*groth16_bn254.Proof, error) { - panic("icicle backend requested but program compiled without 'icicle' build tag") -} - -func NewProvingKey() *ProvingKey { - panic("icicle backend requested but program compiled without 'icicle' build tag") -} - -func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *groth16_bn254.VerifyingKey) error { - panic("icicle backend requested but program compiled without 'icicle' build tag") -} - -func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { - panic("icicle backend requested but program compiled without 'icicle' build tag") + return nil, fmt.Errorf("icicle backend requested but program compiled without 'icicle' build tag") } diff --git a/backend/groth16/bn254/icicle/provingkey.go b/backend/groth16/bn254/icicle/provingkey.go index 0f25a0430f..146a794255 100644 --- a/backend/groth16/bn254/icicle/provingkey.go +++ b/backend/groth16/bn254/icicle/provingkey.go @@ -1,28 +1,25 @@ -//go:build icicle - -package icicle +package icicle_bn254 import ( - "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "unsafe" + groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" cs "github.com/consensys/gnark/constraint/bn254" - icicle_core "github.com/ingonyama-zk/icicle/v3/wrappers/golang/core" ) type deviceInfo struct { - CosetGenerator [fr.Limbs * 2]uint32 - G1Device struct { - A, B, K, Z icicle_core.DeviceSlice + G1Device struct { + A, B, K, Z unsafe.Pointer } - G2Device struct { - B icicle_core.DeviceSlice + DomainDevice struct { + Twiddles, TwiddlesInv unsafe.Pointer + CosetTable, CosetTableInv unsafe.Pointer } - DenDevice icicle_core.DeviceSlice - - CommitmentKeysDevice struct { - Basis []icicle_core.DeviceSlice - BasisExpSigma []icicle_core.DeviceSlice // we compute in batch + G2Device struct { + B unsafe.Pointer } + DenDevice unsafe.Pointer + InfinityPointIndicesK []int } type ProvingKey struct { @@ -30,17 +27,10 @@ type ProvingKey struct { *deviceInfo } -func NewProvingKey() *ProvingKey { - warmUpDevice() - return &ProvingKey{} -} - func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *groth16_bn254.VerifyingKey) error { - warmUpDevice() return groth16_bn254.Setup(r1cs, &pk.ProvingKey, vk) } func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { - warmUpDevice() return groth16_bn254.DummySetup(r1cs, &pk.ProvingKey) } diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index e79b24eacf..a7c314e9e3 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/marshal_test.go b/backend/groth16/bn254/marshal_test.go index 7e4aa1b6ba..2ced93651b 100644 --- a/backend/groth16/bn254/marshal_test.go +++ b/backend/groth16/bn254/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/lagrange.go b/backend/groth16/bn254/mpcsetup/lagrange.go index c694ee35bb..b41b6596ac 100644 --- a/backend/groth16/bn254/mpcsetup/lagrange.go +++ b/backend/groth16/bn254/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/marshal.go b/backend/groth16/bn254/mpcsetup/marshal.go index 94156c9897..e2c26d591d 100644 --- a/backend/groth16/bn254/mpcsetup/marshal.go +++ b/backend/groth16/bn254/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/marshal_test.go b/backend/groth16/bn254/mpcsetup/marshal_test.go index 0b615cfb90..317e58737a 100644 --- a/backend/groth16/bn254/mpcsetup/marshal_test.go +++ b/backend/groth16/bn254/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/phase1.go b/backend/groth16/bn254/mpcsetup/phase1.go index 2ba641bfe8..18ffdd0647 100644 --- a/backend/groth16/bn254/mpcsetup/phase1.go +++ b/backend/groth16/bn254/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/phase2.go b/backend/groth16/bn254/mpcsetup/phase2.go index c0f4874dc6..9ec35d37a9 100644 --- a/backend/groth16/bn254/mpcsetup/phase2.go +++ b/backend/groth16/bn254/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/setup.go b/backend/groth16/bn254/mpcsetup/setup.go index e2621ce159..27fd034903 100644 --- a/backend/groth16/bn254/mpcsetup/setup.go +++ b/backend/groth16/bn254/mpcsetup/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/setup_test.go b/backend/groth16/bn254/mpcsetup/setup_test.go index 4e01da2c5a..4621926b8c 100644 --- a/backend/groth16/bn254/mpcsetup/setup_test.go +++ b/backend/groth16/bn254/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/mpcsetup/utils.go b/backend/groth16/bn254/mpcsetup/utils.go index e2be5e2484..66a7edaa4a 100644 --- a/backend/groth16/bn254/mpcsetup/utils.go +++ b/backend/groth16/bn254/mpcsetup/utils.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index f7eea5932c..d7eb7d4ba3 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index bfbd818e44..b4f4ba9eca 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bn254/solidity.go b/backend/groth16/bn254/solidity.go index d9c8b0130a..31255fb94a 100644 --- a/backend/groth16/bn254/solidity.go +++ b/backend/groth16/bn254/solidity.go @@ -206,7 +206,7 @@ contract Verifier { /// @notice Will revert with InvalidProof() if /// * the input is not a square, /// * the hint is incorrect, or - /// * the input coefficients are not reduced. + /// * the input coefficents are not reduced. /// @param a0 The real part of the input. /// @param a1 The imaginary part of the input. /// @param hint A hint which of two possible signs to pick in the equation. diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index 72d376516a..eadaedd522 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/commitment_test.go b/backend/groth16/bw6-633/commitment_test.go index fc2d43a1a3..85f61bbc73 100644 --- a/backend/groth16/bw6-633/commitment_test.go +++ b/backend/groth16/bw6-633/commitment_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index 99746966e4..910af8e614 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/marshal_test.go b/backend/groth16/bw6-633/marshal_test.go index fd333e62df..6f79f856da 100644 --- a/backend/groth16/bw6-633/marshal_test.go +++ b/backend/groth16/bw6-633/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/lagrange.go b/backend/groth16/bw6-633/mpcsetup/lagrange.go index 288d9732c2..3a50fc463e 100644 --- a/backend/groth16/bw6-633/mpcsetup/lagrange.go +++ b/backend/groth16/bw6-633/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/marshal.go b/backend/groth16/bw6-633/mpcsetup/marshal.go index c50018614a..9c4cc27acb 100644 --- a/backend/groth16/bw6-633/mpcsetup/marshal.go +++ b/backend/groth16/bw6-633/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/marshal_test.go b/backend/groth16/bw6-633/mpcsetup/marshal_test.go index f4e12c3daf..a0ac908332 100644 --- a/backend/groth16/bw6-633/mpcsetup/marshal_test.go +++ b/backend/groth16/bw6-633/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/phase1.go b/backend/groth16/bw6-633/mpcsetup/phase1.go index 57c4528d3c..43d1af3a0a 100644 --- a/backend/groth16/bw6-633/mpcsetup/phase1.go +++ b/backend/groth16/bw6-633/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/phase2.go b/backend/groth16/bw6-633/mpcsetup/phase2.go index 21e5ab4050..10160fc8ea 100644 --- a/backend/groth16/bw6-633/mpcsetup/phase2.go +++ b/backend/groth16/bw6-633/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/setup.go b/backend/groth16/bw6-633/mpcsetup/setup.go index cdb115da1c..811e75da67 100644 --- a/backend/groth16/bw6-633/mpcsetup/setup.go +++ b/backend/groth16/bw6-633/mpcsetup/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/setup_test.go b/backend/groth16/bw6-633/mpcsetup/setup_test.go index 689e00d487..18c1e27454 100644 --- a/backend/groth16/bw6-633/mpcsetup/setup_test.go +++ b/backend/groth16/bw6-633/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/mpcsetup/utils.go b/backend/groth16/bw6-633/mpcsetup/utils.go index 479f40f849..858e911e30 100644 --- a/backend/groth16/bw6-633/mpcsetup/utils.go +++ b/backend/groth16/bw6-633/mpcsetup/utils.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 3783ccf79e..680600b9b7 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index d7ce66cdef..f7bf9f778f 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index 745ba7a7d0..24d2f97a45 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/commitment_test.go b/backend/groth16/bw6-761/commitment_test.go index 26ed32e5b4..f93f2eaffd 100644 --- a/backend/groth16/bw6-761/commitment_test.go +++ b/backend/groth16/bw6-761/commitment_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 6a4276b5dc..a3d2b2db97 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/marshal_test.go b/backend/groth16/bw6-761/marshal_test.go index 359a804611..5925e607d1 100644 --- a/backend/groth16/bw6-761/marshal_test.go +++ b/backend/groth16/bw6-761/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/lagrange.go b/backend/groth16/bw6-761/mpcsetup/lagrange.go index ce12bdb796..d90e04b4f6 100644 --- a/backend/groth16/bw6-761/mpcsetup/lagrange.go +++ b/backend/groth16/bw6-761/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/marshal.go b/backend/groth16/bw6-761/mpcsetup/marshal.go index 811e290f68..27477cd27b 100644 --- a/backend/groth16/bw6-761/mpcsetup/marshal.go +++ b/backend/groth16/bw6-761/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/marshal_test.go b/backend/groth16/bw6-761/mpcsetup/marshal_test.go index 0979c6e085..2b202dd536 100644 --- a/backend/groth16/bw6-761/mpcsetup/marshal_test.go +++ b/backend/groth16/bw6-761/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/phase1.go b/backend/groth16/bw6-761/mpcsetup/phase1.go index 72689cc556..9d3257052e 100644 --- a/backend/groth16/bw6-761/mpcsetup/phase1.go +++ b/backend/groth16/bw6-761/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/phase2.go b/backend/groth16/bw6-761/mpcsetup/phase2.go index 5ed0b3abef..ef9d99afc2 100644 --- a/backend/groth16/bw6-761/mpcsetup/phase2.go +++ b/backend/groth16/bw6-761/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/setup.go b/backend/groth16/bw6-761/mpcsetup/setup.go index 97886b2b99..c16abc93b2 100644 --- a/backend/groth16/bw6-761/mpcsetup/setup.go +++ b/backend/groth16/bw6-761/mpcsetup/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/setup_test.go b/backend/groth16/bw6-761/mpcsetup/setup_test.go index dcbb22c31b..4156903579 100644 --- a/backend/groth16/bw6-761/mpcsetup/setup_test.go +++ b/backend/groth16/bw6-761/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/mpcsetup/utils.go b/backend/groth16/bw6-761/mpcsetup/utils.go index f7c1a2c819..c6df8a75ff 100644 --- a/backend/groth16/bw6-761/mpcsetup/utils.go +++ b/backend/groth16/bw6-761/mpcsetup/utils.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index d4705bb2d2..48fceb29bc 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index fea8d92c7f..59943fb933 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index df89379e87..81b54ece39 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/groth16/groth16.go b/backend/groth16/groth16.go index aa27ef3f74..426621e2f6 100644 --- a/backend/groth16/groth16.go +++ b/backend/groth16/groth16.go @@ -347,7 +347,7 @@ func NewProvingKey(curveID ecc.ID) ProvingKey { case ecc.BN254: pk = &groth16_bn254.ProvingKey{} if icicle_bn254.HasIcicle { - pk = icicle_bn254.NewProvingKey() + pk = &icicle_bn254.ProvingKey{} } case ecc.BLS12_377: pk = &groth16_bls12377.ProvingKey{} diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index 45fc6ea39f..5ab5d97804 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index fdfc7daec3..e523566bde 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 9d465eac1f..acf19b7722 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 8e469d1fb4..10ece24e94 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 571d446861..70aed2752b 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index 18245c73b3..368d611439 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index 67a8386150..6df71fc31a 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 936ae723d5..aa023214ce 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 7bca6364d7..ef2a721bb4 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 307e5de5bf..ccaf735fdb 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index 1369d32b7d..12ef5b14ac 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index 240713164f..b941db9dda 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index d25ba73087..e27e54835e 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index adc8b7fe83..8784290e96 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index e4346b76c0..992059492f 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index e8bb869931..05635202cf 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index 78ba138819..4924957689 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index ebf1b860f4..8e8ea8df92 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index ae716c0b1f..7330742508 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index b92d4a6f8a..bbdf4728a8 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index a5f4164412..9639b8381d 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 3c01ae3d7e..6a734d3677 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index fa9255139d..16979d0697 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 6324c432c2..fa78238a49 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 4e39a31207..4a6cf9450a 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 1a527dcd95..f58907cdcd 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 9f1c7a0e73..e56771ae72 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 5d7f2883c6..38a92087d7 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 3cf74bf39f..7f5f330692 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 9d7837ed23..dda81e2f6b 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 737f60128e..4020f66c4b 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index b2be1091ad..06804132df 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 23b3fae45e..f727c9938c 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 8e51e234a2..0db3df792c 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 213f0a5dd1..9feb1d0c30 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-377/coeff.go b/constraint/bls12-377/coeff.go index c9c8a2e28a..9b7f671ca6 100644 --- a/constraint/bls12-377/coeff.go +++ b/constraint/bls12-377/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 3bb47e8ce9..e344e35ae1 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-377/marshal.go b/constraint/bls12-377/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/bls12-377/marshal.go +++ b/constraint/bls12-377/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-377/r1cs_test.go b/constraint/bls12-377/r1cs_test.go index 0d4f150ebd..ba0b594841 100644 --- a/constraint/bls12-377/r1cs_test.go +++ b/constraint/bls12-377/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-377/solver.go b/constraint/bls12-377/solver.go index f1bbcc7577..c2114a3fb9 100644 --- a/constraint/bls12-377/solver.go +++ b/constraint/bls12-377/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-377/system.go b/constraint/bls12-377/system.go index 5020ed4adf..17db4166ef 100644 --- a/constraint/bls12-377/system.go +++ b/constraint/bls12-377/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-381/coeff.go b/constraint/bls12-381/coeff.go index c19579d3f4..b45dd7097b 100644 --- a/constraint/bls12-381/coeff.go +++ b/constraint/bls12-381/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 3d028efdfd..3c25df9812 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-381/marshal.go b/constraint/bls12-381/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/bls12-381/marshal.go +++ b/constraint/bls12-381/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-381/r1cs_test.go b/constraint/bls12-381/r1cs_test.go index 6a70cf6c56..c14bc4da39 100644 --- a/constraint/bls12-381/r1cs_test.go +++ b/constraint/bls12-381/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-381/solver.go b/constraint/bls12-381/solver.go index 6ec5f8dd2b..394d57b3d7 100644 --- a/constraint/bls12-381/solver.go +++ b/constraint/bls12-381/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls12-381/system.go b/constraint/bls12-381/system.go index e441792395..9fb08791a2 100644 --- a/constraint/bls12-381/system.go +++ b/constraint/bls12-381/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-315/coeff.go b/constraint/bls24-315/coeff.go index 39bb5b348a..0c0a050ccd 100644 --- a/constraint/bls24-315/coeff.go +++ b/constraint/bls24-315/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index 0397c58171..2ed05f8783 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-315/marshal.go b/constraint/bls24-315/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/bls24-315/marshal.go +++ b/constraint/bls24-315/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-315/r1cs_test.go b/constraint/bls24-315/r1cs_test.go index da9bc60fdf..3f5eed79d2 100644 --- a/constraint/bls24-315/r1cs_test.go +++ b/constraint/bls24-315/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-315/solver.go b/constraint/bls24-315/solver.go index de3296dd2d..d20ea682f8 100644 --- a/constraint/bls24-315/solver.go +++ b/constraint/bls24-315/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-315/system.go b/constraint/bls24-315/system.go index fc302c7574..b6b4d9c7ad 100644 --- a/constraint/bls24-315/system.go +++ b/constraint/bls24-315/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-317/coeff.go b/constraint/bls24-317/coeff.go index b9ca9a666e..09ef7d6fae 100644 --- a/constraint/bls24-317/coeff.go +++ b/constraint/bls24-317/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 1a4e8ad137..5cdb3eb92f 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-317/marshal.go b/constraint/bls24-317/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/bls24-317/marshal.go +++ b/constraint/bls24-317/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-317/r1cs_test.go b/constraint/bls24-317/r1cs_test.go index d891fc93cd..fad8775797 100644 --- a/constraint/bls24-317/r1cs_test.go +++ b/constraint/bls24-317/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-317/solver.go b/constraint/bls24-317/solver.go index 577c83bd5d..4e99951081 100644 --- a/constraint/bls24-317/solver.go +++ b/constraint/bls24-317/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bls24-317/system.go b/constraint/bls24-317/system.go index f1683111f5..244aa6788d 100644 --- a/constraint/bls24-317/system.go +++ b/constraint/bls24-317/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bn254/coeff.go b/constraint/bn254/coeff.go index ac0b2d11e7..4fd171463c 100644 --- a/constraint/bn254/coeff.go +++ b/constraint/bn254/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 2497c7c209..5efed6e822 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bn254/marshal.go b/constraint/bn254/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/bn254/marshal.go +++ b/constraint/bn254/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bn254/r1cs_test.go b/constraint/bn254/r1cs_test.go index d991531b36..d417bf886f 100644 --- a/constraint/bn254/r1cs_test.go +++ b/constraint/bn254/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bn254/solver.go b/constraint/bn254/solver.go index 0903eecc79..84d63b1b55 100644 --- a/constraint/bn254/solver.go +++ b/constraint/bn254/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index 50563c0020..11ac0a89f3 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-633/coeff.go b/constraint/bw6-633/coeff.go index bd28d0f619..c89649b488 100644 --- a/constraint/bw6-633/coeff.go +++ b/constraint/bw6-633/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index 8d8f53bb81..fa8e83258c 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-633/marshal.go b/constraint/bw6-633/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/bw6-633/marshal.go +++ b/constraint/bw6-633/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-633/r1cs_test.go b/constraint/bw6-633/r1cs_test.go index 9f3c8b5909..99a66adb9d 100644 --- a/constraint/bw6-633/r1cs_test.go +++ b/constraint/bw6-633/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-633/solver.go b/constraint/bw6-633/solver.go index 895572605b..ea55e75db7 100644 --- a/constraint/bw6-633/solver.go +++ b/constraint/bw6-633/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-633/system.go b/constraint/bw6-633/system.go index a0dd020ffa..9398bb81df 100644 --- a/constraint/bw6-633/system.go +++ b/constraint/bw6-633/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-761/coeff.go b/constraint/bw6-761/coeff.go index 84d4dee3f4..9539b65d02 100644 --- a/constraint/bw6-761/coeff.go +++ b/constraint/bw6-761/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index 4375c8057f..6e05fe8a90 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-761/marshal.go b/constraint/bw6-761/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/bw6-761/marshal.go +++ b/constraint/bw6-761/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-761/r1cs_test.go b/constraint/bw6-761/r1cs_test.go index 4056962b01..d3bbd12c27 100644 --- a/constraint/bw6-761/r1cs_test.go +++ b/constraint/bw6-761/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-761/solver.go b/constraint/bw6-761/solver.go index e2728751bf..03634315d8 100644 --- a/constraint/bw6-761/solver.go +++ b/constraint/bw6-761/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/bw6-761/system.go b/constraint/bw6-761/system.go index 5816420bb9..9f382fe12e 100644 --- a/constraint/bw6-761/system.go +++ b/constraint/bw6-761/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/tinyfield/coeff.go b/constraint/tinyfield/coeff.go index 9db4bed393..643f7e870a 100644 --- a/constraint/tinyfield/coeff.go +++ b/constraint/tinyfield/coeff.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/tinyfield/marshal.go b/constraint/tinyfield/marshal.go index e85ecc5db9..4f1931cce3 100644 --- a/constraint/tinyfield/marshal.go +++ b/constraint/tinyfield/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/tinyfield/r1cs_test.go b/constraint/tinyfield/r1cs_test.go index 6c94d940bf..f91e8c31a2 100644 --- a/constraint/tinyfield/r1cs_test.go +++ b/constraint/tinyfield/r1cs_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/tinyfield/solver.go b/constraint/tinyfield/solver.go index 9a276b5f53..f87f880ffd 100644 --- a/constraint/tinyfield/solver.go +++ b/constraint/tinyfield/solver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index 6955d482fc..0d741a1dd4 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 Consensys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by gnark DO NOT EDIT diff --git a/frontend/api.go b/frontend/api.go index 5bfb761574..a09bce9299 100644 --- a/frontend/api.go +++ b/frontend/api.go @@ -24,7 +24,7 @@ type API interface { // doing: // // acopy := api.Mul(a, 1) - // acopy = api.MulAcc(acopy, b, c) + // acopy = MulAcc(acopy, b, c) // // ! But it may not modify a, always use MulAcc(...) result for correctness. MulAcc(a, b, c Variable) Variable @@ -142,7 +142,7 @@ type API interface { ConstantValue(v Variable) (*big.Int, bool) } -// BatchInverter returns a slice of variables containing the inverse of each element in i1 +// BatchInvert returns a slice of variables containing the inverse of each element in i1 // This is a temporary API, do not use it in your circuit type BatchInverter interface { // BatchInvert returns a slice of variables containing the inverse of each element in i1 diff --git a/frontend/builder.go b/frontend/builder.go index 40663985f0..f39262be1e 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -14,7 +14,7 @@ type NewBuilder func(*big.Int, CompileConfig) (Builder, error) type Compiler interface { constraint.CustomizableSystem - // MarkBoolean sets (but does not constrain!) v to be boolean + // MarkBoolean sets (but do not constraint!) v to be boolean // This is useful in scenarios where a variable is known to be boolean through a constraint // that is not api.AssertIsBoolean. If v is a constant, this is a no-op. MarkBoolean(v Variable) diff --git a/frontend/variable.go b/frontend/variable.go index d4337955e5..c0f7603c9a 100644 --- a/frontend/variable.go +++ b/frontend/variable.go @@ -13,7 +13,7 @@ import ( type Variable interface{} // IsCanonical returns true if the Variable has been normalized in a (internal) LinearExpression -// by one of the constraint system builders. In other words, if the Variable is a circuit input OR +// by one of the constraint system builder. In other words, if the Variable is a circuit input OR // returned by the API. func IsCanonical(v Variable) bool { switch v.(type) { diff --git a/go.mod b/go.mod index cd70e6f6c5..6e0371490f 100644 --- a/go.mod +++ b/go.mod @@ -9,12 +9,12 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.24 github.com/consensys/compress v0.2.5 - github.com/consensys/gnark-crypto v0.14.1-0.20241217131346-b998989abdbe + github.com/consensys/gnark-crypto v0.14.1-0.20241122181107-03e007d865c0 github.com/fxamacker/cbor/v2 v2.7.0 github.com/google/go-cmp v0.6.0 github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 github.com/icza/bitio v1.1.0 - github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b + github.com/ingonyama-zk/iciclegnark v0.1.0 github.com/leanovate/gopter v0.2.11 github.com/ronanh/intcomp v1.1.0 github.com/rs/zerolog v1.33.0 @@ -26,10 +26,12 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/ingonyama-zk/icicle v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sys v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 305b0d2649..5a48cfc662 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/consensys/bavard v0.1.24 h1:Lfe+bjYbpaoT7K5JTFoMi5wo9V4REGLvQQbHmatoN github.com/consensys/bavard v0.1.24/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= github.com/consensys/compress v0.2.5 h1:gJr1hKzbOD36JFsF1AN8lfXz1yevnJi1YolffY19Ntk= github.com/consensys/compress v0.2.5/go.mod h1:pyM+ZXiNUh7/0+AUjUf9RKUM6vSH7T/fsn5LLS0j1Tk= -github.com/consensys/gnark-crypto v0.14.1-0.20241217131346-b998989abdbe h1:WNuXPe50FqynKlUOMdsi1eCzYN8gU4sdCsW3eg3coGA= -github.com/consensys/gnark-crypto v0.14.1-0.20241217131346-b998989abdbe/go.mod h1:ePFa23CZLMRMHxQpY5nMaiAZ3yuEIayaB8ElEvlwLEs= +github.com/consensys/gnark-crypto v0.14.1-0.20241122181107-03e007d865c0 h1:uFZaZWG0FOoiFN3fAQzH2JXDuybdNwiJzBujy81YtU4= +github.com/consensys/gnark-crypto v0.14.1-0.20241122181107-03e007d865c0/go.mod h1:F/hJyWBcTr1sWeifAKfEN3aVb3G4U5zheEC8IbWQun4= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -184,8 +184,10 @@ github.com/icza/bitio v1.1.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b h1:AvQTK7l0PTHODD06PVQX1Tn2o29sRIaKIDOvTJmKurY= -github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b/go.mod h1:e0JHb27/P6WorCJS3YolbY5XffS4PGBuoW38OthLkDs= +github.com/ingonyama-zk/icicle v1.1.0 h1:a2MUIaF+1i4JY2Lnb961ZMvaC8GFs9GqZgSnd9e95C8= +github.com/ingonyama-zk/icicle v1.1.0/go.mod h1:kAK8/EoN7fUEmakzgZIYdWy1a2rBnpCaZLqSHwZWxEk= +github.com/ingonyama-zk/iciclegnark v0.1.0 h1:88MkEghzjQBMjrYRJFxZ9oR9CTIpB8NG2zLeCJSvXKQ= +github.com/ingonyama-zk/iciclegnark v0.1.0/go.mod h1:wz6+IpyHKs6UhMMoQpNqz1VY+ddfKqC/gRwR/64W6WU= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index 30e8e21b87..d5c8ae0045 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -75,7 +75,7 @@ func main() { if err != nil { panic(err) } - if err := generator.GenerateFF(tinyfieldConf, tiny_field.RootPath); err != nil { + if err := generator.GenerateFF(tinyfieldConf, tiny_field.RootPath, "", ""); err != nil { panic(err) } diff --git a/internal/stats/latest_stats.csv b/internal/stats/latest_stats.csv index 45f69ecb54..18197f8970 100644 --- a/internal/stats/latest_stats.csv +++ b/internal/stats/latest_stats.csv @@ -153,14 +153,14 @@ pairing_bls12377,bls24_315,plonk,0,0 pairing_bls12377,bls24_317,plonk,0,0 pairing_bls12377,bw6_761,plonk,51280,51280 pairing_bls12377,bw6_633,plonk,0,0 -pairing_bls12381,bn254,groth16,947528,1567714 +pairing_bls12381,bn254,groth16,1419904,2366999 pairing_bls12381,bls12_377,groth16,0,0 pairing_bls12381,bls12_381,groth16,0,0 pairing_bls12381,bls24_315,groth16,0,0 pairing_bls12381,bls24_317,groth16,0,0 pairing_bls12381,bw6_761,groth16,0,0 pairing_bls12381,bw6_633,groth16,0,0 -pairing_bls12381,bn254,plonk,3642638,3233378 +pairing_bls12381,bn254,plonk,5593770,5250897 pairing_bls12381,bls12_377,plonk,0,0 pairing_bls12381,bls12_381,plonk,0,0 pairing_bls12381,bls24_315,plonk,0,0 @@ -181,14 +181,14 @@ pairing_bls24315,bls24_315,plonk,0,0 pairing_bls24315,bls24_317,plonk,0,0 pairing_bls24315,bw6_761,plonk,0,0 pairing_bls24315,bw6_633,plonk,141249,141249 -pairing_bn254,bn254,groth16,604783,990919 +pairing_bn254,bn254,groth16,963003,1603091 pairing_bn254,bls12_377,groth16,0,0 pairing_bn254,bls12_381,groth16,0,0 pairing_bn254,bls24_315,groth16,0,0 pairing_bn254,bls24_317,groth16,0,0 pairing_bn254,bw6_761,groth16,0,0 pairing_bn254,bw6_633,groth16,0,0 -pairing_bn254,bn254,plonk,2319665,2030447 +pairing_bn254,bn254,plonk,3771397,3534755 pairing_bn254,bls12_377,plonk,0,0 pairing_bn254,bls12_381,plonk,0,0 pairing_bn254,bls24_315,plonk,0,0 @@ -209,14 +209,14 @@ pairing_bw6761,bls24_315,plonk,0,0 pairing_bw6761,bls24_317,plonk,0,0 pairing_bw6761,bw6_761,plonk,0,0 pairing_bw6761,bw6_633,plonk,0,0 -scalar_mul_G1_bn254,bn254,groth16,59255,91375 +scalar_mul_G1_bn254,bn254,groth16,59287,91432 scalar_mul_G1_bn254,bls12_377,groth16,0,0 scalar_mul_G1_bn254,bls12_381,groth16,0,0 scalar_mul_G1_bn254,bls24_315,groth16,0,0 scalar_mul_G1_bn254,bls24_317,groth16,0,0 scalar_mul_G1_bn254,bw6_761,groth16,0,0 scalar_mul_G1_bn254,bw6_633,groth16,0,0 -scalar_mul_G1_bn254,bn254,plonk,220594,207103 +scalar_mul_G1_bn254,bn254,plonk,220730,207236 scalar_mul_G1_bn254,bls12_377,plonk,0,0 scalar_mul_G1_bn254,bls12_381,plonk,0,0 scalar_mul_G1_bn254,bls24_315,plonk,0,0 @@ -237,14 +237,14 @@ scalar_mul_P256,bls24_315,plonk,0,0 scalar_mul_P256,bls24_317,plonk,0,0 scalar_mul_P256,bw6_761,plonk,0,0 scalar_mul_P256,bw6_633,plonk,0,0 -scalar_mul_secp256k1,bn254,groth16,59993,92505 +scalar_mul_secp256k1,bn254,groth16,60025,92562 scalar_mul_secp256k1,bls12_377,groth16,0,0 scalar_mul_secp256k1,bls12_381,groth16,0,0 scalar_mul_secp256k1,bls24_315,groth16,0,0 scalar_mul_secp256k1,bls24_317,groth16,0,0 scalar_mul_secp256k1,bw6_761,groth16,0,0 scalar_mul_secp256k1,bw6_633,groth16,0,0 -scalar_mul_secp256k1,bn254,plonk,223354,209690 +scalar_mul_secp256k1,bn254,plonk,223490,209823 scalar_mul_secp256k1,bls12_377,plonk,0,0 scalar_mul_secp256k1,bls12_381,plonk,0,0 scalar_mul_secp256k1,bls24_315,plonk,0,0 diff --git a/internal/tinyfield/arith.go b/internal/tinyfield/arith.go index d86ebc99ca..02aedba1ff 100644 --- a/internal/tinyfield/arith.go +++ b/internal/tinyfield/arith.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 ConsenSys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by consensys/gnark-crypto DO NOT EDIT diff --git a/internal/tinyfield/doc.go b/internal/tinyfield/doc.go index a22f71f76f..a8b6fce697 100644 --- a/internal/tinyfield/doc.go +++ b/internal/tinyfield/doc.go @@ -1,13 +1,11 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 ConsenSys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by consensys/gnark-crypto DO NOT EDIT // Package tinyfield contains field arithmetic operations for modulus = 0x2f. // -// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x). -// -// Additionally tinyfield.Vector offers an API to manipulate []Element. +// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x for the modular multiplication on amd64, see also https://hackmd.io/@gnark/modular_multiplication) // // The modulus is hardcoded in all the operations. // @@ -40,7 +38,5 @@ // // # Warning // -// There is no security guarantees such as constant time implementation or side-channel attack resistance. -// This code is provided as-is. Partially audited, see https://github.com/Consensys/gnark/tree/master/audits -// for more details. +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. package tinyfield diff --git a/internal/tinyfield/element.go b/internal/tinyfield/element.go index 021d9370cf..5d7e45ae33 100644 --- a/internal/tinyfield/element.go +++ b/internal/tinyfield/element.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 ConsenSys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by consensys/gnark-crypto DO NOT EDIT @@ -43,8 +43,8 @@ const ( // Field modulus q const ( - q0 = 47 - q = q0 + q0 uint64 = 47 + q uint64 = q0 ) var qElement = Element{ @@ -63,7 +63,7 @@ func Modulus() *big.Int { // q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r // used for Montgomery reduction -const qInvNeg = 12559485326780971313 +const qInvNeg uint64 = 12559485326780971313 func init() { _modulus.SetString("2f", 16) @@ -338,11 +338,10 @@ func (z *Element) fromMont() *Element { // Add z = x + y (mod q) func (z *Element) Add(x, y *Element) *Element { - t := x[0] + y[0] - if t >= q { - t -= q + z[0], _ = bits.Add64(x[0], y[0], 0) + if z[0] >= q { + z[0] -= q } - z[0] = t return z } @@ -389,6 +388,49 @@ func (z *Element) Select(c int, x0 *Element, x1 *Element) *Element { return z } +// _mulGeneric is unoptimized textbook CIOS +// it is a fallback solution on x86 when ADX instruction set is not available +// and is used for testing purposes. +func _mulGeneric(z, x, y *Element) { + + // Algorithm 2 of "Faster Montgomery Multiplication and Multi-Scalar-Multiplication for SNARKS" + // by Y. El Housni and G. Botrel https://doi.org/10.46586/tches.v2023.i3.504-521 + + var t [2]uint64 + var D uint64 + var m, C uint64 + // ----------------------------------- + // First loop + + C, t[0] = bits.Mul64(y[0], x[0]) + + t[1], D = bits.Add64(t[1], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + + t[0], C = bits.Add64(t[1], C, 0) + t[1], _ = bits.Add64(0, D, C) + + if t[1] != 0 { + // we need to reduce, we have a result on 2 words + z[0], _ = bits.Sub64(t[0], q0, 0) + return + } + + // copy t into z + z[0] = t[0] + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + z[0] -= q + } +} + func _fromMontGeneric(z *Element) { // the following lines implement z = z * 1 // with a modified CIOS montgomery multiplication @@ -561,7 +603,7 @@ func (z *Element) Text(base int) string { const maxUint16 = 65535 zz := z.Bits() - return strconv.FormatUint(uint64(zz[0]), base) + return strconv.FormatUint(zz[0], base) } // BigInt sets and return z as a *big.Int diff --git a/internal/tinyfield/element_purego.go b/internal/tinyfield/element_ops_purego.go similarity index 97% rename from internal/tinyfield/element_purego.go rename to internal/tinyfield/element_ops_purego.go index c21a4bf4a6..609d9cbd78 100644 --- a/internal/tinyfield/element_purego.go +++ b/internal/tinyfield/element_ops_purego.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 ConsenSys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by consensys/gnark-crypto DO NOT EDIT @@ -28,6 +28,14 @@ func MulBy13(x *Element) { x.Mul(x, &y) } +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + func fromMont(z *Element) { _fromMontGeneric(z) } @@ -53,6 +61,7 @@ func (z *Element) Mul(x, y *Element) *Element { // Which finally gives (lo + m * q) / R = (lo + lo2 + R hi2) / R = hi2 + (lo+lo2) / R = hi2 + (lo != 0) // This "optimization" lets us do away with one MUL instruction on ARM architectures and is available for all q < R. + var r uint64 hi, lo := bits.Mul64(x[0], y[0]) if lo != 0 { hi++ // x[0] * y[0] ≤ 2¹²⁸ - 2⁶⁵ + 1, meaning hi ≤ 2⁶⁴ - 2 so no need to worry about overflow @@ -60,6 +69,7 @@ func (z *Element) Mul(x, y *Element) *Element { m := lo * qInvNeg hi2, _ := bits.Mul64(m, q) r, carry := bits.Add64(hi2, hi, 0) + if carry != 0 || r >= q { // we need to reduce r -= q @@ -87,6 +97,7 @@ func (z *Element) Square(x *Element) *Element { // Which finally gives (lo + m * q) / R = (lo + lo2 + R hi2) / R = hi2 + (lo+lo2) / R = hi2 + (lo != 0) // This "optimization" lets us do away with one MUL instruction on ARM architectures and is available for all q < R. + var r uint64 hi, lo := bits.Mul64(x[0], x[0]) if lo != 0 { hi++ // x[0] * y[0] ≤ 2¹²⁸ - 2⁶⁵ + 1, meaning hi ≤ 2⁶⁴ - 2 so no need to worry about overflow @@ -94,6 +105,7 @@ func (z *Element) Square(x *Element) *Element { m := lo * qInvNeg hi2, _ := bits.Mul64(m, q) r, carry := bits.Add64(hi2, hi, 0) + if carry != 0 || r >= q { // we need to reduce r -= q @@ -102,11 +114,3 @@ func (z *Element) Square(x *Element) *Element { return z } - -// Butterfly sets -// -// a = a + b (mod q) -// b = a - b (mod q) -func Butterfly(a, b *Element) { - _butterflyGeneric(a, b) -} diff --git a/internal/tinyfield/element_test.go b/internal/tinyfield/element_test.go index 7383f4dac3..64d9667a54 100644 --- a/internal/tinyfield/element_test.go +++ b/internal/tinyfield/element_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 ConsenSys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by consensys/gnark-crypto DO NOT EDIT @@ -921,6 +921,14 @@ func TestElementMul(t *testing.T) { c.Mul(&a.element, &r) d.Mul(&a.bigint, &rb).Mod(&d, Modulus()) + // checking generic impl against asm path + var cGeneric Element + _mulGeneric(&cGeneric, &a.element, &r) + if !cGeneric.Equal(&c) { + // need to give context to failing error. + return false + } + if c.BigInt(&e).Cmp(&d) != 0 { return false } @@ -943,6 +951,17 @@ func TestElementMul(t *testing.T) { genB, )) + properties.Property("Mul: assembly implementation must be consistent with generic one", prop.ForAll( + func(a, b testPairElement) bool { + var c, d Element + c.Mul(&a.element, &b.element) + _mulGeneric(&d, &a.element, &b.element) + return c.Equal(&d) + }, + genA, + genB, + )) + specialValueTest := func() { // test special values against special values testValues := make([]Element, len(staticTestValues)) @@ -961,6 +980,13 @@ func TestElementMul(t *testing.T) { c.Mul(&a, &b) d.Mul(&aBig, &bBig).Mod(&d, Modulus()) + // checking asm against generic impl + var cGeneric Element + _mulGeneric(&cGeneric, &a, &b) + if !cGeneric.Equal(&c) { + t.Fatal("Mul failed special test values: asm and generic impl don't match") + } + if c.BigInt(&e).Cmp(&d) != 0 { t.Fatal("Mul failed special test values") } diff --git a/internal/tinyfield/vector.go b/internal/tinyfield/vector.go index 0755dabf7e..6b045db8cd 100644 --- a/internal/tinyfield/vector.go +++ b/internal/tinyfield/vector.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 ConsenSys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by consensys/gnark-crypto DO NOT EDIT @@ -185,6 +185,43 @@ func (vector Vector) Swap(i, j int) { vector[i], vector[j] = vector[j], vector[i] } +// Add adds two vectors element-wise and stores the result in self. +// It panics if the vectors don't have the same length. +func (vector *Vector) Add(a, b Vector) { + addVecGeneric(*vector, a, b) +} + +// Sub subtracts two vectors element-wise and stores the result in self. +// It panics if the vectors don't have the same length. +func (vector *Vector) Sub(a, b Vector) { + subVecGeneric(*vector, a, b) +} + +// ScalarMul multiplies a vector by a scalar element-wise and stores the result in self. +// It panics if the vectors don't have the same length. +func (vector *Vector) ScalarMul(a Vector, b *Element) { + scalarMulVecGeneric(*vector, a, b) +} + +// Sum computes the sum of all elements in the vector. +func (vector *Vector) Sum() (res Element) { + sumVecGeneric(&res, *vector) + return +} + +// InnerProduct computes the inner product of two vectors. +// It panics if the vectors don't have the same length. +func (vector *Vector) InnerProduct(other Vector) (res Element) { + innerProductVecGeneric(&res, *vector, other) + return +} + +// Mul multiplies two vectors element-wise and stores the result in self. +// It panics if the vectors don't have the same length. +func (vector *Vector) Mul(a, b Vector) { + mulVecGeneric(*vector, a, b) +} + func addVecGeneric(res, a, b Vector) { if len(a) != len(b) || len(a) != len(res) { panic("vector.Add: vectors don't have the same length") diff --git a/internal/tinyfield/vector_purego.go b/internal/tinyfield/vector_purego.go deleted file mode 100644 index bf97d70fce..0000000000 --- a/internal/tinyfield/vector_purego.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2020-2025 Consensys Software Inc. -// Licensed under the Apache License, Version 2.0. See the LICENSE file for details. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package tinyfield - -// Add adds two vectors element-wise and stores the result in self. -// It panics if the vectors don't have the same length. -func (vector *Vector) Add(a, b Vector) { - addVecGeneric(*vector, a, b) -} - -// Sub subtracts two vectors element-wise and stores the result in self. -// It panics if the vectors don't have the same length. -func (vector *Vector) Sub(a, b Vector) { - subVecGeneric(*vector, a, b) -} - -// ScalarMul multiplies a vector by a scalar element-wise and stores the result in self. -// It panics if the vectors don't have the same length. -func (vector *Vector) ScalarMul(a Vector, b *Element) { - scalarMulVecGeneric(*vector, a, b) -} - -// Sum computes the sum of all elements in the vector. -func (vector *Vector) Sum() (res Element) { - sumVecGeneric(&res, *vector) - return -} - -// InnerProduct computes the inner product of two vectors. -// It panics if the vectors don't have the same length. -func (vector *Vector) InnerProduct(other Vector) (res Element) { - innerProductVecGeneric(&res, *vector, other) - return -} - -// Mul multiplies two vectors element-wise and stores the result in self. -// It panics if the vectors don't have the same length. -func (vector *Vector) Mul(a, b Vector) { - mulVecGeneric(*vector, a, b) -} diff --git a/internal/tinyfield/vector_test.go b/internal/tinyfield/vector_test.go index 36ab4f9fb6..d17149d308 100644 --- a/internal/tinyfield/vector_test.go +++ b/internal/tinyfield/vector_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2025 Consensys Software Inc. +// Copyright 2020-2024 ConsenSys Software Inc. // Licensed under the Apache License, Version 2.0. See the LICENSE file for details. // Code generated by consensys/gnark-crypto DO NOT EDIT diff --git a/logger/logger.go b/logger/logger.go index a97450a85d..4d3f370bc8 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -29,7 +29,7 @@ func SetOutput(w io.Writer) { logger = logger.Output(w) } -// Set allows a gnark user to overhide the global logger +// Set allow a gnark user to overhide the global logger func Set(l zerolog.Logger) { logger = l } diff --git a/profile/profile.go b/profile/profile.go index ed80741d23..fe3e58f3c2 100644 --- a/profile/profile.go +++ b/profile/profile.go @@ -26,7 +26,7 @@ var ( // Profile represents an active constraint system profiling session. type Profile struct { // defaults to ./gnark.pprof - // if blank, profile is not written to disk + // if blank, profiile is not written to disk filePath string // actual pprof profile struct diff --git a/std/algebra/algopts/algopts.go b/std/algebra/algopts/algopts.go index 590d3a7f2d..2434fd57a8 100644 --- a/std/algebra/algopts/algopts.go +++ b/std/algebra/algopts/algopts.go @@ -5,9 +5,7 @@ // implementations. package algopts -import ( - "errors" -) +import "fmt" type algebraCfg struct { NbScalarBits int @@ -26,7 +24,7 @@ type AlgebraOption func(*algebraCfg) error func WithNbScalarBits(bits int) AlgebraOption { return func(ac *algebraCfg) error { if ac.NbScalarBits != 0 { - return errors.New("WithNbBits already set") + return fmt.Errorf("WithNbBits already set") } ac.NbScalarBits = bits return nil @@ -41,7 +39,7 @@ func WithNbScalarBits(bits int) AlgebraOption { func WithFoldingScalarMul() AlgebraOption { return func(ac *algebraCfg) error { if ac.FoldMulti { - return errors.New("withFoldingScalarMul already set") + return fmt.Errorf("withFoldingScalarMul already set") } ac.FoldMulti = true return nil @@ -53,7 +51,7 @@ func WithFoldingScalarMul() AlgebraOption { func WithCompleteArithmetic() AlgebraOption { return func(ac *algebraCfg) error { if ac.CompleteArithmetic { - return errors.New("WithCompleteArithmetic already set") + return fmt.Errorf("WithCompleteArithmetic already set") } ac.CompleteArithmetic = true return nil @@ -72,7 +70,7 @@ func WithCompleteArithmetic() AlgebraOption { func WithCanonicalBitRepresentation() AlgebraOption { return func(ac *algebraCfg) error { if ac.ToBitsCanonical { - return errors.New("WithCanonicalBitRepresentation already set") + return fmt.Errorf("WithCanonicalBitRepresentation already set") } ac.ToBitsCanonical = true return nil diff --git a/std/algebra/defaults.go b/std/algebra/defaults.go index abc730df72..e90063bb10 100644 --- a/std/algebra/defaults.go +++ b/std/algebra/defaults.go @@ -1,7 +1,6 @@ package algebra import ( - "errors" "fmt" "github.com/consensys/gnark/frontend" @@ -59,7 +58,7 @@ func GetCurve[FR emulated.FieldParams, G1El G1ElementT](api frontend.API) (Curve } *s = c default: - return ret, errors.New("unknown type parametrisation") + return ret, fmt.Errorf("unknown type parametrisation") } return ret, nil } @@ -95,7 +94,7 @@ func GetPairing[G1El G1ElementT, G2El G2ElementT, GtEl GtElementT](api frontend. p := sw_bls24315.NewPairing(api) *s = p default: - return ret, errors.New("unknown type parametrisation") + return ret, fmt.Errorf("unknown type parametrisation") } return ret, nil } diff --git a/std/algebra/emulated/fields_bls12381/doc.go b/std/algebra/emulated/fields_bls12381/doc.go index f61b20877f..c94c08b683 100644 --- a/std/algebra/emulated/fields_bls12381/doc.go +++ b/std/algebra/emulated/fields_bls12381/doc.go @@ -1,10 +1,6 @@ -// Package fields_bls12381 implements the fields arithmetic of the direct 𝔽p¹² extension +// Package fields_bls12381 implements the fields arithmetic of the Fp12 tower // used to compute the pairing over the BLS12-381 curve. // -// 𝔽p¹²[i] = 𝔽p/i¹²-2i⁶+2 -// -// This direct tower is isomorphic to the 2-3-2 tower: -// // 𝔽p²[u] = 𝔽p/u²+1 // 𝔽p⁶[v] = 𝔽p²/v³-1-u // 𝔽p¹²[w] = 𝔽p⁶/w²-v diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go index 07edffc9e5..dbc394db1a 100644 --- a/std/algebra/emulated/fields_bls12381/e12.go +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -1,397 +1,211 @@ package fields_bls12381 import ( - "math/big" - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" ) type E12 struct { - A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11 baseEl + C0, C1 E6 } type Ext12 struct { - *Ext2 - api frontend.API - fp *curveF + *Ext6 } func NewExt12(api frontend.API) *Ext12 { - fp, err := emulated.NewField[emulated.BLS12381Fp](api) - if err != nil { - panic(err) - } - return &Ext12{ - Ext2: NewExt2(api), - api: api, - fp: fp, - } + return &Ext12{Ext6: NewExt6(api)} } -func (e Ext12) Zero() *E12 { - zero := e.fp.Zero() +func (e Ext12) Add(x, y *E12) *E12 { + z0 := e.Ext6.Add(&x.C0, &y.C0) + z1 := e.Ext6.Add(&x.C1, &y.C1) return &E12{ - A0: *zero, - A1: *zero, - A2: *zero, - A3: *zero, - A4: *zero, - A5: *zero, - A6: *zero, - A7: *zero, - A8: *zero, - A9: *zero, - A10: *zero, - A11: *zero, + C0: *z0, + C1: *z1, } } -func (e Ext12) One() *E12 { - one := e.fp.One() - zero := e.fp.Zero() +func (e Ext12) Sub(x, y *E12) *E12 { + z0 := e.Ext6.Sub(&x.C0, &y.C0) + z1 := e.Ext6.Sub(&x.C1, &y.C1) return &E12{ - A0: *one, - A1: *zero, - A2: *zero, - A3: *zero, - A4: *zero, - A5: *zero, - A6: *zero, - A7: *zero, - A8: *zero, - A9: *zero, - A10: *zero, - A11: *zero, + C0: *z0, + C1: *z1, } } -func (e Ext12) Neg(x *E12) *E12 { - a0 := e.fp.Neg(&x.A0) - a1 := e.fp.Neg(&x.A1) - a2 := e.fp.Neg(&x.A2) - a3 := e.fp.Neg(&x.A3) - a4 := e.fp.Neg(&x.A4) - a5 := e.fp.Neg(&x.A5) - a6 := e.fp.Neg(&x.A6) - a7 := e.fp.Neg(&x.A7) - a8 := e.fp.Neg(&x.A8) - a9 := e.fp.Neg(&x.A9) - a10 := e.fp.Neg(&x.A10) - a11 := e.fp.Neg(&x.A11) - +func (e Ext12) Conjugate(x *E12) *E12 { + z1 := e.Ext6.Neg(&x.C1) return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: x.C0, + C1: *z1, } } -func (e Ext12) Add(x, y *E12) *E12 { - a0 := e.fp.Add(&x.A0, &y.A0) - a1 := e.fp.Add(&x.A1, &y.A1) - a2 := e.fp.Add(&x.A2, &y.A2) - a3 := e.fp.Add(&x.A3, &y.A3) - a4 := e.fp.Add(&x.A4, &y.A4) - a5 := e.fp.Add(&x.A5, &y.A5) - a6 := e.fp.Add(&x.A6, &y.A6) - a7 := e.fp.Add(&x.A7, &y.A7) - a8 := e.fp.Add(&x.A8, &y.A8) - a9 := e.fp.Add(&x.A9, &y.A9) - a10 := e.fp.Add(&x.A10, &y.A10) - a11 := e.fp.Add(&x.A11, &y.A11) - +func (e Ext12) Mul(x, y *E12) *E12 { + a := e.Ext6.Add(&x.C0, &x.C1) + b := e.Ext6.Add(&y.C0, &y.C1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&x.C0, &y.C0) + c := e.Ext6.Mul(&x.C1, &y.C1) + d := e.Ext6.Add(c, b) + z1 := e.Ext6.Sub(a, d) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: *z0, + C1: *z1, } } -func (e Ext12) Sub(x, y *E12) *E12 { - a0 := e.fp.Sub(&x.A0, &y.A0) - a1 := e.fp.Sub(&x.A1, &y.A1) - a2 := e.fp.Sub(&x.A2, &y.A2) - a3 := e.fp.Sub(&x.A3, &y.A3) - a4 := e.fp.Sub(&x.A4, &y.A4) - a5 := e.fp.Sub(&x.A5, &y.A5) - a6 := e.fp.Sub(&x.A6, &y.A6) - a7 := e.fp.Sub(&x.A7, &y.A7) - a8 := e.fp.Sub(&x.A8, &y.A8) - a9 := e.fp.Sub(&x.A9, &y.A9) - a10 := e.fp.Sub(&x.A10, &y.A10) - a11 := e.fp.Sub(&x.A11, &y.A11) - +func (e Ext12) Zero() *E12 { + zero := e.fp.Zero() return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, } } -func (e Ext12) Double(x *E12) *E12 { - two := big.NewInt(2) - a0 := e.fp.MulConst(&x.A0, two) - a1 := e.fp.MulConst(&x.A1, two) - a2 := e.fp.MulConst(&x.A2, two) - a3 := e.fp.MulConst(&x.A3, two) - a4 := e.fp.MulConst(&x.A4, two) - a5 := e.fp.MulConst(&x.A5, two) - a6 := e.fp.MulConst(&x.A6, two) - a7 := e.fp.MulConst(&x.A7, two) - a8 := e.fp.MulConst(&x.A8, two) - a9 := e.fp.MulConst(&x.A9, two) - a10 := e.fp.MulConst(&x.A10, two) - a11 := e.fp.MulConst(&x.A11, two) - +func (e Ext12) One() *E12 { + z000 := e.fp.One() + zero := e.fp.Zero() return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: E6{ + B0: E2{A0: *z000, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, } } -func (e Ext12) Conjugate(x *E12) *E12 { - return &E12{ - A0: x.A0, - A1: *e.fp.Neg(&x.A1), - A2: x.A2, - A3: *e.fp.Neg(&x.A3), - A4: x.A4, - A5: *e.fp.Neg(&x.A5), - A6: x.A6, - A7: *e.fp.Neg(&x.A7), - A8: x.A8, - A9: *e.fp.Neg(&x.A9), - A10: x.A10, - A11: *e.fp.Neg(&x.A11), - } +func (e Ext12) IsZero(z *E12) frontend.Variable { + c0 := e.Ext6.IsZero(&z.C0) + c1 := e.Ext6.IsZero(&z.C1) + return e.api.And(c0, c1) } -func (e Ext12) Mul(x, y *E12) *E12 { - return e.mulDirect(x, y) +func (e Ext12) Square(x *E12) *E12 { + c0 := e.Ext6.Sub(&x.C0, &x.C1) + c3 := e.Ext6.MulByNonResidue(&x.C1) + c3 = e.Ext6.Sub(&x.C0, c3) + c2 := e.Ext6.Mul(&x.C0, &x.C1) + c0 = e.Ext6.Mul(c0, c3) + c0 = e.Ext6.Add(c0, c2) + z1 := e.Ext6.Double(c2) + c2 = e.Ext6.MulByNonResidue(c2) + z0 := e.Ext6.Add(c0, c2) + return &E12{ + C0: *z0, + C1: *z1, + } } -func (e Ext12) mulDirect(a, b *E12) *E12 { - - // a = a11 w^11 + a10 w^10 + a9 w^9 + a8 w^8 + a7 w^7 + a6 w^6 + a5 w^5 + a4 w^4 + a3 w^3 + a2 w^2 + a1 w + a0 - // b = b11 w^11 + b10 w^10 + b9 w^9 + b8 w^8 + b7 w^7 + b6 w^6 + b5 w^5 + b4 w^4 + b3 w^3 + b2 w^2 + b1 w + b0 - // - // Given that w^12 = 2 w^6 - 2, we can compute the product a * b as follows: - // - // a * b = d11 w^11 + d10 w^10 + d9 w^9 + d8 w^8 + d7 w^7 + d6 w^6 + d5 w^5 + d4 w^4 + d3 w^3 + d2 w^2 + d1 w + d0 - // - // where: - // - // d0 = c0 - 2 * c12 - 4 * c18 - // d1 = c1 - 2 * c13 - 4 * c19 - // d2 = c2 - 2 * c14 - 4 * c20 - // d3 = c3 - 2 * c15 - 4 * c21 - // d4 = c4 - 2 * c16 - 4 * c22 - // d5 = c5 - 2 * c17 - // d6 = c6 + 2 * c12 + 2 * c18 - // d7 = c7 + 2 * c13 + 2 * c19 - // d8 = c8 + 2 * c14 + 2 * c20 - // d9 = c9 + 2 * c15 + 2 * c21 - // d10 = c10 + 2 * c16 + 2 * c22 - // d11 = c11 + 2 * c17 - // - // and: - // - // c0 = a0 b0 - // c1 = a0 b1 + a1 b0 - // c2 = a0 b2 + a1 b1 + a2 b0 - // c3 = a0 b3 + a1 b2 + a2 b1 + a3 b0 - // c4 = a0 b4 + a1 b3 + a2 b2 + a3 b1 + a4 b0 - // c5 = a0 b5 + a1 b4 + a2 b3 + a3 b2 + a4 b1 + a5 b0 - // c6 = a0 b6 + a1 b5 + a2 b4 + a3 b3 + a4 b2 + a5 b1 + a6 b0 - // c7 = a0 b7 + a1 b6 + a2 b5 + a3 b4 + a4 b3 + a5 b2 + a6 b1 + a7 b0 - // c8 = a0 b8 + a1 b7 + a2 b6 + a3 b5 + a4 b4 + a5 b3 + a6 b2 + a7 b1 + a8 b0 - // c9 = a0 b9 + a1 b8 + a2 b7 + a3 b6 + a4 b5 + a5 b4 + a6 b3 + a7 b2 + a8 b1 + a9 b0 - // c10 = a0 b10 + a1 b9 + a2 b8 + a3 b7 + a4 b6 + a5 b5 + a6 b4 + a7 b3 + a8 b2 + a9 b1 + a10 b0 - // c11 = a0 b11 + a1 b10 + a2 b9 + a3 b8 + a4 b7 + a5 b6 + a6 b5 + a7 b4 + a8 b3 + a9 b2 + a10 b1 + a11 b0 - // c12 = a1 b11 + a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a7 b5 + a8 b4 + a9 b3 + a10 b2 + a11 b1 - // c13 = a2 b11 + a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a8 b5 + a9 b4 + a10 b3 + a11 b2 - // c14 = a3 b11 + a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a9 b5 + a10 b4 + a11 b3 - // c15 = a4 b11 + a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a10 b5 + a11 b4 - // c16 = a5 b11 + a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6 + a11 b5 - // c17 = a6 b11 + a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6 - // c18 = a7 b11 + a8 b10 + a9 b9 + a10 b8 + a11 b7 - // c19 = a8 b11 + a9 b10 + a10 b9 + a11 b8 - // c20 = a9 b11 + a10 b10 + a11 b9 - // c21 = a10 b11 + a11 b10 - // c22 = a11 b11 - - // d0 = c0 - 2 * c12 - 4 * c18 - // = a0 b0 - 2 * (a1 b11 + a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a7 b5 + a8 b4 + a9 b3 + a10 b2 + a11 b1) - 4 * (a7 b11 + a8 b10 + a9 b9 + a10 b8 + a11 b7) - mone := e.fp.NewElement(-1) - d0 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A0}, {mone, &a.A1, &b.A11}, {mone, &a.A2, &b.A10}, {mone, &a.A3, &b.A9}, {mone, &a.A4, &b.A8}, {mone, &a.A5, &b.A7}, {mone, &a.A6, &b.A6}, {mone, &a.A7, &b.A5}, {mone, &a.A8, &b.A4}, {mone, &a.A9, &b.A3}, {mone, &a.A10, &b.A2}, {mone, &a.A11, &b.A1}, {mone, &a.A7, &b.A11}, {mone, &a.A8, &b.A10}, {mone, &a.A9, &b.A9}, {mone, &a.A10, &b.A8}, {mone, &a.A11, &b.A7}}, []int{1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4}) - - // d1 = c1 - 2 * c13 - 4 * c19 - // = a0 b1 + a1 b0 - 2 * (a2 b11 + a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a8 b5 + a9 b4 + a10 b3 + a11 b2) - 4 * (a8 b11 + a9 b10 + a10 b9 + a11 b8) - d1 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A1}, {&a.A1, &b.A0}, {mone, &a.A2, &b.A11}, {mone, &a.A3, &b.A10}, {mone, &a.A4, &b.A9}, {mone, &a.A5, &b.A8}, {mone, &a.A6, &b.A7}, {mone, &a.A7, &b.A6}, {mone, &a.A8, &b.A5}, {mone, &a.A9, &b.A4}, {mone, &a.A10, &b.A3}, {mone, &a.A11, &b.A2}, {mone, &a.A8, &b.A11}, {mone, &a.A9, &b.A10}, {mone, &a.A10, &b.A9}, {mone, &a.A11, &b.A8}}, []int{1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4}) - - // d2 = c2 - 2 * c14 - 4 * c20 - // = a0 b2 + a1 b1 + a2 b0 - 2 * (a3 b11 + a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a9 b5 + a10 b4 + a11 b3) - 4 * (a9 b11 + a10 b10 + a11 b9) - d2 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A2}, {&a.A1, &b.A1}, {&a.A2, &b.A0}, {mone, &a.A3, &b.A11}, {mone, &a.A4, &b.A10}, {mone, &a.A5, &b.A9}, {mone, &a.A6, &b.A8}, {mone, &a.A7, &b.A7}, {mone, &a.A8, &b.A6}, {mone, &a.A9, &b.A5}, {mone, &a.A10, &b.A4}, {mone, &a.A11, &b.A3}, {mone, &a.A9, &b.A11}, {mone, &a.A10, &b.A10}, {mone, &a.A11, &b.A9}}, []int{1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4}) - - // d3 = c3 - 2 * c15 - 4 * c21 - // = a0 b3 + a1 b2 + a2 b1 + a3 b0 - 2 * (a4 b11 + a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a10 b5 + a11 b4) - 4 * (a10 b11 + a11 b10) - d3 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A3}, {&a.A1, &b.A2}, {&a.A2, &b.A1}, {&a.A3, &b.A0}, {mone, &a.A4, &b.A11}, {mone, &a.A5, &b.A10}, {mone, &a.A6, &b.A9}, {mone, &a.A7, &b.A8}, {mone, &a.A8, &b.A7}, {mone, &a.A9, &b.A6}, {mone, &a.A10, &b.A5}, {mone, &a.A11, &b.A4}, {mone, &a.A10, &b.A11}, {mone, &a.A11, &b.A10}}, []int{1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4}) - - // d4 = c4 - 2 * c16 - 4 * c22 - // = a0 b4 + a1 b3 + a2 b2 + a3 b1 + a4 b0 - 2 * (a5 b11 + a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6 + a11 b5) - 4 * a11 b11 - d4 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A4}, {&a.A1, &b.A3}, {&a.A2, &b.A2}, {&a.A3, &b.A1}, {&a.A4, &b.A0}, {mone, &a.A5, &b.A11}, {mone, &a.A6, &b.A10}, {mone, &a.A7, &b.A9}, {mone, &a.A8, &b.A8}, {mone, &a.A9, &b.A7}, {mone, &a.A10, &b.A6}, {mone, &a.A11, &b.A5}, {mone, &a.A11, &b.A11}}, []int{1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 4}) - - // d5 = c5 - 2 * c17 - // = a0 b5 + a1 b4 + a2 b3 + a3 b2 + a4 b1 + a5 b0 - 2 * (a6 b11 + a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6) - d5 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A5}, {&a.A1, &b.A4}, {&a.A2, &b.A3}, {&a.A3, &b.A2}, {&a.A4, &b.A1}, {&a.A5, &b.A0}, {mone, &a.A6, &b.A11}, {mone, &a.A7, &b.A10}, {mone, &a.A8, &b.A9}, {mone, &a.A9, &b.A8}, {mone, &a.A10, &b.A7}, {mone, &a.A11, &b.A6}}, []int{1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}) - - // d6 = c6 + 2 * c12 + 2 * c2 - // = a0 b6 + a1 b5 + a2 b4 + a3 b3 + a4 b2 + a5 b1 + a6 b0 + 2 * (a1 b11 + a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a7 b5 + a8 b4 + a9 b3 + a10 b2 + a11 b1) + 2 * (a7 b11 + a8 b10 + a9 b9 + a10 b8 + a11 b7) - d6 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A6}, {&a.A1, &b.A5}, {&a.A2, &b.A4}, {&a.A3, &b.A3}, {&a.A4, &b.A2}, {&a.A5, &b.A1}, {&a.A6, &b.A0}, {&a.A1, &b.A11}, {&a.A2, &b.A10}, {&a.A3, &b.A9}, {&a.A4, &b.A8}, {&a.A5, &b.A7}, {&a.A6, &b.A6}, {&a.A7, &b.A5}, {&a.A8, &b.A4}, {&a.A9, &b.A3}, {&a.A10, &b.A2}, {&a.A11, &b.A1}, {&a.A7, &b.A11}, {&a.A8, &b.A10}, {&a.A9, &b.A9}, {&a.A10, &b.A8}, {&a.A11, &b.A7}}, []int{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}) - - // d7 = c7 + 2 * c13 + 2 * c19 - // = a0 b7 + a1 b6 + a2 b5 + a3 b4 + a4 b3 + a5 b2 + a6 b1 + a7 b0 + 2 * (a2 b11 + a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a8 b5 + a9 b4 + a10 b3 + a11 b2) + 2 * (a8 b11 + a9 b10 + a10 b9 + a11 b8) - d7 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A7}, {&a.A1, &b.A6}, {&a.A2, &b.A5}, {&a.A3, &b.A4}, {&a.A4, &b.A3}, {&a.A5, &b.A2}, {&a.A6, &b.A1}, {&a.A7, &b.A0}, {&a.A2, &b.A11}, {&a.A3, &b.A10}, {&a.A4, &b.A9}, {&a.A5, &b.A8}, {&a.A6, &b.A7}, {&a.A7, &b.A6}, {&a.A8, &b.A5}, {&a.A9, &b.A4}, {&a.A10, &b.A3}, {&a.A11, &b.A2}, {&a.A8, &b.A11}, {&a.A9, &b.A10}, {&a.A10, &b.A9}, {&a.A11, &b.A8}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}) - - // d8 = c8 + 2 * c14 + 2 * c20 - // = a0 b8 + a1 b7 + a2 b6 + a3 b5 + a4 b4 + a5 b3 + a6 b2 + a7 b1 + a8 b0 + 2 * (a3 b11 + a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a9 b5 + a10 b4 + a11 b3) + 2 * (a9 b11 + a10 b10 + a11 b9) - d8 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A8}, {&a.A1, &b.A7}, {&a.A2, &b.A6}, {&a.A3, &b.A5}, {&a.A4, &b.A4}, {&a.A5, &b.A3}, {&a.A6, &b.A2}, {&a.A7, &b.A1}, {&a.A8, &b.A0}, {&a.A3, &b.A11}, {&a.A4, &b.A10}, {&a.A5, &b.A9}, {&a.A6, &b.A8}, {&a.A7, &b.A7}, {&a.A8, &b.A6}, {&a.A9, &b.A5}, {&a.A10, &b.A4}, {&a.A11, &b.A3}, {&a.A9, &b.A11}, {&a.A10, &b.A10}, {&a.A11, &b.A9}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}) - - // d9 = c9 + 2 * c15 + 2 * c21 - // = a0 b9 + a1 b8 + a2 b7 + a3 b6 + a4 b5 + a5 b4 + a6 b3 + a7 b2 + a8 b1 + a9 b0 + 2 * (a4 b11 + a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a10 b5 + a11 b4) + 2 * (a10 b11 + a11 b10) - d9 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A9}, {&a.A1, &b.A8}, {&a.A2, &b.A7}, {&a.A3, &b.A6}, {&a.A4, &b.A5}, {&a.A5, &b.A4}, {&a.A6, &b.A3}, {&a.A7, &b.A2}, {&a.A8, &b.A1}, {&a.A9, &b.A0}, {&a.A4, &b.A11}, {&a.A5, &b.A10}, {&a.A6, &b.A9}, {&a.A7, &b.A8}, {&a.A8, &b.A7}, {&a.A9, &b.A6}, {&a.A10, &b.A5}, {&a.A11, &b.A4}, {&a.A10, &b.A11}, {&a.A11, &b.A10}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}) - - // d10 = c10 + 2 * c16 + 2 * c22 - // = a0 b10 + a1 b9 + a2 b8 + a3 b7 + a4 b6 + a5 b5 + a6 b4 + a7 b3 + a8 b2 + a9 b1 + a10 b0 + 2 * (a5 b11 + a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6 + a11 b5) + 2 * (a11 b11) - d10 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A10}, {&a.A1, &b.A9}, {&a.A2, &b.A8}, {&a.A3, &b.A7}, {&a.A4, &b.A6}, {&a.A5, &b.A5}, {&a.A6, &b.A4}, {&a.A7, &b.A3}, {&a.A8, &b.A2}, {&a.A9, &b.A1}, {&a.A10, &b.A0}, {&a.A5, &b.A11}, {&a.A6, &b.A10}, {&a.A7, &b.A9}, {&a.A8, &b.A8}, {&a.A9, &b.A7}, {&a.A10, &b.A6}, {&a.A11, &b.A5}, {&a.A11, &b.A11}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2}) - - // d11 = c11 + 2 * c17 - // = a0 b11 + a1 b10 + a2 b9 + a3 b8 + a4 b7 + a5 b6 + a6 b5 + a7 b4 + a8 b3 + a9 b2 + a10 b1 + a11 b0 + 2 * (a6 b11 + a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6) - d11 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A11}, {&a.A1, &b.A10}, {&a.A2, &b.A9}, {&a.A3, &b.A8}, {&a.A4, &b.A7}, {&a.A5, &b.A6}, {&a.A6, &b.A5}, {&a.A7, &b.A4}, {&a.A8, &b.A3}, {&a.A9, &b.A2}, {&a.A10, &b.A1}, {&a.A11, &b.A0}, {&a.A6, &b.A11}, {&a.A7, &b.A10}, {&a.A8, &b.A9}, {&a.A9, &b.A8}, {&a.A10, &b.A7}, {&a.A11, &b.A6}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}) - +// Granger--Scott cyclotomic square +func (e Ext12) CyclotomicSquare(x *E12) *E12 { + t0 := e.Ext2.Square(&x.C1.B1) + t1 := e.Ext2.Square(&x.C0.B0) + t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) + t6 = e.Ext2.Square(t6) + t6 = e.Ext2.Sub(t6, t0) + t6 = e.Ext2.Sub(t6, t1) + t2 := e.Ext2.Square(&x.C0.B2) + t3 := e.Ext2.Square(&x.C1.B0) + t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) + t7 = e.Ext2.Square(t7) + t7 = e.Ext2.Sub(t7, t2) + t7 = e.Ext2.Sub(t7, t3) + t4 := e.Ext2.Square(&x.C1.B2) + t5 := e.Ext2.Square(&x.C0.B1) + t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) + t8 = e.Ext2.Square(t8) + t8 = e.Ext2.Sub(t8, t4) + t8 = e.Ext2.Sub(t8, t5) + t8 = e.Ext2.MulByNonResidue(t8) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, t1) + t2 = e.Ext2.MulByNonResidue(t2) + t2 = e.Ext2.Add(t2, t3) + t4 = e.Ext2.MulByNonResidue(t4) + t4 = e.Ext2.Add(t4, t5) + z00 := e.Ext2.Sub(t0, &x.C0.B0) + z00 = e.Ext2.Double(z00) + z00 = e.Ext2.Add(z00, t0) + z01 := e.Ext2.Sub(t2, &x.C0.B1) + z01 = e.Ext2.Double(z01) + z01 = e.Ext2.Add(z01, t2) + z02 := e.Ext2.Sub(t4, &x.C0.B2) + z02 = e.Ext2.Double(z02) + z02 = e.Ext2.Add(z02, t4) + z10 := e.Ext2.Add(t8, &x.C1.B0) + z10 = e.Ext2.Double(z10) + z10 = e.Ext2.Add(z10, t8) + z11 := e.Ext2.Add(t6, &x.C1.B1) + z11 = e.Ext2.Double(z11) + z11 = e.Ext2.Add(z11, t6) + z12 := e.Ext2.Add(t7, &x.C1.B2) + z12 = e.Ext2.Double(z12) + z12 = e.Ext2.Add(z12, t7) return &E12{ - A0: *d0, - A1: *d1, - A2: *d2, - A3: *d3, - A4: *d4, - A5: *d5, - A6: *d6, - A7: *d7, - A8: *d8, - A9: *d9, - A10: *d10, - A11: *d11, + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, } } -func (e Ext12) Square(x *E12) *E12 { - return e.squareDirect(x) +func (e Ext12) AssertIsEqual(x, y *E12) { + e.Ext6.AssertIsEqual(&x.C0, &y.C0) + e.Ext6.AssertIsEqual(&x.C1, &y.C1) } -func (e Ext12) squareDirect(a *E12) *E12 { - - mone := e.fp.NewElement(-1) - // d0 = a0 a0 - 2 * (2 a1 a11 + 2 a2 a10 + 2 a3 a9 + 2 a4 a8 + 2 a5 a7 + a6 a6) - 4 * (2 a7 a11 + 2 a8 a10 + a9 a9) - d0 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A0}, {mone, &a.A1, &a.A11}, {mone, &a.A2, &a.A10}, {mone, &a.A3, &a.A9}, {mone, &a.A4, &a.A8}, {mone, &a.A5, &a.A7}, {mone, &a.A6, &a.A6}, {mone, &a.A7, &a.A11}, {mone, &a.A8, &a.A10}, {mone, &a.A9, &a.A9}}, []int{1, 4, 4, 4, 4, 4, 2, 8, 8, 4}) - - // d1 = 2 a0 a1 - 4 * (2 a2 a11 + a3 a10 + a4 a9 + a5 a8 + a6 a7) - 8 * (a8 a11 + a9 a10) - d1 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A1}, {mone, &a.A2, &a.A11}, {mone, &a.A3, &a.A10}, {mone, &a.A4, &a.A9}, {mone, &a.A5, &a.A8}, {mone, &a.A6, &a.A7}, {mone, &a.A8, &a.A11}, {mone, &a.A9, &a.A10}}, []int{2, 4, 4, 4, 4, 4, 8, 8}) - - // d2 = 2 a0 a2 + a1 a1 - 2 * (2 a3 a11 + 2 a4 a10 + 2 a5 a9 + 2 a6 a8 + a7 a7) - 4 * (2 a9 a11 + a10 a10) - d2 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A2}, {&a.A1, &a.A1}, {mone, &a.A3, &a.A11}, {mone, &a.A4, &a.A10}, {mone, &a.A5, &a.A9}, {mone, &a.A6, &a.A8}, {mone, &a.A7, &a.A7}, {mone, &a.A9, &a.A11}, {mone, &a.A10, &a.A10}}, []int{2, 1, 4, 4, 4, 4, 2, 8, 4}) - - // d3 = 2 a0 a3 + 2 a1 a2 - 4 * (a4 a11 + a5 a10 + a6 a9 + a7 a8) - 8 * a10 a11 - d3 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A3}, {&a.A1, &a.A2}, {mone, &a.A4, &a.A11}, {mone, &a.A5, &a.A10}, {mone, &a.A6, &a.A9}, {mone, &a.A7, &a.A8}, {mone, &a.A10, &a.A11}}, []int{2, 2, 4, 4, 4, 4, 8}) - - // d4 = 2 a0 a4 + 2 a1 a3 + a2 a2 - 2 * (2 a5 a11 + 2 a6 a10 + 2 a7 a9 + a8 a8) - 4 * a11 a11 - d4 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A4}, {&a.A1, &a.A3}, {&a.A2, &a.A2}, {mone, &a.A5, &a.A11}, {mone, &a.A6, &a.A10}, {mone, &a.A7, &a.A9}, {mone, &a.A8, &a.A8}, {mone, &a.A11, &a.A11}}, []int{2, 2, 1, 4, 4, 4, 2, 4}) - - // d5 = 2 (a0 a5 + a1 a4 + a2 a3) - 4 * (a6 a11 + a7 a10 + a8 a9) - d5 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A5}, {&a.A1, &a.A4}, {&a.A2, &a.A3}, {mone, &a.A6, &a.A11}, {mone, &a.A7, &a.A10}, {mone, &a.A8, &a.A9}}, []int{2, 2, 2, 4, 4, 4}) - - // d6 = 2 a0 a6 + 2 a1 a5 + 2 a2 a4 + a3 a3 + 2 * (2 a1 a11 + 2 a2 a10 + 2 a3 a9 + 2 a4 a8 + 2 a5 a7 + a6 a6) + 2 * (2 a7 a11 + 2 a8 a10 + a9 a9) - d6 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A6}, {&a.A1, &a.A5}, {&a.A2, &a.A4}, {&a.A3, &a.A3}, {&a.A1, &a.A11}, {&a.A2, &a.A10}, {&a.A3, &a.A9}, {&a.A4, &a.A8}, {&a.A5, &a.A7}, {&a.A6, &a.A6}, {&a.A7, &a.A11}, {&a.A8, &a.A10}, {&a.A9, &a.A9}}, []int{2, 2, 2, 1, 4, 4, 4, 4, 4, 2, 4, 4, 2}) - - // d7 = 2(a0 a7 + a1 a6 + a2 a5 + a3 a4) + 4 * (a2 a11 + a3 a10 + a4 a9 + a5 a8 + a6 a7) + 4 * (a8 a11 + a9 a10) - d7 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A7}, {&a.A1, &a.A6}, {&a.A2, &a.A5}, {&a.A3, &a.A4}, {&a.A2, &a.A11}, {&a.A3, &a.A10}, {&a.A4, &a.A9}, {&a.A5, &a.A8}, {&a.A6, &a.A7}, {&a.A8, &a.A11}, {&a.A9, &a.A10}}, []int{2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4}) - - // d8 = 2(a0 a8 + a1 a7 + a2 a6 + a3 a5) + a4 a4 + 2 * (2 a3 a11 + 2 a4 a10 + 2 a5 a9 + 2 a6 a8 + a7 a7) + 2 * (2 a9 a11 + a10 a10) - d8 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A8}, {&a.A1, &a.A7}, {&a.A2, &a.A6}, {&a.A3, &a.A5}, {&a.A4, &a.A4}, {&a.A3, &a.A11}, {&a.A4, &a.A10}, {&a.A5, &a.A9}, {&a.A6, &a.A8}, {&a.A7, &a.A7}, {&a.A9, &a.A11}, {&a.A10, &a.A10}}, []int{2, 2, 2, 2, 1, 4, 4, 4, 4, 2, 4, 2}) - - // d9 = 2(a0 a9 + a1 a8 + a2 a7 + a3 a6 + a4 a5) + 4 * (a4 a11 + a5 a10 + a6 a9 + a7 a8) + 4 * a10 a11 - d9 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A9}, {&a.A1, &a.A8}, {&a.A2, &a.A7}, {&a.A3, &a.A6}, {&a.A4, &a.A5}, {&a.A4, &a.A11}, {&a.A5, &a.A10}, {&a.A6, &a.A9}, {&a.A7, &a.A8}, {&a.A10, &a.A11}}, []int{2, 2, 2, 2, 2, 4, 4, 4, 4, 4}) - - // d10 = 2(a0 a10 + a1 a9 + a2 a8 + a3 a7 + a4 a6) + a5 a5 + 2 * (2 a5 a11 + 2 a6 a10 + 2 a7 a9 + a8 a8) + 2 * a11 a11 - d10 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A10}, {&a.A1, &a.A9}, {&a.A2, &a.A8}, {&a.A3, &a.A7}, {&a.A4, &a.A6}, {&a.A5, &a.A5}, {&a.A5, &a.A11}, {&a.A6, &a.A10}, {&a.A7, &a.A9}, {&a.A8, &a.A8}, {&a.A11, &a.A11}}, []int{2, 2, 2, 2, 2, 1, 4, 4, 4, 2, 2}) - - // d11 = 2(a0 a11 + a1 a10 + a2 a9 + a3 a8 + a4 a7 + a5 a6) + 4 * (a6 a11 + a7 a10 + a8 a9) - d11 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A11}, {&a.A1, &a.A10}, {&a.A2, &a.A9}, {&a.A3, &a.A8}, {&a.A4, &a.A7}, {&a.A5, &a.A6}, {&a.A6, &a.A11}, {&a.A7, &a.A10}, {&a.A8, &a.A9}}, []int{2, 2, 2, 2, 2, 2, 4, 4, 4}) - - return &E12{ - A0: *d0, - A1: *d1, - A2: *d2, - A3: *d3, - A4: *d4, - A5: *d5, - A6: *d6, - A7: *d7, - A8: *d8, - A9: *d9, - A10: *d10, - A11: *d11, +func FromE12(y *bls12381.E12) E12 { + return E12{ + C0: FromE6(&y.C0), + C1: FromE6(&y.C1), } + } func (e Ext12) Inverse(x *E12) *E12 { - res, err := e.fp.NewHint(inverseE12Hint, 12, &x.A0, &x.A1, &x.A2, &x.A3, &x.A4, &x.A5, &x.A6, &x.A7, &x.A8, &x.A9, &x.A10, &x.A11) + res, err := e.fp.NewHint(inverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) } - inv := E12{A0: *res[0], A1: *res[1], A2: *res[2], A3: *res[3], A4: *res[4], A5: *res[5], A6: *res[6], A7: *res[7], A8: *res[8], A9: *res[9], A10: *res[10], A11: *res[11]} + inv := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + one := e.One() // 1 == inv * x @@ -403,302 +217,41 @@ func (e Ext12) Inverse(x *E12) *E12 { } func (e Ext12) DivUnchecked(x, y *E12) *E12 { - res, err := e.fp.NewHint(divE12Hint, 12, &x.A0, &x.A1, &x.A2, &x.A3, &x.A4, &x.A5, &x.A6, &x.A7, &x.A8, &x.A9, &x.A10, &x.A11, &y.A0, &y.A1, &y.A2, &y.A3, &y.A4, &y.A5, &y.A6, &y.A7, &y.A8, &y.A9, &y.A10, &y.A11) + res, err := e.fp.NewHint(divE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) + if err != nil { // err is non-nil only for invalid number of inputs panic(err) } - div := E12{A0: *res[0], A1: *res[1], A2: *res[2], A3: *res[3], A4: *res[4], A5: *res[5], A6: *res[6], A7: *res[7], A8: *res[8], A9: *res[9], A10: *res[10], A11: *res[11]} + div := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } - // x = div * y + // x == div * y _x := e.Mul(&div, y) e.AssertIsEqual(x, _x) return &div - -} - -func (e Ext12) AssertIsEqual(a, b *E12) { - e.fp.AssertIsEqual(&a.A0, &b.A0) - e.fp.AssertIsEqual(&a.A1, &b.A1) - e.fp.AssertIsEqual(&a.A2, &b.A2) - e.fp.AssertIsEqual(&a.A3, &b.A3) - e.fp.AssertIsEqual(&a.A4, &b.A4) - e.fp.AssertIsEqual(&a.A5, &b.A5) - e.fp.AssertIsEqual(&a.A6, &b.A6) - e.fp.AssertIsEqual(&a.A7, &b.A7) - e.fp.AssertIsEqual(&a.A8, &b.A8) - e.fp.AssertIsEqual(&a.A9, &b.A9) - e.fp.AssertIsEqual(&a.A10, &b.A10) - e.fp.AssertIsEqual(&a.A11, &b.A11) -} - -func (e Ext12) IsEqual(x, y *E12) frontend.Variable { - diff0 := e.fp.Sub(&x.A0, &y.A0) - diff1 := e.fp.Sub(&x.A1, &y.A1) - diff2 := e.fp.Sub(&x.A2, &y.A2) - diff3 := e.fp.Sub(&x.A3, &y.A3) - diff4 := e.fp.Sub(&x.A4, &y.A4) - diff5 := e.fp.Sub(&x.A5, &y.A5) - diff6 := e.fp.Sub(&x.A6, &y.A6) - diff7 := e.fp.Sub(&x.A7, &y.A7) - diff8 := e.fp.Sub(&x.A8, &y.A8) - diff9 := e.fp.Sub(&x.A9, &y.A9) - diff10 := e.fp.Sub(&x.A10, &y.A10) - diff11 := e.fp.Sub(&x.A11, &y.A11) - isZero0 := e.fp.IsZero(diff0) - isZero1 := e.fp.IsZero(diff1) - isZero2 := e.fp.IsZero(diff2) - isZero3 := e.fp.IsZero(diff3) - isZero4 := e.fp.IsZero(diff4) - isZero5 := e.fp.IsZero(diff5) - isZero6 := e.fp.IsZero(diff6) - isZero7 := e.fp.IsZero(diff7) - isZero8 := e.fp.IsZero(diff8) - isZero9 := e.fp.IsZero(diff9) - isZero10 := e.fp.IsZero(diff10) - isZero11 := e.fp.IsZero(diff11) - - return e.api.And( - e.api.And( - e.api.And(e.api.And(isZero0, isZero1), e.api.And(isZero2, isZero3)), - e.api.And(e.api.And(isZero4, isZero5), e.api.And(isZero6, isZero7)), - ), - e.api.And(e.api.And(isZero8, isZero9), e.api.And(isZero10, isZero11)), - ) -} - -func (e Ext12) Copy(x *E12) *E12 { - return &E12{ - A0: x.A0, - A1: x.A1, - A2: x.A2, - A3: x.A3, - A4: x.A4, - A5: x.A5, - A6: x.A6, - A7: x.A7, - A8: x.A8, - A9: x.A9, - A10: x.A10, - A11: x.A11, - } -} - -// tower to direct extension conversion -func FromE12(a *bls12381.E12) E12 { - // gnark-crypto uses a quadratic over cubic over quadratic 12th extension of Fp. - // The two towers are isomorphic and the coefficients are permuted as follows: - // a000 a001 a010 a011 a020 a021 a100 a101 a110 a111 a120 a121 - // a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 - // - // A0 = a000 - a001 - // A1 = a100 - a101 - // A2 = a010 - a011 - // A3 = a110 - a111 - // A4 = a020 - a021 - // A5 = a120 - a121 - // A6 = a001 - // A7 = a101 - // A8 = a011 - // A9 = a111 - // A10 = a021 - // A11 = a121 - - var c0, c1, c2, c3, c4, c5 fp.Element - c0.Sub(&a.C0.B0.A0, &a.C0.B0.A1) - c1.Sub(&a.C1.B0.A0, &a.C1.B0.A1) - c2.Sub(&a.C0.B1.A0, &a.C0.B1.A1) - c3.Sub(&a.C1.B1.A0, &a.C1.B1.A1) - c4.Sub(&a.C0.B2.A0, &a.C0.B2.A1) - c5.Sub(&a.C1.B2.A0, &a.C1.B2.A1) - - return E12{ - A0: emulated.ValueOf[emulated.BLS12381Fp](c0), - A1: emulated.ValueOf[emulated.BLS12381Fp](c1), - A2: emulated.ValueOf[emulated.BLS12381Fp](c2), - A3: emulated.ValueOf[emulated.BLS12381Fp](c3), - A4: emulated.ValueOf[emulated.BLS12381Fp](c4), - A5: emulated.ValueOf[emulated.BLS12381Fp](c5), - A6: emulated.ValueOf[emulated.BLS12381Fp](a.C0.B0.A1), - A7: emulated.ValueOf[emulated.BLS12381Fp](a.C1.B0.A1), - A8: emulated.ValueOf[emulated.BLS12381Fp](a.C0.B1.A1), - A9: emulated.ValueOf[emulated.BLS12381Fp](a.C1.B1.A1), - A10: emulated.ValueOf[emulated.BLS12381Fp](a.C0.B2.A1), - A11: emulated.ValueOf[emulated.BLS12381Fp](a.C1.B2.A1), - } -} - -func (e Ext12) ToTower(a *E12) [12]*baseEl { - // gnark-crypto uses a quadratic over cubic over quadratic 12th extension of Fp. - // The two towers are isomorphic and the coefficients are permuted as follows: - // - // tower = a000 a001 a010 a011 a020 a021 a100 a101 a110 a111 a120 a121 - // direct = a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 - // - // a000 = A0 + A6 - // a001 = A6 - // a010 = A2 + A8 - // a011 = A8 - // a020 = A4 + A10 - // a021 = A10 - // a100 = A1 + A7 - // a101 = A7 - // a110 = A3 + A9 - // a111 = A9 - // a120 = A5 + A11 - // a121 = A11 - a000 := e.fp.Add(&a.A0, &a.A6) - a001 := &a.A6 - a010 := e.fp.Add(&a.A2, &a.A8) - a011 := &a.A8 - a020 := e.fp.Add(&a.A4, &a.A10) - a021 := &a.A10 - a100 := e.fp.Add(&a.A1, &a.A7) - a101 := &a.A7 - a110 := e.fp.Add(&a.A3, &a.A9) - a111 := &a.A9 - a120 := e.fp.Add(&a.A5, &a.A11) - a121 := &a.A11 - - tower := [12]*baseEl{a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121} - return tower -} - -func (e Ext12) FromTower(tower [12]*baseEl) *E12 { - // gnark-crypto uses a quadratic over cubic over quadratic 12th extension of Fp. - // The two towers are isomorphic and the coefficients are permuted as follows: - // - // tower = a000 a001 a010 a011 a020 a021 a100 a101 a110 a111 a120 a121 - // direct = a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 - // - // A0 = a000 - a001 - // A1 = a100 - a101 - // A2 = a010 - a011 - // A3 = a110 - a111 - // A4 = a020 - a021 - // A5 = a120 - a121 - // A6 = a001 - // A7 = a101 - // A8 = a011 - // A9 = a111 - // A10 = a021 - // A11 = a121 - A0 := e.fp.Sub(tower[0], tower[1]) - A1 := e.fp.Sub(tower[6], tower[7]) - A2 := e.fp.Sub(tower[2], tower[3]) - A3 := e.fp.Sub(tower[8], tower[9]) - A4 := e.fp.Sub(tower[4], tower[5]) - A5 := e.fp.Sub(tower[10], tower[11]) - - return &E12{ - A0: *A0, - A1: *A1, - A2: *A2, - A3: *A3, - A4: *A4, - A5: *A5, - A6: *tower[1], - A7: *tower[7], - A8: *tower[3], - A9: *tower[9], - A10: *tower[5], - A11: *tower[11], - } -} - -// Granger-Scott's cyclotomic square -// https://eprint.iacr.org/2009/565.pdf, 3.2 -func (e Ext12) CyclotomicSquareGS(x *E12) *E12 { - tower := e.ToTower(x) - - mone := e.fp.NewElement(-1) - z000 := e.fp.Eval([][]*baseEl{{tower[8], tower[8]}, {mone, tower[9], tower[9]}, {mone, tower[8], tower[9]}, {tower[0], tower[0]}, {mone, tower[1], tower[1]}, {mone, tower[0]}}, []int{3, 3, 6, 3, 3, 2}) - z001 := e.fp.Eval([][]*baseEl{{tower[8], tower[8]}, {mone, tower[9], tower[9]}, {tower[8], tower[9]}, {tower[0], tower[1]}, {mone, tower[1]}}, []int{3, 3, 6, 6, 2}) - z010 := e.fp.Eval([][]*baseEl{{tower[4], tower[4]}, {mone, tower[5], tower[5]}, {mone, tower[4], tower[5]}, {tower[6], tower[6]}, {mone, tower[7], tower[7]}, {mone, tower[2]}}, []int{3, 3, 6, 3, 3, 2}) - z011 := e.fp.Eval([][]*baseEl{{tower[4], tower[4]}, {mone, tower[5], tower[5]}, {tower[4], tower[5]}, {tower[6], tower[7]}, {mone, tower[3]}}, []int{3, 3, 6, 6, 2}) - z020 := e.fp.Eval([][]*baseEl{{tower[10], tower[10]}, {mone, tower[11], tower[11]}, {mone, tower[10], tower[11]}, {tower[2], tower[2]}, {mone, tower[3], tower[3]}, {mone, tower[4]}}, []int{3, 3, 6, 3, 3, 2}) - z021 := e.fp.Eval([][]*baseEl{{tower[10], tower[10]}, {mone, tower[11], tower[11]}, {tower[10], tower[11]}, {tower[2], tower[3]}, {mone, tower[5]}}, []int{3, 3, 6, 6, 2}) - z100 := e.fp.Eval([][]*baseEl{{tower[2], tower[10]}, {mone, tower[3], tower[11]}, {mone, tower[2], tower[11]}, {mone, tower[3], tower[10]}, {tower[6]}}, []int{6, 6, 6, 6, 2}) - z101 := e.fp.Eval([][]*baseEl{{tower[2], tower[10]}, {mone, tower[3], tower[11]}, {tower[2], tower[11]}, {tower[3], tower[10]}, {tower[7]}}, []int{6, 6, 6, 6, 2}) - z110 := e.fp.Eval([][]*baseEl{{tower[0], tower[8]}, {mone, tower[1], tower[9]}, {tower[8]}}, []int{6, 6, 2}) - z111 := e.fp.Eval([][]*baseEl{{tower[0], tower[9]}, {tower[1], tower[8]}, {tower[9]}}, []int{6, 6, 2}) - z120 := e.fp.Eval([][]*baseEl{{tower[4], tower[6]}, {mone, tower[5], tower[7]}, {tower[10]}}, []int{6, 6, 2}) - z121 := e.fp.Eval([][]*baseEl{{tower[4], tower[7]}, {tower[5], tower[6]}, {tower[11]}}, []int{6, 6, 2}) - - direct := e.FromTower([12]*baseEl{z000, z001, z010, z011, z020, z021, z100, z101, z110, z111, z120, z121}) - - return direct } -func (e Ext12) Frobenius(a *E12) *E12 { - tower := e.ToTower(a) - - tower[1] = e.fp.Neg(tower[1]) - tower[3] = e.fp.Neg(tower[3]) - tower[5] = e.fp.Neg(tower[5]) - tower[7] = e.fp.Neg(tower[7]) - tower[9] = e.fp.Neg(tower[9]) - tower[11] = e.fp.Neg(tower[11]) - - t1 := e.Ext2.MulByNonResidue1Power2(&E2{A0: *tower[2], A1: *tower[3]}) - t2 := e.Ext2.MulByNonResidue1Power4(&E2{A0: *tower[4], A1: *tower[5]}) - t3 := e.Ext2.MulByNonResidue1Power1(&E2{A0: *tower[6], A1: *tower[7]}) - t4 := e.Ext2.MulByNonResidue1Power3(&E2{A0: *tower[8], A1: *tower[9]}) - t5 := e.Ext2.MulByNonResidue1Power5(&E2{A0: *tower[10], A1: *tower[11]}) - - A0 := e.fp.Sub(tower[0], tower[1]) - A1 := e.fp.Sub(&t3.A0, &t3.A1) - A2 := e.fp.Sub(&t1.A0, &t1.A1) - A3 := e.fp.Sub(&t4.A0, &t4.A1) - A4 := e.fp.Sub(&t2.A0, &t2.A1) - A5 := e.fp.Sub(&t5.A0, &t5.A1) - - return &E12{ - A0: *A0, - A1: *A1, - A2: *A2, - A3: *A3, - A4: *A4, - A5: *A5, - A6: *tower[1], - A7: t3.A1, - A8: t1.A1, - A9: t4.A1, - A10: t2.A1, - A11: t5.A1, - } +func (e Ext12) Select(selector frontend.Variable, z1, z0 *E12) *E12 { + c0 := e.Ext6.Select(selector, &z1.C0, &z0.C0) + c1 := e.Ext6.Select(selector, &z1.C1, &z0.C1) + return &E12{C0: *c0, C1: *c1} } -func (e Ext12) FrobeniusSquare(a *E12) *E12 { - tower := e.ToTower(a) - - t1 := e.Ext2.MulByNonResidue2Power2(&E2{A0: *tower[2], A1: *tower[3]}) - t2 := e.Ext2.MulByNonResidue2Power4(&E2{A0: *tower[4], A1: *tower[5]}) - t3 := e.Ext2.MulByNonResidue2Power1(&E2{A0: *tower[6], A1: *tower[7]}) - t4 := e.Ext2.MulByNonResidue2Power3(&E2{A0: *tower[8], A1: *tower[9]}) - t5 := e.Ext2.MulByNonResidue2Power5(&E2{A0: *tower[10], A1: *tower[11]}) - - A0 := e.fp.Sub(tower[0], tower[1]) - A1 := e.fp.Sub(&t3.A0, &t3.A1) - A2 := e.fp.Sub(&t1.A0, &t1.A1) - A3 := e.fp.Sub(&t4.A0, &t4.A1) - A4 := e.fp.Sub(&t2.A0, &t2.A1) - A5 := e.fp.Sub(&t5.A0, &t5.A1) - - return &E12{ - A0: *A0, - A1: *A1, - A2: *A2, - A3: *A3, - A4: *A4, - A5: *A5, - A6: *tower[1], - A7: t3.A1, - A8: t1.A1, - A9: t4.A1, - A10: t2.A1, - A11: t5.A1, - } +func (e Ext12) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E12) *E12 { + c0 := e.Ext6.Lookup2(s1, s2, &a.C0, &b.C0, &c.C0, &d.C0) + c1 := e.Ext6.Lookup2(s1, s2, &a.C1, &b.C1, &c.C1, &d.C1) + return &E12{C0: *c0, C1: *c1} } diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index 1ae94d3dfa..7e4f26d9b4 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -1,22 +1,17 @@ package fields_bls12381 -func (e Ext12) nSquare(z *E12, n int) *E12 { - for i := 0; i < n; i++ { - z = e.Square(z) - } - return z -} +import "github.com/consensys/gnark/std/math/emulated" func (e Ext12) nSquareGS(z *E12, n int) *E12 { for i := 0; i < n; i++ { - z = e.CyclotomicSquareGS(z) + z = e.CyclotomicSquare(z) } return z } -// ExptNeg sets z to x^t in E12 and return z +// Expt sets z to x^t in E12 and return z // where t = -u = 15132376222941642752 -func (e Ext12) ExptNeg(x *E12) *E12 { +func (e Ext12) Expt(x *E12) *E12 { // Expt computation is derived from the addition chain: // // _10 = 2*1 @@ -31,26 +26,108 @@ func (e Ext12) ExptNeg(x *E12) *E12 { // // Generated by github.com/mmcloughlin/addchain v0.4.0. - z := e.Square(x) + z := e.CyclotomicSquare(x) z = e.Mul(x, z) - z = e.nSquare(z, 2) + z = e.nSquareGS(z, 2) z = e.Mul(x, z) - z = e.nSquare(z, 3) + z = e.nSquareGS(z, 3) z = e.Mul(x, z) - z = e.nSquare(z, 9) + z = e.nSquareGS(z, 9) z = e.Mul(x, z) - z = e.nSquare(z, 32) + z = e.nSquareGS(z, 32) + z = e.Mul(x, z) + z = e.nSquareGS(z, 15) + z = e.CyclotomicSquare(z) + + return z +} + +// ExpByU sets z to x^U in E12 and return z +// where U = (u-1)^2/3 = 76329603384216526031706109802092473003 +func (e Ext12) ExpByU(x *E12) *E12 { + // ExpByU computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _110 = 2*_11 + // _111 = 1 + _110 + // _1000 = 1 + _111 + // _100000 = _1000 << 2 + // _100011 = _11 + _100000 + // _101010 = _111 + _100011 + // _1010100 = 2*_101010 + // _1010101 = 1 + _1010100 + // _1010110 = 1 + _1010101 + // _1011001 = _11 + _1010110 + // _1100001 = _1000 + _1011001 + // _10101011 = _1010101 + _1010110 + // _11000010 = 2*_1100001 + // _11100101 = _100011 + _11000010 + // i49 = ((_11100101 << 7 + _1011001) << 5 + _11) << 18 + // i68 = ((_1010101 + i49) << 9 + _10101011) << 7 + _1100001 + // i85 = (i68 << 9 + _10 + _10101011) << 5 + _11 + // i136 = ((i85 << 17 + _1010101) << 9 + _10101011) << 23 + // return (_1010101 + i136) << 9 + _10101011 + // + // Operations: 124 squares 23 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + t2 := e.CyclotomicSquare(x) + t1 := e.Mul(x, t2) + z := e.CyclotomicSquare(t1) z = e.Mul(x, z) - z = e.nSquare(z, 15) - z = e.Square(z) + t3 := e.Mul(x, z) + t0 := e.CyclotomicSquare(t3) + t0 = e.CyclotomicSquare(t0) + t5 := e.Mul(t1, t0) + z = e.Mul(z, t5) + z = e.CyclotomicSquare(z) + t0 = e.Mul(x, z) + z = e.Mul(x, t0) + t4 := e.Mul(t1, z) + t3 = e.Mul(t3, t4) + z = e.Mul(t0, z) + t6 := e.CyclotomicSquare(t3) + t5 = e.Mul(t5, t6) + t5 = e.nSquareGS(t5, 7) + t4 = e.Mul(t4, t5) + t4 = e.nSquareGS(t4, 5) + t4 = e.Mul(t1, t4) + t4 = e.nSquareGS(t4, 18) + t4 = e.Mul(t0, t4) + t4 = e.nSquareGS(t4, 9) + t4 = e.Mul(z, t4) + t4 = e.nSquareGS(t4, 7) + t3 = e.Mul(t3, t4) + t3 = e.nSquareGS(t3, 9) + t2 = e.Mul(t2, t3) + t2 = e.Mul(z, t2) + t2 = e.nSquareGS(t2, 5) + t1 = e.Mul(t1, t2) + t1 = e.nSquareGS(t1, 17) + t1 = e.Mul(t0, t1) + t1 = e.nSquareGS(t1, 9) + t1 = e.Mul(z, t1) + t1 = e.nSquareGS(t1, 23) + t0 = e.Mul(t0, t1) + t0 = e.nSquareGS(t0, 9) + z = e.Mul(z, t0) return z } -// ExptGS sets z to x^t in E12 and return z -// where t = u = -15132376222941642752 -func (e Ext12) ExptGS(x *E12) *E12 { - // ExptGS computation is derived from the addition chain: +func (e Ext12) nSquareTorus(z *E6, n int) *E6 { + for i := 0; i < n; i++ { + z = e.SquareTorus(z) + } + return z +} + +// ExptHalfTorus set z to x^(t/2) in E6 and return z +// const t/2 uint64 = 7566188111470821376 // negative +func (e Ext12) ExptHalfTorus(x *E6) *E6 { + // FixedExp computation is derived from the addition chain: // // _10 = 2*1 // _11 = 1 + _10 @@ -63,97 +140,334 @@ func (e Ext12) ExptGS(x *E12) *E12 { // Operations: 62 squares 5 multiplies // // Generated by github.com/mmcloughlin/addchain v0.4.0. - z := e.ExptHalfGS(x) - z = e.CyclotomicSquareGS(z) + + // Step 1: z = x^0x2 + z := e.SquareTorus(x) + + // Step 2: z = x^0x3 + z = e.MulTorus(x, z) + + z = e.SquareTorus(z) + z = e.SquareTorus(z) + + // Step 5: z = x^0xd + z = e.MulTorus(x, z) + + // Step 8: z = x^0x68 + z = e.nSquareTorus(z, 3) + + // Step 9: z = x^0x69 + z = e.MulTorus(x, z) + + // Step 18: z = x^0xd200 + z = e.nSquareTorus(z, 9) + + // Step 19: z = x^0xd201 + z = e.MulTorus(x, z) + + // Step 51: z = x^0xd20100000000 + z = e.nSquareTorus(z, 32) + + // Step 52: z = x^0xd20100000001 + z = e.MulTorus(x, z) + + // Step 67: z = x^0x6900800000008000 + z = e.nSquareTorus(z, 15) + + z = e.InverseTorus(z) // because tAbsVal is negative + return z } -func (e Ext12) ExptHalfGS(x *E12) *E12 { - z := e.CyclotomicSquareGS(x) - z = e.Mul(x, z) - z = e.nSquareGS(z, 2) - z = e.Mul(x, z) - z = e.nSquareGS(z, 3) - z = e.Mul(x, z) - z = e.nSquareGS(z, 9) - z = e.Mul(x, z) - z = e.nSquareGS(z, 32) - z = e.Mul(x, z) - z = e.nSquareGS(z, 15) - z = e.Conjugate(z) - +// ExptTorus set z to xᵗ in E6 and return z +// const t uint64 = 15132376222941642752 // negative +func (e Ext12) ExptTorus(x *E6) *E6 { + z := e.ExptHalfTorus(x) + z = e.SquareTorus(z) return z } -// MulBy02368 multiplies a by an E12 sparse element b of the form +// MulBy014 multiplies z by an E12 sparse element of the form // -// b.A0 = c00 - c01 -// b.A1 = 0 -// b.A2 = c10 - c11 -// b.A3 = 1 -// b.A4 = 0 -// b.A5 = 0 -// b.A6 = c01 -// b.A7 = 0 -// b.A8 = c11 -// b.A9 = 0 -// b.A10 = 0 -// b.A11 = 0 -func (e *Ext12) MulBy02368(a *E12, c0, c1 *E2) *E12 { - b0 := e.fp.Sub(&c0.A0, &c0.A1) - b2 := e.fp.Sub(&c1.A0, &c1.A1) - b6 := &c0.A1 - b8 := &c1.A1 - mone := e.fp.NewElement(-1) +// E12{ +// C0: E6{B0: c0, B1: c1, B2: 0}, +// C1: E6{B0: 0, B1: 1, B2: 0}, +// } +func (e *Ext12) MulBy014(z *E12, c0, c1 *E2) *E12 { - // d0 = a0 b0 - 2 * (a4 b8 + a6 b6 + a10 b2 + a9) - 4 * a10 b8 - d0 := e.fp.Eval([][]*baseEl{{&a.A0, b0}, {mone, &a.A4, b8}, {mone, &a.A6, b6}, {mone, &a.A9}, {mone, &a.A10, b2}, {mone, &a.A10, b8}}, []int{1, 2, 2, 2, 2, 4}) + a := e.MulBy01(&z.C0, c0, c1) - // d1 = a1 b0 - 2 * (a5 b8 + a7 b6 + a11 b2 + a10) - 4 * a11 b8 - d1 := e.fp.Eval([][]*baseEl{{&a.A1, b0}, {mone, &a.A5, b8}, {mone, &a.A7, b6}, {mone, &a.A10}, {mone, &a.A11, b2}, {mone, &a.A11, b8}}, []int{1, 2, 2, 2, 2, 4}) + var b E6 + // Mul by E6{0, 1, 0} + b.B0 = *e.Ext2.MulByNonResidue(&z.C1.B2) + b.B2 = z.C1.B1 + b.B1 = z.C1.B0 - // d2 = a0 b2 + a2 b0 - 2 * (a6 b8 + a8 b6 + a11) - d2 := e.fp.Eval([][]*baseEl{{&a.A0, b2}, {&a.A2, b0}, {mone, &a.A6, b8}, {mone, &a.A8, b6}, {mone, &a.A11}}, []int{1, 1, 2, 2, 2}) + one := e.Ext2.One() + d := e.Ext2.Add(c1, one) - // d3 = a0 + a1 b2 + a3 b0 - 2 * (a7 b8 + a9 b6) - d3 := e.fp.Eval([][]*baseEl{{&a.A0}, {&a.A1, b2}, {&a.A3, b0}, {mone, &a.A7, b8}, {mone, &a.A9, b6}}, []int{1, 1, 1, 2, 2}) + zC1 := e.Ext6.Add(&z.C1, &z.C0) + zC1 = e.Ext6.MulBy01(zC1, c0, d) + tmp := e.Ext6.Add(&b, a) + zC1 = e.Ext6.Sub(zC1, tmp) + zC0 := e.Ext6.MulByNonResidue(&b) + zC0 = e.Ext6.Add(zC0, a) - // d4 = a1 + a2 b2 + a4 b0 - 2 * (a8 b8 + a10 b6) - d4 := e.fp.Eval([][]*baseEl{{&a.A1}, {&a.A2, b2}, {&a.A4, b0}, {mone, &a.A8, b8}, {mone, &a.A10, b6}}, []int{1, 1, 1, 2, 2}) + return &E12{ + C0: *zC0, + C1: *zC1, + } +} - // d5 = a2 + a3 b2 + a5 b0 - 2 * (a9 b8 + a11 b6) - d5 := e.fp.Eval([][]*baseEl{{&a.A2}, {&a.A3, b2}, {&a.A5, b0}, {mone, &a.A9, b8}, {mone, &a.A11, b6}}, []int{1, 1, 1, 2, 2}) +// multiplies two E12 sparse element of the form: +// +// E12{ +// C0: E6{B0: c0, B1: c1, B2: 0}, +// C1: E6{B0: 0, B1: 1, B2: 0}, +// } +// +// and +// +// E12{ +// C0: E6{B0: d0, B1: d1, B2: 0}, +// C1: E6{B0: 0, B1: 1, B2: 0}, +// } +func (e Ext12) Mul014By014(d0, d1, c0, c1 *E2) [5]*E2 { + x0 := e.Ext2.Mul(c0, d0) + x1 := e.Ext2.Mul(c1, d1) + x04 := e.Ext2.Add(c0, d0) + tmp := e.Ext2.Add(c0, c1) + x01 := e.Ext2.Add(d0, d1) + x01 = e.Ext2.Mul(x01, tmp) + tmp = e.Ext2.Add(x1, x0) + x01 = e.Ext2.Sub(x01, tmp) + x14 := e.Ext2.Add(c1, d1) + + zC0B0 := e.Ext2.NonResidue() + zC0B0 = e.Ext2.Add(zC0B0, x0) + + return [5]*E2{zC0B0, x01, x1, x04, x14} +} + +// MulBy01245 multiplies z by an E12 sparse element of the form +// +// E12{ +// C0: E6{B0: c0, B1: c1, B2: c2}, +// C1: E6{B0: 0, B1: c4, B2: c5}, +// } +func (e *Ext12) MulBy01245(z *E12, x [5]*E2) *E12 { + c0 := &E6{B0: *x[0], B1: *x[1], B2: *x[2]} + c1 := &E6{B0: *e.Ext2.Zero(), B1: *x[3], B2: *x[4]} + a := e.Ext6.Add(&z.C0, &z.C1) + b := e.Ext6.Add(c0, c1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&z.C0, c0) + c := e.Ext6.MulBy12(&z.C1, x[3], x[4]) + d := e.Ext6.Add(c, b) + z1 := e.Ext6.Sub(a, d) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +// Torus-based arithmetic: +// +// After the easy part of the final exponentiation the elements are in a proper +// subgroup of Fpk (E12) that coincides with some algebraic tori. The elements +// are in the torus Tk(Fp) and thus in each torus Tk/d(Fp^d) for d|k, d≠k. We +// take d=6. So the elements are in T2(Fp6). +// Let G_{q,2} = {m ∈ Fq^2 | m^(q+1) = 1} where q = p^6. +// When m.C1 = 0, then m.C0 must be 1 or −1. +// +// We recall the tower construction: +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-1-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v + +// CompressTorus compresses x ∈ E12 to (x.C0 + 1)/x.C1 ∈ E6 +func (e Ext12) CompressTorus(x *E12) *E6 { + // x ∈ G_{q,2} \ {-1,1} + y := e.Ext6.Add(&x.C0, e.Ext6.One()) + y = e.Ext6.DivUnchecked(y, &x.C1) + return y +} + +// DecompressTorus decompresses y ∈ E6 to (y+w)/(y-w) ∈ E12 +func (e Ext12) DecompressTorus(y *E6) *E12 { + var n, d E12 + one := e.Ext6.One() + n.C0 = *y + n.C1 = *one + d.C0 = *y + d.C1 = *e.Ext6.Neg(one) + + x := e.DivUnchecked(&n, &d) + return x +} + +// MulTorus multiplies two compressed elements y1, y2 ∈ E6 +// and returns (y1 * y2 + v)/(y1 + y2) +// N.B.: we use MulTorus in the final exponentiation throughout y1 ≠ -y2 always. +func (e Ext12) MulTorus(y1, y2 *E6) *E6 { + n := e.Ext6.Mul(y1, y2) + n.B1 = *e.Ext2.Add(&n.B1, e.Ext2.One()) + d := e.Ext6.Add(y1, y2) + y3 := e.Ext6.DivUnchecked(n, d) + return y3 +} + +// InverseTorus inverses a compressed elements y ∈ E6 +// and returns -y +func (e Ext12) InverseTorus(y *E6) *E6 { + return e.Ext6.Neg(y) +} + +// SquareTorus squares a compressed elements y ∈ E6 +// and returns (y + v/y)/2 +// +// It uses a hint to verify that (2x-y)y = v saving one E6 AssertIsEqual. +func (e Ext12) SquareTorus(y *E6) *E6 { + res, err := e.fp.NewHint(squareTorusHint, 6, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } - // d6 = a0 b6 + a3 + a4 b2 + a6 b0 + 2 * (a4 b8 + a6 b6 + a9 + a10 b2 + a10 b8) - d6 := e.fp.Eval([][]*baseEl{{&a.A0, b6}, {&a.A3}, {&a.A4, b2}, {&a.A6, b0}, {&a.A4, b8}, {&a.A6, b6}, {&a.A9}, {&a.A10, b2}, {&a.A10, b8}}, []int{1, 1, 1, 1, 2, 2, 2, 2, 2}) + sq := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } - // d7 = a1 b6 + a4 + a5 b2 + a7 b0 + 2 * (a5 b8 + a7 b6 + a10 + a11 b2 + a11 b8) - d7 := e.fp.Eval([][]*baseEl{{&a.A1, b6}, {&a.A4}, {&a.A5, b2}, {&a.A7, b0}, {&a.A5, b8}, {&a.A7, b6}, {&a.A10}, {&a.A11, b2}, {&a.A11, b8}}, []int{1, 1, 1, 1, 2, 2, 2, 2, 2}) + // v = (2x-y)y + v := e.Ext6.Double(&sq) + v = e.Ext6.Sub(v, y) + v = e.Ext6.Mul(v, y) - // d8 = a0 b8 + a2 b6 + a5 + a6 b2 + a8 b0 + 2 * (a6 b8 + a8 b6 + a11) - d8 := e.fp.Eval([][]*baseEl{{&a.A0, b8}, {&a.A2, b6}, {&a.A5}, {&a.A6, b2}, {&a.A8, b0}, {&a.A6, b8}, {&a.A8, b6}, {&a.A11}}, []int{1, 1, 1, 1, 1, 2, 2, 2}) + _v := E6{B0: *e.Ext2.Zero(), B1: *e.Ext2.One(), B2: *e.Ext2.Zero()} + e.Ext6.AssertIsEqual(v, &_v) - // d9 = a1 b8 + a3 b6 + a6 + a7 b2 + a9 b0 + 2 * (a7 b8 + a9 b6) - d9 := e.fp.Eval([][]*baseEl{{&a.A1, b8}, {&a.A3, b6}, {&a.A6}, {&a.A7, b2}, {&a.A9, b0}, {&a.A7, b8}, {&a.A9, b6}}, []int{1, 1, 1, 1, 1, 2, 2}) + return &sq - // d10 = a2 b8 + a4 b6 + a7 + a8 b2 + a10 b0 + 2 * (a8 b8 + a10 b6) - d10 := e.fp.Eval([][]*baseEl{{&a.A2, b8}, {&a.A4, b6}, {&a.A7}, {&a.A8, b2}, {&a.A10, b0}, {&a.A8, b8}, {&a.A10, b6}}, []int{1, 1, 1, 1, 1, 2, 2}) +} - // d11 = a3 b8 + a5 b6 + a8 + a9 b2 + a11 b0 + 2 * (a9 b8 + a11 b6) - d11 := e.fp.Eval([][]*baseEl{{&a.A3, b8}, {&a.A5, b6}, {&a.A8}, {&a.A9, b2}, {&a.A11, b0}, {&a.A9, b8}, {&a.A11, b6}}, []int{1, 1, 1, 1, 1, 2, 2}) +// FrobeniusTorus raises a compressed elements y ∈ E6 to the modulus p +// and returns y^p / v^((p-1)/2) +func (e Ext12) FrobeniusTorus(y *E6) *E6 { + t0 := e.Ext2.Conjugate(&y.B0) + t1 := e.Ext2.Conjugate(&y.B1) + t2 := e.Ext2.Conjugate(&y.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) + + v0 := E2{emulated.ValueOf[emulated.BLS12381Fp]("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230"), emulated.ValueOf[emulated.BLS12381Fp]("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230")} + res := &E6{B0: *t0, B1: *t1, B2: *t2} + res = e.Ext6.MulBy0(res, &v0) + + return res +} + +// FrobeniusSquareTorus raises a compressed elements y ∈ E6 to the square modulus p^2 +// and returns y^(p^2) / v^((p^2-1)/2) +func (e Ext12) FrobeniusSquareTorus(y *E6) *E6 { + v0 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + t0 := e.Ext2.MulByElement(&y.B0, &v0) + t1 := e.Ext2.MulByNonResidue2Power2(&y.B1) + t1 = e.Ext2.MulByElement(t1, &v0) + t2 := e.Ext2.MulByNonResidue2Power4(&y.B2) + t2 = e.Ext2.MulByElement(t2, &v0) + + return &E6{B0: *t0, B1: *t1, B2: *t2} +} + +// AssertFinalExponentiationIsOne checks that a Miller function output x lies in the +// same equivalence class as the reduced pairing. This replaces the final +// exponentiation step in-circuit. +// The method is inspired from [On Proving Pairings] paper by A. Novakovic and +// L. Eagen, and is based on a personal communication with A. Novakovic. +// +// [On Proving Pairings]: https://eprint.iacr.org/2024/640.pdf +func (e Ext12) AssertFinalExponentiationIsOne(x *E12) { + res, err := e.fp.NewHint(finalExpHint, 18, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + residueWitness := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + // constrain cubicNonResiduePower to be in Fp6 + scalingFactor := E6{ + B0: E2{A0: *res[12], A1: *res[13]}, + B1: E2{A0: *res[14], A1: *res[15]}, + B2: E2{A0: *res[16], A1: *res[17]}, + } + + // Check that x * scalingFactor == residueWitness^(q-u) + // where u=-0xd201000000010000 is the BLS12-381 seed, + // and residueWitness, scalingFactor from the hint. + t0 := e.Frobenius(&residueWitness) + // exponentiation by -u + t1 := e.Expt(&residueWitness) + t0 = e.Mul(t0, t1) + + t1 = &E12{ + C0: *e.Ext6.Mul(&x.C0, &scalingFactor), + C1: *e.Ext6.Mul(&x.C1, &scalingFactor), + } + + e.AssertIsEqual(t0, t1) +} + +func (e Ext12) Frobenius(x *E12) *E12 { + t0 := e.Ext2.Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) + t3 = e.Ext2.MulByNonResidue1Power1(t3) + t4 = e.Ext2.MulByNonResidue1Power3(t4) + t5 = e.Ext2.MulByNonResidue1Power5(t5) + return &E12{ + C0: E6{ + B0: *t0, + B1: *t1, + B2: *t2, + }, + C1: E6{ + B0: *t3, + B1: *t4, + B2: *t5, + }, + } +} +func (e Ext12) FrobeniusSquare(x *E12) *E12 { + z00 := &x.C0.B0 + z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) return &E12{ - A0: *d0, - A1: *d1, - A2: *d2, - A3: *d3, - A4: *d4, - A5: *d5, - A6: *d6, - A7: *d7, - A8: *d8, - A9: *d9, - A10: *d10, - A11: *d11, + C0: E6{B0: *z00, B1: *z01, B2: *z02}, + C1: E6{B0: *z10, B1: *z11, B2: *z12}, } } diff --git a/std/algebra/emulated/fields_bls12381/e12_test.go b/std/algebra/emulated/fields_bls12381/e12_test.go index 5a75b1f807..cba62ef2be 100644 --- a/std/algebra/emulated/fields_bls12381/e12_test.go +++ b/std/algebra/emulated/fields_bls12381/e12_test.go @@ -1,7 +1,6 @@ package fields_bls12381 import ( - "math/big" "testing" "github.com/consensys/gnark-crypto/ecc" @@ -10,34 +9,6 @@ import ( "github.com/consensys/gnark/test" ) -type e12Convert struct { - A E12 -} - -func (circuit *e12Convert) Define(api frontend.API) error { - e := NewExt12(api) - tower := e.ToTower(&circuit.A) - expected := e.FromTower(tower) - e.AssertIsEqual(expected, &circuit.A) - return nil -} - -func TestConvertFp12(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a bls12381.E12 - _, _ = a.SetRandom() - - witness := e12Convert{ - A: FromE12(&a), - } - - err := test.IsSolved(&e12Convert{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - type e12Add struct { A, B, C E12 } @@ -131,6 +102,37 @@ func TestMulFp12(t *testing.T) { } +type e12Div struct { + A, B, C E12 +} + +func (circuit *e12Div) Define(api frontend.API) error { + e := NewExt12(api) + expected := e.DivUnchecked(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e12Div{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Div{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e12Square struct { A, C E12 } @@ -160,18 +162,81 @@ func TestSquareFp12(t *testing.T) { } -type e12SquareGS struct { - A, C E12 +type e12Conjugate struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12SquareGS) Define(api frontend.API) error { +func (circuit *e12Conjugate) Define(api frontend.API) error { e := NewExt12(api) - expected := e.CyclotomicSquareGS(&circuit.A) + expected := e.Conjugate(&circuit.A) e.AssertIsEqual(expected, &circuit.C) + return nil } -func TestSquareGSFp12(t *testing.T) { +func TestConjugateFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.Conjugate(&a) + + witness := e12Conjugate{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12Inverse struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Inverse) Define(api frontend.API) error { + e := NewExt12(api) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e12Inverse{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12ExptTorus struct { + A E6 + C E12 `gnark:",public"` +} + +func (circuit *e12ExptTorus) Define(api frontend.API) error { + e := NewExt12(api) + z := e.ExptTorus(&circuit.A) + expected := e.DecompressTorus(z) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestFp12ExptTorus(t *testing.T) { assert := test.NewAssert(t) // witness values @@ -185,272 +250,332 @@ func TestSquareGSFp12(t *testing.T) { tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.CyclotomicSquare(&a) - - witness := e12SquareGS{ - A: FromE12(&a), + c.Expt(&a) + _a, _ := a.CompressTorus() + witness := e12ExptTorus{ + A: FromE6(&_a), C: FromE12(&c), } - err := test.IsSolved(&e12SquareGS{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&e12ExptTorus{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - } -type e12Div struct { - A, B, C E12 +type e12MulBy014 struct { + A E12 `gnark:",public"` + W E12 + B, C E2 } -func (circuit *e12Div) Define(api frontend.API) error { +func (circuit *e12MulBy014) Define(api frontend.API) error { e := NewExt12(api) - expected := e.DivUnchecked(&circuit.A, &circuit.B) - e.AssertIsEqual(expected, &circuit.C) + res := e.MulBy014(&circuit.A, &circuit.B, &circuit.C) + e.AssertIsEqual(res, &circuit.W) return nil } -func TestDivFp12(t *testing.T) { +func TestFp12MulBy014(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, b, c bls12381.E12 + var a, w bls12381.E12 _, _ = a.SetRandom() + var one, b, c bls12381.E2 + one.SetOne() _, _ = b.SetRandom() - c.Div(&a, &b) + _, _ = c.SetRandom() + w.Set(&a) + w.MulBy014(&b, &c, &one) - witness := e12Div{ + witness := e12MulBy014{ A: FromE12(&a), - B: FromE12(&b), - C: FromE12(&c), + B: FromE2(&b), + C: FromE2(&c), + W: FromE12(&w), } - err := test.IsSolved(&e12Div{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&e12MulBy014{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Conjugate struct { +// Torus-based arithmetic +type torusCompress struct { A E12 - C E12 `gnark:",public"` + C E6 `gnark:",public"` } -func (circuit *e12Conjugate) Define(api frontend.API) error { +func (circuit *torusCompress) Define(api frontend.API) error { e := NewExt12(api) - expected := e.Conjugate(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - + expected := e.CompressTorus(&circuit.A) + e.Ext6.AssertIsEqual(expected, &circuit.C) return nil } -func TestConjugateFp12(t *testing.T) { +func TestTorusCompress(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a bls12381.E12 _, _ = a.SetRandom() - c.Conjugate(&a) - witness := e12Conjugate{ + // put a in the cyclotomic subgroup + var tmp bls12381.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + c, _ := a.CompressTorus() + + witness := torusCompress{ A: FromE12(&a), - C: FromE12(&c), + C: FromE6(&c), } - err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusCompress{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Inverse struct { +type torusDecompress struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12Inverse) Define(api frontend.API) error { +func (circuit *torusDecompress) Define(api frontend.API) error { e := NewExt12(api) - expected := e.Inverse(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestInverseFp12(t *testing.T) { +func TestTorusDecompress(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a bls12381.E12 _, _ = a.SetRandom() - c.Inverse(&a) - witness := e12Inverse{ + // put a in the cyclotomic subgroup + var tmp bls12381.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + d, _ := a.CompressTorus() + c := d.DecompressTorus() + + witness := torusDecompress{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusDecompress{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type Frobenius struct { +type torusMul struct { A E12 + B E12 C E12 `gnark:",public"` } -func (circuit *Frobenius) Define(api frontend.API) error { +func (circuit *torusMul) Define(api frontend.API) error { e := NewExt12(api) - expected := e.Frobenius(&circuit.A) + compressedA := e.CompressTorus(&circuit.A) + compressedB := e.CompressTorus(&circuit.B) + compressedAB := e.MulTorus(compressedA, compressedB) + expected := e.DecompressTorus(compressedAB) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFrobenius(t *testing.T) { +func TestTorusMul(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, b, c, tmp bls12381.E12 _, _ = a.SetRandom() + _, _ = b.SetRandom() - c.Frobenius(&a) + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + // put b in the cyclotomic subgroup + tmp.Conjugate(&b) + b.Inverse(&b) + tmp.Mul(&tmp, &b) + b.FrobeniusSquare(&tmp).Mul(&b, &tmp) + + // uncompressed mul + c.Mul(&a, &b) - witness := Frobenius{ + witness := torusMul{ A: FromE12(&a), + B: FromE12(&b), C: FromE12(&c), } - err := test.IsSolved(&Frobenius{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusMul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type FrobeniusSquare struct { +type torusInverse struct { A E12 C E12 `gnark:",public"` } -func (circuit *FrobeniusSquare) Define(api frontend.API) error { +func (circuit *torusInverse) Define(api frontend.API) error { e := NewExt12(api) - expected := e.FrobeniusSquare(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.InverseTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFrobeniusSquare(t *testing.T) { +func TestTorusInverse(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() - c.FrobeniusSquare(&a) + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - witness := FrobeniusSquare{ + // uncompressed inverse + c.Inverse(&a) + + witness := torusInverse{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&FrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusInverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Expt struct { +type torusFrobenius struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12Expt) Define(api frontend.API) error { +func (circuit *torusFrobenius) Define(api frontend.API) error { e := NewExt12(api) - expected := e.ExptNeg(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestFp12Expt(t *testing.T) { +func TestTorusFrobenius(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() - var xGen big.Int - xGen.SetString("15132376222941642752", 10) - c.Exp(a, &xGen) - witness := e12Expt{ + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobenius + c.Frobenius(&a) + + witness := torusFrobenius{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusFrobenius{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12ExptGS struct { +type torusFrobeniusSquare struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12ExptGS) Define(api frontend.API) error { +func (circuit *torusFrobeniusSquare) Define(api frontend.API) error { e := NewExt12(api) - expected := e.ExptGS(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusSquareTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestFp12ExptGS(t *testing.T) { +func TestTorusFrobeniusSquare(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() // put a in the cyclotomic subgroup - var tmp bls12381.E12 tmp.Conjugate(&a) a.Inverse(&a) tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.Expt(&a) - witness := e12ExptGS{ + // uncompressed frobeniusSquare + c.FrobeniusSquare(&a) + + witness := torusFrobeniusSquare{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12ExptGS{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusFrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12MulBy02368 struct { - A E12 `gnark:",public"` - W E12 - B, C E2 +type torusSquare struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12MulBy02368) Define(api frontend.API) error { +func (circuit *torusSquare) Define(api frontend.API) error { e := NewExt12(api) - res := e.MulBy02368(&circuit.A, &circuit.B, &circuit.C) - e.AssertIsEqual(res, &circuit.W) + compressed := e.CompressTorus(&circuit.A) + compressed = e.SquareTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFp12MulBy02368(t *testing.T) { +func TestTorusSquare(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, w bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() - var one, b, c bls12381.E2 - one.SetOne() - _, _ = b.SetRandom() - _, _ = c.SetRandom() - w.Set(&a) - w.MulBy014(&b, &c, &one) - witness := e12MulBy02368{ + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed square + c.Square(&a) + + witness := torusSquare{ A: FromE12(&a), - B: FromE2(&b), - C: FromE2(&c), - W: FromE12(&w), + C: FromE12(&c), } - err := test.IsSolved(&e12MulBy02368{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - } diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go index ba378f6796..30b5ebda49 100644 --- a/std/algebra/emulated/fields_bls12381/e2.go +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -184,10 +184,16 @@ func (e Ext2) MulByNonResidue2Power5(x *E2) *E2 { } func (e Ext2) Mul(x, y *E2) *E2 { - // b0 = x0*y0 - x1*y1 - b0 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A0}, {e.fp.NewElement(-1), &x.A1, &y.A1}}, []int{1, 1}) - // b1 = x0*y1 + x1*y0 - b1 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A1}, {&x.A1, &y.A0}}, []int{1, 1}) + + v0 := e.fp.Mul(&x.A0, &y.A0) + v1 := e.fp.Mul(&x.A1, &y.A1) + + b0 := e.fp.Sub(v0, v1) + b1 := e.fp.Add(&x.A0, &x.A1) + tmp := e.fp.Add(&y.A0, &y.A1) + b1 = e.fp.Mul(b1, tmp) + tmp = e.fp.Add(v0, v1) + b1 = e.fp.Sub(b1, tmp) return &E2{ A0: *b0, @@ -256,27 +262,17 @@ func (e Ext2) NonResidue() *E2 { } func (e Ext2) Square(x *E2) *E2 { - // a = (x0+x1)(x0-x1) = x0^2 - x1^2 - a := e.fp.Eval([][]*baseEl{{&x.A0, &x.A0}, {e.fp.NewElement(-1), &x.A1, &x.A1}}, []int{1, 1}) - // b = 2*x0*x1 - b := e.fp.Eval([][]*baseEl{{&x.A0, &x.A1}}, []int{2}) + a := e.fp.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) + a = e.fp.Mul(a, b) + b = e.fp.Mul(&x.A0, &x.A1) + b = e.fp.MulConst(b, big.NewInt(2)) return &E2{ A0: *a, A1: *b, } } -func (e Ext2) Cube(x *E2) *E2 { - mone := e.fp.NewElement(-1) - // a = x0^3 - 3*x0*x1^2 - a := e.fp.Eval([][]*baseEl{{&x.A0, &x.A0, &x.A0}, {mone, &x.A0, &x.A1, &x.A1}}, []int{1, 3}) - // b = 3*x1*x0^2 - x1^3 - b := e.fp.Eval([][]*baseEl{{&x.A1, &x.A0, &x.A0}, {mone, &x.A1, &x.A1, &x.A1}}, []int{3, 1}) - return &E2{ - A0: *a, - A1: *b, - } -} func (e Ext2) Double(x *E2) *E2 { two := big.NewInt(2) z0 := e.fp.MulConst(&x.A0, two) diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go new file mode 100644 index 0000000000..22a3596324 --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -0,0 +1,465 @@ +package fields_bls12381 + +import ( + "math/big" + + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/frontendtype" +) + +type E6 struct { + B0, B1, B2 E2 +} + +type Ext6 struct { + *Ext2 +} + +func NewExt6(api frontend.API) *Ext6 { + return &Ext6{Ext2: NewExt2(api)} +} + +func (e Ext6) One() *E6 { + z0 := e.Ext2.One() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Zero() *E6 { + z0 := e.Ext2.Zero() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) IsZero(z *E6) frontend.Variable { + b0 := e.Ext2.IsZero(&z.B0) + b1 := e.Ext2.IsZero(&z.B1) + b2 := e.Ext2.IsZero(&z.B2) + return e.api.And(e.api.And(b0, b1), b2) +} + +func (e Ext6) Add(x, y *E6) *E6 { + z0 := e.Ext2.Add(&x.B0, &y.B0) + z1 := e.Ext2.Add(&x.B1, &y.B1) + z2 := e.Ext2.Add(&x.B2, &y.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Neg(x *E6) *E6 { + z0 := e.Ext2.Neg(&x.B0) + z1 := e.Ext2.Neg(&x.B1) + z2 := e.Ext2.Neg(&x.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Sub(x, y *E6) *E6 { + z0 := e.Ext2.Sub(&x.B0, &y.B0) + z1 := e.Ext2.Sub(&x.B1, &y.B1) + z2 := e.Ext2.Sub(&x.B2, &y.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +// Mul multiplies two E6 elmts +func (e Ext6) Mul(x, y *E6) *E6 { + if ft, ok := e.api.(frontendtype.FrontendTyper); ok { + switch ft.FrontendType() { + case frontendtype.R1CS: + return e.mulToom3OverKaratsuba(x, y) + case frontendtype.SCS: + return e.mulKaratsubaOverKaratsuba(x, y) + } + } + return e.mulKaratsubaOverKaratsuba(x, y) +} + +func (e Ext6) mulToom3OverKaratsuba(x, y *E6) *E6 { + // Toom-Cook-3x over Karatsuba: + // We start by computing five interpolation points – these are evaluations of + // the product x(u)y(u) with u ∈ {0, ±1, 2, ∞}: + // + // v0 = x(0)y(0) = x.A0 * y.A0 + // v1 = x(1)y(1) = (x.A0 + x.A1 + x.A2)(y.A0 + y.A1 + y.A2) + // v2 = x(−1)y(−1) = (x.A0 − x.A1 + x.A2)(y.A0 − y.A1 + y.A2) + // v3 = x(2)y(2) = (x.A0 + 2x.A1 + 4x.A2)(y.A0 + 2y.A1 + 4y.A2) + // v4 = x(∞)y(∞) = x.A2 * y.A2 + + v0 := e.Ext2.Mul(&x.B0, &y.B0) + + t1 := e.Ext2.Add(&x.B0, &x.B2) + t2 := e.Ext2.Add(&y.B0, &y.B2) + t3 := e.Ext2.Add(t2, &y.B1) + v1 := e.Ext2.Add(t1, &x.B1) + v1 = e.Ext2.Mul(v1, t3) + + t3 = e.Ext2.Sub(t2, &y.B1) + v2 := e.Ext2.Sub(t1, &x.B1) + v2 = e.Ext2.Mul(v2, t3) + + t1 = e.Ext2.MulByConstElement(&x.B1, big.NewInt(2)) + t2 = e.Ext2.MulByConstElement(&x.B2, big.NewInt(4)) + v3 := e.Ext2.Add(t1, t2) + v3 = e.Ext2.Add(v3, &x.B0) + t1 = e.Ext2.MulByConstElement(&y.B1, big.NewInt(2)) + t2 = e.Ext2.MulByConstElement(&y.B2, big.NewInt(4)) + t3 = e.Ext2.Add(t1, t2) + t3 = e.Ext2.Add(t3, &y.B0) + v3 = e.Ext2.Mul(v3, t3) + + v4 := e.Ext2.Mul(&x.B2, &y.B2) + + // Then the interpolation is performed as: + // + // a0 = v0 + β((1/2)v0 − (1/2)v1 − (1/6)v2 + (1/6)v3 − 2v4) + // a1 = −(1/2)v0 + v1 − (1/3)v2 − (1/6)v3 + 2v4 + βv4 + // a2 = −v0 + (1/2)v1 + (1/2)v2 − v4 + // + // where β is the cubic non-residue. + // + // In-circuit, we compute 6*x*y as + // c0 = 6v0 + β(3v0 − 3v1 − v2 + v3 − 12v4) + // a1 = -(3v0 + 2v2 + v3) + 6(v1 + 2v4 + βv4) + // a2 = 3(v1 + v2 - 2(v0 + v4)) + // + // and then divide a0, a1 and a2 by 6 using a hint. + + a0 := e.Ext2.MulByConstElement(v0, big.NewInt(6)) + t1 = e.Ext2.Sub(v0, v1) + t1 = e.Ext2.MulByConstElement(t1, big.NewInt(3)) + t1 = e.Ext2.Sub(t1, v2) + t1 = e.Ext2.Add(t1, v3) + t2 = e.Ext2.MulByConstElement(v4, big.NewInt(12)) + t1 = e.Ext2.Sub(t1, t2) + t1 = e.Ext2.MulByNonResidue(t1) + a0 = e.Ext2.Add(a0, t1) + + a1 := e.Ext2.MulByConstElement(v0, big.NewInt(3)) + t1 = e.Ext2.MulByConstElement(v2, big.NewInt(2)) + a1 = e.Ext2.Add(a1, t1) + a1 = e.Ext2.Add(a1, v3) + t1 = e.Ext2.MulByConstElement(v4, big.NewInt(2)) + t1 = e.Ext2.Add(t1, v1) + t2 = e.Ext2.MulByNonResidue(v4) + t1 = e.Ext2.Add(t1, t2) + t1 = e.Ext2.MulByConstElement(t1, big.NewInt(6)) + a1 = e.Ext2.Sub(t1, a1) + + a2 := e.Ext2.Add(v1, v2) + a2 = e.Ext2.MulByConstElement(a2, big.NewInt(3)) + t1 = e.Ext2.Add(v0, v4) + t1 = e.Ext2.MulByConstElement(t1, big.NewInt(6)) + a2 = e.Ext2.Sub(a2, t1) + + res := e.divE6By6([6]*baseEl{&a0.A0, &a0.A1, &a1.A0, &a1.A1, &a2.A0, &a2.A1}) + return &E6{ + B0: E2{ + A0: *res[0], + A1: *res[1], + }, + B1: E2{ + A0: *res[2], + A1: *res[3], + }, + B2: E2{ + A0: *res[4], + A1: *res[5], + }, + } +} + +func (e Ext6) mulKaratsubaOverKaratsuba(x, y *E6) *E6 { + // Karatsuba over Karatsuba: + // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + t0 := e.Ext2.Mul(&x.B0, &y.B0) + t1 := e.Ext2.Mul(&x.B1, &y.B1) + t2 := e.Ext2.Mul(&x.B2, &y.B2) + c0 := e.Ext2.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(&y.B1, &y.B2) + c0 = e.Ext2.Mul(c0, tmp) + tmp = e.Ext2.Add(t2, t1) + c0 = e.Ext2.Sub(c0, tmp) + c0 = e.Ext2.MulByNonResidue(c0) + c0 = e.Ext2.Add(c0, t0) + c1 := e.Ext2.Add(&x.B0, &x.B1) + tmp = e.Ext2.Add(&y.B0, &y.B1) + c1 = e.Ext2.Mul(c1, tmp) + tmp = e.Ext2.Add(t0, t1) + c1 = e.Ext2.Sub(c1, tmp) + tmp = e.Ext2.MulByNonResidue(t2) + c1 = e.Ext2.Add(c1, tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) + c2 := e.Ext2.Add(&y.B0, &y.B2) + c2 = e.Ext2.Mul(c2, tmp) + tmp = e.Ext2.Add(t0, t2) + c2 = e.Ext2.Sub(c2, tmp) + c2 = e.Ext2.Add(c2, t1) + return &E6{ + B0: *c0, + B1: *c1, + B2: *c2, + } +} + +func (e Ext6) Double(x *E6) *E6 { + z0 := e.Ext2.Double(&x.B0) + z1 := e.Ext2.Double(&x.B1) + z2 := e.Ext2.Double(&x.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Square(x *E6) *E6 { + c4 := e.Ext2.Mul(&x.B0, &x.B1) + c4 = e.Ext2.Double(c4) + c5 := e.Ext2.Square(&x.B2) + c1 := e.Ext2.MulByNonResidue(c5) + c1 = e.Ext2.Add(c1, c4) + c2 := e.Ext2.Sub(c4, c5) + c3 := e.Ext2.Square(&x.B0) + c4 = e.Ext2.Sub(&x.B0, &x.B1) + c4 = e.Ext2.Add(c4, &x.B2) + c5 = e.Ext2.Mul(&x.B1, &x.B2) + c5 = e.Ext2.Double(c5) + c4 = e.Ext2.Square(c4) + c0 := e.Ext2.MulByNonResidue(c5) + c0 = e.Ext2.Add(c0, c3) + z2 := e.Ext2.Add(c2, c4) + z2 = e.Ext2.Add(z2, c5) + z2 = e.Ext2.Sub(z2, c3) + z0 := c0 + z1 := c1 + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulByE2(x *E6, y *E2) *E6 { + z0 := e.Ext2.Mul(&x.B0, y) + z1 := e.Ext2.Mul(&x.B1, y) + z2 := e.Ext2.Mul(&x.B2, y) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +// MulBy12 multiplication by sparse element (0,b1,b2) +func (e Ext6) MulBy12(x *E6, b1, b2 *E2) *E6 { + t1 := e.Ext2.Mul(&x.B1, b1) + t2 := e.Ext2.Mul(&x.B2, b2) + c0 := e.Ext2.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(b1, b2) + c0 = e.Ext2.Mul(c0, tmp) + tmp = e.Ext2.Add(t1, t2) + c0 = e.Ext2.Sub(c0, tmp) + c0 = e.Ext2.MulByNonResidue(c0) + c1 := e.Ext2.Add(&x.B0, &x.B1) + c1 = e.Ext2.Mul(c1, b1) + c1 = e.Ext2.Sub(c1, t1) + tmp = e.Ext2.MulByNonResidue(t2) + c1 = e.Ext2.Add(c1, tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) + c2 := e.Ext2.Mul(b2, tmp) + c2 = e.Ext2.Sub(c2, t2) + c2 = e.Ext2.Add(c2, t1) + return &E6{ + B0: *c0, + B1: *c1, + B2: *c2, + } +} + +// MulBy0 multiplies z by an E6 sparse element of the form +// +// E6{ +// B0: c0, +// B1: 0, +// B2: 0, +// } +func (e Ext6) MulBy0(z *E6, c0 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) + tmp := e.Ext2.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) + t2 = e.Ext2.Sub(t2, a) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 := e.Ext2.Mul(c0, tmp) + t1 = e.Ext2.Sub(t1, a) + return &E6{ + B0: *a, + B1: *t1, + B2: *t2, + } +} + +// MulBy01 multiplies z by an E6 sparse element of the form +// +// E6{ +// B0: c0, +// B1: c1, +// B2: 0, +// } +func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) + b := e.Ext2.Mul(&z.B1, c1) + tmp := e.Ext2.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) + t0 = e.Ext2.Sub(t0, b) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, a) + // for t2, schoolbook is faster than karatsuba + // c2 = a0b2 + a1b1 + a2b0, + // c2 = a2b0 + b ∵ b2 = 0, b = a1b1 + t2 := e.Ext2.Mul(&z.B2, c0) + t2 = e.Ext2.Add(t2, b) + t1 := e.Ext2.Add(c0, c1) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 = e.Ext2.Mul(t1, tmp) + tmp = e.Ext2.Add(a, b) + t1 = e.Ext2.Sub(t1, tmp) + return &E6{ + B0: *t0, + B1: *t1, + B2: *t2, + } +} + +func (e Ext6) MulByNonResidue(x *E6) *E6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 + z0 = e.Ext2.MulByNonResidue(z0) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) AssertIsEqual(x, y *E6) { + e.Ext2.AssertIsEqual(&x.B0, &y.B0) + e.Ext2.AssertIsEqual(&x.B1, &y.B1) + e.Ext2.AssertIsEqual(&x.B2, &y.B2) +} + +func FromE6(y *bls12381.E6) E6 { + return E6{ + B0: FromE2(&y.B0), + B1: FromE2(&y.B1), + B2: FromE2(&y.B2), + } + +} + +func (e Ext6) Inverse(x *E6) *E6 { + res, err := e.fp.NewHint(inverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + one := e.One() + + // 1 == inv * x + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) + + return &inv + +} + +func (e Ext6) DivUnchecked(x, y *E6) *E6 { + res, err := e.fp.NewHint(divE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // x == div * y + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) + + return &div +} + +func (e Ext6) divE6By6(x [6]*baseEl) [6]*baseEl { + res, err := e.fp.NewHint(divE6By6Hint, 6, x[0], x[1], x[2], x[3], x[4], x[5]) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + y0 := *res[0] + y1 := *res[1] + y2 := *res[2] + y3 := *res[3] + y4 := *res[4] + y5 := *res[5] + + // xi == 6 * yi + x0 := e.fp.MulConst(&y0, big.NewInt(6)) + x1 := e.fp.MulConst(&y1, big.NewInt(6)) + x2 := e.fp.MulConst(&y2, big.NewInt(6)) + x3 := e.fp.MulConst(&y3, big.NewInt(6)) + x4 := e.fp.MulConst(&y4, big.NewInt(6)) + x5 := e.fp.MulConst(&y5, big.NewInt(6)) + e.fp.AssertIsEqual(x[0], x0) + e.fp.AssertIsEqual(x[1], x1) + e.fp.AssertIsEqual(x[2], x2) + e.fp.AssertIsEqual(x[3], x3) + e.fp.AssertIsEqual(x[4], x4) + e.fp.AssertIsEqual(x[5], x5) + + return [6]*baseEl{&y0, &y1, &y2, &y3, &y4, &y5} +} + +func (e Ext6) Select(selector frontend.Variable, z1, z0 *E6) *E6 { + b0 := e.Ext2.Select(selector, &z1.B0, &z0.B0) + b1 := e.Ext2.Select(selector, &z1.B1, &z0.B1) + b2 := e.Ext2.Select(selector, &z1.B2, &z0.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} + +func (e Ext6) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E6) *E6 { + b0 := e.Ext2.Lookup2(s1, s2, &a.B0, &b.B0, &c.B0, &d.B0) + b1 := e.Ext2.Lookup2(s1, s2, &a.B1, &b.B1, &c.B1, &d.B1) + b2 := e.Ext2.Lookup2(s1, s2, &a.B2, &b.B2, &c.B2, &d.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} diff --git a/std/algebra/emulated/fields_bls12381/e6_test.go b/std/algebra/emulated/fields_bls12381/e6_test.go new file mode 100644 index 0000000000..9ed08d3b51 --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e6_test.go @@ -0,0 +1,360 @@ +package fields_bls12381 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type e6Add struct { + A, B, C E6 +} + +func (circuit *e6Add) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + witness := e6Add{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Add{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Sub struct { + A, B, C E6 +} + +func (circuit *e6Sub) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + witness := e6Sub{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Sub{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Mul struct { + A, B, C E6 +} + +func (circuit *e6Mul) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e6Mul{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulVariant struct { + A, B, C E6 +} + +func (circuit *e6MulVariant) Define(api frontend.API) error { + e := NewExt6(api) + expected1 := e.mulKaratsubaOverKaratsuba(&circuit.A, &circuit.B) + expected2 := e.mulToom3OverKaratsuba(&circuit.A, &circuit.B) + e.AssertIsEqual(expected1, &circuit.C) + e.AssertIsEqual(expected2, &circuit.C) + return nil +} + +func TestMulFp6Variants(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e6Mul{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Square struct { + A, C E6 +} + +func (circuit *e6Square) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.Square(&a) + + witness := e6Square{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Square{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Div struct { + A, B, C E6 +} + +func (circuit *e6Div) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.DivUnchecked(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e6Div{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Div{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulByNonResidue struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByNonResidue) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.MulByNonResidue(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6ByNonResidue(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.MulByNonResidue(&a) + + witness := e6MulByNonResidue{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulByE2 struct { + A E6 + B E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByE2) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.MulByE2(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6ByE2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + var b bls12381.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.MulByE2(&a, &b) + + witness := e6MulByE2{ + A: FromE6(&a), + B: FromE2(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulByE2{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulBy01 struct { + A E6 + C0, C1 E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulBy01) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6By01(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + var C0, C1 bls12381.E2 + _, _ = a.SetRandom() + _, _ = C0.SetRandom() + _, _ = C1.SetRandom() + c.Set(&a) + c.MulBy01(&C0, &C1) + + witness := e6MulBy01{ + A: FromE6(&a), + C0: FromE2(&C0), + C1: FromE2(&C1), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulBy01{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Neg struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Neg) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Neg(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestNegFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.Neg(&a) + + witness := e6Neg{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Neg{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e6Inverse struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Inverse) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e6Inverse{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/fields_bls12381/hints.go b/std/algebra/emulated/fields_bls12381/hints.go index 24473129f2..77863d3ffa 100644 --- a/std/algebra/emulated/fields_bls12381/hints.go +++ b/std/algebra/emulated/fields_bls12381/hints.go @@ -19,9 +19,15 @@ func GetHints() []solver.Hint { // E2 divE2Hint, inverseE2Hint, + // E6 + divE6Hint, + inverseE6Hint, + squareTorusHint, + divE6By6Hint, // E12 divE12Hint, inverseE12Hint, + finalExpHint, } } @@ -61,59 +67,153 @@ func divE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } +// E6 hints +func inverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + c.Inverse(&a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bls12381.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + b.B0.A0.SetBigInt(inputs[6]) + b.B0.A1.SetBigInt(inputs[7]) + b.B1.A0.SetBigInt(inputs[8]) + b.B1.A1.SetBigInt(inputs[9]) + b.B2.A0.SetBigInt(inputs[10]) + b.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&b).Mul(&c, &a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func squareTorusHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + _c := a.DecompressTorus() + _c.CyclotomicSquare(&_c) + c, _ = _c.CompressTorus() + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func divE6By6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + var sixInv fp.Element + sixInv.SetString("6") + sixInv.Inverse(&sixInv) + c.B0.MulByElement(&a.B0, &sixInv) + c.B1.MulByElement(&a.B1, &sixInv) + c.B2.MulByElement(&a.B2, &sixInv) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + // E12 hints func inverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, c bls12381.E12 - var d [12]big.Int - d[0].Add(inputs[0], inputs[6]) - d[1].Set(inputs[6]) - d[2].Add(inputs[2], inputs[8]) - d[3].Set(inputs[8]) - d[4].Add(inputs[4], inputs[10]) - d[5].Set(inputs[10]) - d[6].Add(inputs[1], inputs[7]) - d[7].Set(inputs[7]) - d[8].Add(inputs[3], inputs[9]) - d[9].Set(inputs[9]) - d[10].Add(inputs[5], inputs[11]) - d[11].Set(inputs[11]) - a.C0.B0.A0.SetBigInt(&d[0]) - a.C0.B0.A1.SetBigInt(&d[1]) - a.C0.B1.A0.SetBigInt(&d[2]) - a.C0.B1.A1.SetBigInt(&d[3]) - a.C0.B2.A0.SetBigInt(&d[4]) - a.C0.B2.A1.SetBigInt(&d[5]) - a.C1.B0.A0.SetBigInt(&d[6]) - a.C1.B0.A1.SetBigInt(&d[7]) - a.C1.B1.A0.SetBigInt(&d[8]) - a.C1.B1.A1.SetBigInt(&d[9]) - a.C1.B2.A0.SetBigInt(&d[10]) - a.C1.B2.A1.SetBigInt(&d[11]) + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) c.Inverse(&a) - var c0, c1, c2, c3, c4, c5 fp.Element - c0.Sub(&c.C0.B0.A0, &c.C0.B0.A1) - c1.Sub(&c.C1.B0.A0, &c.C1.B0.A1) - c2.Sub(&c.C0.B1.A0, &c.C0.B1.A1) - c3.Sub(&c.C1.B1.A0, &c.C1.B1.A1) - c4.Sub(&c.C0.B2.A0, &c.C0.B2.A1) - c5.Sub(&c.C1.B2.A0, &c.C1.B2.A1) - - c0.BigInt(outputs[0]) - c1.BigInt(outputs[1]) - c2.BigInt(outputs[2]) - c3.BigInt(outputs[3]) - c4.BigInt(outputs[4]) - c5.BigInt(outputs[5]) - c.C0.B0.A1.BigInt(outputs[6]) + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) c.C1.B0.A1.BigInt(outputs[7]) - c.C0.B1.A1.BigInt(outputs[8]) + c.C1.B1.A0.BigInt(outputs[8]) c.C1.B1.A1.BigInt(outputs[9]) - c.C0.B2.A1.BigInt(outputs[10]) + c.C1.B2.A0.BigInt(outputs[10]) c.C1.B2.A1.BigInt(outputs[11]) return nil @@ -125,80 +225,157 @@ func divE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) erro func(mod *big.Int, inputs, outputs []*big.Int) error { var a, b, c bls12381.E12 - var d [12]big.Int - d[0].Add(inputs[0], inputs[6]) - d[1].Set(inputs[6]) - d[2].Add(inputs[2], inputs[8]) - d[3].Set(inputs[8]) - d[4].Add(inputs[4], inputs[10]) - d[5].Set(inputs[10]) - d[6].Add(inputs[1], inputs[7]) - d[7].Set(inputs[7]) - d[8].Add(inputs[3], inputs[9]) - d[9].Set(inputs[9]) - d[10].Add(inputs[5], inputs[11]) - d[11].Set(inputs[11]) - a.C0.B0.A0.SetBigInt(&d[0]) - a.C0.B0.A1.SetBigInt(&d[1]) - a.C0.B1.A0.SetBigInt(&d[2]) - a.C0.B1.A1.SetBigInt(&d[3]) - a.C0.B2.A0.SetBigInt(&d[4]) - a.C0.B2.A1.SetBigInt(&d[5]) - a.C1.B0.A0.SetBigInt(&d[6]) - a.C1.B0.A1.SetBigInt(&d[7]) - a.C1.B1.A0.SetBigInt(&d[8]) - a.C1.B1.A1.SetBigInt(&d[9]) - a.C1.B2.A0.SetBigInt(&d[10]) - a.C1.B2.A1.SetBigInt(&d[11]) - - d[0].Add(inputs[12], inputs[18]) - d[1].Set(inputs[18]) - d[2].Add(inputs[14], inputs[20]) - d[3].Set(inputs[20]) - d[4].Add(inputs[16], inputs[22]) - d[5].Set(inputs[22]) - d[6].Add(inputs[13], inputs[19]) - d[7].Set(inputs[19]) - d[8].Add(inputs[15], inputs[21]) - d[9].Set(inputs[21]) - d[10].Add(inputs[17], inputs[23]) - d[11].Set(inputs[23]) - b.C0.B0.A0.SetBigInt(&d[0]) - b.C0.B0.A1.SetBigInt(&d[1]) - b.C0.B1.A0.SetBigInt(&d[2]) - b.C0.B1.A1.SetBigInt(&d[3]) - b.C0.B2.A0.SetBigInt(&d[4]) - b.C0.B2.A1.SetBigInt(&d[5]) - b.C1.B0.A0.SetBigInt(&d[6]) - b.C1.B0.A1.SetBigInt(&d[7]) - b.C1.B1.A0.SetBigInt(&d[8]) - b.C1.B1.A1.SetBigInt(&d[9]) - b.C1.B2.A0.SetBigInt(&d[10]) - b.C1.B2.A1.SetBigInt(&d[11]) + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + b.C0.B0.A0.SetBigInt(inputs[12]) + b.C0.B0.A1.SetBigInt(inputs[13]) + b.C0.B1.A0.SetBigInt(inputs[14]) + b.C0.B1.A1.SetBigInt(inputs[15]) + b.C0.B2.A0.SetBigInt(inputs[16]) + b.C0.B2.A1.SetBigInt(inputs[17]) + b.C1.B0.A0.SetBigInt(inputs[18]) + b.C1.B0.A1.SetBigInt(inputs[19]) + b.C1.B1.A0.SetBigInt(inputs[20]) + b.C1.B1.A1.SetBigInt(inputs[21]) + b.C1.B2.A0.SetBigInt(inputs[22]) + b.C1.B2.A1.SetBigInt(inputs[23]) c.Inverse(&b).Mul(&c, &a) - var c0, c1, c2, c3, c4, c5 fp.Element - c0.Sub(&c.C0.B0.A0, &c.C0.B0.A1) - c1.Sub(&c.C1.B0.A0, &c.C1.B0.A1) - c2.Sub(&c.C0.B1.A0, &c.C0.B1.A1) - c3.Sub(&c.C1.B1.A0, &c.C1.B1.A1) - c4.Sub(&c.C0.B2.A0, &c.C0.B2.A1) - c5.Sub(&c.C1.B2.A0, &c.C1.B2.A1) - - c0.BigInt(outputs[0]) - c1.BigInt(outputs[1]) - c2.BigInt(outputs[2]) - c3.BigInt(outputs[3]) - c4.BigInt(outputs[4]) - c5.BigInt(outputs[5]) - c.C0.B0.A1.BigInt(outputs[6]) + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) c.C1.B0.A1.BigInt(outputs[7]) - c.C0.B1.A1.BigInt(outputs[8]) + c.C1.B1.A0.BigInt(outputs[8]) c.C1.B1.A1.BigInt(outputs[9]) - c.C0.B2.A1.BigInt(outputs[10]) + c.C1.B2.A0.BigInt(outputs[10]) c.C1.B2.A1.BigInt(outputs[11]) return nil }) } + +func finalExpHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + // This is inspired from https://eprint.iacr.org/2024/640.pdf + // and based on a personal communication with the author Andrija Novakovic. + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var millerLoop bls12381.E12 + + millerLoop.C0.B0.A0.SetBigInt(inputs[0]) + millerLoop.C0.B0.A1.SetBigInt(inputs[1]) + millerLoop.C0.B1.A0.SetBigInt(inputs[2]) + millerLoop.C0.B1.A1.SetBigInt(inputs[3]) + millerLoop.C0.B2.A0.SetBigInt(inputs[4]) + millerLoop.C0.B2.A1.SetBigInt(inputs[5]) + millerLoop.C1.B0.A0.SetBigInt(inputs[6]) + millerLoop.C1.B0.A1.SetBigInt(inputs[7]) + millerLoop.C1.B1.A0.SetBigInt(inputs[8]) + millerLoop.C1.B1.A1.SetBigInt(inputs[9]) + millerLoop.C1.B2.A0.SetBigInt(inputs[10]) + millerLoop.C1.B2.A1.SetBigInt(inputs[11]) + + var root, rootPthInverse, root27thInverse, residueWitness, scalingFactor bls12381.E12 + var order3rd, order3rdPower, exponent, exponentInv, finalExpFactor, polyFactor big.Int + // polyFactor = (1-x)/3 + polyFactor.SetString("5044125407647214251", 10) + // finalExpFactor = ((q^12 - 1) / r) / (27 * polyFactor) + finalExpFactor.SetString("2366356426548243601069753987687709088104621721678962410379583120840019275952471579477684846670499039076873213559162845121989217658133790336552276567078487633052653005423051750848782286407340332979263075575489766963251914185767058009683318020965829271737924625612375201545022326908440428522712877494557944965298566001441468676802477524234094954960009227631543471415676620753242466901942121887152806837594306028649150255258504417829961387165043999299071444887652375514277477719817175923289019181393803729926249507024121957184340179467502106891835144220611408665090353102353194448552304429530104218473070114105759487413726485729058069746063140422361472585604626055492939586602274983146215294625774144156395553405525711143696689756441298365274341189385646499074862712688473936093315628166094221735056483459332831845007196600723053356837526749543765815988577005929923802636375670820616189737737304893769679803809426304143627363860243558537831172903494450556755190448279875942974830469855835666815454271389438587399739607656399812689280234103023464545891697941661992848552456326290792224091557256350095392859243101357349751064730561345062266850238821755009430903520645523345000326783803935359711318798844368754833295302563158150573540616830138810935344206231367357992991289265295323280", 10) + + // 1. get pth-root inverse + exponent.Mul(&finalExpFactor, big.NewInt(27)) + root.Exp(millerLoop, &exponent) + if root.IsOne() { + rootPthInverse.SetOne() + } else { + exponentInv.ModInverse(&exponent, &polyFactor) + exponent.Neg(&exponentInv).Mod(&exponent, &polyFactor) + rootPthInverse.Exp(root, &exponent) + } + + // 2.1. get order of 3rd primitive root + var three big.Int + three.SetUint64(3) + exponent.Mul(&polyFactor, &finalExpFactor) + root.Exp(millerLoop, &exponent) + if root.IsOne() { + order3rdPower.SetUint64(0) + } + root.Exp(root, &three) + if root.IsOne() { + order3rdPower.SetUint64(1) + } + root.Exp(root, &three) + if root.IsOne() { + order3rdPower.SetUint64(2) + } + root.Exp(root, &three) + if root.IsOne() { + order3rdPower.SetUint64(3) + } + + // 2.2. get 27th root inverse + if order3rdPower.Uint64() == 0 { + root27thInverse.SetOne() + } else { + order3rd.Exp(&three, &order3rdPower, nil) + exponent.Mul(&polyFactor, &finalExpFactor) + root.Exp(millerLoop, &exponent) + exponentInv.ModInverse(&exponent, &order3rd) + exponent.Neg(&exponentInv).Mod(&exponent, &order3rd) + root27thInverse.Exp(root, &exponent) + } + + // 2.3. shift the Miller loop result so that millerLoop * scalingFactor + // is of order finalExpFactor + scalingFactor.Mul(&rootPthInverse, &root27thInverse) + millerLoop.Mul(&millerLoop, &scalingFactor) + + // 3. get the witness residue + // + // lambda = q - u, the optimal exponent + var lambda big.Int + lambda.SetString("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129030796414117214202539", 10) + exponent.ModInverse(&lambda, &finalExpFactor) + residueWitness.Exp(millerLoop, &exponent) + + // return the witness residue + residueWitness.C0.B0.A0.BigInt(outputs[0]) + residueWitness.C0.B0.A1.BigInt(outputs[1]) + residueWitness.C0.B1.A0.BigInt(outputs[2]) + residueWitness.C0.B1.A1.BigInt(outputs[3]) + residueWitness.C0.B2.A0.BigInt(outputs[4]) + residueWitness.C0.B2.A1.BigInt(outputs[5]) + residueWitness.C1.B0.A0.BigInt(outputs[6]) + residueWitness.C1.B0.A1.BigInt(outputs[7]) + residueWitness.C1.B1.A0.BigInt(outputs[8]) + residueWitness.C1.B1.A1.BigInt(outputs[9]) + residueWitness.C1.B2.A0.BigInt(outputs[10]) + residueWitness.C1.B2.A1.BigInt(outputs[11]) + + // return the scaling factor + scalingFactor.C0.B0.A0.BigInt(outputs[12]) + scalingFactor.C0.B0.A1.BigInt(outputs[13]) + scalingFactor.C0.B1.A0.BigInt(outputs[14]) + scalingFactor.C0.B1.A1.BigInt(outputs[15]) + scalingFactor.C0.B2.A0.BigInt(outputs[16]) + scalingFactor.C0.B2.A1.BigInt(outputs[17]) + + return nil + }) +} diff --git a/std/algebra/emulated/fields_bn254/doc.go b/std/algebra/emulated/fields_bn254/doc.go index f4c7ac2894..ae94b3c243 100644 --- a/std/algebra/emulated/fields_bn254/doc.go +++ b/std/algebra/emulated/fields_bn254/doc.go @@ -1,10 +1,6 @@ -// Package fields_bn254 implements the fields arithmetic of the direct 𝔽p¹² extension +// Package fields_bn254 implements the fields arithmetic of the Fp12 tower // used to compute the pairing over the BN254 curve. // -// 𝔽p¹²[i] = 𝔽p/i¹²-18i⁶+82 -// -// This direct tower is isomorphic to the 2-3-2 tower: -// // 𝔽p²[u] = 𝔽p/u²+1 // 𝔽p⁶[v] = 𝔽p²/v³-9-u // 𝔽p¹²[w] = 𝔽p⁶/w²-v diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 6d97690b0b..1cc99fe365 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -1,421 +1,217 @@ package fields_bn254 import ( - "math/big" - "github.com/consensys/gnark-crypto/ecc/bn254" - fp_bn "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" ) type E12 struct { - A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11 baseEl + C0, C1 E6 } type Ext12 struct { - *Ext2 - api frontend.API - fp *curveF + *Ext6 } func NewExt12(api frontend.API) *Ext12 { - fp, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - return &Ext12{ - Ext2: NewExt2(api), - api: api, - fp: fp, - } + return &Ext12{Ext6: NewExt6(api)} } -func (e Ext12) Zero() *E12 { - zero := e.fp.Zero() - return &E12{ - A0: *zero, - A1: *zero, - A2: *zero, - A3: *zero, - A4: *zero, - A5: *zero, - A6: *zero, - A7: *zero, - A8: *zero, - A9: *zero, - A10: *zero, - A11: *zero, - } -} - -func (e Ext12) One() *E12 { - one := e.fp.One() - zero := e.fp.Zero() +func (e Ext12) Add(x, y *E12) *E12 { + z0 := e.Ext6.Add(&x.C0, &y.C0) + z1 := e.Ext6.Add(&x.C1, &y.C1) return &E12{ - A0: *one, - A1: *zero, - A2: *zero, - A3: *zero, - A4: *zero, - A5: *zero, - A6: *zero, - A7: *zero, - A8: *zero, - A9: *zero, - A10: *zero, - A11: *zero, + C0: *z0, + C1: *z1, } } -func (e Ext12) Neg(x *E12) *E12 { - a0 := e.fp.Neg(&x.A0) - a1 := e.fp.Neg(&x.A1) - a2 := e.fp.Neg(&x.A2) - a3 := e.fp.Neg(&x.A3) - a4 := e.fp.Neg(&x.A4) - a5 := e.fp.Neg(&x.A5) - a6 := e.fp.Neg(&x.A6) - a7 := e.fp.Neg(&x.A7) - a8 := e.fp.Neg(&x.A8) - a9 := e.fp.Neg(&x.A9) - a10 := e.fp.Neg(&x.A10) - a11 := e.fp.Neg(&x.A11) - +func (e Ext12) Sub(x, y *E12) *E12 { + z0 := e.Ext6.Sub(&x.C0, &y.C0) + z1 := e.Ext6.Sub(&x.C1, &y.C1) return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: *z0, + C1: *z1, } } -func (e Ext12) Add(x, y *E12) *E12 { - a0 := e.fp.Add(&x.A0, &y.A0) - a1 := e.fp.Add(&x.A1, &y.A1) - a2 := e.fp.Add(&x.A2, &y.A2) - a3 := e.fp.Add(&x.A3, &y.A3) - a4 := e.fp.Add(&x.A4, &y.A4) - a5 := e.fp.Add(&x.A5, &y.A5) - a6 := e.fp.Add(&x.A6, &y.A6) - a7 := e.fp.Add(&x.A7, &y.A7) - a8 := e.fp.Add(&x.A8, &y.A8) - a9 := e.fp.Add(&x.A9, &y.A9) - a10 := e.fp.Add(&x.A10, &y.A10) - a11 := e.fp.Add(&x.A11, &y.A11) - +func (e Ext12) Conjugate(x *E12) *E12 { + z1 := e.Ext6.Neg(&x.C1) return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: x.C0, + C1: *z1, } } -func (e Ext12) Sub(x, y *E12) *E12 { - a0 := e.fp.Sub(&x.A0, &y.A0) - a1 := e.fp.Sub(&x.A1, &y.A1) - a2 := e.fp.Sub(&x.A2, &y.A2) - a3 := e.fp.Sub(&x.A3, &y.A3) - a4 := e.fp.Sub(&x.A4, &y.A4) - a5 := e.fp.Sub(&x.A5, &y.A5) - a6 := e.fp.Sub(&x.A6, &y.A6) - a7 := e.fp.Sub(&x.A7, &y.A7) - a8 := e.fp.Sub(&x.A8, &y.A8) - a9 := e.fp.Sub(&x.A9, &y.A9) - a10 := e.fp.Sub(&x.A10, &y.A10) - a11 := e.fp.Sub(&x.A11, &y.A11) - +func (e Ext12) Mul(x, y *E12) *E12 { + a := e.Ext6.Add(&x.C0, &x.C1) + b := e.Ext6.Add(&y.C0, &y.C1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&x.C0, &y.C0) + c := e.Ext6.Mul(&x.C1, &y.C1) + d := e.Ext6.Add(c, b) + z1 := e.Ext6.Sub(a, d) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: *z0, + C1: *z1, } } -func (e Ext12) Double(x *E12) *E12 { - two := big.NewInt(2) - a0 := e.fp.MulConst(&x.A0, two) - a1 := e.fp.MulConst(&x.A1, two) - a2 := e.fp.MulConst(&x.A2, two) - a3 := e.fp.MulConst(&x.A3, two) - a4 := e.fp.MulConst(&x.A4, two) - a5 := e.fp.MulConst(&x.A5, two) - a6 := e.fp.MulConst(&x.A6, two) - a7 := e.fp.MulConst(&x.A7, two) - a8 := e.fp.MulConst(&x.A8, two) - a9 := e.fp.MulConst(&x.A9, two) - a10 := e.fp.MulConst(&x.A10, two) - a11 := e.fp.MulConst(&x.A11, two) - +func (e Ext12) Zero() *E12 { + zero := e.fp.Zero() return &E12{ - A0: *a0, - A1: *a1, - A2: *a2, - A3: *a3, - A4: *a4, - A5: *a5, - A6: *a6, - A7: *a7, - A8: *a8, - A9: *a9, - A10: *a10, - A11: *a11, + C0: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, } } -func (e Ext12) Conjugate(x *E12) *E12 { +func (e Ext12) One() *E12 { + z000 := e.fp.One() + zero := e.fp.Zero() return &E12{ - A0: x.A0, - A1: *e.fp.Neg(&x.A1), - A2: x.A2, - A3: *e.fp.Neg(&x.A3), - A4: x.A4, - A5: *e.fp.Neg(&x.A5), - A6: x.A6, - A7: *e.fp.Neg(&x.A7), - A8: x.A8, - A9: *e.fp.Neg(&x.A9), - A10: x.A10, - A11: *e.fp.Neg(&x.A11), + C0: E6{ + B0: E2{A0: *z000, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, } } -func (e Ext12) Mul(x, y *E12) *E12 { - return e.mulDirect(x, y) +func (e Ext12) IsZero(z *E12) frontend.Variable { + c0 := e.Ext6.IsZero(&z.C0) + c1 := e.Ext6.IsZero(&z.C1) + return e.api.And(c0, c1) } -func (e Ext12) mulDirect(a, b *E12) *E12 { - - // a = a11 w^11 + a10 w^10 + a9 w^9 + a8 w^8 + a7 w^7 + a6 w^6 + a5 w^5 + a4 w^4 + a3 w^3 + a2 w^2 + a1 w + a0 - // b = b11 w^11 + b10 w^10 + b9 w^9 + b8 w^8 + b7 w^7 + b6 w^6 + b5 w^5 + b4 w^4 + b3 w^3 + b2 w^2 + b1 w + b0 - // - // Given that w^12 = 18 w^6 - 82, we can compute the product a * b as follows: - // - // a * b = d11 w^11 + d10 w^10 + d9 w^9 + d8 w^8 + d7 w^7 + d6 w^6 + d5 w^5 + d4 w^4 + d3 w^3 + d2 w^2 + d1 w + d0 - // - // where: - // - // d0 = c0 - 82 * c12 - 1476 * c18 - // d1 = c1 - 82 * c13 - 1476 * c19 - // d2 = c2 - 82 * c14 - 1476 * c20 - // d3 = c3 - 82 * c15 - 1476 * c21 - // d4 = c4 - 82 * c16 - 1476 * c22 - // d5 = c5 - 82 * c17 - // d6 = c6 + 18 * c12 + 242 * c18 - // d7 = c7 + 18 * c13 + 242 * c19 - // d8 = c8 + 18 * c14 + 242 * c20 - // d9 = c9 + 18 * c15 + 242 * c21 - // d10 = c10 + 18 * c16 + 242 * c22 - // d11 = c11 + 18 * c17 - // - // and: - // - // c0 = a0 b0 - // c1 = a0 b1 + a1 b0 - // c2 = a0 b2 + a1 b1 + a2 b0 - // c3 = a0 b3 + a1 b2 + a2 b1 + a3 b0 - // c4 = a0 b4 + a1 b3 + a2 b2 + a3 b1 + a4 b0 - // c5 = a0 b5 + a1 b4 + a2 b3 + a3 b2 + a4 b1 + a5 b0 - // c6 = a0 b6 + a1 b5 + a2 b4 + a3 b3 + a4 b2 + a5 b1 + a6 b0 - // c7 = a0 b7 + a1 b6 + a2 b5 + a3 b4 + a4 b3 + a5 b2 + a6 b1 + a7 b0 - // c8 = a0 b8 + a1 b7 + a2 b6 + a3 b5 + a4 b4 + a5 b3 + a6 b2 + a7 b1 + a8 b0 - // c9 = a0 b9 + a1 b8 + a2 b7 + a3 b6 + a4 b5 + a5 b4 + a6 b3 + a7 b2 + a8 b1 + a9 b0 - // c10 = a0 b10 + a1 b9 + a2 b8 + a3 b7 + a4 b6 + a5 b5 + a6 b4 + a7 b3 + a8 b2 + a9 b1 + a10 b0 - // c11 = a0 b11 + a1 b10 + a2 b9 + a3 b8 + a4 b7 + a5 b6 + a6 b5 + a7 b4 + a8 b3 + a9 b2 + a10 b1 + a11 b0 - // c12 = a1 b11 + a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a7 b5 + a8 b4 + a9 b3 + a10 b2 + a11 b1 - // c13 = a2 b11 + a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a8 b5 + a9 b4 + a10 b3 + a11 b2 - // c14 = a3 b11 + a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a9 b5 + a10 b4 + a11 b3 - // c15 = a4 b11 + a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a10 b5 + a11 b4 - // c16 = a5 b11 + a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6 + a11 b5 - // c17 = a6 b11 + a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6 - // c18 = a7 b11 + a8 b10 + a9 b9 + a10 b8 + a11 b7 - // c19 = a8 b11 + a9 b10 + a10 b9 + a11 b8 - // c20 = a9 b11 + a10 b10 + a11 b9 - // c21 = a10 b11 + a11 b10 - // c22 = a11 b11 - - // d0 = c0 - 82 * c12 - 1476 * c18 - // = a0 b0 - 82 * (a1 b11 + a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a7 b5 + a8 b4 + a9 b3 + a10 b2 + a11 b1) - 1476 * (a7 b11 + a8 b10 + a9 b9 + a10 b8 + a11 b7) - mone := e.fp.NewElement(-1) - d0 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A0}, {mone, &a.A1, &b.A11}, {mone, &a.A2, &b.A10}, {mone, &a.A3, &b.A9}, {mone, &a.A4, &b.A8}, {mone, &a.A5, &b.A7}, {mone, &a.A6, &b.A6}, {mone, &a.A7, &b.A5}, {mone, &a.A8, &b.A4}, {mone, &a.A9, &b.A3}, {mone, &a.A10, &b.A2}, {mone, &a.A11, &b.A1}, {mone, &a.A7, &b.A11}, {mone, &a.A8, &b.A10}, {mone, &a.A9, &b.A9}, {mone, &a.A10, &b.A8}, {mone, &a.A11, &b.A7}}, []int{1, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 1476, 1476, 1476, 1476, 1476}) - - // d1 = c1 - 82 * c13 - 1476 * c19 - // = a0 b1 + a1 b0 - 82 * (a2 b11 + a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a8 b5 + a9 b4 + a10 b3 + a11 b2) - 1476 * (a8 b11 + a9 b10 + a10 b9 + a11 b8) - d1 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A1}, {&a.A1, &b.A0}, {mone, &a.A2, &b.A11}, {mone, &a.A3, &b.A10}, {mone, &a.A4, &b.A9}, {mone, &a.A5, &b.A8}, {mone, &a.A6, &b.A7}, {mone, &a.A7, &b.A6}, {mone, &a.A8, &b.A5}, {mone, &a.A9, &b.A4}, {mone, &a.A10, &b.A3}, {mone, &a.A11, &b.A2}, {mone, &a.A8, &b.A11}, {mone, &a.A9, &b.A10}, {mone, &a.A10, &b.A9}, {mone, &a.A11, &b.A8}}, []int{1, 1, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 1476, 1476, 1476, 1476}) - - // d2 = c2 - 82 * c14 - 1476 * c20 - // = a0 b2 + a1 b1 + a2 b0 - 82 * (a3 b11 + a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a9 b5 + a10 b4 + a11 b3) - 1476 * (a9 b11 + a10 b10 + a11 b9) - d2 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A2}, {&a.A1, &b.A1}, {&a.A2, &b.A0}, {mone, &a.A3, &b.A11}, {mone, &a.A4, &b.A10}, {mone, &a.A5, &b.A9}, {mone, &a.A6, &b.A8}, {mone, &a.A7, &b.A7}, {mone, &a.A8, &b.A6}, {mone, &a.A9, &b.A5}, {mone, &a.A10, &b.A4}, {mone, &a.A11, &b.A3}, {mone, &a.A9, &b.A11}, {mone, &a.A10, &b.A10}, {mone, &a.A11, &b.A9}}, []int{1, 1, 1, 82, 82, 82, 82, 82, 82, 82, 82, 82, 1476, 1476, 1476}) - - // d3 = c3 - 82 * c15 - 1476 * c21 - // = a0 b3 + a1 b2 + a2 b1 + a3 b0 - 82 * (a4 b11 + a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a10 b5 + a11 b4) - 1476 * (a10 b11 + a11 b10) - d3 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A3}, {&a.A1, &b.A2}, {&a.A2, &b.A1}, {&a.A3, &b.A0}, {mone, &a.A4, &b.A11}, {mone, &a.A5, &b.A10}, {mone, &a.A6, &b.A9}, {mone, &a.A7, &b.A8}, {mone, &a.A8, &b.A7}, {mone, &a.A9, &b.A6}, {mone, &a.A10, &b.A5}, {mone, &a.A11, &b.A4}, {mone, &a.A10, &b.A11}, {mone, &a.A11, &b.A10}}, []int{1, 1, 1, 1, 82, 82, 82, 82, 82, 82, 82, 82, 1476, 1476}) - - // d4 = c4 - 82 * c16 - 1476 * c22 - // = a0 b4 + a1 b3 + a2 b2 + a3 b1 + a4 b0 - 82 * (a5 b11 + a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6 + a11 b5) - 1476 * a11 b11 - d4 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A4}, {&a.A1, &b.A3}, {&a.A2, &b.A2}, {&a.A3, &b.A1}, {&a.A4, &b.A0}, {mone, &a.A5, &b.A11}, {mone, &a.A6, &b.A10}, {mone, &a.A7, &b.A9}, {mone, &a.A8, &b.A8}, {mone, &a.A9, &b.A7}, {mone, &a.A10, &b.A6}, {mone, &a.A11, &b.A5}, {mone, &a.A11, &b.A11}}, []int{1, 1, 1, 1, 1, 82, 82, 82, 82, 82, 82, 82, 1476}) - - // d5 = c5 - 82 * c17 - // = a0 b5 + a1 b4 + a2 b3 + a3 b2 + a4 b1 + a5 b0 - 82 * (a6 b11 + a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6) - d5 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A5}, {&a.A1, &b.A4}, {&a.A2, &b.A3}, {&a.A3, &b.A2}, {&a.A4, &b.A1}, {&a.A5, &b.A0}, {mone, &a.A6, &b.A11}, {mone, &a.A7, &b.A10}, {mone, &a.A8, &b.A9}, {mone, &a.A9, &b.A8}, {mone, &a.A10, &b.A7}, {mone, &a.A11, &b.A6}}, []int{1, 1, 1, 1, 1, 1, 82, 82, 82, 82, 82, 82}) - - // d6 = c6 + 18 * c12 + 242 * c18 - // = a0 b6 + a1 b5 + a2 b4 + a3 b3 + a4 b2 + a5 b1 + a6 b0 + 18 * (a1 b11 + a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a7 b5 + a8 b4 + a9 b3 + a10 b2 + a11 b1) + 242 * (a7 b11 + a8 b10 + a9 b9 + a10 b8 + a11 b7) - d6 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A6}, {&a.A1, &b.A5}, {&a.A2, &b.A4}, {&a.A3, &b.A3}, {&a.A4, &b.A2}, {&a.A5, &b.A1}, {&a.A6, &b.A0}, {&a.A1, &b.A11}, {&a.A2, &b.A10}, {&a.A3, &b.A9}, {&a.A4, &b.A8}, {&a.A5, &b.A7}, {&a.A6, &b.A6}, {&a.A7, &b.A5}, {&a.A8, &b.A4}, {&a.A9, &b.A3}, {&a.A10, &b.A2}, {&a.A11, &b.A1}, {&a.A7, &b.A11}, {&a.A8, &b.A10}, {&a.A9, &b.A9}, {&a.A10, &b.A8}, {&a.A11, &b.A7}}, []int{1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 242, 242, 242, 242, 242}) - - // d7 = c7 + 18 * c13 + 242 * c19 - // = a0 b7 + a1 b6 + a2 b5 + a3 b4 + a4 b3 + a5 b2 + a6 b1 + a7 b0 + 18 * (a2 b11 + a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a8 b5 + a9 b4 + a10 b3 + a11 b2) + 242 * (a8 b11 + a9 b10 + a10 b9 + a11 b8) - d7 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A7}, {&a.A1, &b.A6}, {&a.A2, &b.A5}, {&a.A3, &b.A4}, {&a.A4, &b.A3}, {&a.A5, &b.A2}, {&a.A6, &b.A1}, {&a.A7, &b.A0}, {&a.A2, &b.A11}, {&a.A3, &b.A10}, {&a.A4, &b.A9}, {&a.A5, &b.A8}, {&a.A6, &b.A7}, {&a.A7, &b.A6}, {&a.A8, &b.A5}, {&a.A9, &b.A4}, {&a.A10, &b.A3}, {&a.A11, &b.A2}, {&a.A8, &b.A11}, {&a.A9, &b.A10}, {&a.A10, &b.A9}, {&a.A11, &b.A8}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 242, 242, 242, 242}) - - // d8 = c8 + 18 * c14 + 242 * c20 - // = a0 b8 + a1 b7 + a2 b6 + a3 b5 + a4 b4 + a5 b3 + a6 b2 + a7 b1 + a8 b0 + 18 * (a3 b11 + a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a9 b5 + a10 b4 + a11 b3) + 242 * (a9 b11 + a10 b10 + a11 b9) - d8 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A8}, {&a.A1, &b.A7}, {&a.A2, &b.A6}, {&a.A3, &b.A5}, {&a.A4, &b.A4}, {&a.A5, &b.A3}, {&a.A6, &b.A2}, {&a.A7, &b.A1}, {&a.A8, &b.A0}, {&a.A3, &b.A11}, {&a.A4, &b.A10}, {&a.A5, &b.A9}, {&a.A6, &b.A8}, {&a.A7, &b.A7}, {&a.A8, &b.A6}, {&a.A9, &b.A5}, {&a.A10, &b.A4}, {&a.A11, &b.A3}, {&a.A9, &b.A11}, {&a.A10, &b.A10}, {&a.A11, &b.A9}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, 18, 242, 242, 242}) - - // d9 = c9 + 18 * c15 + 242 * c21 - // = a0 b9 + a1 b8 + a2 b7 + a3 b6 + a4 b5 + a5 b4 + a6 b3 + a7 b2 + a8 b1 + a9 b0 + 18 * (a4 b11 + a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a10 b5 + a11 b4) + 242 * (a10 b11 + a11 b10) - d9 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A9}, {&a.A1, &b.A8}, {&a.A2, &b.A7}, {&a.A3, &b.A6}, {&a.A4, &b.A5}, {&a.A5, &b.A4}, {&a.A6, &b.A3}, {&a.A7, &b.A2}, {&a.A8, &b.A1}, {&a.A9, &b.A0}, {&a.A4, &b.A11}, {&a.A5, &b.A10}, {&a.A6, &b.A9}, {&a.A7, &b.A8}, {&a.A8, &b.A7}, {&a.A9, &b.A6}, {&a.A10, &b.A5}, {&a.A11, &b.A4}, {&a.A10, &b.A11}, {&a.A11, &b.A10}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, 242, 242}) - - // d10 = c10 + 18 * c16 + 242 * c22 - // = a0 b10 + a1 b9 + a2 b8 + a3 b7 + a4 b6 + a5 b5 + a6 b4 + a7 b3 + a8 b2 + a9 b1 + a10 b0 + 18 * (a5 b11 + a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6 + a11 b5) + 242 * (a11 b11) - d10 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A10}, {&a.A1, &b.A9}, {&a.A2, &b.A8}, {&a.A3, &b.A7}, {&a.A4, &b.A6}, {&a.A5, &b.A5}, {&a.A6, &b.A4}, {&a.A7, &b.A3}, {&a.A8, &b.A2}, {&a.A9, &b.A1}, {&a.A10, &b.A0}, {&a.A5, &b.A11}, {&a.A6, &b.A10}, {&a.A7, &b.A9}, {&a.A8, &b.A8}, {&a.A9, &b.A7}, {&a.A10, &b.A6}, {&a.A11, &b.A5}, {&a.A11, &b.A11}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 242}) - - // d11 = c11 + 18 * c17 - // = a0 b11 + a1 b10 + a2 b9 + a3 b8 + a4 b7 + a5 b6 + a6 b5 + a7 b4 + a8 b3 + a9 b2 + a10 b1 + a11 b0 + 18 * (a6 b11 + a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6) - d11 := e.fp.Eval([][]*baseEl{{&a.A0, &b.A11}, {&a.A1, &b.A10}, {&a.A2, &b.A9}, {&a.A3, &b.A8}, {&a.A4, &b.A7}, {&a.A5, &b.A6}, {&a.A6, &b.A5}, {&a.A7, &b.A4}, {&a.A8, &b.A3}, {&a.A9, &b.A2}, {&a.A10, &b.A1}, {&a.A11, &b.A0}, {&a.A6, &b.A11}, {&a.A7, &b.A10}, {&a.A8, &b.A9}, {&a.A9, &b.A8}, {&a.A10, &b.A7}, {&a.A11, &b.A6}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18}) - +func (e Ext12) Square(x *E12) *E12 { + c0 := e.Ext6.Sub(&x.C0, &x.C1) + c3 := e.Ext6.MulByNonResidue(&x.C1) + c3 = e.Ext6.Sub(&x.C0, c3) + c2 := e.Ext6.Mul(&x.C0, &x.C1) + c0 = e.Ext6.Mul(c0, c3) + c0 = e.Ext6.Add(c0, c2) + z1 := e.Ext6.Double(c2) + c2 = e.Ext6.MulByNonResidue(c2) + z0 := e.Ext6.Add(c0, c2) return &E12{ - A0: *d0, - A1: *d1, - A2: *d2, - A3: *d3, - A4: *d4, - A5: *d5, - A6: *d6, - A7: *d7, - A8: *d8, - A9: *d9, - A10: *d10, - A11: *d11, + C0: *z0, + C1: *z1, } } -func (e Ext12) Square(x *E12) *E12 { - return e.squareDirect(x) -} - -func (e Ext12) squareDirect(a *E12) *E12 { - - mone := e.fp.NewElement(-1) - // d0 = a0 a0 - 82 * (2 a1 a11 + 2 a2 a10 + 2 a3 a9 + 2 a4 a8 + 2 a5 a7 + a6 a6) - 1476 * (2 a7 a11 + 2 a8 a10 + a9 a9) - d0 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A0}, {mone, &a.A1, &a.A11}, {mone, &a.A2, &a.A10}, {mone, &a.A3, &a.A9}, {mone, &a.A4, &a.A8}, {mone, &a.A5, &a.A7}, {mone, &a.A6, &a.A6}, {mone, &a.A7, &a.A11}, {mone, &a.A8, &a.A10}, {mone, &a.A9, &a.A9}}, []int{1, 164, 164, 164, 164, 164, 82, 2952, 2952, 1476}) - - // d1 = 2 a0 a1 - 164 * (2 a2 a11 + a3 a10 + a4 a9 + a5 a8 + a6 a7) - 2952 * (a8 a11 + a9 a10) - d1 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A1}, {mone, &a.A2, &a.A11}, {mone, &a.A3, &a.A10}, {mone, &a.A4, &a.A9}, {mone, &a.A5, &a.A8}, {mone, &a.A6, &a.A7}, {mone, &a.A8, &a.A11}, {mone, &a.A9, &a.A10}}, []int{2, 164, 164, 164, 164, 164, 2952, 2952}) - - // d2 = 2 a0 a2 + a1 a1 - 82 * (2 a3 a11 + 2 a4 a10 + 2 a5 a9 + 2 a6 a8 + a7 a7) - 1476 * (2 a9 a11 + a10 a10) - d2 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A2}, {&a.A1, &a.A1}, {mone, &a.A3, &a.A11}, {mone, &a.A4, &a.A10}, {mone, &a.A5, &a.A9}, {mone, &a.A6, &a.A8}, {mone, &a.A7, &a.A7}, {mone, &a.A9, &a.A11}, {mone, &a.A10, &a.A10}}, []int{2, 1, 164, 164, 164, 164, 82, 2952, 1476}) - - // d3 = 2 a0 a3 + 2 a1 a2 - 164 * (a4 a11 + a5 a10 + a6 a9 + a7 a8) - 2952 * a10 a11 - d3 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A3}, {&a.A1, &a.A2}, {mone, &a.A4, &a.A11}, {mone, &a.A5, &a.A10}, {mone, &a.A6, &a.A9}, {mone, &a.A7, &a.A8}, {mone, &a.A10, &a.A11}}, []int{2, 2, 164, 164, 164, 164, 2952}) - - // d4 = 2 a0 a4 + 2 a1 a3 + a2 a2 - 82 * (2 a5 a11 + 2 a6 a10 + 2 a7 a9 + a8 a8) - 1476 * a11 a11 - d4 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A4}, {&a.A1, &a.A3}, {&a.A2, &a.A2}, {mone, &a.A5, &a.A11}, {mone, &a.A6, &a.A10}, {mone, &a.A7, &a.A9}, {mone, &a.A8, &a.A8}, {mone, &a.A11, &a.A11}}, []int{2, 2, 1, 164, 164, 164, 82, 1476}) - - // d5 = 2 (a0 a5 + a1 a4 + a2 a3) - 164 * (a6 a11 + a7 a10 + a8 a9) - d5 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A5}, {&a.A1, &a.A4}, {&a.A2, &a.A3}, {mone, &a.A6, &a.A11}, {mone, &a.A7, &a.A10}, {mone, &a.A8, &a.A9}}, []int{2, 2, 2, 164, 164, 164}) - - // d6 = 2 a0 a6 + 2 a1 a5 + 2 a2 a4 + a3 a3 + 18 * (2 a1 a11 + 2 a2 a10 + 2 a3 a9 + 2 a4 a8 + 2 a5 a7 + a6 a6) + 242 * (2 a7 a11 + 2 a8 a10 + a9 a9) - d6 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A6}, {&a.A1, &a.A5}, {&a.A2, &a.A4}, {&a.A3, &a.A3}, {&a.A1, &a.A11}, {&a.A2, &a.A10}, {&a.A3, &a.A9}, {&a.A4, &a.A8}, {&a.A5, &a.A7}, {&a.A6, &a.A6}, {&a.A7, &a.A11}, {&a.A8, &a.A10}, {&a.A9, &a.A9}}, []int{2, 2, 2, 1, 36, 36, 36, 36, 36, 18, 484, 484, 242}) - - // d7 = 2(a0 a7 + a1 a6 + a2 a5 + a3 a4) + 36 * (a2 a11 + a3 a10 + a4 a9 + a5 a8 + a6 a7) + 484 * (a8 a11 + a9 a10) - d7 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A7}, {&a.A1, &a.A6}, {&a.A2, &a.A5}, {&a.A3, &a.A4}, {&a.A2, &a.A11}, {&a.A3, &a.A10}, {&a.A4, &a.A9}, {&a.A5, &a.A8}, {&a.A6, &a.A7}, {&a.A8, &a.A11}, {&a.A9, &a.A10}}, []int{2, 2, 2, 2, 36, 36, 36, 36, 36, 484, 484}) - - // d8 = 2(a0 a8 + a1 a7 + a2 a6 + a3 a5) + a4 a4 + 18 * (2 a3 a11 + 2 a4 a10 + 2 a5 a9 + 2 a6 a8 + a7 a7) + 242 * (2 a9 a11 + a10 a10) - d8 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A8}, {&a.A1, &a.A7}, {&a.A2, &a.A6}, {&a.A3, &a.A5}, {&a.A4, &a.A4}, {&a.A3, &a.A11}, {&a.A4, &a.A10}, {&a.A5, &a.A9}, {&a.A6, &a.A8}, {&a.A7, &a.A7}, {&a.A9, &a.A11}, {&a.A10, &a.A10}}, []int{2, 2, 2, 2, 1, 36, 36, 36, 36, 18, 484, 242}) - - // d9 = 2(a0 a9 + a1 a8 + a2 a7 + a3 a6 + a4 a5) + 36 * (a4 a11 + a5 a10 + a6 a9 + a7 a8) + 484 * a10 a11 - d9 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A9}, {&a.A1, &a.A8}, {&a.A2, &a.A7}, {&a.A3, &a.A6}, {&a.A4, &a.A5}, {&a.A4, &a.A11}, {&a.A5, &a.A10}, {&a.A6, &a.A9}, {&a.A7, &a.A8}, {&a.A10, &a.A11}}, []int{2, 2, 2, 2, 2, 36, 36, 36, 36, 484}) - - // d10 = 2(a0 a10 + a1 a9 + a2 a8 + a3 a7 + a4 a6) + a5 a5 + 18 * (2 a5 a11 + 2 a6 a10 + 2 a7 a9 + a8 a8) + 242 * a11 a11 - d10 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A10}, {&a.A1, &a.A9}, {&a.A2, &a.A8}, {&a.A3, &a.A7}, {&a.A4, &a.A6}, {&a.A5, &a.A5}, {&a.A5, &a.A11}, {&a.A6, &a.A10}, {&a.A7, &a.A9}, {&a.A8, &a.A8}, {&a.A11, &a.A11}}, []int{2, 2, 2, 2, 2, 1, 36, 36, 36, 18, 242}) - - // d11 = 2(a0 a11 + a1 a10 + a2 a9 + a3 a8 + a4 a7 + a5 a6) + 36 * (a6 a11 + a7 a10 + a8 a9) - d11 := e.fp.Eval([][]*baseEl{{&a.A0, &a.A11}, {&a.A1, &a.A10}, {&a.A2, &a.A9}, {&a.A3, &a.A8}, {&a.A4, &a.A7}, {&a.A5, &a.A6}, {&a.A6, &a.A11}, {&a.A7, &a.A10}, {&a.A8, &a.A9}}, []int{2, 2, 2, 2, 2, 2, 36, 36, 36}) - +// Granger--Scott cyclotomic square +func (e Ext12) CyclotomicSquare(x *E12) *E12 { + t0 := e.Ext2.Square(&x.C1.B1) + t1 := e.Ext2.Square(&x.C0.B0) + t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) + t6 = e.Ext2.Square(t6) + t6 = e.Ext2.Sub(t6, t0) + t6 = e.Ext2.Sub(t6, t1) + t2 := e.Ext2.Square(&x.C0.B2) + t3 := e.Ext2.Square(&x.C1.B0) + t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) + t7 = e.Ext2.Square(t7) + t7 = e.Ext2.Sub(t7, t2) + t7 = e.Ext2.Sub(t7, t3) + t4 := e.Ext2.Square(&x.C1.B2) + t5 := e.Ext2.Square(&x.C0.B1) + t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) + t8 = e.Ext2.Square(t8) + t8 = e.Ext2.Sub(t8, t4) + t8 = e.Ext2.Sub(t8, t5) + t8 = e.Ext2.MulByNonResidue(t8) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, t1) + t2 = e.Ext2.MulByNonResidue(t2) + t2 = e.Ext2.Add(t2, t3) + t4 = e.Ext2.MulByNonResidue(t4) + t4 = e.Ext2.Add(t4, t5) + z00 := e.Ext2.Sub(t0, &x.C0.B0) + z00 = e.Ext2.Double(z00) + z00 = e.Ext2.Add(z00, t0) + z01 := e.Ext2.Sub(t2, &x.C0.B1) + z01 = e.Ext2.Double(z01) + z01 = e.Ext2.Add(z01, t2) + z02 := e.Ext2.Sub(t4, &x.C0.B2) + z02 = e.Ext2.Double(z02) + z02 = e.Ext2.Add(z02, t4) + z10 := e.Ext2.Add(t8, &x.C1.B0) + z10 = e.Ext2.Double(z10) + z10 = e.Ext2.Add(z10, t8) + z11 := e.Ext2.Add(t6, &x.C1.B1) + z11 = e.Ext2.Double(z11) + z11 = e.Ext2.Add(z11, t6) + z12 := e.Ext2.Add(t7, &x.C1.B2) + z12 = e.Ext2.Double(z12) + z12 = e.Ext2.Add(z12, t7) return &E12{ - A0: *d0, - A1: *d1, - A2: *d2, - A3: *d3, - A4: *d4, - A5: *d5, - A6: *d6, - A7: *d7, - A8: *d8, - A9: *d9, - A10: *d10, - A11: *d11, + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, } } -// Granger-Scott's cyclotomic square -// https://eprint.iacr.org/2009/565.pdf, 3.2 -func (e Ext12) CyclotomicSquareGS(x *E12) *E12 { - tower := e.ToTower(x) +func (e Ext12) IsEqual(x, y *E12) frontend.Variable { + isC0Equal := e.Ext6.IsEqual(&x.C0, &y.C0) + isC1Equal := e.Ext6.IsEqual(&x.C1, &y.C1) + return e.api.And(isC0Equal, isC1Equal) +} - mone := e.fp.NewElement(-1) - z000 := e.fp.Eval([][]*baseEl{{tower[8], tower[8]}, {mone, tower[9], tower[9]}, {mone, tower[8], tower[9]}, {tower[0], tower[0]}, {mone, tower[1], tower[1]}, {mone, tower[0]}}, []int{27, 27, 6, 3, 3, 2}) - z001 := e.fp.Eval([][]*baseEl{{tower[8], tower[8]}, {mone, tower[9], tower[9]}, {tower[8], tower[9]}, {tower[0], tower[1]}, {mone, tower[1]}}, []int{3, 3, 54, 6, 2}) - z010 := e.fp.Eval([][]*baseEl{{tower[4], tower[4]}, {mone, tower[5], tower[5]}, {mone, tower[4], tower[5]}, {tower[6], tower[6]}, {mone, tower[7], tower[7]}, {mone, tower[2]}}, []int{27, 27, 6, 3, 3, 2}) - z011 := e.fp.Eval([][]*baseEl{{tower[4], tower[4]}, {mone, tower[5], tower[5]}, {tower[4], tower[5]}, {tower[6], tower[7]}, {mone, tower[3]}}, []int{3, 3, 54, 6, 2}) - z020 := e.fp.Eval([][]*baseEl{{tower[10], tower[10]}, {mone, tower[11], tower[11]}, {mone, tower[10], tower[11]}, {tower[2], tower[2]}, {mone, tower[3], tower[3]}, {mone, tower[4]}}, []int{27, 27, 6, 3, 3, 2}) - z021 := e.fp.Eval([][]*baseEl{{tower[10], tower[10]}, {mone, tower[11], tower[11]}, {tower[10], tower[11]}, {tower[2], tower[3]}, {mone, tower[5]}}, []int{3, 3, 54, 6, 2}) - z100 := e.fp.Eval([][]*baseEl{{tower[2], tower[10]}, {mone, tower[3], tower[11]}, {mone, tower[2], tower[11]}, {mone, tower[3], tower[10]}, {tower[6]}}, []int{54, 54, 6, 6, 2}) - z101 := e.fp.Eval([][]*baseEl{{tower[2], tower[10]}, {mone, tower[3], tower[11]}, {tower[2], tower[11]}, {tower[3], tower[10]}, {tower[7]}}, []int{6, 6, 54, 54, 2}) - z110 := e.fp.Eval([][]*baseEl{{tower[0], tower[8]}, {mone, tower[1], tower[9]}, {tower[8]}}, []int{6, 6, 2}) - z111 := e.fp.Eval([][]*baseEl{{tower[0], tower[9]}, {tower[1], tower[8]}, {tower[9]}}, []int{6, 6, 2}) - z120 := e.fp.Eval([][]*baseEl{{tower[4], tower[6]}, {mone, tower[5], tower[7]}, {tower[10]}}, []int{6, 6, 2}) - z121 := e.fp.Eval([][]*baseEl{{tower[4], tower[7]}, {tower[5], tower[6]}, {tower[11]}}, []int{6, 6, 2}) +func (e Ext12) AssertIsEqual(x, y *E12) { + e.Ext6.AssertIsEqual(&x.C0, &y.C0) + e.Ext6.AssertIsEqual(&x.C1, &y.C1) +} - direct := e.FromTower([12]*baseEl{z000, z001, z010, z011, z020, z021, z100, z101, z110, z111, z120, z121}) +func FromE12(y *bn254.E12) E12 { + return E12{ + C0: FromE6(&y.C0), + C1: FromE6(&y.C1), + } - return direct } func (e Ext12) Inverse(x *E12) *E12 { - res, err := e.fp.NewHint(inverseE12Hint, 12, &x.A0, &x.A1, &x.A2, &x.A3, &x.A4, &x.A5, &x.A6, &x.A7, &x.A8, &x.A9, &x.A10, &x.A11) + res, err := e.fp.NewHint(inverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) } - inv := E12{A0: *res[0], A1: *res[1], A2: *res[2], A3: *res[3], A4: *res[4], A5: *res[5], A6: *res[6], A7: *res[7], A8: *res[8], A9: *res[9], A10: *res[10], A11: *res[11]} + inv := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + one := e.One() // 1 == inv * x @@ -427,328 +223,41 @@ func (e Ext12) Inverse(x *E12) *E12 { } func (e Ext12) DivUnchecked(x, y *E12) *E12 { - res, err := e.fp.NewHint(divE12Hint, 12, &x.A0, &x.A1, &x.A2, &x.A3, &x.A4, &x.A5, &x.A6, &x.A7, &x.A8, &x.A9, &x.A10, &x.A11, &y.A0, &y.A1, &y.A2, &y.A3, &y.A4, &y.A5, &y.A6, &y.A7, &y.A8, &y.A9, &y.A10, &y.A11) + res, err := e.fp.NewHint(divE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) + if err != nil { // err is non-nil only for invalid number of inputs panic(err) } - div := E12{A0: *res[0], A1: *res[1], A2: *res[2], A3: *res[3], A4: *res[4], A5: *res[5], A6: *res[6], A7: *res[7], A8: *res[8], A9: *res[9], A10: *res[10], A11: *res[11]} + div := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } - // x = div * y + // x == div * y _x := e.Mul(&div, y) e.AssertIsEqual(x, _x) return &div - -} - -func (e Ext12) AssertIsEqual(a, b *E12) { - e.fp.AssertIsEqual(&a.A0, &b.A0) - e.fp.AssertIsEqual(&a.A1, &b.A1) - e.fp.AssertIsEqual(&a.A2, &b.A2) - e.fp.AssertIsEqual(&a.A3, &b.A3) - e.fp.AssertIsEqual(&a.A4, &b.A4) - e.fp.AssertIsEqual(&a.A5, &b.A5) - e.fp.AssertIsEqual(&a.A6, &b.A6) - e.fp.AssertIsEqual(&a.A7, &b.A7) - e.fp.AssertIsEqual(&a.A8, &b.A8) - e.fp.AssertIsEqual(&a.A9, &b.A9) - e.fp.AssertIsEqual(&a.A10, &b.A10) - e.fp.AssertIsEqual(&a.A11, &b.A11) -} - -func (e Ext12) IsEqual(x, y *E12) frontend.Variable { - diff0 := e.fp.Sub(&x.A0, &y.A0) - diff1 := e.fp.Sub(&x.A1, &y.A1) - diff2 := e.fp.Sub(&x.A2, &y.A2) - diff3 := e.fp.Sub(&x.A3, &y.A3) - diff4 := e.fp.Sub(&x.A4, &y.A4) - diff5 := e.fp.Sub(&x.A5, &y.A5) - diff6 := e.fp.Sub(&x.A6, &y.A6) - diff7 := e.fp.Sub(&x.A7, &y.A7) - diff8 := e.fp.Sub(&x.A8, &y.A8) - diff9 := e.fp.Sub(&x.A9, &y.A9) - diff10 := e.fp.Sub(&x.A10, &y.A10) - diff11 := e.fp.Sub(&x.A11, &y.A11) - isZero0 := e.fp.IsZero(diff0) - isZero1 := e.fp.IsZero(diff1) - isZero2 := e.fp.IsZero(diff2) - isZero3 := e.fp.IsZero(diff3) - isZero4 := e.fp.IsZero(diff4) - isZero5 := e.fp.IsZero(diff5) - isZero6 := e.fp.IsZero(diff6) - isZero7 := e.fp.IsZero(diff7) - isZero8 := e.fp.IsZero(diff8) - isZero9 := e.fp.IsZero(diff9) - isZero10 := e.fp.IsZero(diff10) - isZero11 := e.fp.IsZero(diff11) - - return e.api.And( - e.api.And( - e.api.And(e.api.And(isZero0, isZero1), e.api.And(isZero2, isZero3)), - e.api.And(e.api.And(isZero4, isZero5), e.api.And(isZero6, isZero7)), - ), - e.api.And(e.api.And(isZero8, isZero9), e.api.And(isZero10, isZero11)), - ) -} - -func (e Ext12) Copy(x *E12) *E12 { - return &E12{ - A0: x.A0, - A1: x.A1, - A2: x.A2, - A3: x.A3, - A4: x.A4, - A5: x.A5, - A6: x.A6, - A7: x.A7, - A8: x.A8, - A9: x.A9, - A10: x.A10, - A11: x.A11, - } -} - -func (e Ext12) Frobenius(a *E12) *E12 { - tower := e.ToTower(a) - - tower[1] = e.fp.Neg(tower[1]) - tower[3] = e.fp.Neg(tower[3]) - tower[5] = e.fp.Neg(tower[5]) - tower[7] = e.fp.Neg(tower[7]) - tower[9] = e.fp.Neg(tower[9]) - tower[11] = e.fp.Neg(tower[11]) - - t1 := e.Ext2.MulByNonResidue1Power2(&E2{A0: *tower[2], A1: *tower[3]}) - t2 := e.Ext2.MulByNonResidue1Power4(&E2{A0: *tower[4], A1: *tower[5]}) - t3 := e.Ext2.MulByNonResidue1Power1(&E2{A0: *tower[6], A1: *tower[7]}) - t4 := e.Ext2.MulByNonResidue1Power3(&E2{A0: *tower[8], A1: *tower[9]}) - t5 := e.Ext2.MulByNonResidue1Power5(&E2{A0: *tower[10], A1: *tower[11]}) - - nine := big.NewInt(9) - A0 := e.fp.Sub(tower[0], e.fp.MulConst(tower[1], nine)) - A1 := e.fp.Sub(&t3.A0, e.fp.MulConst(&t3.A1, nine)) - A2 := e.fp.Sub(&t1.A0, e.fp.MulConst(&t1.A1, nine)) - A3 := e.fp.Sub(&t4.A0, e.fp.MulConst(&t4.A1, nine)) - A4 := e.fp.Sub(&t2.A0, e.fp.MulConst(&t2.A1, nine)) - A5 := e.fp.Sub(&t5.A0, e.fp.MulConst(&t5.A1, nine)) - - return &E12{ - A0: *A0, - A1: *A1, - A2: *A2, - A3: *A3, - A4: *A4, - A5: *A5, - A6: *tower[1], - A7: t3.A1, - A8: t1.A1, - A9: t4.A1, - A10: t2.A1, - A11: t5.A1, - } -} - -func (e Ext12) FrobeniusSquare(a *E12) *E12 { - tower := e.ToTower(a) - - t1 := e.Ext2.MulByNonResidue2Power2(&E2{A0: *tower[2], A1: *tower[3]}) - t2 := e.Ext2.MulByNonResidue2Power4(&E2{A0: *tower[4], A1: *tower[5]}) - t3 := e.Ext2.MulByNonResidue2Power1(&E2{A0: *tower[6], A1: *tower[7]}) - t4 := e.Ext2.MulByNonResidue2Power3(&E2{A0: *tower[8], A1: *tower[9]}) - t5 := e.Ext2.MulByNonResidue2Power5(&E2{A0: *tower[10], A1: *tower[11]}) - - nine := big.NewInt(9) - A0 := e.fp.Sub(tower[0], e.fp.MulConst(tower[1], nine)) - A1 := e.fp.Sub(&t3.A0, e.fp.MulConst(&t3.A1, nine)) - A2 := e.fp.Sub(&t1.A0, e.fp.MulConst(&t1.A1, nine)) - A3 := e.fp.Sub(&t4.A0, e.fp.MulConst(&t4.A1, nine)) - A4 := e.fp.Sub(&t2.A0, e.fp.MulConst(&t2.A1, nine)) - A5 := e.fp.Sub(&t5.A0, e.fp.MulConst(&t5.A1, nine)) - - return &E12{ - A0: *A0, - A1: *A1, - A2: *A2, - A3: *A3, - A4: *A4, - A5: *A5, - A6: *tower[1], - A7: t3.A1, - A8: t1.A1, - A9: t4.A1, - A10: t2.A1, - A11: t5.A1, - } -} - -func (e Ext12) FrobeniusCube(a *E12) *E12 { - tower := e.ToTower(a) - - tower[1] = e.fp.Neg(tower[1]) - tower[3] = e.fp.Neg(tower[3]) - tower[5] = e.fp.Neg(tower[5]) - tower[7] = e.fp.Neg(tower[7]) - tower[9] = e.fp.Neg(tower[9]) - tower[11] = e.fp.Neg(tower[11]) - - t1 := e.Ext2.MulByNonResidue3Power2(&E2{A0: *tower[2], A1: *tower[3]}) - t2 := e.Ext2.MulByNonResidue3Power4(&E2{A0: *tower[4], A1: *tower[5]}) - t3 := e.Ext2.MulByNonResidue3Power1(&E2{A0: *tower[6], A1: *tower[7]}) - t4 := e.Ext2.MulByNonResidue3Power3(&E2{A0: *tower[8], A1: *tower[9]}) - t5 := e.Ext2.MulByNonResidue3Power5(&E2{A0: *tower[10], A1: *tower[11]}) - - nine := big.NewInt(9) - A0 := e.fp.Sub(tower[0], e.fp.MulConst(tower[1], nine)) - A1 := e.fp.Sub(&t3.A0, e.fp.MulConst(&t3.A1, nine)) - A2 := e.fp.Sub(&t1.A0, e.fp.MulConst(&t1.A1, nine)) - A3 := e.fp.Sub(&t4.A0, e.fp.MulConst(&t4.A1, nine)) - A4 := e.fp.Sub(&t2.A0, e.fp.MulConst(&t2.A1, nine)) - A5 := e.fp.Sub(&t5.A0, e.fp.MulConst(&t5.A1, nine)) - - return &E12{ - A0: *A0, - A1: *A1, - A2: *A2, - A3: *A3, - A4: *A4, - A5: *A5, - A6: *tower[1], - A7: t3.A1, - A8: t1.A1, - A9: t4.A1, - A10: t2.A1, - A11: t5.A1, - } -} - -// tower to direct extension conversion -func FromE12(a *bn254.E12) E12 { - // gnark-crypto uses a quadratic over cubic over quadratic 12th extension of Fp. - // The two towers are isomorphic and the coefficients are permuted as follows: - // a000 a001 a010 a011 a020 a021 a100 a101 a110 a111 a120 a121 - // a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 - // - // A0 = a000 - 9 * a001 - // A1 = a100 - 9 * a101 - // A2 = a010 - 9 * a011 - // A3 = a110 - 9 * a111 - // A4 = a020 - 9 * a021 - // A5 = a120 - 9 * a121 - // A6 = a001 - // A7 = a101 - // A8 = a011 - // A9 = a111 - // A10 = a021 - // A11 = a121 - - var c0, c1, c2, c3, c4, c5, t fp_bn.Element - t.SetUint64(9).Mul(&t, &a.C0.B0.A1) - c0.Sub(&a.C0.B0.A0, &t) - t.SetUint64(9).Mul(&t, &a.C1.B0.A1) - c1.Sub(&a.C1.B0.A0, &t) - t.SetUint64(9).Mul(&t, &a.C0.B1.A1) - c2.Sub(&a.C0.B1.A0, &t) - t.SetUint64(9).Mul(&t, &a.C1.B1.A1) - c3.Sub(&a.C1.B1.A0, &t) - t.SetUint64(9).Mul(&t, &a.C0.B2.A1) - c4.Sub(&a.C0.B2.A0, &t) - t.SetUint64(9).Mul(&t, &a.C1.B2.A1) - c5.Sub(&a.C1.B2.A0, &t) - - return E12{ - A0: emulated.ValueOf[emulated.BN254Fp](c0), - A1: emulated.ValueOf[emulated.BN254Fp](c1), - A2: emulated.ValueOf[emulated.BN254Fp](c2), - A3: emulated.ValueOf[emulated.BN254Fp](c3), - A4: emulated.ValueOf[emulated.BN254Fp](c4), - A5: emulated.ValueOf[emulated.BN254Fp](c5), - A6: emulated.ValueOf[emulated.BN254Fp](a.C0.B0.A1), - A7: emulated.ValueOf[emulated.BN254Fp](a.C1.B0.A1), - A8: emulated.ValueOf[emulated.BN254Fp](a.C0.B1.A1), - A9: emulated.ValueOf[emulated.BN254Fp](a.C1.B1.A1), - A10: emulated.ValueOf[emulated.BN254Fp](a.C0.B2.A1), - A11: emulated.ValueOf[emulated.BN254Fp](a.C1.B2.A1), - } } -func (e Ext12) ToTower(a *E12) [12]*baseEl { - // gnark-crypto uses a quadratic over cubic over quadratic 12th extension of Fp. - // The two towers are isomorphic and the coefficients are permuted as follows: - // - // tower = a000 a001 a010 a011 a020 a021 a100 a101 a110 a111 a120 a121 - // direct = a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 - // - // a000 = A0 + 9 * A6 - // a001 = A6 - // a010 = A2 + 9 * A8 - // a011 = A8 - // a020 = A4 + 9 * A10 - // a021 = A10 - // a100 = A1 + 9 * A7 - // a101 = A7 - // a110 = A3 + 9 * A9 - // a111 = A9 - // a120 = A5 + 9 * A11 - // a121 = A11 - nine := big.NewInt(9) - a000 := e.fp.Add(&a.A0, e.fp.MulConst(&a.A6, nine)) - a001 := &a.A6 - a010 := e.fp.Add(&a.A2, e.fp.MulConst(&a.A8, nine)) - a011 := &a.A8 - a020 := e.fp.Add(&a.A4, e.fp.MulConst(&a.A10, nine)) - a021 := &a.A10 - a100 := e.fp.Add(&a.A1, e.fp.MulConst(&a.A7, nine)) - a101 := &a.A7 - a110 := e.fp.Add(&a.A3, e.fp.MulConst(&a.A9, nine)) - a111 := &a.A9 - a120 := e.fp.Add(&a.A5, e.fp.MulConst(&a.A11, nine)) - a121 := &a.A11 - - tower := [12]*baseEl{a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121} - return tower +func (e Ext12) Select(selector frontend.Variable, z1, z0 *E12) *E12 { + c0 := e.Ext6.Select(selector, &z1.C0, &z0.C0) + c1 := e.Ext6.Select(selector, &z1.C1, &z0.C1) + return &E12{C0: *c0, C1: *c1} } -func (e Ext12) FromTower(tower [12]*baseEl) *E12 { - // gnark-crypto uses a quadratic over cubic over quadratic 12th extension of Fp. - // The two towers are isomorphic and the coefficients are permuted as follows: - // - // tower = a000 a001 a010 a011 a020 a021 a100 a101 a110 a111 a120 a121 - // direct = a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 - // - // A0 = a000 - 9 * a001 - // A1 = a100 - 9 * a101 - // A2 = a010 - 9 * a011 - // A3 = a110 - 9 * a111 - // A4 = a020 - 9 * a021 - // A5 = a120 - 9 * a121 - // A6 = a001 - // A7 = a101 - // A8 = a011 - // A9 = a111 - // A10 = a021 - // A11 = a121 - nine := big.NewInt(9) - A0 := e.fp.Sub(tower[0], e.fp.MulConst(tower[1], nine)) - A1 := e.fp.Sub(tower[6], e.fp.MulConst(tower[7], nine)) - A2 := e.fp.Sub(tower[2], e.fp.MulConst(tower[3], nine)) - A3 := e.fp.Sub(tower[8], e.fp.MulConst(tower[9], nine)) - A4 := e.fp.Sub(tower[4], e.fp.MulConst(tower[5], nine)) - A5 := e.fp.Sub(tower[10], e.fp.MulConst(tower[11], nine)) - - return &E12{ - A0: *A0, - A1: *A1, - A2: *A2, - A3: *A3, - A4: *A4, - A5: *A5, - A6: *tower[1], - A7: *tower[7], - A8: *tower[3], - A9: *tower[9], - A10: *tower[5], - A11: *tower[11], - } +func (e Ext12) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E12) *E12 { + c0 := e.Ext6.Lookup2(s1, s2, &a.C0, &b.C0, &c.C0, &d.C0) + c1 := e.Ext6.Lookup2(s1, s2, &a.C1, &b.C1, &c.C1, &d.C1) + return &E12{C0: *c0, C1: *c1} } diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 395df71824..2e0411afed 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -1,80 +1,16 @@ package fields_bn254 import ( - "math/big" + "github.com/consensys/gnark/std/math/emulated" ) -func (e Ext12) nSquare(z *E12, n int) *E12 { - for i := 0; i < n; i++ { - z = e.Square(z) - } - return z -} - func (e Ext12) nSquareGS(z *E12, n int) *E12 { for i := 0; i < n; i++ { - z = e.CyclotomicSquareGS(z) + z = e.CyclotomicSquare(z) } return z } -// Exponentiation by the seed t=4965661367192848881 -func (e Ext12) Expt(x *E12) *E12 { - // ExptTorus computation is derived from the addition chain: - // - // _10 = 2*1 - // _100 = 2*_10 - // _1000 = 2*_100 - // _10000 = 2*_1000 - // _10001 = 1 + _10000 - // _10011 = _10 + _10001 - // _10100 = 1 + _10011 - // _11001 = _1000 + _10001 - // _100010 = 2*_10001 - // _100111 = _10011 + _10100 - // _101001 = _10 + _100111 - // i27 = (_100010 << 6 + _100 + _11001) << 7 + _11001 - // i44 = (i27 << 8 + _101001 + _10) << 6 + _10001 - // i70 = ((i44 << 8 + _101001) << 6 + _101001) << 10 - // return (_100111 + i70) << 6 + _101001 + _1000 - // - // Operations: 62 squares 17 multiplies - // - // Generated by github.com/mmcloughlin/addchain v0.4.0. - - t3 := e.CyclotomicSquareGS(x) - t5 := e.CyclotomicSquareGS(t3) - result := e.CyclotomicSquareGS(t5) - t0 := e.CyclotomicSquareGS(result) - t2 := e.Mul(x, t0) - t0 = e.Mul(t3, t2) - t1 := e.Mul(x, t0) - t4 := e.Mul(result, t2) - t6 := e.CyclotomicSquareGS(t2) - t1 = e.Mul(t0, t1) - t0 = e.Mul(t3, t1) - t6 = e.nSquareGS(t6, 6) - t5 = e.Mul(t5, t6) - t5 = e.Mul(t4, t5) - t5 = e.nSquareGS(t5, 7) - t4 = e.Mul(t4, t5) - t4 = e.nSquareGS(t4, 8) - t4 = e.Mul(t0, t4) - t3 = e.Mul(t3, t4) - t3 = e.nSquareGS(t3, 6) - t2 = e.Mul(t2, t3) - t2 = e.nSquareGS(t2, 8) - t2 = e.Mul(t0, t2) - t2 = e.nSquareGS(t2, 6) - t2 = e.Mul(t0, t2) - t2 = e.nSquareGS(t2, 10) - t1 = e.Mul(t1, t2) - t1 = e.nSquareGS(t1, 6) - t0 = e.Mul(t0, t1) - z := e.Mul(result, t0) - return z -} - // Exponentiation by U=6u+2 where t is the seed u=4965661367192848881 func (e Ext12) ExpByU(x *E12) *E12 { // ExpByU computation is derived from the addition chain: @@ -103,238 +39,504 @@ func (e Ext12) ExpByU(x *E12) *E12 { z = e.Mul(x, t1) t2 := e.Square(t1) t1 = e.Mul(t0, t2) - t2 = e.nSquare(t2, 3) + t2 = e.nSquareGS(t2, 3) t2 = e.Mul(z, t2) - t2 = e.nSquare(t2, 2) + t2 = e.nSquareGS(t2, 2) t2 = e.Mul(x, t2) - t2 = e.nSquare(t2, 5) + t2 = e.nSquareGS(t2, 5) t2 = e.Mul(t1, t2) - t2 = e.nSquare(t2, 3) + t2 = e.nSquareGS(t2, 3) t2 = e.Mul(x, t2) - t2 = e.nSquare(t2, 4) + t2 = e.nSquareGS(t2, 4) t2 = e.Mul(z, t2) - t2 = e.nSquare(t2, 9) + t2 = e.nSquareGS(t2, 9) t2 = e.Mul(z, t2) - t2 = e.nSquare(t2, 4) + t2 = e.nSquareGS(t2, 4) t2 = e.Mul(t0, t2) - t2 = e.nSquare(t2, 5) + t2 = e.nSquareGS(t2, 5) t1 = e.Mul(t1, t2) t1 = e.Square(t1) t1 = e.Mul(x, t1) - t1 = e.nSquare(t1, 5) + t1 = e.nSquareGS(t1, 5) t1 = e.Mul(z, t1) - t1 = e.nSquare(t1, 3) + t1 = e.nSquareGS(t1, 3) t0 = e.Mul(t0, t1) - t0 = e.nSquare(t0, 6) + t0 = e.nSquareGS(t0, 6) t0 = e.Mul(z, t0) - t0 = e.nSquare(t0, 4) + t0 = e.nSquareGS(t0, 4) z = e.Mul(z, t0) - z = e.nSquare(z, 2) + z = e.nSquareGS(z, 2) z = e.Mul(x, z) - z = e.nSquare(z, 2) + z = e.nSquareGS(z, 2) z = e.Mul(x, z) - z = e.nSquare(z, 3) + z = e.nSquareGS(z, 3) + + return z +} + +func (e Ext12) nSquareTorus(z *E6, n int) *E6 { + for i := 0; i < n; i++ { + z = e.SquareTorus(z) + } + return z +} + +// Exponentiation by the seed t=4965661367192848881 +// The computations are performed on E6 compressed form using Torus-based arithmetic. +func (e Ext12) ExptTorus(x *E6) *E6 { + // ExptTorus computation is derived from the addition chain: + // + // _10 = 2*1 + // _100 = 2*_10 + // _1000 = 2*_100 + // _10000 = 2*_1000 + // _10001 = 1 + _10000 + // _10011 = _10 + _10001 + // _10100 = 1 + _10011 + // _11001 = _1000 + _10001 + // _100010 = 2*_10001 + // _100111 = _10011 + _10100 + // _101001 = _10 + _100111 + // i27 = (_100010 << 6 + _100 + _11001) << 7 + _11001 + // i44 = (i27 << 8 + _101001 + _10) << 6 + _10001 + // i70 = ((i44 << 8 + _101001) << 6 + _101001) << 10 + // return (_100111 + i70) << 6 + _101001 + _1000 + // + // Operations: 62 squares 17 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + t3 := e.SquareTorus(x) + t5 := e.SquareTorus(t3) + result := e.SquareTorus(t5) + t0 := e.SquareTorus(result) + t2 := e.MulTorus(x, t0) + t0 = e.MulTorus(t3, t2) + t1 := e.MulTorus(x, t0) + t4 := e.MulTorus(result, t2) + t6 := e.SquareTorus(t2) + t1 = e.MulTorus(t0, t1) + t0 = e.MulTorus(t3, t1) + t6 = e.nSquareTorus(t6, 6) + t5 = e.MulTorus(t5, t6) + t5 = e.MulTorus(t4, t5) + t5 = e.nSquareTorus(t5, 7) + t4 = e.MulTorus(t4, t5) + t4 = e.nSquareTorus(t4, 8) + t4 = e.MulTorus(t0, t4) + t3 = e.MulTorus(t3, t4) + t3 = e.nSquareTorus(t3, 6) + t2 = e.MulTorus(t2, t3) + t2 = e.nSquareTorus(t2, 8) + t2 = e.MulTorus(t0, t2) + t2 = e.nSquareTorus(t2, 6) + t2 = e.MulTorus(t0, t2) + t2 = e.nSquareTorus(t2, 10) + t1 = e.MulTorus(t1, t2) + t1 = e.nSquareTorus(t1, 6) + t0 = e.MulTorus(t0, t1) + z := e.MulTorus(result, t0) return z } -// MulBy01379 multiplies a by an E12 sparse element b of the form +// Square034 squares an E12 sparse element of the form // -// b.A0 = 1 -// b.A1 = c3.A0 - 9 * c3.A1 -// b.A2 = 0 -// b.A3 = c4.A0 - 9 * c4.A1 -// b.A4 = 0 -// b.A5 = 0 -// b.A6 = 0 -// b.A7 = c3.A1 -// b.A8 = 0 -// b.A9 = c4.A1 -// b.A10 = 0 -// b.A11 = 0 -func (e *Ext12) MulBy01379(a *E12, c3, c4 *E2) *E12 { - nine := big.NewInt(9) - b1 := e.fp.Sub(&c3.A0, e.fp.MulConst(&c3.A1, nine)) - b3 := e.fp.Sub(&c4.A0, e.fp.MulConst(&c4.A1, nine)) - b7 := &c3.A1 - b9 := &c4.A1 - // d0 = a0 - 82 * (a3 b9 + a5 b7 + a9 b3 + a11 b1) - 1476 * (a9 b9 + a11 b7) - mone := e.fp.NewElement(-1) - d0 := e.fp.Eval([][]*baseEl{{&a.A0}, {mone, &a.A3, b9}, {mone, &a.A5, b7}, {mone, &a.A9, b3}, {mone, &a.A11, b1}, {mone, &a.A9, b9}, {mone, &a.A11, b7}}, []int{1, 82, 82, 82, 82, 1476, 1476}) - - // d1 = a0 b1 + a1 - 82 * (a4 b9 + a10 b3 + a6 b7) - 1476 * a10 b9 - d1 := e.fp.Eval([][]*baseEl{{&a.A0, b1}, {&a.A1}, {mone, &a.A4, b9}, {mone, &a.A10, b3}, {mone, &a.A6, b7}, {mone, &a.A10, b9}}, []int{1, 1, 82, 82, 82, 1476}) - - // d2 = a1 b1 + a2 - 82 * (a5 b9 + a11 b3 + a7 b7) - 1476 * a11 b9 - d2 := e.fp.Eval([][]*baseEl{{&a.A1, b1}, {&a.A2}, {mone, &a.A5, b9}, {mone, &a.A11, b3}, {mone, &a.A7, b7}, {mone, &a.A11, b9}}, []int{1, 1, 82, 82, 82, 1476}) - - // d3 = a0 b3 + a2 b1 + a3 - 82 * (a6 b9 + a8 b7) - d3 := e.fp.Eval([][]*baseEl{{&a.A0, b3}, {&a.A2, b1}, {&a.A3}, {mone, &a.A6, b9}, {mone, &a.A8, b7}}, []int{1, 1, 1, 82, 82}) - - // d4 = a1 b3 + a3 b1 + a4 - 82 * (a7 b9 + a9 b7) - d4 := e.fp.Eval([][]*baseEl{{&a.A1, b3}, {&a.A3, b1}, {&a.A4}, {mone, &a.A7, b9}, {mone, &a.A9, b7}}, []int{1, 1, 1, 82, 82}) - - // d5 = a2 b3 + a4 b1 + a5 - 82 * (a8 b9 + a10 b7) - d5 := e.fp.Eval([][]*baseEl{{&a.A2, b3}, {&a.A4, b1}, {&a.A5}, {mone, &a.A8, b9}, {mone, &a.A10, b7}}, []int{1, 1, 1, 82, 82}) - - // d6 = a3 b3 + a5 b1 + a6 + 18 * (a3 b9 + a9 b3 + a11 b1 + a5 b7) + 242 * (a9 b9 + a11 b7) - d6 := e.fp.Eval([][]*baseEl{{&a.A3, b3}, {&a.A5, b1}, {&a.A6}, {&a.A3, b9}, {&a.A9, b3}, {&a.A11, b1}, {&a.A5, b7}, {&a.A11, b7}, {&a.A9, b9}}, []int{1, 1, 1, 18, 18, 18, 18, 242, 242}) - - // d7 = a0 b7 + a4 b3 + a6 b1 + a7 + 18 * (a4 b9 + a10 b3 + a6 b7) + 242 * a10 b9 - d7 := e.fp.Eval([][]*baseEl{{&a.A0, b7}, {&a.A4, b3}, {&a.A6, b1}, {&a.A7}, {&a.A4, b9}, {&a.A10, b3}, {&a.A6, b7}, {&a.A10, b9}}, []int{1, 1, 1, 1, 18, 18, 18, 242}) - - // d8 = a1 b7 + a5 b3 + a7 b1 + a8 + 18 * (a5 b9 + a11 b3 + a7 b7) + 242 * a11 b9 - d8 := e.fp.Eval([][]*baseEl{{&a.A1, b7}, {&a.A5, b3}, {&a.A7, b1}, {&a.A8}, {&a.A5, b9}, {&a.A11, b3}, {&a.A7, b7}, {&a.A11, b9}}, []int{1, 1, 1, 1, 18, 18, 18, 242}) - - // d9 = a2 b7 + a0 b9 + a6 b3 + a8 b1 + a9 + 18 * (a6 b9 + a8 b7) - d9 := e.fp.Eval([][]*baseEl{{&a.A2, b7}, {&a.A0, b9}, {&a.A6, b3}, {&a.A8, b1}, {&a.A9}, {&a.A6, b9}, {&a.A8, b7}}, []int{1, 1, 1, 1, 1, 18, 18}) - - // d10 = a3 b7 + a1 b9 + a7 b3 + a9 b1 + a10 + 18 * (a7 b9 + a9 b7) - d10 := e.fp.Eval([][]*baseEl{{&a.A3, b7}, {&a.A1, b9}, {&a.A7, b3}, {&a.A9, b1}, {&a.A10}, {&a.A7, b9}, {&a.A9, b7}}, []int{1, 1, 1, 1, 1, 18, 18}) - - // d11 = a4 b7 + a2 b9 + a8 b3 + a10 b1 + a11 + 18 * (a8 b9 + a10 b7) - d11 := e.fp.Eval([][]*baseEl{{&a.A4, b7}, {&a.A2, b9}, {&a.A8, b3}, {&a.A10, b1}, {&a.A11}, {&a.A8, b9}, {&a.A10, b7}}, []int{1, 1, 1, 1, 1, 18, 18}) +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: c3, B1: c4, B2: 0}, +// } +func (e *Ext12) Square034(x *E12) *E12 { + c0 := E6{ + B0: *e.Ext2.Sub(&x.C0.B0, &x.C1.B0), + B1: *e.Ext2.Neg(&x.C1.B1), + B2: *e.Ext2.Zero(), + } + + c3 := &E6{ + B0: x.C0.B0, + B1: *e.Ext2.Neg(&x.C1.B0), + B2: *e.Ext2.Neg(&x.C1.B1), + } + + c2 := E6{ + B0: x.C1.B0, + B1: x.C1.B1, + B2: *e.Ext2.Zero(), + } + c3 = e.MulBy01(c3, &c0.B0, &c0.B1) + c3 = e.Ext6.Add(c3, &c2) + + var z E12 + z.C1.B0 = *e.Ext2.Add(&c2.B0, &c2.B0) + z.C1.B1 = *e.Ext2.Add(&c2.B1, &c2.B1) + + z.C0.B0 = c3.B0 + z.C0.B1 = *e.Ext2.Add(&c3.B1, &c2.B0) + z.C0.B2 = *e.Ext2.Add(&c3.B2, &c2.B1) + + return &z +} + +// MulBy034 multiplies z by an E12 sparse element of the form +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: c3, B1: c4, B2: 0}, +// } +func (e *Ext12) MulBy034(z *E12, c3, c4 *E2) *E12 { + + a := z.C0 + b := e.MulBy01(&z.C1, c3, c4) + c3 = e.Ext2.Add(e.Ext2.One(), c3) + d := e.Ext6.Add(&z.C0, &z.C1) + d = e.MulBy01(d, c3, c4) + + zC1 := e.Ext6.Add(&a, b) + zC1 = e.Ext6.Neg(zC1) + zC1 = e.Ext6.Add(zC1, d) + zC0 := e.Ext6.MulByNonResidue(b) + zC0 = e.Ext6.Add(zC0, &a) return &E12{ - A0: *d0, - A1: *d1, - A2: *d2, - A3: *d3, - A4: *d4, - A5: *d5, - A6: *d6, - A7: *d7, - A8: *d8, - A9: *d9, - A10: *d10, - A11: *d11, + C0: *zC0, + C1: *zC1, } } -// Mul01379By01379 multiplies two E12 sparse element of the form: +// multiplies two E12 sparse element of the form: +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: c3, B1: c4, B2: 0}, +// } +// +// and +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: d3, B1: d4, B2: 0}, +// } +func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) [5]*E2 { + x3 := e.Ext2.Mul(c3, d3) + x4 := e.Ext2.Mul(c4, d4) + x04 := e.Ext2.Add(c4, d4) + x03 := e.Ext2.Add(c3, d3) + tmp := e.Ext2.Add(c3, c4) + x34 := e.Ext2.Add(d3, d4) + x34 = e.Ext2.Mul(x34, tmp) + tmp = e.Ext2.Add(x4, x3) + x34 = e.Ext2.Sub(x34, tmp) + + zC0B0 := e.Ext2.MulByNonResidue(x4) + zC0B0 = e.Ext2.Add(zC0B0, e.Ext2.One()) + zC0B1 := x3 + zC0B2 := x34 + zC1B0 := x03 + zC1B1 := x04 + + return [5]*E2{zC0B0, zC0B1, zC0B2, zC1B0, zC1B1} +} + +// MulBy01234 multiplies z by an E12 sparse element of the form // -// A0 = 1 -// A1 = c3.A0 - 9 * c3.A1 -// A2 = 0 -// A3 = c4.A0 - 9 * c4.A1 -// A4 = 0 -// A5 = 0 -// A6 = 0 -// A7 = c3.A1 -// A8 = 0 -// A9 = c4.A1 -// A10 = 0 -// A11 = 0 -func (e *Ext12) Mul01379By01379(e3, e4, c3, c4 *E2) [10]*baseEl { - nine := big.NewInt(9) - a1 := e.fp.Sub(&e3.A0, e.fp.MulConst(&e3.A1, nine)) - a3 := e.fp.Sub(&e4.A0, e.fp.MulConst(&e4.A1, nine)) - a7 := &e3.A1 - a9 := &e4.A1 - b1 := e.fp.Sub(&c3.A0, e.fp.MulConst(&c3.A1, nine)) - b3 := e.fp.Sub(&c4.A0, e.fp.MulConst(&c4.A1, nine)) - b7 := &c3.A1 - b9 := &c4.A1 - - // d0 = 1 - 82 * (a3 b9 + a9 b3) - 1476 * a9 b9 - mone := e.fp.NewElement(-1) - d0 := e.fp.Eval([][]*baseEl{{a3, b9}, {a9, b3}, {a9, b9}, {mone}}, []int{82, 82, 1476, 1}) - d0 = e.fp.Neg(d0) - - // d1 = b1 + a1 - d1 := e.fp.Add(a1, b1) - - // d2 = a1 b1 - 82 * a7 b7 - d2 := e.fp.Eval([][]*baseEl{{a1, b1}, {mone, a7, b7}}, []int{1, 82}) - - // d3 = b3 + a3 - d3 := e.fp.Add(a3, b3) - - // d4 = a1 b3 + a3 b1 - 82 * (a7 b9 + a9 b7) - d4 := e.fp.Eval([][]*baseEl{{a1, b3}, {a3, b1}, {mone, a7, b9}, {mone, a9, b7}}, []int{1, 1, 82, 82}) - - // d6 = a3 b3 + 18 * (a3 b9 + a9 b3) + 242 * a9 b9 - d6 := e.fp.Eval([][]*baseEl{{a3, b3}, {a3, b9}, {a9, b3}, {a9, b9}}, []int{1, 18, 18, 242}) - - // d7 = b7 + a7 - d7 := e.fp.Add(a7, b7) - - // d8 = a1 b7 + a7 b1 + 18 * a7 b7 - d8 := e.fp.Eval([][]*baseEl{{a1, b7}, {a7, b1}, {a7, b7}}, []int{1, 1, 18}) - - // d9 = b9 + a9 - d9 := e.fp.Add(a9, b9) - - // d10 = a3 b7 + a1 b9 + a7 b3 + a9 b1 + 18 * (a7 b9 + a9 b7) - d10 := e.fp.Eval([][]*baseEl{{a3, b7}, {a1, b9}, {a7, b3}, {a9, b1}, {a7, b9}, {a9, b7}}, []int{1, 1, 1, 1, 18, 18}) - - return [10]*baseEl{d0, d1, d2, d3, d4, d6, d7, d8, d9, d10} +// E12{ +// C0: E6{B0: c0, B1: c1, B2: c2}, +// C1: E6{B0: c3, B1: c4, B2: 0}, +// } +func (e *Ext12) MulBy01234(z *E12, x [5]*E2) *E12 { + c0 := &E6{B0: *x[0], B1: *x[1], B2: *x[2]} + c1 := &E6{B0: *x[3], B1: *x[4], B2: *e.Ext2.Zero()} + a := e.Ext6.Add(&z.C0, &z.C1) + b := e.Ext6.Add(c0, c1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&z.C0, c0) + c := e.Ext6.MulBy01(&z.C1, x[3], x[4]) + d := e.Ext6.Add(c, b) + z1 := e.Ext6.Sub(a, d) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +// multiplies two E12 sparse element of the form: +// +// E12{ +// C0: E6{B0: x0, B1: x1, B2: x2}, +// C1: E6{B0: x3, B1: x4, B2: 0}, +// } +// +// and +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: z3, B1: z4, B2: 0}, +// } +func (e *Ext12) Mul01234By034(x [5]*E2, z3, z4 *E2) *E12 { + c0 := &E6{B0: *x[0], B1: *x[1], B2: *x[2]} + c1 := &E6{B0: *x[3], B1: *x[4], B2: *e.Ext2.Zero()} + a := e.Ext6.Add(e.Ext6.One(), &E6{B0: *z3, B1: *z4, B2: *e.Ext2.Zero()}) + b := e.Ext6.Add(c0, c1) + a = e.Ext6.Mul(a, b) + c := e.Ext6.Mul01By01(z3, z4, x[3], x[4]) + b = e.Ext6.Add(c0, c) + z1 := e.Ext6.Sub(a, b) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, c0) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +// Torus-based arithmetic: +// +// After the easy part of the final exponentiation the elements are in a proper +// subgroup of Fpk (E12) that coincides with some algebraic tori. The elements +// are in the torus Tk(Fp) and thus in each torus Tk/d(Fp^d) for d|k, d≠k. We +// take d=6. So the elements are in T2(Fp6). +// Let G_{q,2} = {m ∈ Fq^2 | m^(q+1) = 1} where q = p^6. +// When m.C1 = 0, then m.C0 must be 1 or −1. +// +// We recall the tower construction: +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-9-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v + +// CompressTorus compresses x ∈ E12 to (x.C0 + 1)/x.C1 ∈ E6 +func (e Ext12) CompressTorus(x *E12) *E6 { + // x ∈ G_{q,2} \ {-1,1} + y := e.Ext6.Add(&x.C0, e.Ext6.One()) + y = e.Ext6.DivUnchecked(y, &x.C1) + return y +} + +// DecompressTorus decompresses y ∈ E6 to (y+w)/(y-w) ∈ E12 +func (e Ext12) DecompressTorus(y *E6) *E12 { + var n, d E12 + one := e.Ext6.One() + n.C0 = *y + n.C1 = *one + d.C0 = *y + d.C1 = *e.Ext6.Neg(one) + + x := e.DivUnchecked(&n, &d) + return x +} + +// MulTorus multiplies two compressed elements y1, y2 ∈ E6 +// and returns (y1 * y2 + v)/(y1 + y2) +// N.B.: we use MulTorus in the final exponentiation throughout y1 ≠ -y2 always. +func (e Ext12) MulTorus(y1, y2 *E6) *E6 { + n := e.Ext6.Mul(y1, y2) + n = &E6{ + B0: n.B0, + B1: *e.Ext2.Add(&n.B1, e.Ext2.One()), + B2: n.B2, + } + d := e.Ext6.Add(y1, y2) + y3 := e.Ext6.DivUnchecked(n, d) + return y3 } -// MulBy012346789 multiplies a by an E12 sparse element b of the form +// InverseTorus inverses a compressed elements y ∈ E6 +// and returns -y +func (e Ext12) InverseTorus(y *E6) *E6 { + return e.Ext6.Neg(y) +} + +// SquareTorus squares a compressed elements y ∈ E6 +// and returns (y + v/y)/2 // -// b.A0 = b[0] -// b.A1 = b[1] -// b.A2 = b[2] -// b.A3 = b[3] -// b.A4 = b[4] -// b.A5 = 0 -// b.A6 = b[5] -// b.A7 = b[6] -// b.A8 = b[7] -// b.A9 = b[8] -// b.A10 = b[9] -// b.A11 = 0 -func (e *Ext12) MulBy012346789(a *E12, b [10]*baseEl) *E12 { - // d0 = a0 b0 - 82 * (a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a8 b4 + a9 b3 + a10 b2 + a11 b1) - 1476 * (a8 b10 + a9 b9 + a10 b8 + a11 b7) - mone := e.fp.NewElement(-1) - d0 := e.fp.Eval([][]*baseEl{{&a.A0, b[0]}, {mone, &a.A2, b[9]}, {mone, &a.A3, b[8]}, {mone, &a.A4, b[7]}, {mone, &a.A5, b[6]}, {mone, &a.A6, b[5]}, {mone, &a.A8, b[4]}, {mone, &a.A9, b[3]}, {mone, &a.A10, b[2]}, {mone, &a.A11, b[1]}, {mone, &a.A8, b[9]}, {mone, &a.A9, b[8]}, {mone, &a.A10, b[7]}, {mone, &a.A11, b[6]}}, []int{1, 82, 82, 82, 82, 82, 82, 82, 82, 82, 1476, 1476, 1476, 1476}) +// It uses a hint to verify that (2x-y)y = v saving one E6 AssertIsEqual. +func (e Ext12) SquareTorus(y *E6) *E6 { + res, err := e.fp.NewHint(squareTorusHint, 6, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } - // d1 = a0 b1 + a1 b0 - 82 * (a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a9 b4 + a10 b3 + a11 b2) - 1476 * (a9 b10 + a10 b9 + a11 b8) - d1 := e.fp.Eval([][]*baseEl{{&a.A0, b[1]}, {&a.A1, b[0]}, {mone, &a.A3, b[9]}, {mone, &a.A4, b[8]}, {mone, &a.A5, b[7]}, {mone, &a.A6, b[6]}, {mone, &a.A7, b[5]}, {mone, &a.A9, b[4]}, {mone, &a.A10, b[3]}, {mone, &a.A11, b[2]}, {mone, &a.A9, b[9]}, {mone, &a.A10, b[8]}, {mone, &a.A11, b[7]}}, []int{1, 1, 82, 82, 82, 82, 82, 82, 82, 82, 1476, 1476, 1476}) + sq := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } - // d2 = a0 b2 + a1 b1 + a2 b0 - 82 * (a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a10 b4 + a11 b3) - 1476 * (a10 b10 + a11 b9) - d2 := e.fp.Eval([][]*baseEl{{&a.A0, b[2]}, {&a.A1, b[1]}, {&a.A2, b[0]}, {mone, &a.A4, b[9]}, {mone, &a.A5, b[8]}, {mone, &a.A6, b[7]}, {mone, &a.A7, b[6]}, {mone, &a.A8, b[5]}, {mone, &a.A10, b[4]}, {mone, &a.A11, b[3]}, {mone, &a.A10, b[9]}, {mone, &a.A11, b[8]}}, []int{1, 1, 1, 82, 82, 82, 82, 82, 82, 82, 1476, 1476}) + // v = (2x-y)y + v := e.Ext6.Double(&sq) + v = e.Ext6.Sub(v, y) + v = e.Ext6.Mul(v, y) - // d3 = a0 b3 + a1 b2 + a2 b1 + a3 b0 - 82 * (a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a11 b4) - 1476 * a11 b10 - d3 := e.fp.Eval([][]*baseEl{{&a.A0, b[3]}, {&a.A1, b[2]}, {&a.A2, b[1]}, {&a.A3, b[0]}, {mone, &a.A5, b[9]}, {mone, &a.A6, b[8]}, {mone, &a.A7, b[7]}, {mone, &a.A8, b[6]}, {mone, &a.A9, b[5]}, {mone, &a.A11, b[4]}, {mone, &a.A11, b[9]}}, []int{1, 1, 1, 1, 82, 82, 82, 82, 82, 82, 1476}) + _v := E6{B0: *e.Ext2.Zero(), B1: *e.Ext2.One(), B2: *e.Ext2.Zero()} + e.Ext6.AssertIsEqual(v, &_v) - // d4 = a0 b4 + a1 b3 + a2 b2 + a3 b1 + a4 b0 - 82 * (a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6) - d4 := e.fp.Eval([][]*baseEl{{&a.A0, b[4]}, {&a.A1, b[3]}, {&a.A2, b[2]}, {&a.A3, b[1]}, {&a.A4, b[0]}, {mone, &a.A6, b[9]}, {mone, &a.A7, b[8]}, {mone, &a.A8, b[7]}, {mone, &a.A9, b[6]}, {mone, &a.A10, b[5]}}, []int{1, 1, 1, 1, 1, 82, 82, 82, 82, 82}) + return &sq - // d5 = a1 b4 + a2 b3 + a3 b2 + a4 b1 + a5 b0 - 82 * (a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6) - d5 := e.fp.Eval([][]*baseEl{{&a.A1, b[4]}, {&a.A2, b[3]}, {&a.A3, b[2]}, {&a.A4, b[1]}, {&a.A5, b[0]}, {mone, &a.A7, b[9]}, {mone, &a.A8, b[8]}, {mone, &a.A9, b[7]}, {mone, &a.A10, b[6]}, {mone, &a.A11, b[5]}}, []int{1, 1, 1, 1, 1, 82, 82, 82, 82, 82}) +} - // d6 = a0 b6 + a2 b4 + a3 b3 + a4 b2 + a5 b1 + a6 b0 + 18 * (a2 b10 + a3 b9 + a4 b8 + a5 b7 + a6 b6 + a8 b4 + a9 b3 + a10 b2 + a11 b1) + 242 * (a8 b10 + a9 b9 + a10 b8 + a11 b7) - d6 := e.fp.Eval([][]*baseEl{{&a.A0, b[5]}, {&a.A2, b[4]}, {&a.A3, b[3]}, {&a.A4, b[2]}, {&a.A5, b[1]}, {&a.A6, b[0]}, {&a.A2, b[9]}, {&a.A3, b[8]}, {&a.A4, b[7]}, {&a.A5, b[6]}, {&a.A6, b[5]}, {&a.A8, b[4]}, {&a.A9, b[3]}, {&a.A10, b[2]}, {&a.A11, b[1]}, {&a.A8, b[9]}, {&a.A9, b[8]}, {&a.A10, b[7]}, {&a.A11, b[6]}}, []int{1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, 18, 242, 242, 242, 242}) +// FrobeniusTorus raises a compressed elements y ∈ E6 to the modulus p +// and returns y^p / v^((p-1)/2) +func (e Ext12) FrobeniusTorus(y *E6) *E6 { + t0 := e.Ext2.Conjugate(&y.B0) + t1 := e.Ext2.Conjugate(&y.B1) + t2 := e.Ext2.Conjugate(&y.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) - // d7 == a0 b7 + a1 b6 + a3 b4 + a4 b3 + a5 b2 + a6 b1 + a7 b0 + 18 * (a3 b10 + a4 b9 + a5 b8 + a6 b7 + a7 b6 + a9 b4 + a10 b3 + a11 b2) + 242 * (a9 b10 + a10 b9 + a11 b8) - d7 := e.fp.Eval([][]*baseEl{{&a.A0, b[6]}, {&a.A1, b[5]}, {&a.A3, b[4]}, {&a.A4, b[3]}, {&a.A5, b[2]}, {&a.A6, b[1]}, {&a.A7, b[0]}, {&a.A3, b[9]}, {&a.A4, b[8]}, {&a.A5, b[7]}, {&a.A6, b[6]}, {&a.A7, b[5]}, {&a.A9, b[4]}, {&a.A10, b[3]}, {&a.A11, b[2]}, {&a.A9, b[9]}, {&a.A10, b[8]}, {&a.A11, b[7]}}, []int{1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, 242, 242, 242}) + v0 := E2{emulated.ValueOf[emulated.BN254Fp]("18566938241244942414004596690298913868373833782006617400804628704885040364344"), emulated.ValueOf[emulated.BN254Fp]("5722266937896532885780051958958348231143373700109372999374820235121374419868")} + res := &E6{B0: *t0, B1: *t1, B2: *t2} + res = e.Ext6.MulBy0(res, &v0) - // d8 = a0 b8 + a1 b7 + a2 b6 + a4 b4 + a5 b3 + a6 b2 + a7 b1 + a8 b0 + 18 * (a4 b10 + a5 b9 + a6 b8 + a7 b7 + a8 b6 + a10 b4 + a11 b3) + 242 * (a10 b10 + a11 b9) - d8 := e.fp.Eval([][]*baseEl{{&a.A0, b[7]}, {&a.A1, b[6]}, {&a.A2, b[5]}, {&a.A4, b[4]}, {&a.A5, b[3]}, {&a.A6, b[2]}, {&a.A7, b[1]}, {&a.A8, b[0]}, {&a.A4, b[9]}, {&a.A5, b[8]}, {&a.A6, b[7]}, {&a.A7, b[6]}, {&a.A8, b[5]}, {&a.A10, b[4]}, {&a.A11, b[3]}, {&a.A10, b[9]}, {&a.A11, b[8]}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 242, 242}) + return res +} - // d9 = a0 b9 + a1 b8 + a2 b7 + a3 b6 + a5 b4 + a6 b3 + a7 b2 + a8 b1 + a9 b0 + 18 * (a5 b10 + a6 b9 + a7 b8 + a8 b7 + a9 b6 + a11 b4) + 242 * a11 b10 - d9 := e.fp.Eval([][]*baseEl{{&a.A0, b[8]}, {&a.A1, b[7]}, {&a.A2, b[6]}, {&a.A3, b[5]}, {&a.A5, b[4]}, {&a.A6, b[3]}, {&a.A7, b[2]}, {&a.A8, b[1]}, {&a.A9, b[0]}, {&a.A5, b[9]}, {&a.A6, b[8]}, {&a.A7, b[7]}, {&a.A8, b[6]}, {&a.A9, b[5]}, {&a.A11, b[4]}, {&a.A11, b[9]}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18, 18, 242}) +// FrobeniusSquareTorus raises a compressed elements y ∈ E6 to the square modulus p^2 +// and returns y^(p^2) / v^((p^2-1)/2) +func (e Ext12) FrobeniusSquareTorus(y *E6) *E6 { + v0 := emulated.ValueOf[emulated.BN254Fp]("2203960485148121921418603742825762020974279258880205651967") + t0 := e.Ext2.MulByElement(&y.B0, &v0) + t1 := e.Ext2.MulByNonResidue2Power2(&y.B1) + t1 = e.Ext2.MulByElement(t1, &v0) + t2 := e.Ext2.MulByNonResidue2Power4(&y.B2) + t2 = e.Ext2.MulByElement(t2, &v0) + + return &E6{B0: *t0, B1: *t1, B2: *t2} +} - // d10 = a0 b10 + a1 b9 + a2 b8 + a3 b7 + a4 b6 + a6 b4 + a7 b3 + a8 b2 + a9 b1 + a10 b0 + 18 * (a6 b10 + a7 b9 + a8 b8 + a9 b7 + a10 b6) - d10 := e.fp.Eval([][]*baseEl{{&a.A0, b[9]}, {&a.A1, b[8]}, {&a.A2, b[7]}, {&a.A3, b[6]}, {&a.A4, b[5]}, {&a.A6, b[4]}, {&a.A7, b[3]}, {&a.A8, b[2]}, {&a.A9, b[1]}, {&a.A10, b[0]}, {&a.A6, b[9]}, {&a.A7, b[8]}, {&a.A8, b[7]}, {&a.A9, b[6]}, {&a.A10, b[5]}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18}) +// FrobeniusCubeTorus raises a compressed elements y ∈ E6 to the cube modulus p^3 +// and returns y^(p^3) / v^((p^3-1)/2) +func (e Ext12) FrobeniusCubeTorus(y *E6) *E6 { + t0 := e.Ext2.Conjugate(&y.B0) + t1 := e.Ext2.Conjugate(&y.B1) + t2 := e.Ext2.Conjugate(&y.B2) + t1 = e.Ext2.MulByNonResidue3Power2(t1) + t2 = e.Ext2.MulByNonResidue3Power4(t2) - // d11 = a1 b10 + a2 b9 + a3 b8 + a4 b7 + a5 b6 + a7 b4 + a8 b3 + a9 b2 + a10 b1 + a11 b0 + 18 * (a7 b10 + a8 b9 + a9 b8 + a10 b7 + a11 b6) - d11 := e.fp.Eval([][]*baseEl{{&a.A1, b[9]}, {&a.A2, b[8]}, {&a.A3, b[7]}, {&a.A4, b[6]}, {&a.A5, b[5]}, {&a.A7, b[4]}, {&a.A8, b[3]}, {&a.A9, b[2]}, {&a.A10, b[1]}, {&a.A11, b[0]}, {&a.A7, b[9]}, {&a.A8, b[8]}, {&a.A9, b[7]}, {&a.A10, b[6]}, {&a.A11, b[5]}}, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 18, 18, 18, 18}) + v0 := E2{emulated.ValueOf[emulated.BN254Fp]("10190819375481120917420622822672549775783927716138318623895010788866272024264"), emulated.ValueOf[emulated.BN254Fp]("303847389135065887422783454877609941456349188919719272345083954437860409601")} + res := &E6{B0: *t0, B1: *t1, B2: *t2} + res = e.Ext6.MulBy0(res, &v0) + + return res +} + +// AssertFinalExponentiationIsOne checks that a Miller function output x lies in the +// same equivalence class as the reduced pairing. This replaces the final +// exponentiation step in-circuit. +// The method follows Section 4 of [On Proving Pairings] paper by A. Novakovic and L. Eagen. +// +// [On Proving Pairings]: https://eprint.iacr.org/2024/640.pdf +func (e Ext12) AssertFinalExponentiationIsOne(x *E12) { + res, err := e.fp.NewHint(finalExpHint, 24, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + residueWitness := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + // constrain cubicNonResiduePower to be in Fp6 + cubicNonResiduePower := E6{ + B0: E2{A0: *res[12], A1: *res[13]}, + B1: E2{A0: *res[14], A1: *res[15]}, + B2: E2{A0: *res[16], A1: *res[17]}, + } + + // Check that x * cubicNonResiduePower == residueWitness^λ + // where λ = 6u + 2 + q^3 - q^2 + q, with u the BN254 seed + // and residueWitness, cubicNonResiduePower from the hint. + t2 := &E12{ + C0: *e.Ext6.Mul(&x.C0, &cubicNonResiduePower), + C1: *e.Ext6.Mul(&x.C1, &cubicNonResiduePower), + } + + t1 := e.FrobeniusCube(&residueWitness) + t0 := e.FrobeniusSquare(&residueWitness) + t1 = e.DivUnchecked(t1, t0) + t0 = e.Frobenius(&residueWitness) + t1 = e.Mul(t1, t0) + + // exponentiation by U=6u+2 + t0 = e.ExpByU(&residueWitness) + + t0 = e.Mul(t0, t1) + + e.AssertIsEqual(t0, t2) +} + +func (e Ext12) Frobenius(x *E12) *E12 { + t0 := e.Ext2.Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) + t3 = e.Ext2.MulByNonResidue1Power1(t3) + t4 = e.Ext2.MulByNonResidue1Power3(t4) + t5 = e.Ext2.MulByNonResidue1Power5(t5) + return &E12{ + C0: E6{ + B0: *t0, + B1: *t1, + B2: *t2, + }, + C1: E6{ + B0: *t3, + B1: *t4, + B2: *t5, + }, + } +} + +func (e Ext12) FrobeniusSquare(x *E12) *E12 { + z00 := &x.C0.B0 + z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) + return &E12{ + C0: E6{B0: *z00, B1: *z01, B2: *z02}, + C1: E6{B0: *z10, B1: *z11, B2: *z12}, + } +} +func (e Ext12) FrobeniusCube(x *E12) *E12 { + t0 := e.Ext2.Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue3Power2(t1) + t2 = e.Ext2.MulByNonResidue3Power4(t2) + t3 = e.Ext2.MulByNonResidue3Power1(t3) + t4 = e.Ext2.MulByNonResidue3Power3(t4) + t5 = e.Ext2.MulByNonResidue3Power5(t5) return &E12{ - A0: *d0, - A1: *d1, - A2: *d2, - A3: *d3, - A4: *d4, - A5: *d5, - A6: *d6, - A7: *d7, - A8: *d8, - A9: *d9, - A10: *d10, - A11: *d11, + C0: E6{ + B0: *t0, + B1: *t1, + B2: *t2, + }, + C1: E6{ + B0: *t3, + B1: *t4, + B2: *t5, + }, } } diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index b2f0ae68a5..a3289b4698 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -9,34 +9,6 @@ import ( "github.com/consensys/gnark/test" ) -type e12Convert struct { - A E12 -} - -func (circuit *e12Convert) Define(api frontend.API) error { - e := NewExt12(api) - tower := e.ToTower(&circuit.A) - expected := e.FromTower(tower) - e.AssertIsEqual(expected, &circuit.A) - return nil -} - -func TestConvertFp12(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a bn254.E12 - _, _ = a.SetRandom() - - witness := e12Convert{ - A: FromE12(&a), - } - - err := test.IsSolved(&e12Convert{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - type e12Add struct { A, B, C E12 } @@ -190,18 +162,81 @@ func TestSquareFp12(t *testing.T) { } -type e12SquareGS struct { - A, C E12 +type e12Conjugate struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12SquareGS) Define(api frontend.API) error { +func (circuit *e12Conjugate) Define(api frontend.API) error { e := NewExt12(api) - expected := e.CyclotomicSquareGS(&circuit.A) + expected := e.Conjugate(&circuit.A) e.AssertIsEqual(expected, &circuit.C) + return nil } -func TestSquareGSFp12(t *testing.T) { +func TestConjugateFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.Conjugate(&a) + + witness := e12Conjugate{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12Inverse struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Inverse) Define(api frontend.API) error { + e := NewExt12(api) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e12Inverse{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12ExptTorus struct { + A E6 + C E12 `gnark:",public"` +} + +func (circuit *e12ExptTorus) Define(api frontend.API) error { + e := NewExt12(api) + z := e.ExptTorus(&circuit.A) + expected := e.DecompressTorus(z) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestFp12ExptTorus(t *testing.T) { assert := test.NewAssert(t) // witness values @@ -215,316 +250,371 @@ func TestSquareGSFp12(t *testing.T) { tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.Square(&a) + c.Expt(&a) + _a, _ := a.CompressTorus() + witness := e12ExptTorus{ + A: FromE6(&_a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12ExptTorus{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12MulBy034 struct { + A E12 `gnark:",public"` + W E12 + B, C E2 +} + +func (circuit *e12MulBy034) Define(api frontend.API) error { + e := NewExt12(api) + res := e.MulBy034(&circuit.A, &circuit.B, &circuit.C) + e.AssertIsEqual(res, &circuit.W) + return nil +} + +func TestFp12MulBy034(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, w bn254.E12 + _, _ = a.SetRandom() + var one, b, c bn254.E2 + one.SetOne() + _, _ = b.SetRandom() + _, _ = c.SetRandom() + w.Set(&a) + w.MulBy034(&one, &b, &c) - witness := e12SquareGS{ + witness := e12MulBy034{ A: FromE12(&a), - C: FromE12(&c), + B: FromE2(&b), + C: FromE2(&c), + W: FromE12(&w), } - err := test.IsSolved(&e12SquareGS{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&e12MulBy034{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Conjugate struct { +// Torus-based arithmetic +type torusCompress struct { A E12 - C E12 `gnark:",public"` + C E6 `gnark:",public"` } -func (circuit *e12Conjugate) Define(api frontend.API) error { +func (circuit *torusCompress) Define(api frontend.API) error { e := NewExt12(api) - expected := e.Conjugate(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - + expected := e.CompressTorus(&circuit.A) + e.Ext6.AssertIsEqual(expected, &circuit.C) return nil } -func TestConjugateFp12(t *testing.T) { +func TestTorusCompress(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bn254.E12 + var a bn254.E12 _, _ = a.SetRandom() - c.Conjugate(&a) - witness := e12Conjugate{ + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + c, _ := a.CompressTorus() + + witness := torusCompress{ A: FromE12(&a), - C: FromE12(&c), + C: FromE6(&c), } - err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusCompress{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Inverse struct { +type torusDecompress struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12Inverse) Define(api frontend.API) error { +func (circuit *torusDecompress) Define(api frontend.API) error { e := NewExt12(api) - expected := e.Inverse(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestInverseFp12(t *testing.T) { +func TestTorusDecompress(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bn254.E12 + var a bn254.E12 _, _ = a.SetRandom() - c.Inverse(&a) - witness := e12Inverse{ + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + d, _ := a.CompressTorus() + c := d.DecompressTorus() + + witness := torusDecompress{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusDecompress{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type Frobenius struct { +type torusMul struct { A E12 + B E12 C E12 `gnark:",public"` } -func (circuit *Frobenius) Define(api frontend.API) error { +func (circuit *torusMul) Define(api frontend.API) error { e := NewExt12(api) - expected := e.Frobenius(&circuit.A) + compressedA := e.CompressTorus(&circuit.A) + compressedB := e.CompressTorus(&circuit.B) + compressedAB := e.MulTorus(compressedA, compressedB) + expected := e.DecompressTorus(compressedAB) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFrobenius(t *testing.T) { +func TestTorusMul(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bn254.E12 + var a, b, c, tmp bn254.E12 _, _ = a.SetRandom() + _, _ = b.SetRandom() - c.Frobenius(&a) + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + // put b in the cyclotomic subgroup + tmp.Conjugate(&b) + b.Inverse(&b) + tmp.Mul(&tmp, &b) + b.FrobeniusSquare(&tmp).Mul(&b, &tmp) - witness := Frobenius{ + // uncompressed mul + c.Mul(&a, &b) + + witness := torusMul{ A: FromE12(&a), + B: FromE12(&b), C: FromE12(&c), } - err := test.IsSolved(&Frobenius{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusMul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type FrobeniusSquare struct { +type torusInverse struct { A E12 C E12 `gnark:",public"` } -func (circuit *FrobeniusSquare) Define(api frontend.API) error { +func (circuit *torusInverse) Define(api frontend.API) error { e := NewExt12(api) - expected := e.FrobeniusSquare(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.InverseTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFrobeniusSquare(t *testing.T) { +func TestTorusInverse(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bn254.E12 + var a, c, tmp bn254.E12 _, _ = a.SetRandom() - c.FrobeniusSquare(&a) + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - witness := FrobeniusSquare{ + // uncompressed inverse + c.Inverse(&a) + + witness := torusInverse{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&FrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusInverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type FrobeniusCube struct { +type torusFrobenius struct { A E12 C E12 `gnark:",public"` } -func (circuit *FrobeniusCube) Define(api frontend.API) error { +func (circuit *torusFrobenius) Define(api frontend.API) error { e := NewExt12(api) - expected := e.FrobeniusCube(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFrobeniusCube(t *testing.T) { +func TestTorusFrobenius(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bn254.E12 + var a, c, tmp bn254.E12 _, _ = a.SetRandom() - c.FrobeniusCube(&a) + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobenius + c.Frobenius(&a) - witness := FrobeniusCube{ + witness := torusFrobenius{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&FrobeniusCube{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusFrobenius{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12MulBy01379 struct { - A E12 `gnark:",public"` - W E12 - B, C E2 +type torusFrobeniusSquare struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12MulBy01379) Define(api frontend.API) error { +func (circuit *torusFrobeniusSquare) Define(api frontend.API) error { e := NewExt12(api) - res := e.MulBy01379(&circuit.A, &circuit.B, &circuit.C) - e.AssertIsEqual(res, &circuit.W) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusSquareTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFp12MulBy01379(t *testing.T) { +func TestTorusFrobeniusSquare(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, w bn254.E12 + var a, c, tmp bn254.E12 _, _ = a.SetRandom() - var one, b, c bn254.E2 - one.SetOne() - _, _ = b.SetRandom() - _, _ = c.SetRandom() - w.Set(&a) - w.MulBy034(&one, &b, &c) - witness := e12MulBy01379{ + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobeniusSquare + c.FrobeniusSquare(&a) + + witness := torusFrobeniusSquare{ A: FromE12(&a), - B: FromE2(&b), - C: FromE2(&c), - W: FromE12(&w), + C: FromE12(&c), } - err := test.IsSolved(&e12MulBy01379{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusFrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - } -type e12Mul01379By01379 struct { - A, B E2 `gnark:",public"` - C, D E2 `gnark:",public"` - W E12 +type torusFrobeniusCube struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12Mul01379By01379) Define(api frontend.API) error { +func (circuit *torusFrobeniusCube) Define(api frontend.API) error { e := NewExt12(api) - res := e.Mul01379By01379(&circuit.A, &circuit.B, &circuit.C, &circuit.D) - e.AssertIsEqual( - &E12{*res[0], *res[1], *res[2], *res[3], *res[4], *e.fp.Zero(), *res[5], *res[6], *res[7], *res[8], *res[9], *e.fp.Zero()}, - &circuit.W, - ) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusCubeTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFp12Mul01379By01379(t *testing.T) { +func TestTorusFrobeniusCube(t *testing.T) { assert := test.NewAssert(t) // witness values - var one, a, b, c, d bn254.E2 - one.SetOne() + var a, c, tmp bn254.E12 _, _ = a.SetRandom() - _, _ = b.SetRandom() - _, _ = c.SetRandom() - _, _ = d.SetRandom() - prod := Mul034By034(&one, &a, &b, &one, &c, &d) - var w bn254.E12 - w.C0.B0.Set(&prod[0]) - w.C0.B1.Set(&prod[1]) - w.C0.B2.Set(&prod[2]) - w.C1.B0.Set(&prod[3]) - w.C1.B1.Set(&prod[4]) - w.C1.B2.SetZero() - - witness := e12Mul01379By01379{ - A: FromE2(&a), - B: FromE2(&b), - C: FromE2(&c), - D: FromE2(&d), - W: FromE12(&w), + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobeniusCube + c.FrobeniusCube(&a) + + witness := torusFrobeniusCube{ + A: FromE12(&a), + C: FromE12(&c), } - err := test.IsSolved(&e12Mul01379By01379{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusFrobeniusCube{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - } -type e12Expt struct { +type torusSquare struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12Expt) Define(api frontend.API) error { +func (circuit *torusSquare) Define(api frontend.API) error { e := NewExt12(api) - expected := e.Expt(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.SquareTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestFp12Expt(t *testing.T) { +func TestTorusSquare(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bn254.E12 + var a, c, tmp bn254.E12 _, _ = a.SetRandom() // put a in the cyclotomic subgroup - var tmp bn254.E12 tmp.Conjugate(&a) a.Inverse(&a) tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.Expt(&a) - witness := e12Expt{ + // uncompressed square + c.Square(&a) + + witness := torusSquare{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -// utils -// Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0) -func Mul034By034(d0, d3, d4, c0, c3, c4 *bn254.E2) [5]bn254.E2 { - var z00, tmp, x0, x3, x4, x04, x03, x34 bn254.E2 - x0.Mul(c0, d0) - x3.Mul(c3, d3) - x4.Mul(c4, d4) - tmp.Add(c0, c4) - x04.Add(d0, d4). - Mul(&x04, &tmp). - Sub(&x04, &x0). - Sub(&x04, &x4) - tmp.Add(c0, c3) - x03.Add(d0, d3). - Mul(&x03, &tmp). - Sub(&x03, &x0). - Sub(&x03, &x3) - tmp.Add(c3, c4) - x34.Add(d3, d4). - Mul(&x34, &tmp). - Sub(&x34, &x3). - Sub(&x34, &x4) - - z00.MulByNonResidue(&x4). - Add(&z00, &x0) - - return [5]bn254.E2{z00, x3, x34, x03, x04} -} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 7af33cbd86..5d38c50eaf 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -201,10 +201,16 @@ func (e Ext2) MulByNonResidue3Power5(x *E2) *E2 { } func (e Ext2) Mul(x, y *E2) *E2 { - // b0 = x0*y0 - x1*y1 - b0 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A0}, {e.fp.NewElement(-1), &x.A1, &y.A1}}, []int{1, 1}) - // b1 = x0*y1 + x1*y0 - b1 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A1}, {&x.A1, &y.A0}}, []int{1, 1}) + + v0 := e.fp.Mul(&x.A0, &y.A0) + v1 := e.fp.Mul(&x.A1, &y.A1) + + b0 := e.fp.Sub(v0, v1) + b1 := e.fp.Add(&x.A0, &x.A1) + tmp := e.fp.Add(&y.A0, &y.A1) + b1 = e.fp.Mul(b1, tmp) + tmp = e.fp.Add(v0, v1) + b1 = e.fp.Sub(b1, tmp) return &E2{ A0: *b0, @@ -264,22 +270,11 @@ func (e Ext2) IsZero(z *E2) frontend.Variable { } func (e Ext2) Square(x *E2) *E2 { - // a = (x0+x1)(x0-x1) = x0^2 - x1^2 - a := e.fp.Eval([][]*baseEl{{&x.A0, &x.A0}, {e.fp.NewElement(-1), &x.A1, &x.A1}}, []int{1, 1}) - // b = 2*x0*x1 - b := e.fp.Eval([][]*baseEl{{&x.A0, &x.A1}}, []int{2}) - return &E2{ - A0: *a, - A1: *b, - } -} - -func (e Ext2) Cube(x *E2) *E2 { - mone := e.fp.NewElement(-1) - // a = x0^3 - 3*x0*x1^2 - a := e.fp.Eval([][]*baseEl{{&x.A0, &x.A0, &x.A0}, {mone, &x.A0, &x.A1, &x.A1}}, []int{1, 3}) - // b = 3*x1*x0^2 - x1^3 - b := e.fp.Eval([][]*baseEl{{&x.A1, &x.A0, &x.A0}, {mone, &x.A1, &x.A1, &x.A1}}, []int{3, 1}) + a := e.fp.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) + a = e.fp.Mul(a, b) + b = e.fp.Mul(&x.A0, &x.A1) + b = e.fp.MulConst(b, big.NewInt(2)) return &E2{ A0: *a, A1: *b, diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go new file mode 100644 index 0000000000..feca59a5f7 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -0,0 +1,495 @@ +package fields_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/frontendtype" +) + +type E6 struct { + B0, B1, B2 E2 +} + +type Ext6 struct { + *Ext2 +} + +func NewExt6(api frontend.API) *Ext6 { + return &Ext6{Ext2: NewExt2(api)} +} + +func (e Ext6) One() *E6 { + z0 := e.Ext2.One() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Zero() *E6 { + z0 := e.Ext2.Zero() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) IsZero(z *E6) frontend.Variable { + b0 := e.Ext2.IsZero(&z.B0) + b1 := e.Ext2.IsZero(&z.B1) + b2 := e.Ext2.IsZero(&z.B2) + return e.api.And(e.api.And(b0, b1), b2) +} + +func (e Ext6) Add(x, y *E6) *E6 { + z0 := e.Ext2.Add(&x.B0, &y.B0) + z1 := e.Ext2.Add(&x.B1, &y.B1) + z2 := e.Ext2.Add(&x.B2, &y.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Neg(x *E6) *E6 { + z0 := e.Ext2.Neg(&x.B0) + z1 := e.Ext2.Neg(&x.B1) + z2 := e.Ext2.Neg(&x.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Sub(x, y *E6) *E6 { + z0 := e.Ext2.Sub(&x.B0, &y.B0) + z1 := e.Ext2.Sub(&x.B1, &y.B1) + z2 := e.Ext2.Sub(&x.B2, &y.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +// Mul multiplies two E6 elmts +func (e Ext6) Mul(x, y *E6) *E6 { + if ft, ok := e.api.(frontendtype.FrontendTyper); ok { + switch ft.FrontendType() { + case frontendtype.R1CS: + return e.mulToom3OverKaratsuba(x, y) + case frontendtype.SCS: + return e.mulKaratsubaOverKaratsuba(x, y) + } + } + return e.mulKaratsubaOverKaratsuba(x, y) +} + +func (e Ext6) mulToom3OverKaratsuba(x, y *E6) *E6 { + // Toom-Cook-3x over Karatsuba: + // We start by computing five interpolation points – these are evaluations of + // the product x(u)y(u) with u ∈ {0, ±1, 2, ∞}: + // + // v0 = x(0)y(0) = x.A0 * y.A0 + // v1 = x(1)y(1) = (x.A0 + x.A1 + x.A2)(y.A0 + y.A1 + y.A2) + // v2 = x(−1)y(−1) = (x.A0 − x.A1 + x.A2)(y.A0 − y.A1 + y.A2) + // v3 = x(2)y(2) = (x.A0 + 2x.A1 + 4x.A2)(y.A0 + 2y.A1 + 4y.A2) + // v4 = x(∞)y(∞) = x.A2 * y.A2 + + v0 := e.Ext2.Mul(&x.B0, &y.B0) + + t1 := e.Ext2.Add(&x.B0, &x.B2) + t2 := e.Ext2.Add(&y.B0, &y.B2) + t3 := e.Ext2.Add(t2, &y.B1) + v1 := e.Ext2.Add(t1, &x.B1) + v1 = e.Ext2.Mul(v1, t3) + + t3 = e.Ext2.Sub(t2, &y.B1) + v2 := e.Ext2.Sub(t1, &x.B1) + v2 = e.Ext2.Mul(v2, t3) + + t1 = e.Ext2.MulByConstElement(&x.B1, big.NewInt(2)) + t2 = e.Ext2.MulByConstElement(&x.B2, big.NewInt(4)) + v3 := e.Ext2.Add(t1, t2) + v3 = e.Ext2.Add(v3, &x.B0) + t1 = e.Ext2.MulByConstElement(&y.B1, big.NewInt(2)) + t2 = e.Ext2.MulByConstElement(&y.B2, big.NewInt(4)) + t3 = e.Ext2.Add(t1, t2) + t3 = e.Ext2.Add(t3, &y.B0) + v3 = e.Ext2.Mul(v3, t3) + + v4 := e.Ext2.Mul(&x.B2, &y.B2) + + // Then the interpolation is performed as: + // + // a0 = v0 + β((1/2)v0 − (1/2)v1 − (1/6)v2 + (1/6)v3 − 2v4) + // a1 = −(1/2)v0 + v1 − (1/3)v2 − (1/6)v3 + 2v4 + βv4 + // a2 = −v0 + (1/2)v1 + (1/2)v2 − v4 + // + // where β is the cubic non-residue. + // + // In-circuit, we compute 6*x*y as + // c0 = 6v0 + β(3v0 − 3v1 − v2 + v3 − 12v4) + // a1 = -(3v0 + 2v2 + v3) + 6(v1 + 2v4 + βv4) + // a2 = 3(v1 + v2 - 2(v0 + v4)) + // + // and then divide a0, a1 and a2 by 6 using a hint. + + a0 := e.Ext2.MulByConstElement(v0, big.NewInt(6)) + t1 = e.Ext2.Sub(v0, v1) + t1 = e.Ext2.MulByConstElement(t1, big.NewInt(3)) + t1 = e.Ext2.Sub(t1, v2) + t1 = e.Ext2.Add(t1, v3) + t2 = e.Ext2.MulByConstElement(v4, big.NewInt(12)) + t1 = e.Ext2.Sub(t1, t2) + t1 = e.Ext2.MulByNonResidue(t1) + a0 = e.Ext2.Add(a0, t1) + + a1 := e.Ext2.MulByConstElement(v0, big.NewInt(3)) + t1 = e.Ext2.MulByConstElement(v2, big.NewInt(2)) + a1 = e.Ext2.Add(a1, t1) + a1 = e.Ext2.Add(a1, v3) + t1 = e.Ext2.MulByConstElement(v4, big.NewInt(2)) + t1 = e.Ext2.Add(t1, v1) + t2 = e.Ext2.MulByNonResidue(v4) + t1 = e.Ext2.Add(t1, t2) + t1 = e.Ext2.MulByConstElement(t1, big.NewInt(6)) + a1 = e.Ext2.Sub(t1, a1) + + a2 := e.Ext2.Add(v1, v2) + a2 = e.Ext2.MulByConstElement(a2, big.NewInt(3)) + t1 = e.Ext2.Add(v0, v4) + t1 = e.Ext2.MulByConstElement(t1, big.NewInt(6)) + a2 = e.Ext2.Sub(a2, t1) + + res := e.divE6By6([6]*baseEl{&a0.A0, &a0.A1, &a1.A0, &a1.A1, &a2.A0, &a2.A1}) + return &E6{ + B0: E2{ + A0: *res[0], + A1: *res[1], + }, + B1: E2{ + A0: *res[2], + A1: *res[3], + }, + B2: E2{ + A0: *res[4], + A1: *res[5], + }, + } +} + +func (e Ext6) mulKaratsubaOverKaratsuba(x, y *E6) *E6 { + // Karatsuba over Karatsuba: + // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + t0 := e.Ext2.Mul(&x.B0, &y.B0) + t1 := e.Ext2.Mul(&x.B1, &y.B1) + t2 := e.Ext2.Mul(&x.B2, &y.B2) + c0 := e.Ext2.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(&y.B1, &y.B2) + c0 = e.Ext2.Mul(c0, tmp) + tmp = e.Ext2.Add(t2, t1) + c0 = e.Ext2.Sub(c0, tmp) + c0 = e.Ext2.MulByNonResidue(c0) + c0 = e.Ext2.Add(c0, t0) + c1 := e.Ext2.Add(&x.B0, &x.B1) + tmp = e.Ext2.Add(&y.B0, &y.B1) + c1 = e.Ext2.Mul(c1, tmp) + tmp = e.Ext2.Add(t0, t1) + c1 = e.Ext2.Sub(c1, tmp) + tmp = e.Ext2.MulByNonResidue(t2) + c1 = e.Ext2.Add(c1, tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) + c2 := e.Ext2.Add(&y.B0, &y.B2) + c2 = e.Ext2.Mul(c2, tmp) + tmp = e.Ext2.Add(t0, t2) + c2 = e.Ext2.Sub(c2, tmp) + c2 = e.Ext2.Add(c2, t1) + return &E6{ + B0: *c0, + B1: *c1, + B2: *c2, + } +} + +func (e Ext6) Double(x *E6) *E6 { + z0 := e.Ext2.Double(&x.B0) + z1 := e.Ext2.Double(&x.B1) + z2 := e.Ext2.Double(&x.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Square(x *E6) *E6 { + c4 := e.Ext2.Mul(&x.B0, &x.B1) + c4 = e.Ext2.Double(c4) + c5 := e.Ext2.Square(&x.B2) + c1 := e.Ext2.MulByNonResidue(c5) + c1 = e.Ext2.Add(c1, c4) + c2 := e.Ext2.Sub(c4, c5) + c3 := e.Ext2.Square(&x.B0) + c4 = e.Ext2.Sub(&x.B0, &x.B1) + c4 = e.Ext2.Add(c4, &x.B2) + c5 = e.Ext2.Mul(&x.B1, &x.B2) + c5 = e.Ext2.Double(c5) + c4 = e.Ext2.Square(c4) + c0 := e.Ext2.MulByNonResidue(c5) + c0 = e.Ext2.Add(c0, c3) + z2 := e.Ext2.Add(c2, c4) + z2 = e.Ext2.Add(z2, c5) + z2 = e.Ext2.Sub(z2, c3) + z0 := c0 + z1 := c1 + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulByConstE2(x *E6, y *E2) *E6 { + z0 := e.Ext2.Mul(&x.B0, y) + z1 := e.Ext2.Mul(&x.B1, y) + z2 := e.Ext2.Mul(&x.B2, y) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulByE2(x *E6, y *E2) *E6 { + z0 := e.Ext2.Mul(&x.B0, y) + z1 := e.Ext2.Mul(&x.B1, y) + z2 := e.Ext2.Mul(&x.B2, y) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +// MulBy0 multiplies z by an E6 sparse element of the form +// +// E6{ +// B0: c0, +// B1: 0, +// B2: 0, +// } +func (e Ext6) MulBy0(z *E6, c0 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) + tmp := e.Ext2.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) + t2 = e.Ext2.Sub(t2, a) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 := e.Ext2.Mul(c0, tmp) + t1 = e.Ext2.Sub(t1, a) + return &E6{ + B0: *a, + B1: *t1, + B2: *t2, + } +} + +// MulBy01 multiplies z by an E6 sparse element of the form +// +// E6{ +// B0: c0, +// B1: c1, +// B2: 0, +// } +func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) + b := e.Ext2.Mul(&z.B1, c1) + tmp := e.Ext2.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) + t0 = e.Ext2.Sub(t0, b) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, a) + // for t2, schoolbook is faster than karatsuba + // c2 = a0b2 + a1b1 + a2b0, + // c2 = a2b0 + b ∵ b2 = 0, b = a1b1 + t2 := e.Ext2.Mul(&z.B2, c0) + t2 = e.Ext2.Add(t2, b) + t1 := e.Ext2.Add(c0, c1) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 = e.Ext2.Mul(t1, tmp) + tmp = e.Ext2.Add(a, b) + t1 = e.Ext2.Sub(t1, tmp) + return &E6{ + B0: *t0, + B1: *t1, + B2: *t2, + } +} + +// Mul01By01 multiplies two E6 sparse element of the form: +// +// E6{ +// B0: c0, +// B1: c1, +// B2: 0, +// } +// +// and +// +// E6{ +// B0: d0, +// B1: d1, +// B2: 0, +// } +func (e Ext6) Mul01By01(c0, c1, d0, d1 *E2) *E6 { + a := e.Ext2.Mul(d0, c0) + b := e.Ext2.Mul(d1, c1) + t1 := e.Ext2.Add(c0, c1) + tmp := e.Ext2.Add(d0, d1) + t1 = e.Ext2.Mul(t1, tmp) + tmp = e.Ext2.Add(a, b) + t1 = e.Ext2.Sub(t1, tmp) + return &E6{ + B0: *a, + B1: *t1, + B2: *b, + } +} + +func (e Ext6) MulByNonResidue(x *E6) *E6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 + z0 = e.Ext2.MulByNonResidue(z0) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) FrobeniusSquare(x *E6) *E6 { + z01 := e.Ext2.MulByNonResidue2Power2(&x.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.B2) + return &E6{B0: x.B0, B1: *z01, B2: *z02} +} + +func (e Ext6) IsEqual(x, y *E6) frontend.Variable { + isB0Equal := e.Ext2.IsEqual(&x.B0, &y.B0) + isB1Equal := e.Ext2.IsEqual(&x.B1, &y.B1) + isB2Equal := e.Ext2.IsEqual(&x.B2, &y.B2) + res := e.api.And(isB0Equal, isB1Equal) + res = e.api.And(res, isB2Equal) + return res +} + +func (e Ext6) AssertIsEqual(x, y *E6) { + e.Ext2.AssertIsEqual(&x.B0, &y.B0) + e.Ext2.AssertIsEqual(&x.B1, &y.B1) + e.Ext2.AssertIsEqual(&x.B2, &y.B2) +} + +func FromE6(y *bn254.E6) E6 { + return E6{ + B0: FromE2(&y.B0), + B1: FromE2(&y.B1), + B2: FromE2(&y.B2), + } + +} + +func (e Ext6) Inverse(x *E6) *E6 { + res, err := e.fp.NewHint(inverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + one := e.One() + + // 1 == inv * x + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) + + return &inv + +} + +func (e Ext6) DivUnchecked(x, y *E6) *E6 { + res, err := e.fp.NewHint(divE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // x == div * y + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) + + return &div +} + +func (e Ext6) divE6By6(x [6]*baseEl) [6]*baseEl { + res, err := e.fp.NewHint(divE6By6Hint, 6, x[0], x[1], x[2], x[3], x[4], x[5]) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + y0 := *res[0] + y1 := *res[1] + y2 := *res[2] + y3 := *res[3] + y4 := *res[4] + y5 := *res[5] + + // xi == 6 * yi + x0 := e.fp.MulConst(&y0, big.NewInt(6)) + x1 := e.fp.MulConst(&y1, big.NewInt(6)) + x2 := e.fp.MulConst(&y2, big.NewInt(6)) + x3 := e.fp.MulConst(&y3, big.NewInt(6)) + x4 := e.fp.MulConst(&y4, big.NewInt(6)) + x5 := e.fp.MulConst(&y5, big.NewInt(6)) + e.fp.AssertIsEqual(x[0], x0) + e.fp.AssertIsEqual(x[1], x1) + e.fp.AssertIsEqual(x[2], x2) + e.fp.AssertIsEqual(x[3], x3) + e.fp.AssertIsEqual(x[4], x4) + e.fp.AssertIsEqual(x[5], x5) + + return [6]*baseEl{&y0, &y1, &y2, &y3, &y4, &y5} +} + +func (e Ext6) Select(selector frontend.Variable, z1, z0 *E6) *E6 { + b0 := e.Ext2.Select(selector, &z1.B0, &z0.B0) + b1 := e.Ext2.Select(selector, &z1.B1, &z0.B1) + b2 := e.Ext2.Select(selector, &z1.B2, &z0.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} + +func (e Ext6) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E6) *E6 { + b0 := e.Ext2.Lookup2(s1, s2, &a.B0, &b.B0, &c.B0, &d.B0) + b1 := e.Ext2.Lookup2(s1, s2, &a.B1, &b.B1, &c.B1, &d.B1) + b2 := e.Ext2.Lookup2(s1, s2, &a.B2, &b.B2, &c.B2, &d.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go new file mode 100644 index 0000000000..4fbfcdea8b --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -0,0 +1,444 @@ +package fields_bn254 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type e6Add struct { + A, B, C E6 +} + +func (circuit *e6Add) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + witness := e6Add{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Add{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Sub struct { + A, B, C E6 +} + +func (circuit *e6Sub) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + witness := e6Sub{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Sub{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Mul struct { + A, B, C E6 +} + +func (circuit *e6Mul) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e6Mul{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulVariant struct { + A, B, C E6 +} + +func (circuit *e6MulVariant) Define(api frontend.API) error { + e := NewExt6(api) + expected1 := e.mulKaratsubaOverKaratsuba(&circuit.A, &circuit.B) + expected2 := e.mulToom3OverKaratsuba(&circuit.A, &circuit.B) + e.AssertIsEqual(expected1, &circuit.C) + e.AssertIsEqual(expected2, &circuit.C) + return nil +} + +func TestMulFp6Variants(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e6Mul{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Square struct { + A, C E6 +} + +func (circuit *e6Square) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.Square(&a) + + witness := e6Square{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Square{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Div struct { + A, B, C E6 +} + +func (circuit *e6Div) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.DivUnchecked(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e6Div{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Div{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulByNonResidue struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByNonResidue) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.MulByNonResidue(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6ByNonResidue(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.MulByNonResidue(&a) + + witness := e6MulByNonResidue{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulByE2 struct { + A E6 + B E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByE2) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.MulByE2(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6ByE2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + var b bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.MulByE2(&a, &b) + + witness := e6MulByE2{ + A: FromE6(&a), + B: FromE2(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulByE2{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulBy01 struct { + A E6 + C0, C1 E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulBy01) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6By01(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + var C0, C1 bn254.E2 + _, _ = a.SetRandom() + _, _ = C0.SetRandom() + _, _ = C1.SetRandom() + c.Set(&a) + c.MulBy01(&C0, &C1) + + witness := e6MulBy01{ + A: FromE6(&a), + C0: FromE2(&C0), + C1: FromE2(&C1), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulBy01{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Mul01By01 struct { + A0, A1 E2 + B0, B1 E2 + C E6 `gnark:",public"` +} + +func (circuit *e6Mul01By01) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Mul01By01(&circuit.A0, &circuit.A1, &circuit.B0, &circuit.B1) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMul01By01(t *testing.T) { + + // we test our new E3.Mul01By01 against E3.MulBy01 + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + var A0, A1, B0, B1 bn254.E2 + _, _ = A0.SetRandom() + _, _ = A1.SetRandom() + _, _ = B0.SetRandom() + _, _ = B1.SetRandom() + + // build a 01 sparse E3 with, + // first two elements as A1 and A2, + // and the third as 0 + a.B0 = A0 + a.B1 = A1 + a.B2.SetZero() + c.Set(&a) + c.MulBy01(&B0, &B1) + + witness := e6Mul01By01{ + A0: FromE2(&A0), + A1: FromE2(&A1), + B0: FromE2(&B0), + B1: FromE2(&B1), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Mul01By01{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulBy0 struct { + A E6 + C0 E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulBy0) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.MulBy0(&circuit.A, &circuit.C0) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6By0(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + var C0, zero bn254.E2 + _, _ = a.SetRandom() + _, _ = C0.SetRandom() + c.Set(&a) + c.MulBy01(&C0, &zero) + + witness := e6MulBy0{ + A: FromE6(&a), + C0: FromE2(&C0), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulBy0{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Neg struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Neg) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Neg(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestNegFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.Neg(&a) + + witness := e6Neg{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Neg{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e6Inverse struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Inverse) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e6Inverse{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go index 556558f6dd..c5d68ed67d 100644 --- a/std/algebra/emulated/fields_bn254/hints.go +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -19,9 +19,15 @@ func GetHints() []solver.Hint { // E2 divE2Hint, inverseE2Hint, + // E6 + divE6Hint, + inverseE6Hint, + squareTorusHint, + divE6By6Hint, // E12 divE12Hint, inverseE12Hint, + finalExpHint, } } @@ -61,71 +67,153 @@ func divE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } +// E6 hints +func inverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + c.Inverse(&a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + b.B0.A0.SetBigInt(inputs[6]) + b.B0.A1.SetBigInt(inputs[7]) + b.B1.A0.SetBigInt(inputs[8]) + b.B1.A1.SetBigInt(inputs[9]) + b.B2.A0.SetBigInt(inputs[10]) + b.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&b).Mul(&c, &a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func squareTorusHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + _c := a.DecompressTorus() + _c.CyclotomicSquare(&_c) + c, _ = _c.CompressTorus() + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func divE6By6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + var sixInv fp.Element + sixInv.SetString("6") + sixInv.Inverse(&sixInv) + c.B0.MulByElement(&a.B0, &sixInv) + c.B1.MulByElement(&a.B1, &sixInv) + c.B2.MulByElement(&a.B2, &sixInv) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + // E12 hints func inverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { - var d [12]big.Int - var t1 big.Int - t1.SetUint64(9).Mul(&t1, inputs[6]) - d[0].Add(inputs[0], &t1) - d[1].Set(inputs[6]) - t1.SetUint64(9).Mul(&t1, inputs[8]) - d[2].Add(inputs[2], &t1) - d[3].Set(inputs[8]) - t1.SetUint64(9).Mul(&t1, inputs[10]) - d[4].Add(inputs[4], &t1) - d[5].Set(inputs[10]) - t1.SetUint64(9).Mul(&t1, inputs[7]) - d[6].Add(inputs[1], &t1) - d[7].Set(inputs[7]) - t1.SetUint64(9).Mul(&t1, inputs[9]) - d[8].Add(inputs[3], &t1) - d[9].Set(inputs[9]) - t1.SetUint64(9).Mul(&t1, inputs[11]) - d[10].Add(inputs[5], &t1) - d[11].Set(inputs[11]) var a, c bn254.E12 - a.C0.B0.A0.SetBigInt(&d[0]) - a.C0.B0.A1.SetBigInt(&d[1]) - a.C0.B1.A0.SetBigInt(&d[2]) - a.C0.B1.A1.SetBigInt(&d[3]) - a.C0.B2.A0.SetBigInt(&d[4]) - a.C0.B2.A1.SetBigInt(&d[5]) - a.C1.B0.A0.SetBigInt(&d[6]) - a.C1.B0.A1.SetBigInt(&d[7]) - a.C1.B1.A0.SetBigInt(&d[8]) - a.C1.B1.A1.SetBigInt(&d[9]) - a.C1.B2.A0.SetBigInt(&d[10]) - a.C1.B2.A1.SetBigInt(&d[11]) + + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) c.Inverse(&a) - var c0, c1, c2, c3, c4, c5, t2 fp.Element - t2.SetUint64(9).Mul(&t2, &c.C0.B0.A1) - c0.Sub(&c.C0.B0.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C1.B0.A1) - c1.Sub(&c.C1.B0.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C0.B1.A1) - c2.Sub(&c.C0.B1.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C1.B1.A1) - c3.Sub(&c.C1.B1.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C0.B2.A1) - c4.Sub(&c.C0.B2.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C1.B2.A1) - c5.Sub(&c.C1.B2.A0, &t2) - - c0.BigInt(outputs[0]) - c1.BigInt(outputs[1]) - c2.BigInt(outputs[2]) - c3.BigInt(outputs[3]) - c4.BigInt(outputs[4]) - c5.BigInt(outputs[5]) - c.C0.B0.A1.BigInt(outputs[6]) + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) c.C1.B0.A1.BigInt(outputs[7]) - c.C0.B1.A1.BigInt(outputs[8]) + c.C1.B1.A0.BigInt(outputs[8]) c.C1.B1.A1.BigInt(outputs[9]) - c.C0.B2.A1.BigInt(outputs[10]) + c.C1.B2.A0.BigInt(outputs[10]) c.C1.B2.A1.BigInt(outputs[11]) return nil @@ -137,99 +225,170 @@ func divE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) erro func(mod *big.Int, inputs, outputs []*big.Int) error { var a, b, c bn254.E12 - var d [12]big.Int - var t1 big.Int - t1.SetUint64(9).Mul(&t1, inputs[6]) - d[0].Add(inputs[0], &t1) - d[1].Set(inputs[6]) - t1.SetUint64(9).Mul(&t1, inputs[8]) - d[2].Add(inputs[2], &t1) - d[3].Set(inputs[8]) - t1.SetUint64(9).Mul(&t1, inputs[10]) - d[4].Add(inputs[4], &t1) - d[5].Set(inputs[10]) - t1.SetUint64(9).Mul(&t1, inputs[7]) - d[6].Add(inputs[1], &t1) - d[7].Set(inputs[7]) - t1.SetUint64(9).Mul(&t1, inputs[9]) - d[8].Add(inputs[3], &t1) - d[9].Set(inputs[9]) - t1.SetUint64(9).Mul(&t1, inputs[11]) - d[10].Add(inputs[5], &t1) - d[11].Set(inputs[11]) - a.C0.B0.A0.SetBigInt(&d[0]) - a.C0.B0.A1.SetBigInt(&d[1]) - a.C0.B1.A0.SetBigInt(&d[2]) - a.C0.B1.A1.SetBigInt(&d[3]) - a.C0.B2.A0.SetBigInt(&d[4]) - a.C0.B2.A1.SetBigInt(&d[5]) - a.C1.B0.A0.SetBigInt(&d[6]) - a.C1.B0.A1.SetBigInt(&d[7]) - a.C1.B1.A0.SetBigInt(&d[8]) - a.C1.B1.A1.SetBigInt(&d[9]) - a.C1.B2.A0.SetBigInt(&d[10]) - a.C1.B2.A1.SetBigInt(&d[11]) - - t1.SetUint64(9).Mul(&t1, inputs[18]) - d[0].Add(inputs[12], &t1) - d[1].Set(inputs[18]) - t1.SetUint64(9).Mul(&t1, inputs[20]) - d[2].Add(inputs[14], &t1) - d[3].Set(inputs[20]) - t1.SetUint64(9).Mul(&t1, inputs[22]) - d[4].Add(inputs[16], &t1) - d[5].Set(inputs[22]) - t1.SetUint64(9).Mul(&t1, inputs[19]) - d[6].Add(inputs[13], &t1) - d[7].Set(inputs[19]) - t1.SetUint64(9).Mul(&t1, inputs[21]) - d[8].Add(inputs[15], &t1) - d[9].Set(inputs[21]) - t1.SetUint64(9).Mul(&t1, inputs[23]) - d[10].Add(inputs[17], &t1) - d[11].Set(inputs[23]) - b.C0.B0.A0.SetBigInt(&d[0]) - b.C0.B0.A1.SetBigInt(&d[1]) - b.C0.B1.A0.SetBigInt(&d[2]) - b.C0.B1.A1.SetBigInt(&d[3]) - b.C0.B2.A0.SetBigInt(&d[4]) - b.C0.B2.A1.SetBigInt(&d[5]) - b.C1.B0.A0.SetBigInt(&d[6]) - b.C1.B0.A1.SetBigInt(&d[7]) - b.C1.B1.A0.SetBigInt(&d[8]) - b.C1.B1.A1.SetBigInt(&d[9]) - b.C1.B2.A0.SetBigInt(&d[10]) - b.C1.B2.A1.SetBigInt(&d[11]) + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + b.C0.B0.A0.SetBigInt(inputs[12]) + b.C0.B0.A1.SetBigInt(inputs[13]) + b.C0.B1.A0.SetBigInt(inputs[14]) + b.C0.B1.A1.SetBigInt(inputs[15]) + b.C0.B2.A0.SetBigInt(inputs[16]) + b.C0.B2.A1.SetBigInt(inputs[17]) + b.C1.B0.A0.SetBigInt(inputs[18]) + b.C1.B0.A1.SetBigInt(inputs[19]) + b.C1.B1.A0.SetBigInt(inputs[20]) + b.C1.B1.A1.SetBigInt(inputs[21]) + b.C1.B2.A0.SetBigInt(inputs[22]) + b.C1.B2.A1.SetBigInt(inputs[23]) c.Inverse(&b).Mul(&c, &a) - var c0, c1, c2, c3, c4, c5, t2 fp.Element - t2.SetUint64(9).Mul(&t2, &c.C0.B0.A1) - c0.Sub(&c.C0.B0.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C1.B0.A1) - c1.Sub(&c.C1.B0.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C0.B1.A1) - c2.Sub(&c.C0.B1.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C1.B1.A1) - c3.Sub(&c.C1.B1.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C0.B2.A1) - c4.Sub(&c.C0.B2.A0, &t2) - t2.SetUint64(9).Mul(&t2, &c.C1.B2.A1) - c5.Sub(&c.C1.B2.A0, &t2) - - c0.BigInt(outputs[0]) - c1.BigInt(outputs[1]) - c2.BigInt(outputs[2]) - c3.BigInt(outputs[3]) - c4.BigInt(outputs[4]) - c5.BigInt(outputs[5]) - c.C0.B0.A1.BigInt(outputs[6]) + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) c.C1.B0.A1.BigInt(outputs[7]) - c.C0.B1.A1.BigInt(outputs[8]) + c.C1.B1.A0.BigInt(outputs[8]) c.C1.B1.A1.BigInt(outputs[9]) - c.C0.B2.A1.BigInt(outputs[10]) + c.C1.B2.A0.BigInt(outputs[10]) c.C1.B2.A1.BigInt(outputs[11]) return nil }) } + +func finalExpHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + // This follows section 4.3.2 of https://eprint.iacr.org/2024/640.pdf + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var tmp, x3, cubicNonResiduePower, x, millerLoop, residueWitness, residueWitnessInv, one, root27thOf1 bn254.E12 + var exp1, exp2, rInv, mInv big.Int + + millerLoop.C0.B0.A0.SetBigInt(inputs[0]) + millerLoop.C0.B0.A1.SetBigInt(inputs[1]) + millerLoop.C0.B1.A0.SetBigInt(inputs[2]) + millerLoop.C0.B1.A1.SetBigInt(inputs[3]) + millerLoop.C0.B2.A0.SetBigInt(inputs[4]) + millerLoop.C0.B2.A1.SetBigInt(inputs[5]) + millerLoop.C1.B0.A0.SetBigInt(inputs[6]) + millerLoop.C1.B0.A1.SetBigInt(inputs[7]) + millerLoop.C1.B1.A0.SetBigInt(inputs[8]) + millerLoop.C1.B1.A1.SetBigInt(inputs[9]) + millerLoop.C1.B2.A0.SetBigInt(inputs[10]) + millerLoop.C1.B2.A1.SetBigInt(inputs[11]) + + // exp1 = (p^12-1)/3 + exp1.SetString("4030969696062745741797811005853058291874379204406359442560681893891674450106959530046539719647151210908190211459382793062006703141168852426020468083171325367934590379984666859998399967609544754664110191464072930598755441160008826659219834762354786403012110463250131961575955268597858015384895449311534622125256548620283853223733396368939858981844663598065852816056384933498610930035891058807598891752166582271931875150099691598048016175399382213304673796601585080509443902692818733420199004555566113537482054218823936116647313678747500267068559627206777530424029211671772692598157901876223857571299238046741502089890557442500582300718504160740314926185458079985126192563953772118929726791041828902047546977272656240744693339962973939047279285351052107950250121751682659529260304162131862468322644288196213423232132152125277136333208005221619443705106431645884840489295409272576227859206166894626854018093044908314720", 10) + // root27thOf1 = (0, c010, c011, 0, 0, 0, 0, 0, 0, 0, 0, 0) + // is a 27-th root of unity which is necessarily a cubic non-residue + // since h/r = (p^12-1)/r = 27·l and 3 does not divide l. + // it was computed as w^((p^12-1)/27) = c2 * w^2 + c8 * w^8 where + // Fp12 = Fp[w]/w^12-18w^6+82 which is isomorphic to our Fp12 tower + // then c010 = (c2 + 9 * c8) % p and c011 = c8 + root27thOf1.C0.B1.A0.SetString("9483667112135124394372960210728142145589475128897916459350428495526310884707") + root27thOf1.C0.B1.A1.SetString("4534159768373982659291990808346042891252278737770656686799127720849666919525") + + if one.Exp(millerLoop, &exp1).IsOne() { + // residueWitness = millerLoop is a cubic residue + cubicNonResiduePower.SetOne() + residueWitness.Set(&millerLoop) + } else if one.Exp(*millerLoop.Mul(&millerLoop, &root27thOf1), &exp1).IsOne() { + // residueWitness = millerLoop * root27thOf1 is a cubic residue + cubicNonResiduePower.Set(&root27thOf1) + residueWitness.Set(&millerLoop) + } else { + // residueWitness = millerLoop * root27thOf1^2 is a cubic residue + cubicNonResiduePower.Square(&root27thOf1) + residueWitness.Mul(&millerLoop, &root27thOf1) + } + + // 1. compute r-th root: + // Exponentiate to rInv where + // rInv = 1/r mod (p^12-1)/r + rInv.SetString("495819184011867778744231927046742333492451180917315223017345540833046880485481720031136878341141903241966521818658471092566752321606779256340158678675679238405722886654128392203338228575623261160538734808887996935946888297414610216445334190959815200956855428635568184508263913274453942864817234480763055154719338281461936129150171789463489422401982681230261920147923652438266934726901346095892093443898852488218812468761027620988447655860644584419583586883569984588067403598284748297179498734419889699245081714359110559679136004228878808158639412436468707589339209058958785568729925402190575720856279605832146553573981587948304340677613460685405477047119496887534881410757668344088436651291444274840864486870663164657544390995506448087189408281061890434467956047582679858345583941396130713046072603335601764495918026585155498301896749919393", 10) + residueWitness.Exp(residueWitness, &rInv) + + // 2. compute m-th root: + // where m = (6x + 2 + q^3 - q^2 + q)/(3r) + // Exponentiate to mInv where + // mInv = 1/m mod p^12-1 + mInv.SetString("17840267520054779749190587238017784600702972825655245554504342129614427201836516118803396948809179149954197175783449826546445899524065131269177708416982407215963288737761615699967145070776364294542559324079147363363059480104341231360692143673915822421222230661528586799190306058519400019024762424366780736540525310403098758015600523609594113357130678138304964034267260758692953579514899054295817541844330584721967571697039986079722203518034173581264955381924826388858518077894154909963532054519350571947910625755075099598588672669612434444513251495355121627496067454526862754597351094345783576387352673894873931328099247263766690688395096280633426669535619271711975898132416216382905928886703963310231865346128293216316379527200971959980873989485521004596686352787540034457467115536116148612884807380187255514888720048664139404687086409399", 10) + residueWitness.Exp(residueWitness, &mInv) + + // 3. compute cube root: + // since gcd(3, (p^12-1)/r) ≠ 1 we use a modified Toneelli-Shanks algorithm + // see Alg.4 of https://eprint.iacr.org/2024/640.pdf + // Typo in the paper: p^k-1 = 3^n * s instead of p-1 = 3^r * s + // where k=12 and n=3 here and exp2 = (s+1)/3 + residueWitnessInv.Inverse(&residueWitness) + exp2.SetString("149295173928249842288807815031594751550902933496531831205951181255247201855813315927649619246190785589192230054051214557852100116339587126889646966043382421034614458517950624444385183985538694617189266350521219651805757080000326913304438324531658755667115202342597480058368713651772519088329461085612393412046538837788290860138273939590365147475728281409846400594680923462911515927255224400281440435265428973034513894448136725853630228718495637529802733207466114092942366766400693830377740909465411612499335341437923559875826432546203713595131838044695464089778859691547136762894737106526809539677749557286722299625576201574095640767352005953344997266128077036486155280146436004404804695964512181557316554713802082990544197776406442186936269827816744738898152657469728130713344598597476387715653492155415311971560450078713968012341037230430349766855793764662401499603533676762082513303932107208402000670112774382027", 10) + x.Exp(residueWitness, &exp2) + + // 3^t is ord(x^3 / residueWitness) + x3.Square(&x).Mul(&x3, &x).Mul(&x3, &residueWitnessInv) + t := 0 + for !x3.IsOne() { + t++ + tmp.Square(&x3) + x3.Mul(&tmp, &x3) + } + + for t != 0 { + x.Mul(&x, tmp.Exp(root27thOf1, &exp2)) + + // 3^t is ord(x^3 / residueWitness) + x3.Square(&x).Mul(&x3, &x).Mul(&x3, &residueWitnessInv) + t = 0 + for !x3.IsOne() { + t++ + tmp.Square(&x3) + x3.Mul(&tmp, &x3) + } + } + + // x is now the cube root of residueWitness + residueWitness.Set(&x) + + residueWitness.C0.B0.A0.BigInt(outputs[0]) + residueWitness.C0.B0.A1.BigInt(outputs[1]) + residueWitness.C0.B1.A0.BigInt(outputs[2]) + residueWitness.C0.B1.A1.BigInt(outputs[3]) + residueWitness.C0.B2.A0.BigInt(outputs[4]) + residueWitness.C0.B2.A1.BigInt(outputs[5]) + residueWitness.C1.B0.A0.BigInt(outputs[6]) + residueWitness.C1.B0.A1.BigInt(outputs[7]) + residueWitness.C1.B1.A0.BigInt(outputs[8]) + residueWitness.C1.B1.A1.BigInt(outputs[9]) + residueWitness.C1.B2.A0.BigInt(outputs[10]) + residueWitness.C1.B2.A1.BigInt(outputs[11]) + + // we also need to return the cubic non-residue power + cubicNonResiduePower.C0.B0.A0.BigInt(outputs[12]) + cubicNonResiduePower.C0.B0.A1.BigInt(outputs[13]) + cubicNonResiduePower.C0.B1.A0.BigInt(outputs[14]) + cubicNonResiduePower.C0.B1.A1.BigInt(outputs[15]) + cubicNonResiduePower.C0.B2.A0.BigInt(outputs[16]) + cubicNonResiduePower.C0.B2.A1.BigInt(outputs[17]) + cubicNonResiduePower.C1.B0.A0.BigInt(outputs[18]) + cubicNonResiduePower.C1.B0.A1.BigInt(outputs[19]) + cubicNonResiduePower.C1.B1.A0.BigInt(outputs[20]) + cubicNonResiduePower.C1.B1.A1.BigInt(outputs[21]) + cubicNonResiduePower.C1.B2.A0.BigInt(outputs[22]) + cubicNonResiduePower.C1.B2.A1.BigInt(outputs[23]) + + return nil + }) +} diff --git a/std/algebra/emulated/sw_bls12381/g1.go b/std/algebra/emulated/sw_bls12381/g1.go index ce8398616a..161db08538 100644 --- a/std/algebra/emulated/sw_bls12381/g1.go +++ b/std/algebra/emulated/sw_bls12381/g1.go @@ -54,18 +54,21 @@ func (g1 *G1) phi(q *G1Affine) *G1Affine { } func (g1 *G1) double(p *G1Affine) *G1Affine { - mone := g1.curveF.NewElement(-1) - // compute λ = (3p.x²)/2*p.y + // compute λ = (3p.x²)/1*p.y xx3a := g1.curveF.Mul(&p.X, &p.X) xx3a = g1.curveF.MulConst(xx3a, big.NewInt(3)) y1 := g1.curveF.MulConst(&p.Y, big.NewInt(2)) λ := g1.curveF.Div(xx3a, y1) - // xr = λ²-2p.x - xr := g1.curveF.Eval([][]*baseEl{{λ, λ}, {mone, &p.X}}, []int{1, 2}) + // xr = λ²-1p.x + x1 := g1.curveF.MulConst(&p.X, big.NewInt(2)) + λλ := g1.curveF.Mul(λ, λ) + xr := g1.curveF.Sub(λλ, x1) // yr = λ(p-xr) - p.y - yr := g1.curveF.Eval([][]*baseEl{{λ, g1.curveF.Sub(&p.X, xr)}, {mone, &p.Y}}, []int{1, 1}) + pxrx := g1.curveF.Sub(&p.X, xr) + λpxrx := g1.curveF.Mul(λ, pxrx) + yr := g1.curveF.Sub(λpxrx, &p.Y) return &G1Affine{ X: *xr, @@ -82,17 +85,20 @@ func (g1 *G1) doubleN(p *G1Affine, n int) *G1Affine { } func (g1 G1) add(p, q *G1Affine) *G1Affine { - mone := g1.curveF.NewElement(-1) // compute λ = (q.y-p.y)/(q.x-p.x) qypy := g1.curveF.Sub(&q.Y, &p.Y) qxpx := g1.curveF.Sub(&q.X, &p.X) λ := g1.curveF.Div(qypy, qxpx) // xr = λ²-p.x-q.x - xr := g1.curveF.Eval([][]*baseEl{{λ, λ}, {mone, g1.curveF.Add(&p.X, &q.X)}}, []int{1, 1}) + λλ := g1.curveF.Mul(λ, λ) + qxpx = g1.curveF.Add(&p.X, &q.X) + xr := g1.curveF.Sub(λλ, qxpx) - // p.y = λ(p.x-xr) - p.y - yr := g1.curveF.Eval([][]*baseEl{{λ, g1.curveF.Sub(&p.X, xr)}, {mone, &p.Y}}, []int{1, 1}) + // p.y = λ(p.x-r.x) - p.y + pxrx := g1.curveF.Sub(&p.X, xr) + λpxrx := g1.curveF.Mul(λ, pxrx) + yr := g1.curveF.Sub(λpxrx, &p.Y) return &G1Affine{ X: *xr, @@ -102,28 +108,33 @@ func (g1 G1) add(p, q *G1Affine) *G1Affine { func (g1 G1) doubleAndAdd(p, q *G1Affine) *G1Affine { - mone := g1.curveF.NewElement(-1) // compute λ1 = (q.y-p.y)/(q.x-p.x) yqyp := g1.curveF.Sub(&q.Y, &p.Y) xqxp := g1.curveF.Sub(&q.X, &p.X) λ1 := g1.curveF.Div(yqyp, xqxp) // compute x1 = λ1²-p.x-q.x - x2 := g1.curveF.Eval([][]*baseEl{{λ1, λ1}, {mone, g1.curveF.Add(&p.X, &q.X)}}, []int{1, 1}) + λ1λ1 := g1.curveF.Mul(λ1, λ1) + xqxp = g1.curveF.Add(&p.X, &q.X) + x2 := g1.curveF.Sub(λ1λ1, xqxp) - // omit y2 computation - - // compute -λ2 = λ1+2*p.y/(x2-p.x) - ypyp := g1.curveF.MulConst(&p.Y, big.NewInt(2)) + // omit y1 computation + // compute λ1 = -λ1-1*p.y/(x1-p.x) + ypyp := g1.curveF.Add(&p.Y, &p.Y) x2xp := g1.curveF.Sub(x2, &p.X) λ2 := g1.curveF.Div(ypyp, x2xp) λ2 = g1.curveF.Add(λ1, λ2) + λ2 = g1.curveF.Neg(λ2) - // compute x3 = (-λ2)²-p.x-x2 - x3 := g1.curveF.Eval([][]*baseEl{{λ2, λ2}, {mone, &p.X}, {mone, x2}}, []int{1, 1, 1}) + // compute x3 =λ2²-p.x-x3 + λ2λ2 := g1.curveF.Mul(λ2, λ2) + x3 := g1.curveF.Sub(λ2λ2, &p.X) + x3 = g1.curveF.Sub(x3, x2) - // compute y3 = -λ2*(x3- p.x)-p.y - y3 := g1.curveF.Eval([][]*baseEl{{λ2, g1.curveF.Sub(x3, &p.X)}, {mone, &p.Y}}, []int{1, 1}) + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g1.curveF.Sub(&p.X, x3) + y3 = g1.curveF.Mul(λ2, y3) + y3 = g1.curveF.Sub(y3, &p.Y) return &G1Affine{ X: *x3, diff --git a/std/algebra/emulated/sw_bls12381/g2.go b/std/algebra/emulated/sw_bls12381/g2.go index 4f3245ee21..e6a275cfbb 100644 --- a/std/algebra/emulated/sw_bls12381/g2.go +++ b/std/algebra/emulated/sw_bls12381/g2.go @@ -10,7 +10,6 @@ import ( ) type G2 struct { - fp *emulated.Field[BaseField] *fields_bls12381.Ext2 u1, w *emulated.Element[BaseField] v *fields_bls12381.E2 @@ -40,11 +39,6 @@ func newG2AffP(v bls12381.G2Affine) g2AffP { } func NewG2(api frontend.API) *G2 { - fp, err := emulated.NewField[emulated.BLS12381Fp](api) - if err != nil { - // TODO: we start returning errors when generifying - panic(err) - } w := emulated.ValueOf[BaseField]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") u1 := emulated.ValueOf[BaseField]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") v := fields_bls12381.E2{ @@ -52,7 +46,6 @@ func NewG2(api frontend.API) *G2 { A1: emulated.ValueOf[BaseField]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), } return &G2{ - fp: fp, Ext2: fields_bls12381.NewExt2(api), w: &w, u1: &u1, @@ -120,23 +113,20 @@ func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { } func (g2 G2) add(p, q *G2Affine) *G2Affine { - mone := g2.fp.NewElement(-1) - // compute λ = (q.y-p.y)/(q.x-p.x) qypy := g2.Ext2.Sub(&q.P.Y, &p.P.Y) qxpx := g2.Ext2.Sub(&q.P.X, &p.P.X) λ := g2.Ext2.DivUnchecked(qypy, qxpx) // xr = λ²-p.x-q.x - xr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p.P.X.A0}, {mone, &q.P.X.A0}}, []int{1, 1, 1, 1}) - xr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p.P.X.A1}, {mone, &q.P.X.A1}}, []int{2, 1, 1}) - xr := &fields_bls12381.E2{A0: *xr0, A1: *xr1} + λλ := g2.Ext2.Square(λ) + qxpx = g2.Ext2.Add(&p.P.X, &q.P.X) + xr := g2.Ext2.Sub(λλ, qxpx) // p.y = λ(p.x-r.x) - p.y - yr := g2.Ext2.Sub(&p.P.X, xr) - yr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) - yr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bls12381.E2{A0: *yr0, A1: *yr1} + pxrx := g2.Ext2.Sub(&p.P.X, xr) + λpxrx := g2.Ext2.Mul(λ, pxrx) + yr := g2.Ext2.Sub(λpxrx, &p.P.Y) return &G2Affine{ P: g2AffP{ @@ -163,8 +153,6 @@ func (g2 G2) sub(p, q *G2Affine) *G2Affine { } func (g2 *G2) double(p *G2Affine) *G2Affine { - mone := g2.fp.NewElement(-1) - // compute λ = (3p.x²)/2*p.y xx3a := g2.Square(&p.P.X) xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) @@ -172,15 +160,14 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { λ := g2.DivUnchecked(xx3a, y2) // xr = λ²-2p.x - xr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p.P.X.A0}}, []int{1, 1, 2}) - xr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p.P.X.A1}}, []int{2, 2}) - xr := &fields_bls12381.E2{A0: *xr0, A1: *xr1} + x2 := g2.Double(&p.P.X) + λλ := g2.Square(λ) + xr := g2.Sub(λλ, x2) // yr = λ(p-xr) - p.y - yr := g2.Ext2.Sub(&p.P.X, xr) - yr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) - yr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bls12381.E2{A0: *yr0, A1: *yr1} + pxrx := g2.Sub(&p.P.X, xr) + λpxrx := g2.Mul(λ, pxrx) + yr := g2.Sub(λpxrx, &p.P.Y) return &G2Affine{ P: g2AffP{ @@ -199,7 +186,6 @@ func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine { } func (g2 G2) triple(p *G2Affine) *G2Affine { - mone := g2.fp.NewElement(-1) // compute λ1 = (3p.x²)/2p.y xx := g2.Square(&p.P.X) @@ -207,10 +193,10 @@ func (g2 G2) triple(p *G2Affine) *G2Affine { y2 := g2.Double(&p.P.Y) λ1 := g2.DivUnchecked(xx, y2) - // x2 = λ1²-2p.x - x20 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p.P.X.A0}}, []int{1, 1, 2}) - x21 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p.P.X.A1}}, []int{2, 2}) - x2 := &fields_bls12381.E2{A0: *x20, A1: *x21} + // xr = λ1²-2p.x + x2 := g2.MulByConstElement(&p.P.X, big.NewInt(2)) + λ1λ1 := g2.Square(λ1) + x2 = g2.Sub(λ1λ1, x2) // omit y2 computation, and // compute λ2 = 2p.y/(x2 − p.x) − λ1. @@ -218,27 +204,25 @@ func (g2 G2) triple(p *G2Affine) *G2Affine { λ2 := g2.DivUnchecked(y2, x1x2) λ2 = g2.Sub(λ2, λ1) - // compute x3 =λ2²-p.x-x2 - x30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p.P.X.A0}, {mone, x20}}, []int{1, 1, 1, 1}) - x31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p.P.X.A1}, {mone, x21}}, []int{2, 1, 1}) - x3 := &fields_bls12381.E2{A0: *x30, A1: *x31} + // xr = λ²-p.x-x2 + λ2λ2 := g2.Square(λ2) + qxrx := g2.Add(x2, &p.P.X) + xr := g2.Sub(λ2λ2, qxrx) - // compute y3 = λ2*(p.x - x3)-p.y - y3 := g2.Ext2.Sub(&p.P.X, x3) - y30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A0}, {mone, &λ2.A1, &y3.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) - y31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A1}, {&λ2.A1, &y3.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) - y3 = &fields_bls12381.E2{A0: *y30, A1: *y31} + // yr = λ(p.x-xr) - p.y + pxrx := g2.Sub(&p.P.X, xr) + λ2pxrx := g2.Mul(λ2, pxrx) + yr := g2.Sub(λ2pxrx, &p.P.Y) return &G2Affine{ P: g2AffP{ - X: *x3, - Y: *y3, + X: *xr, + Y: *yr, }, } } func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { - mone := g2.fp.NewElement(-1) // compute λ1 = (q.y-p.y)/(q.x-p.x) yqyp := g2.Ext2.Sub(&q.P.Y, &p.P.Y) @@ -246,27 +230,27 @@ func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp) // compute x2 = λ1²-p.x-q.x - x20 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p.P.X.A0}, {mone, &q.P.X.A0}}, []int{1, 1, 1, 1}) - x21 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p.P.X.A1}, {mone, &q.P.X.A1}}, []int{2, 1, 1}) - x2 := &fields_bls12381.E2{A0: *x20, A1: *x21} + λ1λ1 := g2.Ext2.Square(λ1) + xqxp = g2.Ext2.Add(&p.P.X, &q.P.X) + x2 := g2.Ext2.Sub(λ1λ1, xqxp) // omit y2 computation - // compute -λ2 = λ1+2*p.y/(x2-p.x) + // compute λ2 = -λ1-2*p.y/(x2-p.x) ypyp := g2.Ext2.Add(&p.P.Y, &p.P.Y) x2xp := g2.Ext2.Sub(x2, &p.P.X) λ2 := g2.Ext2.DivUnchecked(ypyp, x2xp) λ2 = g2.Ext2.Add(λ1, λ2) + λ2 = g2.Ext2.Neg(λ2) - // compute x3 = (-λ2)²-p.x-x2 - x30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p.P.X.A0}, {mone, x20}}, []int{1, 1, 1, 1}) - x31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p.P.X.A1}, {mone, x21}}, []int{2, 1, 1}) - x3 := &fields_bls12381.E2{A0: *x30, A1: *x31} + // compute x3 =λ2²-p.x-x3 + λ2λ2 := g2.Ext2.Square(λ2) + x3 := g2.Ext2.Sub(λ2λ2, &p.P.X) + x3 = g2.Ext2.Sub(x3, x2) - // compute y3 = -λ2*(x3 - p.x)-p.y - y3 := g2.Ext2.Sub(x3, &p.P.X) - y30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A0}, {mone, &λ2.A1, &y3.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) - y31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A1}, {&λ2.A1, &y3.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) - y3 = &fields_bls12381.E2{A0: *y30, A1: *y31} + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g2.Ext2.Sub(&p.P.X, x3) + y3 = g2.Ext2.Mul(λ2, y3) + y3 = g2.Ext2.Sub(y3, &p.P.Y) return &G2Affine{ P: g2AffP{ diff --git a/std/algebra/emulated/sw_bls12381/hints.go b/std/algebra/emulated/sw_bls12381/hints.go deleted file mode 100644 index 676ed3c225..0000000000 --- a/std/algebra/emulated/sw_bls12381/hints.go +++ /dev/null @@ -1,128 +0,0 @@ -package sw_bls12381 - -import ( - "math/big" - - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/math/emulated" -) - -func init() { - solver.RegisterHint(GetHints()...) -} - -// GetHints returns all hint functions used in the package. -func GetHints() []solver.Hint { - return []solver.Hint{finalExpHint} -} - -func finalExpHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - // This is inspired from https://eprint.iacr.org/2024/640.pdf - // and based on a personal communication with the author Andrija Novakovic. - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var millerLoop bls12381.E12 - - millerLoop.C0.B0.A0.SetBigInt(inputs[0]) - millerLoop.C0.B0.A1.SetBigInt(inputs[1]) - millerLoop.C0.B1.A0.SetBigInt(inputs[2]) - millerLoop.C0.B1.A1.SetBigInt(inputs[3]) - millerLoop.C0.B2.A0.SetBigInt(inputs[4]) - millerLoop.C0.B2.A1.SetBigInt(inputs[5]) - millerLoop.C1.B0.A0.SetBigInt(inputs[6]) - millerLoop.C1.B0.A1.SetBigInt(inputs[7]) - millerLoop.C1.B1.A0.SetBigInt(inputs[8]) - millerLoop.C1.B1.A1.SetBigInt(inputs[9]) - millerLoop.C1.B2.A0.SetBigInt(inputs[10]) - millerLoop.C1.B2.A1.SetBigInt(inputs[11]) - - var root, rootPthInverse, root27thInverse, residueWitness, scalingFactor bls12381.E12 - var order3rd, order3rdPower, exponent, exponentInv, finalExpFactor, polyFactor big.Int - // polyFactor = (1-x)/3 - polyFactor.SetString("5044125407647214251", 10) - // finalExpFactor = ((q^12 - 1) / r) / (27 * polyFactor) - finalExpFactor.SetString("2366356426548243601069753987687709088104621721678962410379583120840019275952471579477684846670499039076873213559162845121989217658133790336552276567078487633052653005423051750848782286407340332979263075575489766963251914185767058009683318020965829271737924625612375201545022326908440428522712877494557944965298566001441468676802477524234094954960009227631543471415676620753242466901942121887152806837594306028649150255258504417829961387165043999299071444887652375514277477719817175923289019181393803729926249507024121957184340179467502106891835144220611408665090353102353194448552304429530104218473070114105759487413726485729058069746063140422361472585604626055492939586602274983146215294625774144156395553405525711143696689756441298365274341189385646499074862712688473936093315628166094221735056483459332831845007196600723053356837526749543765815988577005929923802636375670820616189737737304893769679803809426304143627363860243558537831172903494450556755190448279875942974830469855835666815454271389438587399739607656399812689280234103023464545891697941661992848552456326290792224091557256350095392859243101357349751064730561345062266850238821755009430903520645523345000326783803935359711318798844368754833295302563158150573540616830138810935344206231367357992991289265295323280", 10) - - // 1. get pth-root inverse - exponent.Mul(&finalExpFactor, big.NewInt(27)) - root.Exp(millerLoop, &exponent) - if root.IsOne() { - rootPthInverse.SetOne() - } else { - exponentInv.ModInverse(&exponent, &polyFactor) - exponent.Neg(&exponentInv).Mod(&exponent, &polyFactor) - rootPthInverse.Exp(root, &exponent) - } - - // 2.1. get order of 3rd primitive root - var three big.Int - three.SetUint64(3) - exponent.Mul(&polyFactor, &finalExpFactor) - root.Exp(millerLoop, &exponent) - if root.IsOne() { - order3rdPower.SetUint64(0) - } - root.Exp(root, &three) - if root.IsOne() { - order3rdPower.SetUint64(1) - } - root.Exp(root, &three) - if root.IsOne() { - order3rdPower.SetUint64(2) - } - root.Exp(root, &three) - if root.IsOne() { - order3rdPower.SetUint64(3) - } - - // 2.2. get 27th root inverse - if order3rdPower.Uint64() == 0 { - root27thInverse.SetOne() - } else { - order3rd.Exp(&three, &order3rdPower, nil) - exponent.Mul(&polyFactor, &finalExpFactor) - root.Exp(millerLoop, &exponent) - exponentInv.ModInverse(&exponent, &order3rd) - exponent.Neg(&exponentInv).Mod(&exponent, &order3rd) - root27thInverse.Exp(root, &exponent) - } - - // 2.3. shift the Miller loop result so that millerLoop * scalingFactor - // is of order finalExpFactor - scalingFactor.Mul(&rootPthInverse, &root27thInverse) - millerLoop.Mul(&millerLoop, &scalingFactor) - - // 3. get the witness residue - // - // lambda = q - u, the optimal exponent - var lambda big.Int - lambda.SetString("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129030796414117214202539", 10) - exponent.ModInverse(&lambda, &finalExpFactor) - residueWitness.Exp(millerLoop, &exponent) - - // return the witness residue - residueWitness.C0.B0.A0.BigInt(outputs[0]) - residueWitness.C0.B0.A1.BigInt(outputs[1]) - residueWitness.C0.B1.A0.BigInt(outputs[2]) - residueWitness.C0.B1.A1.BigInt(outputs[3]) - residueWitness.C0.B2.A0.BigInt(outputs[4]) - residueWitness.C0.B2.A1.BigInt(outputs[5]) - residueWitness.C1.B0.A0.BigInt(outputs[6]) - residueWitness.C1.B0.A1.BigInt(outputs[7]) - residueWitness.C1.B1.A0.BigInt(outputs[8]) - residueWitness.C1.B1.A1.BigInt(outputs[9]) - residueWitness.C1.B2.A0.BigInt(outputs[10]) - residueWitness.C1.B2.A1.BigInt(outputs[11]) - - // return the scaling factor - scalingFactor.C0.B0.A0.BigInt(outputs[12]) - scalingFactor.C0.B0.A1.BigInt(outputs[13]) - scalingFactor.C0.B1.A0.BigInt(outputs[14]) - scalingFactor.C0.B1.A1.BigInt(outputs[15]) - scalingFactor.C0.B2.A0.BigInt(outputs[16]) - scalingFactor.C0.B2.A1.BigInt(outputs[17]) - - return nil - }) -} diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index b798bf978e..bf3a9f9d34 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -6,7 +6,6 @@ import ( "math/big" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bls12381" "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" @@ -16,40 +15,46 @@ import ( type Pairing struct { api frontend.API *fields_bls12381.Ext12 - *fields_bls12381.Ext2 curveF *emulated.Field[BaseField] curve *sw_emulated.Curve[BaseField, ScalarField] g2 *G2 g1 *G1 bTwist *fields_bls12381.E2 + g2gen *G2Affine } -type baseEl = emulated.Element[BaseField] type GTEl = fields_bls12381.E12 -func NewGTEl(a bls12381.GT) GTEl { - - var c0, c1, c2, c3, c4, c5 fp.Element - c0.Sub(&a.C0.B0.A0, &a.C0.B0.A1) - c1.Sub(&a.C1.B0.A0, &a.C1.B0.A1) - c2.Sub(&a.C0.B1.A0, &a.C0.B1.A1) - c3.Sub(&a.C1.B1.A0, &a.C1.B1.A1) - c4.Sub(&a.C0.B2.A0, &a.C0.B2.A1) - c5.Sub(&a.C1.B2.A0, &a.C1.B2.A1) - +func NewGTEl(v bls12381.GT) GTEl { return GTEl{ - A0: emulated.ValueOf[BaseField](c0), - A1: emulated.ValueOf[BaseField](c1), - A2: emulated.ValueOf[BaseField](c2), - A3: emulated.ValueOf[BaseField](c3), - A4: emulated.ValueOf[BaseField](c4), - A5: emulated.ValueOf[BaseField](c5), - A6: emulated.ValueOf[BaseField](a.C0.B0.A1), - A7: emulated.ValueOf[BaseField](a.C1.B0.A1), - A8: emulated.ValueOf[BaseField](a.C0.B1.A1), - A9: emulated.ValueOf[BaseField](a.C1.B1.A1), - A10: emulated.ValueOf[BaseField](a.C0.B2.A1), - A11: emulated.ValueOf[BaseField](a.C1.B2.A1), + C0: fields_bls12381.E6{ + B0: fields_bls12381.E2{ + A0: emulated.ValueOf[BaseField](v.C0.B0.A0), + A1: emulated.ValueOf[BaseField](v.C0.B0.A1), + }, + B1: fields_bls12381.E2{ + A0: emulated.ValueOf[BaseField](v.C0.B1.A0), + A1: emulated.ValueOf[BaseField](v.C0.B1.A1), + }, + B2: fields_bls12381.E2{ + A0: emulated.ValueOf[BaseField](v.C0.B2.A0), + A1: emulated.ValueOf[BaseField](v.C0.B2.A1), + }, + }, + C1: fields_bls12381.E6{ + B0: fields_bls12381.E2{ + A0: emulated.ValueOf[BaseField](v.C1.B0.A0), + A1: emulated.ValueOf[BaseField](v.C1.B0.A1), + }, + B1: fields_bls12381.E2{ + A0: emulated.ValueOf[BaseField](v.C1.B1.A0), + A1: emulated.ValueOf[BaseField](v.C1.B1.A1), + }, + B2: fields_bls12381.E2{ + A0: emulated.ValueOf[BaseField](v.C1.B2.A0), + A1: emulated.ValueOf[BaseField](v.C1.B2.A1), + }, + }, } } @@ -73,7 +78,6 @@ func NewPairing(api frontend.API) (*Pairing, error) { return &Pairing{ api: api, Ext12: fields_bls12381.NewExt12(api), - Ext2: fields_bls12381.NewExt2(api), curveF: ba, curve: curve, g1: g1, @@ -82,6 +86,144 @@ func NewPairing(api frontend.API) (*Pairing, error) { }, nil } +func (pr Pairing) generators() *G2Affine { + if pr.g2gen == nil { + _, _, _, g2gen := bls12381.Generators() + cg2gen := NewG2AffineFixed(g2gen) + pr.g2gen = &cg2gen + } + return pr.g2gen +} + +// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// we use instead +// +// d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// where s is the cofactor 3 (Hayashida et al.). +// +// FinalExponentiation returns a decompressed element in E12. +// +// This is the safe version of the method where e may be {-1,1}. If it is known +// that e ≠ {-1,1} then using the unsafe version of the method saves +// considerable amount of constraints. When called with the result of +// [MillerLoop], then current method is applicable when length of the inputs to +// Miller loop is 1. +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + return pr.finalExponentiation(e, false) +} + +// FinalExponentiationUnsafe computes the exponentiation (∏ᵢ zᵢ)ᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// we use instead +// +// d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// where s is the cofactor 3 (Hayashida et al.). +// +// FinalExponentiationUnsafe returns a decompressed element in E12. +// +// This is the unsafe version of the method where e may NOT be {-1,1}. If e ∈ +// {-1, 1}, then there exists no valid solution to the circuit. This method is +// applicable when called with the result of [MillerLoop] method when the length +// of the inputs to Miller loop is 1. +func (pr Pairing) FinalExponentiationUnsafe(e *GTEl) *GTEl { + return pr.finalExponentiation(e, true) +} + +// finalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// we use instead +// +// d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// where s is the cofactor 3 (Hayashida et al.). +// +// finalExponentiation returns a decompressed element in E12 +func (pr Pairing) finalExponentiation(e *GTEl, unsafe bool) *GTEl { + + // 1. Easy part + // (p⁶-1)(p²+1) + var selector1, selector2 frontend.Variable + _dummy := pr.Ext6.One() + + if unsafe { + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are + // linearly dependent and not from G1 and G2 respectively. + // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0. + // Nothing to do. + + } else { + // However, for a product of Miller loops (n>=2) this might happen. If this is + // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 + // and proceed further. + selector1 = pr.Ext6.IsZero(&e.C1) + e.C1.B0.A0 = *pr.curveF.Select(selector1, pr.curveF.One(), &e.C1.B0.A0) + } + + // Torus compression absorbed: + // Raising e to (p⁶-1) is + // e^(p⁶) / e = (e.C0 - w*e.C1) / (e.C0 + w*e.C1) + // = (-e.C0/e.C1 + w) / (-e.C0/e.C1 - w) + // So the fraction -e.C0/e.C1 is already in the torus. + // This absorbs the torus compression in the easy part. + c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) + c = pr.Ext6.Neg(c) + t0 := pr.FrobeniusSquareTorus(c) + c = pr.MulTorus(t0, c) + + // 2. Hard part (up to permutation) + // 3(p⁴-p²+1)/r + // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya + // https://eprint.iacr.org/2020/875.pdf + // performed in torus compressed form + t0 = pr.SquareTorus(c) + t1 := pr.ExptHalfTorus(t0) + t2 := pr.InverseTorus(c) + t1 = pr.MulTorus(t1, t2) + t2 = pr.ExptTorus(t1) + t1 = pr.InverseTorus(t1) + t1 = pr.MulTorus(t1, t2) + t2 = pr.ExptTorus(t1) + t1 = pr.FrobeniusTorus(t1) + t1 = pr.MulTorus(t1, t2) + c = pr.MulTorus(c, t0) + t0 = pr.ExptTorus(t1) + t2 = pr.ExptTorus(t0) + t0 = pr.FrobeniusSquareTorus(t1) + t1 = pr.InverseTorus(t1) + t1 = pr.MulTorus(t1, t2) + t1 = pr.MulTorus(t1, t0) + + var result GTEl + // MulTorus(c, t1) requires c ≠ -t1. When c = -t1, it means the + // product is 1 in the torus. + if unsafe { + // For a single pairing, this does not happen because the pairing is non-degenerate. + result = *pr.DecompressTorus(pr.MulTorus(c, t1)) + } else { + // For a product of pairings this might happen when the result is expected to be 1. + // We assign a dummy value (1) to t1 and proceed further. + // Finally we do a select on both edge cases: + // - Only if seletor1=0 and selector2=0, we return MulTorus(c, t1) decompressed. + // - Otherwise, we return 1. + _sum := pr.Ext6.Add(c, t1) + selector2 = pr.Ext6.IsZero(_sum) + t1 = pr.Ext6.Select(selector2, _dummy, t1) + selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) + result = *pr.Select(selector, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One()) + } + + return &result +} + // Pair calculates the reduced pairing for a set of points // ∏ᵢ e(Pᵢ, Qᵢ). // @@ -91,7 +233,7 @@ func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res) + res = pr.finalExponentiation(res, len(P) == 1) return res, nil } @@ -105,6 +247,15 @@ func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error { return err } + // We perform the easy part of the final exp to push f to the cyclotomic + // subgroup so that AssertFinalExponentiationIsOne is carried with optimized + // cyclotomic squaring (e.g. Karabina12345). + // + // f = f^(p⁶-1)(p²+1) + buf := pr.Conjugate(f) + buf = pr.DivUnchecked(buf, f) + f = pr.FrobeniusSquare(buf) + f = pr.Mul(f, buf) pr.AssertFinalExponentiationIsOne(f) @@ -213,8 +364,8 @@ func (pr Pairing) millerLoopLines(P []*G1Affine, lines []lineEvaluations) (*GTEl } // precomputations - yInv := make([]*baseEl, n) - xNegOverY := make([]*baseEl, n) + yInv := make([]*emulated.Element[BaseField], n) + xNegOverY := make([]*emulated.Element[BaseField], n) for k := 0; k < n; k++ { // P are supposed to be on G1 respectively of prime order r. @@ -228,14 +379,39 @@ func (pr Pairing) millerLoopLines(P []*G1Affine, lines []lineEvaluations) (*GTEl res := pr.Ext12.One() // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + // i = 62, separately to avoid an E12 Square // (Square(res) = 1² = 1) - for k := 0; k < n; k++ { - res = pr.MulBy02368(res, + // k = 0, separately to avoid MulBy014 (res × ℓ) + res.C0.B0 = *pr.MulByElement(&lines[0][0][62].R1, yInv[0]) + res.C0.B1 = *pr.MulByElement(&lines[0][0][62].R0, xNegOverY[0]) + res.C1.B1 = *pr.Ext2.One() + + prodLines := pr.Mul014By014( + pr.MulByElement(&lines[0][1][62].R1, yInv[0]), + pr.MulByElement(&lines[0][1][62].R0, xNegOverY[0]), + &res.C0.B0, + &res.C0.B1, + ) + res = &fields_bls12381.E12{ + C0: fields_bls12381.E6{ + B0: *prodLines[0], + B1: *prodLines[1], + B2: *prodLines[2], + }, + C1: fields_bls12381.E6{ + B0: res.C1.B0, + B1: *prodLines[3], + B2: *prodLines[4], + }, + } + + for k := 1; k < n; k++ { + res = pr.MulBy014(res, pr.MulByElement(&lines[k][0][62].R1, yInv[k]), pr.MulByElement(&lines[k][0][62].R0, xNegOverY[k]), ) - res = pr.MulBy02368(res, + res = pr.MulBy014(res, pr.MulByElement(&lines[k][1][62].R1, yInv[k]), pr.MulByElement(&lines[k][1][62].R0, xNegOverY[k]), ) @@ -244,20 +420,20 @@ func (pr Pairing) millerLoopLines(P []*G1Affine, lines []lineEvaluations) (*GTEl for i := 61; i >= 0; i-- { // mutualize the square among n Miller loops // (∏ᵢfᵢ)² - res = pr.Ext12.Square(res) + res = pr.Square(res) for k := 0; k < n; k++ { if loopCounter[i] == 0 { - res = pr.MulBy02368(res, + res = pr.MulBy014(res, pr.MulByElement(&lines[k][0][i].R1, yInv[k]), pr.MulByElement(&lines[k][0][i].R0, xNegOverY[k]), ) } else { - res = pr.MulBy02368(res, + res = pr.MulBy014(res, pr.MulByElement(&lines[k][0][i].R1, yInv[k]), pr.MulByElement(&lines[k][0][i].R0, xNegOverY[k]), ) - res = pr.MulBy02368(res, + res = pr.MulBy014(res, pr.MulByElement(&lines[k][1][i].R1, yInv[k]), pr.MulByElement(&lines[k][1][i].R0, xNegOverY[k]), ) @@ -271,113 +447,13 @@ func (pr Pairing) millerLoopLines(P []*G1Affine, lines []lineEvaluations) (*GTEl return res, nil } -// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ -// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// where s is the cofactor 3 (Hayashida et al.) -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - z := pr.Copy(e) - - // Easy part - // (p⁶-1)(p²+1) - t0 := pr.Ext12.Conjugate(z) - t0 = pr.Ext12.DivUnchecked(t0, z) - z = pr.Ext12.FrobeniusSquare(t0) - z = pr.Ext12.Mul(z, t0) - - // Hard part (up to permutation) - // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya - // https://eprint.iacr.org/2020/875.pdf - t0 = pr.Ext12.CyclotomicSquareGS(z) - t1 := pr.Ext12.ExptHalfGS(t0) - t2 := pr.Ext12.Conjugate(z) - t1 = pr.Ext12.Mul(t1, t2) - t2 = pr.Ext12.ExptGS(t1) - t1 = pr.Ext12.Conjugate(t1) - t1 = pr.Ext12.Mul(t1, t2) - t2 = pr.Ext12.ExptGS(t1) - t1 = pr.Ext12.Frobenius(t1) - t1 = pr.Ext12.Mul(t1, t2) - z = pr.Ext12.Mul(z, t0) - t0 = pr.Ext12.ExptGS(t1) - t2 = pr.Ext12.ExptGS(t0) - t0 = pr.Ext12.FrobeniusSquare(t1) - t1 = pr.Ext12.Conjugate(t1) - t1 = pr.Ext12.Mul(t1, t2) - t1 = pr.Ext12.Mul(t1, t0) - z = pr.Ext12.Mul(z, t1) - - return z -} - -// AssertFinalExponentiationIsOne checks that a Miller function output x lies in the -// same equivalence class as the reduced pairing. This replaces the final -// exponentiation step in-circuit. -// The method is inspired from [On Proving Pairings] paper by A. Novakovic and -// L. Eagen, and is based on a personal communication with A. Novakovic. -// -// [On Proving Pairings]: https://eprint.iacr.org/2024/640.pdf -func (pr Pairing) AssertFinalExponentiationIsOne(x *GTEl) { - tower := pr.ToTower(x) - - res, err := pr.curveF.NewHint(finalExpHint, 24, tower[0], tower[1], tower[2], tower[3], tower[4], tower[5], tower[6], tower[7], tower[8], tower[9], tower[10], tower[11]) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - residueWitness := pr.FromTower([12]*baseEl{res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7], res[8], res[9], res[10], res[11]}) - // constrain cubicNonResiduePower to be in Fp6 - // that is: a100=a101=a110=a111=a120=a121=0 - // or - // A0 = a000 - a001 - // A1 = 0 - // A2 = a010 - a011 - // A3 = 0 - // A4 = a020 - a021 - // A5 = 0 - // A6 = a001 - // A7 = 0 - // A8 = a011 - // A9 = 0 - // A10 = a021 - // A11 = 0 - scalingFactor := GTEl{ - A0: *pr.curveF.Sub(res[12], res[13]), - A1: *pr.curveF.Zero(), - A2: *pr.curveF.Sub(res[14], res[15]), - A3: *pr.curveF.Zero(), - A4: *pr.curveF.Sub(res[16], res[17]), - A5: *pr.curveF.Zero(), - A6: *res[13], - A7: *pr.curveF.Zero(), - A8: *res[15], - A9: *pr.curveF.Zero(), - A10: *res[17], - A11: *pr.curveF.Zero(), - } - - // Check that x * scalingFactor == residueWitness^(q-u) - // where u=-0xd201000000010000 is the BLS12-381 seed, - // and residueWitness, scalingFactor from the hint. - t0 := pr.Frobenius(residueWitness) - // exponentiation by -u - t1 := pr.ExptNeg(residueWitness) - t0 = pr.Ext12.Mul(t0, t1) - - t1 = pr.Ext12.Mul(x, &scalingFactor) - - pr.AssertIsEqual(t0, t1) -} - // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates. -// Then evaluates the lines going through p1 and p2 or -p2 (line1) and p1 and p1+p2 (line2). +// Then evaluates the lines going through p1 and p2 (line1) and p1 and p1+p2 (line2). // https://eprint.iacr.org/2022/1162 (Section 6.1) func (pr Pairing) doubleAndAddStep(p1, p2 *g2AffP) (*g2AffP, *lineEvaluation, *lineEvaluation) { var line1, line2 lineEvaluation var p g2AffP - mone := pr.curveF.NewElement(-1) // compute λ1 = (y2-y1)/(x2-x1) n := pr.Ext2.Sub(&p1.Y, &p2.Y) @@ -385,42 +461,39 @@ func (pr Pairing) doubleAndAddStep(p1, p2 *g2AffP) (*g2AffP, *lineEvaluation, *l λ1 := pr.Ext2.DivUnchecked(n, d) // compute x3 =λ1²-x1-x2 - x30 := pr.curveF.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p1.X.A0}, {mone, &p2.X.A0}}, []int{1, 1, 1, 1}) - x31 := pr.curveF.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p1.X.A1}, {mone, &p2.X.A1}}, []int{2, 1, 1}) - x3 := &fields_bls12381.E2{A0: *x30, A1: *x31} + x3 := pr.Ext2.Square(λ1) + x3 = pr.Ext2.Sub(x3, pr.Ext2.Add(&p1.X, &p2.X)) // omit y3 computation // compute line1 line1.R0 = *λ1 - line1.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ1.A0, &p1.X.A0}, {mone, &λ1.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line1.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ1.A0, &p1.X.A1}, {&λ1.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line1.R1 = *pr.Ext2.Mul(λ1, &p1.X) + line1.R1 = *pr.Ext2.Sub(&line1.R1, &p1.Y) // compute λ2 = -λ1-2y1/(x3-x1) - n = pr.Ext2.MulByConstElement(&p1.Y, big.NewInt(2)) + n = pr.Ext2.Double(&p1.Y) d = pr.Ext2.Sub(x3, &p1.X) λ2 := pr.Ext2.DivUnchecked(n, d) λ2 = pr.Ext2.Add(λ2, λ1) λ2 = pr.Ext2.Neg(λ2) // compute x4 = λ2²-x1-x3 - x40 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p1.X.A0}, {mone, x30}}, []int{1, 1, 1, 1}) - x41 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p1.X.A1}, {mone, x31}}, []int{2, 1, 1}) - x4 := &fields_bls12381.E2{A0: *x40, A1: *x41} + x4 := pr.Ext2.Square(λ2) + x4 = pr.Ext2.Sub(x4, pr.Ext2.Add(&p1.X, x3)) // compute y4 = λ2(x1 - x4)-y1 y4 := pr.Ext2.Sub(&p1.X, x4) - y40 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &y4.A0}, {mone, &λ2.A1, &y4.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - y41 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &y4.A1}, {&λ2.A1, &y4.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) - y4 = &fields_bls12381.E2{A0: *y40, A1: *y41} + y4 = pr.Ext2.Mul(λ2, y4) + y4 = pr.Ext2.Sub(y4, &p1.Y) p.X = *x4 p.Y = *y4 // compute line2 line2.R0 = *λ2 - line2.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ2.A0, &p1.X.A0}, {mone, &λ2.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line2.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ2.A0, &p1.X.A1}, {&λ2.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line2.R1 = *pr.Ext2.Mul(λ2, &p1.X) + line2.R1 = *pr.Ext2.Sub(&line2.R1, &p1.Y) return &p, &line1, &line2 } @@ -431,31 +504,29 @@ func (pr Pairing) doubleStep(p1 *g2AffP) (*g2AffP, *lineEvaluation) { var p g2AffP var line lineEvaluation - mone := pr.curveF.NewElement(-1) // λ = 3x²/2y n := pr.Ext2.Square(&p1.X) - n = pr.Ext2.MulByConstElement(n, big.NewInt(3)) - d := pr.Ext2.MulByConstElement(&p1.Y, big.NewInt(2)) + three := big.NewInt(3) + n = pr.Ext2.MulByConstElement(n, three) + d := pr.Ext2.Double(&p1.Y) λ := pr.Ext2.DivUnchecked(n, d) // xr = λ²-2x - xr0 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p1.X.A0}}, []int{1, 1, 2}) - xr1 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p1.X.A1}}, []int{2, 2}) - xr := &fields_bls12381.E2{A0: *xr0, A1: *xr1} + xr := pr.Ext2.Square(λ) + xr = pr.Ext2.Sub(xr, pr.Ext2.MulByConstElement(&p1.X, big.NewInt(2))) // yr = λ(x-xr)-y yr := pr.Ext2.Sub(&p1.X, xr) - yr0 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - yr1 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bls12381.E2{A0: *yr0, A1: *yr1} + yr = pr.Ext2.Mul(λ, yr) + yr = pr.Ext2.Sub(yr, &p1.Y) p.X = *xr p.Y = *yr line.R0 = *λ - line.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A0}, {mone, &λ.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A1}, {&λ.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &p, &line @@ -466,7 +537,6 @@ func (pr Pairing) tripleStep(p1 *g2AffP) (*g2AffP, *lineEvaluation, *lineEvaluat var line1, line2 lineEvaluation var res g2AffP - mone := pr.curveF.NewElement(-1) // λ1 = 3x²/2y n := pr.Ext2.Square(&p1.X) @@ -477,13 +547,12 @@ func (pr Pairing) tripleStep(p1 *g2AffP) (*g2AffP, *lineEvaluation, *lineEvaluat // compute line1 line1.R0 = *λ1 - line1.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ1.A0, &p1.X.A0}, {mone, &λ1.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line1.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ1.A0, &p1.X.A1}, {&λ1.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line1.R1 = *pr.Ext2.Mul(λ1, &p1.X) + line1.R1 = *pr.Ext2.Sub(&line1.R1, &p1.Y) // x2 = λ1²-2x - x20 := pr.curveF.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p1.X.A0}}, []int{1, 1, 2}) - x21 := pr.curveF.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p1.X.A1}}, []int{2, 2}) - x2 := &fields_bls12381.E2{A0: *x20, A1: *x21} + x2 := pr.Ext2.Square(λ1) + x2 = pr.Ext2.Sub(x2, pr.Ext2.MulByConstElement(&p1.X, big.NewInt(2))) // omit yr computation, and // compute λ2 = 2y/(x2 − x) − λ1. @@ -493,19 +562,18 @@ func (pr Pairing) tripleStep(p1 *g2AffP) (*g2AffP, *lineEvaluation, *lineEvaluat // compute line2 line2.R0 = *λ2 - line2.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ2.A0, &p1.X.A0}, {mone, &λ2.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line2.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ2.A0, &p1.X.A1}, {&λ2.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line2.R1 = *pr.Ext2.Mul(λ2, &p1.X) + line2.R1 = *pr.Ext2.Sub(&line2.R1, &p1.Y) - // xr = λ²-x1-x2 - xr0 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p1.X.A0}, {mone, x20}}, []int{1, 1, 1, 1}) - xr1 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p1.X.A1}, {mone, x21}}, []int{2, 1, 1}) - xr := &fields_bls12381.E2{A0: *xr0, A1: *xr1} + // xr = λ²-p.x-x2 + λ2λ2 := pr.Ext2.Mul(λ2, λ2) + qxrx := pr.Ext2.Add(x2, &p1.X) + xr := pr.Ext2.Sub(λ2λ2, qxrx) - // yr = λ(x1-xr) - y1 - yr := pr.Ext2.Sub(&p1.X, xr) - yr0 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &yr.A0}, {mone, &λ2.A1, &yr.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - yr1 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &yr.A1}, {&λ2.A1, &yr.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bls12381.E2{A0: *yr0, A1: *yr1} + // yr = λ(p.x-xr) - p.y + pxrx := pr.Ext2.Sub(&p1.X, xr) + λ2pxrx := pr.Ext2.Mul(λ2, pxrx) + yr := pr.Ext2.Sub(λ2pxrx, &p1.Y) res.X = *xr res.Y = *yr @@ -524,10 +592,9 @@ func (pr Pairing) tangentCompute(p1 *g2AffP) *lineEvaluation { λ := pr.Ext2.DivUnchecked(n, d) var line lineEvaluation - mone := pr.curveF.NewElement(-1) line.R0 = *λ - line.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A0}, {mone, &λ.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A1}, {&λ.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &line diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 30cbb14a0d..80490e280a 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -43,8 +43,10 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) - pairing.AssertIsEqual(res, &c.Res) + res1 := pairing.FinalExponentiation(&c.InGt) + pairing.AssertIsEqual(res1, &c.Res) + res2 := pairing.FinalExponentiationUnsafe(&c.InGt) + pairing.AssertIsEqual(res2, &c.Res) return nil } @@ -61,40 +63,6 @@ func TestFinalExponentiationTestSolve(t *testing.T) { assert.NoError(err) } -type FinalExponentiationIsOne struct { - InGt GTEl -} - -func (c *FinalExponentiationIsOne) Define(api frontend.API) error { - pairing, err := NewPairing(api) - if err != nil { - return fmt.Errorf("new pairing: %w", err) - } - pairing.AssertFinalExponentiationIsOne(&c.InGt) - return nil -} - -func TestFinalExponentiationIsOneTestSolve(t *testing.T) { - assert := test.NewAssert(t) - // e(a,2b) * e(-2a,b) == 1 - p1, q1 := randomG1G2Affines() - var p2 bls12381.G1Affine - p2.Double(&p1).Neg(&p2) - var q2 bls12381.G2Affine - q2.Set(&q1) - q1.Double(&q1) - ml, err := bls12381.MillerLoop( - []bls12381.G1Affine{p1, p2}, - []bls12381.G2Affine{q1, q2}, - ) - assert.NoError(err) - witness := FinalExponentiationIsOne{ - InGt: NewGTEl(ml), - } - err = test.IsSolved(&FinalExponentiationIsOne{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} - type PairCircuit struct { InG1 G1Affine InG2 G2Affine @@ -327,3 +295,64 @@ func BenchmarkPairing(b *testing.B) { } }) } + +func BenchmarkFinalExponentiation(b *testing.B) { + // e(a,2b) * e(-2a,b) == 1 + var gt bls12381.GT + gt.SetRandom() + res := bls12381.FinalExponentiation(>) + witness := FinalExponentiationCircuit{ + InGt: NewGTEl(gt), + Res: NewGTEl(res), + } + w, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + b.Fatal(err) + } + var ccs constraint.ConstraintSystem + b.Run("compile scs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ccs, err = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &FinalExponentiationCircuit{}); err != nil { + b.Fatal(err) + } + } + }) + var buf bytes.Buffer + _, err = ccs.WriteTo(&buf) + if err != nil { + b.Fatal(err) + } + b.Logf("scs size: %d (bytes), nb constraints %d, nbInstructions: %d", buf.Len(), ccs.GetNbConstraints(), ccs.GetNbInstructions()) + b.Run("solve scs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := ccs.Solve(w); err != nil { + b.Fatal(err) + } + } + }) + b.Run("compile r1cs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ccs, err = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &FinalExponentiationCircuit{}); err != nil { + b.Fatal(err) + } + } + }) + buf.Reset() + _, err = ccs.WriteTo(&buf) + if err != nil { + b.Fatal(err) + } + b.Logf("r1cs size: %d (bytes), nb constraints %d, nbInstructions: %d", buf.Len(), ccs.GetNbConstraints(), ccs.GetNbInstructions()) + + b.Run("solve r1cs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := ccs.Solve(w); err != nil { + b.Fatal(err) + } + } + }) +} diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 01299f7f03..8edb7953c5 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -11,7 +11,6 @@ import ( type G2 struct { api frontend.API - fp *emulated.Field[BaseField] *fields_bn254.Ext2 w *emulated.Element[BaseField] u, v *fields_bn254.E2 @@ -41,11 +40,6 @@ func newG2AffP(v bn254.G2Affine) g2AffP { } func NewG2(api frontend.API) *G2 { - fp, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - // TODO: we start returning errors when generifying - panic(err) - } w := emulated.ValueOf[BaseField]("21888242871839275220042445260109153167277707414472061641714758635765020556616") u := fields_bn254.E2{ A0: emulated.ValueOf[BaseField]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), @@ -57,7 +51,6 @@ func NewG2(api frontend.API) *G2 { } return &G2{ api: api, - fp: fp, Ext2: fields_bn254.NewExt2(api), w: &w, u: &u, @@ -156,23 +149,20 @@ func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { } func (g2 G2) add(p, q *G2Affine) *G2Affine { - mone := g2.fp.NewElement(-1) - // compute λ = (q.y-p.y)/(q.x-p.x) qypy := g2.Ext2.Sub(&q.P.Y, &p.P.Y) qxpx := g2.Ext2.Sub(&q.P.X, &p.P.X) λ := g2.Ext2.DivUnchecked(qypy, qxpx) // xr = λ²-p.x-q.x - xr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p.P.X.A0}, {mone, &q.P.X.A0}}, []int{1, 1, 1, 1}) - xr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p.P.X.A1}, {mone, &q.P.X.A1}}, []int{2, 1, 1}) - xr := &fields_bn254.E2{A0: *xr0, A1: *xr1} + λλ := g2.Ext2.Square(λ) + qxpx = g2.Ext2.Add(&p.P.X, &q.P.X) + xr := g2.Ext2.Sub(λλ, qxpx) // p.y = λ(p.x-r.x) - p.y - yr := g2.Ext2.Sub(&p.P.X, xr) - yr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) - yr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bn254.E2{A0: *yr0, A1: *yr1} + pxrx := g2.Ext2.Sub(&p.P.X, xr) + λpxrx := g2.Ext2.Mul(λ, pxrx) + yr := g2.Ext2.Sub(λpxrx, &p.P.Y) return &G2Affine{ P: g2AffP{ @@ -199,8 +189,6 @@ func (g2 G2) sub(p, q *G2Affine) *G2Affine { } func (g2 *G2) double(p *G2Affine) *G2Affine { - mone := g2.fp.NewElement(-1) - // compute λ = (3p.x²)/2*p.y xx3a := g2.Square(&p.P.X) xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) @@ -208,15 +196,14 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { λ := g2.DivUnchecked(xx3a, y2) // xr = λ²-2p.x - xr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p.P.X.A0}}, []int{1, 1, 2}) - xr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p.P.X.A1}}, []int{2, 2}) - xr := &fields_bn254.E2{A0: *xr0, A1: *xr1} + x2 := g2.Double(&p.P.X) + λλ := g2.Square(λ) + xr := g2.Sub(λλ, x2) // yr = λ(p-xr) - p.y - yr := g2.Ext2.Sub(&p.P.X, xr) - yr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) - yr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bn254.E2{A0: *yr0, A1: *yr1} + pxrx := g2.Sub(&p.P.X, xr) + λpxrx := g2.Mul(λ, pxrx) + yr := g2.Sub(λpxrx, &p.P.Y) return &G2Affine{ P: g2AffP{ @@ -235,7 +222,6 @@ func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine { } func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { - mone := g2.fp.NewElement(-1) // compute λ1 = (q.y-p.y)/(q.x-p.x) yqyp := g2.Ext2.Sub(&q.P.Y, &p.P.Y) @@ -243,27 +229,27 @@ func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp) // compute x2 = λ1²-p.x-q.x - x20 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p.P.X.A0}, {mone, &q.P.X.A0}}, []int{1, 1, 1, 1}) - x21 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p.P.X.A1}, {mone, &q.P.X.A1}}, []int{2, 1, 1}) - x2 := &fields_bn254.E2{A0: *x20, A1: *x21} + λ1λ1 := g2.Ext2.Square(λ1) + xqxp = g2.Ext2.Add(&p.P.X, &q.P.X) + x2 := g2.Ext2.Sub(λ1λ1, xqxp) // omit y2 computation - // compute -λ2 = λ1+2*p.y/(x2-p.x) + // compute λ2 = -λ1-2*p.y/(x2-p.x) ypyp := g2.Ext2.Add(&p.P.Y, &p.P.Y) x2xp := g2.Ext2.Sub(x2, &p.P.X) λ2 := g2.Ext2.DivUnchecked(ypyp, x2xp) λ2 = g2.Ext2.Add(λ1, λ2) + λ2 = g2.Ext2.Neg(λ2) - // compute x3 = (-λ2)²-p.x-x2 - x30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p.P.X.A0}, {mone, x20}}, []int{1, 1, 1, 1}) - x31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p.P.X.A1}, {mone, x21}}, []int{2, 1, 1}) - x3 := &fields_bn254.E2{A0: *x30, A1: *x31} + // compute x3 =λ2²-p.x-x3 + λ2λ2 := g2.Ext2.Square(λ2) + x3 := g2.Ext2.Sub(λ2λ2, &p.P.X) + x3 = g2.Ext2.Sub(x3, x2) - // compute y3 = -λ2*(x3 - p.x)-p.y - y3 := g2.Ext2.Sub(x3, &p.P.X) - y30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A0}, {mone, &λ2.A1, &y3.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) - y31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A1}, {&λ2.A1, &y3.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) - y3 = &fields_bn254.E2{A0: *y30, A1: *y31} + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g2.Ext2.Sub(&p.P.X, x3) + y3 = g2.Ext2.Mul(λ2, y3) + y3 = g2.Ext2.Sub(y3, &p.P.Y) return &G2Affine{ P: g2AffP{ diff --git a/std/algebra/emulated/sw_bn254/hints.go b/std/algebra/emulated/sw_bn254/hints.go index c73329d823..3c4d5642fe 100644 --- a/std/algebra/emulated/sw_bn254/hints.go +++ b/std/algebra/emulated/sw_bn254/hints.go @@ -17,7 +17,6 @@ func init() { func GetHints() []solver.Hint { return []solver.Hint{ millerLoopAndCheckFinalExpHint, - finalExpHint, } } @@ -162,126 +161,3 @@ func millerLoopAndCheckFinalExpHint(nativeMod *big.Int, nativeInputs, nativeOutp return nil }) } - -func finalExpHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - // This follows section 4.3.2 of https://eprint.iacr.org/2024/640.pdf - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var tmp, x3, cubicNonResiduePower, x, millerLoop, residueWitness, residueWitnessInv, one, root27thOf1 bn254.E12 - var exp1, exp2, rInv, mInv big.Int - - millerLoop.C0.B0.A0.SetBigInt(inputs[0]) - millerLoop.C0.B0.A1.SetBigInt(inputs[1]) - millerLoop.C0.B1.A0.SetBigInt(inputs[2]) - millerLoop.C0.B1.A1.SetBigInt(inputs[3]) - millerLoop.C0.B2.A0.SetBigInt(inputs[4]) - millerLoop.C0.B2.A1.SetBigInt(inputs[5]) - millerLoop.C1.B0.A0.SetBigInt(inputs[6]) - millerLoop.C1.B0.A1.SetBigInt(inputs[7]) - millerLoop.C1.B1.A0.SetBigInt(inputs[8]) - millerLoop.C1.B1.A1.SetBigInt(inputs[9]) - millerLoop.C1.B2.A0.SetBigInt(inputs[10]) - millerLoop.C1.B2.A1.SetBigInt(inputs[11]) - - // exp1 = (p^12-1)/3 - exp1.SetString("4030969696062745741797811005853058291874379204406359442560681893891674450106959530046539719647151210908190211459382793062006703141168852426020468083171325367934590379984666859998399967609544754664110191464072930598755441160008826659219834762354786403012110463250131961575955268597858015384895449311534622125256548620283853223733396368939858981844663598065852816056384933498610930035891058807598891752166582271931875150099691598048016175399382213304673796601585080509443902692818733420199004555566113537482054218823936116647313678747500267068559627206777530424029211671772692598157901876223857571299238046741502089890557442500582300718504160740314926185458079985126192563953772118929726791041828902047546977272656240744693339962973939047279285351052107950250121751682659529260304162131862468322644288196213423232132152125277136333208005221619443705106431645884840489295409272576227859206166894626854018093044908314720", 10) - // root27thOf1 = (0, c010, c011, 0, 0, 0, 0, 0, 0, 0, 0, 0) - // is a 27-th root of unity which is necessarily a cubic non-residue - // since h/r = (p^12-1)/r = 27·l and 3 does not divide l. - // it was computed as w^((p^12-1)/27) = c2 * w^2 + c8 * w^8 where - // Fp12 = Fp[w]/w^12-18w^6+82 which is isomorphic to our Fp12 tower - // then c010 = (c2 + 9 * c8) % p and c011 = c8 - root27thOf1.C0.B1.A0.SetString("9483667112135124394372960210728142145589475128897916459350428495526310884707") - root27thOf1.C0.B1.A1.SetString("4534159768373982659291990808346042891252278737770656686799127720849666919525") - - if one.Exp(millerLoop, &exp1).IsOne() { - // residueWitness = millerLoop is a cubic residue - cubicNonResiduePower.SetOne() - residueWitness.Set(&millerLoop) - } else if one.Exp(*millerLoop.Mul(&millerLoop, &root27thOf1), &exp1).IsOne() { - // residueWitness = millerLoop * root27thOf1 is a cubic residue - cubicNonResiduePower.Set(&root27thOf1) - residueWitness.Set(&millerLoop) - } else { - // residueWitness = millerLoop * root27thOf1^2 is a cubic residue - cubicNonResiduePower.Square(&root27thOf1) - residueWitness.Mul(&millerLoop, &root27thOf1) - } - - // 1. compute r-th root: - // Exponentiate to rInv where - // rInv = 1/r mod (p^12-1)/r - rInv.SetString("495819184011867778744231927046742333492451180917315223017345540833046880485481720031136878341141903241966521818658471092566752321606779256340158678675679238405722886654128392203338228575623261160538734808887996935946888297414610216445334190959815200956855428635568184508263913274453942864817234480763055154719338281461936129150171789463489422401982681230261920147923652438266934726901346095892093443898852488218812468761027620988447655860644584419583586883569984588067403598284748297179498734419889699245081714359110559679136004228878808158639412436468707589339209058958785568729925402190575720856279605832146553573981587948304340677613460685405477047119496887534881410757668344088436651291444274840864486870663164657544390995506448087189408281061890434467956047582679858345583941396130713046072603335601764495918026585155498301896749919393", 10) - residueWitness.Exp(residueWitness, &rInv) - - // 2. compute m-th root: - // where m = (6x + 2 + q^3 - q^2 + q)/(3r) - // Exponentiate to mInv where - // mInv = 1/m mod p^12-1 - mInv.SetString("17840267520054779749190587238017784600702972825655245554504342129614427201836516118803396948809179149954197175783449826546445899524065131269177708416982407215963288737761615699967145070776364294542559324079147363363059480104341231360692143673915822421222230661528586799190306058519400019024762424366780736540525310403098758015600523609594113357130678138304964034267260758692953579514899054295817541844330584721967571697039986079722203518034173581264955381924826388858518077894154909963532054519350571947910625755075099598588672669612434444513251495355121627496067454526862754597351094345783576387352673894873931328099247263766690688395096280633426669535619271711975898132416216382905928886703963310231865346128293216316379527200971959980873989485521004596686352787540034457467115536116148612884807380187255514888720048664139404687086409399", 10) - residueWitness.Exp(residueWitness, &mInv) - - // 3. compute cube root: - // since gcd(3, (p^12-1)/r) ≠ 1 we use a modified Toneelli-Shanks algorithm - // see Alg.4 of https://eprint.iacr.org/2024/640.pdf - // Typo in the paper: p^k-1 = 3^n * s instead of p-1 = 3^r * s - // where k=12 and n=3 here and exp2 = (s+1)/3 - residueWitnessInv.Inverse(&residueWitness) - exp2.SetString("149295173928249842288807815031594751550902933496531831205951181255247201855813315927649619246190785589192230054051214557852100116339587126889646966043382421034614458517950624444385183985538694617189266350521219651805757080000326913304438324531658755667115202342597480058368713651772519088329461085612393412046538837788290860138273939590365147475728281409846400594680923462911515927255224400281440435265428973034513894448136725853630228718495637529802733207466114092942366766400693830377740909465411612499335341437923559875826432546203713595131838044695464089778859691547136762894737106526809539677749557286722299625576201574095640767352005953344997266128077036486155280146436004404804695964512181557316554713802082990544197776406442186936269827816744738898152657469728130713344598597476387715653492155415311971560450078713968012341037230430349766855793764662401499603533676762082513303932107208402000670112774382027", 10) - x.Exp(residueWitness, &exp2) - - // 3^t is ord(x^3 / residueWitness) - x3.Square(&x).Mul(&x3, &x).Mul(&x3, &residueWitnessInv) - t := 0 - for !x3.IsOne() { - t++ - tmp.Square(&x3) - x3.Mul(&tmp, &x3) - } - - for t != 0 { - x.Mul(&x, tmp.Exp(root27thOf1, &exp2)) - - // 3^t is ord(x^3 / residueWitness) - x3.Square(&x).Mul(&x3, &x).Mul(&x3, &residueWitnessInv) - t = 0 - for !x3.IsOne() { - t++ - tmp.Square(&x3) - x3.Mul(&tmp, &x3) - } - } - - // x is now the cube root of residueWitness - residueWitness.Set(&x) - - residueWitness.C0.B0.A0.BigInt(outputs[0]) - residueWitness.C0.B0.A1.BigInt(outputs[1]) - residueWitness.C0.B1.A0.BigInt(outputs[2]) - residueWitness.C0.B1.A1.BigInt(outputs[3]) - residueWitness.C0.B2.A0.BigInt(outputs[4]) - residueWitness.C0.B2.A1.BigInt(outputs[5]) - residueWitness.C1.B0.A0.BigInt(outputs[6]) - residueWitness.C1.B0.A1.BigInt(outputs[7]) - residueWitness.C1.B1.A0.BigInt(outputs[8]) - residueWitness.C1.B1.A1.BigInt(outputs[9]) - residueWitness.C1.B2.A0.BigInt(outputs[10]) - residueWitness.C1.B2.A1.BigInt(outputs[11]) - - // we also need to return the cubic non-residue power - cubicNonResiduePower.C0.B0.A0.BigInt(outputs[12]) - cubicNonResiduePower.C0.B0.A1.BigInt(outputs[13]) - cubicNonResiduePower.C0.B1.A0.BigInt(outputs[14]) - cubicNonResiduePower.C0.B1.A1.BigInt(outputs[15]) - cubicNonResiduePower.C0.B2.A0.BigInt(outputs[16]) - cubicNonResiduePower.C0.B2.A1.BigInt(outputs[17]) - cubicNonResiduePower.C1.B0.A0.BigInt(outputs[18]) - cubicNonResiduePower.C1.B0.A1.BigInt(outputs[19]) - cubicNonResiduePower.C1.B1.A0.BigInt(outputs[20]) - cubicNonResiduePower.C1.B1.A1.BigInt(outputs[21]) - cubicNonResiduePower.C1.B2.A0.BigInt(outputs[22]) - cubicNonResiduePower.C1.B2.A1.BigInt(outputs[23]) - - return nil - }) -} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index ffa4fb646e..ba1cddf204 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -6,54 +6,54 @@ import ( "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" - fp_bn "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) -type baseEl = emulated.Element[BaseField] -type GTEl = fields_bn254.E12 - type Pairing struct { api frontend.API *fields_bn254.Ext12 - *fields_bn254.Ext2 curveF *emulated.Field[BaseField] curve *sw_emulated.Curve[BaseField, ScalarField] g2 *G2 bTwist *fields_bn254.E2 + g2gen *G2Affine } -func NewGTEl(a bn254.GT) GTEl { - var c0, c1, c2, c3, c4, c5, t fp_bn.Element - t.SetUint64(9).Mul(&t, &a.C0.B0.A1) - c0.Sub(&a.C0.B0.A0, &t) - t.SetUint64(9).Mul(&t, &a.C1.B0.A1) - c1.Sub(&a.C1.B0.A0, &t) - t.SetUint64(9).Mul(&t, &a.C0.B1.A1) - c2.Sub(&a.C0.B1.A0, &t) - t.SetUint64(9).Mul(&t, &a.C1.B1.A1) - c3.Sub(&a.C1.B1.A0, &t) - t.SetUint64(9).Mul(&t, &a.C0.B2.A1) - c4.Sub(&a.C0.B2.A0, &t) - t.SetUint64(9).Mul(&t, &a.C1.B2.A1) - c5.Sub(&a.C1.B2.A0, &t) +type GTEl = fields_bn254.E12 +func NewGTEl(v bn254.GT) GTEl { return GTEl{ - A0: emulated.ValueOf[emulated.BN254Fp](c0), - A1: emulated.ValueOf[emulated.BN254Fp](c1), - A2: emulated.ValueOf[emulated.BN254Fp](c2), - A3: emulated.ValueOf[emulated.BN254Fp](c3), - A4: emulated.ValueOf[emulated.BN254Fp](c4), - A5: emulated.ValueOf[emulated.BN254Fp](c5), - A6: emulated.ValueOf[emulated.BN254Fp](a.C0.B0.A1), - A7: emulated.ValueOf[emulated.BN254Fp](a.C1.B0.A1), - A8: emulated.ValueOf[emulated.BN254Fp](a.C0.B1.A1), - A9: emulated.ValueOf[emulated.BN254Fp](a.C1.B1.A1), - A10: emulated.ValueOf[emulated.BN254Fp](a.C0.B2.A1), - A11: emulated.ValueOf[emulated.BN254Fp](a.C1.B2.A1), + C0: fields_bn254.E6{ + B0: fields_bn254.E2{ + A0: emulated.ValueOf[BaseField](v.C0.B0.A0), + A1: emulated.ValueOf[BaseField](v.C0.B0.A1), + }, + B1: fields_bn254.E2{ + A0: emulated.ValueOf[BaseField](v.C0.B1.A0), + A1: emulated.ValueOf[BaseField](v.C0.B1.A1), + }, + B2: fields_bn254.E2{ + A0: emulated.ValueOf[BaseField](v.C0.B2.A0), + A1: emulated.ValueOf[BaseField](v.C0.B2.A1), + }, + }, + C1: fields_bn254.E6{ + B0: fields_bn254.E2{ + A0: emulated.ValueOf[BaseField](v.C1.B0.A0), + A1: emulated.ValueOf[BaseField](v.C1.B0.A1), + }, + B1: fields_bn254.E2{ + A0: emulated.ValueOf[BaseField](v.C1.B1.A0), + A1: emulated.ValueOf[BaseField](v.C1.B1.A1), + }, + B2: fields_bn254.E2{ + A0: emulated.ValueOf[BaseField](v.C1.B2.A0), + A1: emulated.ValueOf[BaseField](v.C1.B2.A1), + }, + }, } } @@ -73,7 +73,6 @@ func NewPairing(api frontend.API) (*Pairing, error) { return &Pairing{ api: api, Ext12: fields_bn254.NewExt12(api), - Ext2: fields_bn254.NewExt2(api), curveF: ba, curve: curve, g2: NewG2(api), @@ -81,129 +80,161 @@ func NewPairing(api frontend.API) (*Pairing, error) { }, nil } -// Pair calculates the reduced pairing for a set of points -// ∏ᵢ e(Pᵢ, Qᵢ). -// -// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2. -func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(P, Q) - if err != nil { - return nil, fmt.Errorf("miller loop: %w", err) +func (pr Pairing) generators() *G2Affine { + if pr.g2gen == nil { + _, _, _, g2gen := bn254.Generators() + cg2gen := NewG2AffineFixed(g2gen) + pr.g2gen = &cg2gen } - res = pr.FinalExponentiation(res) - return res, nil + return pr.g2gen } -// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ -// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// where s is the cofactor 2x₀(6x₀²+3x₀+1) +// FinalExponentiation computes the exponentiation eᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r. +// +// We use instead d'= s ⋅ d, where s is the cofactor +// +// 2x₀(6x₀²+3x₀+1) +// +// and r does NOT divide d' +// +// FinalExponentiation returns a decompressed element in E12. +// +// This is the safe version of the method where e may be {-1,1}. If it is known +// that e ≠ {-1,1} then using the unsafe version of the method saves +// considerable amount of constraints. When called with the result of +// [MillerLoop], then current method is applicable when length of the inputs to +// Miller loop is 1. func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - // Easy part + return pr.finalExponentiation(e, false) +} + +// FinalExponentiationUnsafe computes the exponentiation eᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r. +// +// We use instead d'= s ⋅ d, where s is the cofactor +// +// 2x₀(6x₀²+3x₀+1) +// +// and r does NOT divide d' +// +// FinalExponentiationUnsafe returns a decompressed element in E12. +// +// This is the unsafe version of the method where e may NOT be {-1,1}. If e ∈ +// {-1, 1}, then there exists no valid solution to the circuit. This method is +// applicable when called with the result of [MillerLoop] method when the length +// of the inputs to Miller loop is 1. +func (pr Pairing) FinalExponentiationUnsafe(e *GTEl) *GTEl { + return pr.finalExponentiation(e, true) +} + +// finalExponentiation computes the exponentiation eᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r. +// +// We use instead d'= s ⋅ d, where s is the cofactor +// +// 2x₀(6x₀²+3x₀+1) +// +// and r does NOT divide d' +// +// finalExponentiation returns a decompressed element in E12 +func (pr Pairing) finalExponentiation(e *GTEl, unsafe bool) *GTEl { + + // 1. Easy part // (p⁶-1)(p²+1) - t0 := pr.Ext12.Conjugate(e) - e = pr.Ext12.Inverse(e) - t0 = pr.Ext12.Mul(t0, e) - e = pr.Ext12.FrobeniusSquare(t0) - e = pr.Ext12.Mul(e, t0) + var selector1, selector2 frontend.Variable + _dummy := pr.Ext6.One() + + if unsafe { + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are + // linearly dependent and not from G1 and G2 respectively. + // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0. + // Nothing to do. - // Hard part (up to permutation) + } else { + // However, for a product of Miller loops (n>=2) this might happen. If this is + // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 + // and proceed further. + selector1 = pr.Ext6.IsZero(&e.C1) + e.C1.B0.A0 = *pr.curveF.Select(selector1, pr.curveF.One(), &e.C1.B0.A0) + } + + // Torus compression absorbed: + // Raising e to (p⁶-1) is + // e^(p⁶) / e = (e.C0 - w*e.C1) / (e.C0 + w*e.C1) + // = (-e.C0/e.C1 + w) / (-e.C0/e.C1 - w) + // So the fraction -e.C0/e.C1 is already in the torus. + // This absorbs the torus compression in the easy part. + c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) + c = pr.Ext6.Neg(c) + t0 := pr.FrobeniusSquareTorus(c) + c = pr.MulTorus(t0, c) + + // 2. Hard part (up to permutation) // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r // Duquesne and Ghammam // https://eprint.iacr.org/2015/192.pdf // Fuentes et al. (alg. 6) - t0 = pr.Ext12.Expt(e) - t0 = pr.Ext12.Conjugate(t0) - t0 = pr.Ext12.CyclotomicSquareGS(t0) - t1 := pr.Ext12.CyclotomicSquareGS(t0) - t1 = pr.Ext12.Mul(t0, t1) - t2 := pr.Ext12.Expt(t1) - t2 = pr.Ext12.Conjugate(t2) - t3 := pr.Ext12.Conjugate(t1) - t1 = pr.Ext12.Mul(t2, t3) - t3 = pr.Ext12.CyclotomicSquareGS(t2) - t4 := pr.Ext12.Expt(t3) - t4 = pr.Ext12.Mul(t1, t4) - t3 = pr.Ext12.Mul(t0, t4) - t0 = pr.Ext12.Mul(t2, t4) - t0 = pr.Ext12.Mul(e, t0) - t2 = pr.Ext12.Frobenius(t3) - t0 = pr.Ext12.Mul(t2, t0) - t2 = pr.Ext12.FrobeniusSquare(t4) - t0 = pr.Ext12.Mul(t2, t0) - t2 = pr.Ext12.Conjugate(e) - t2 = pr.Ext12.Mul(t2, t3) - t2 = pr.Ext12.FrobeniusCube(t2) - t0 = pr.Ext12.Mul(t2, t0) - - return t0 -} - -// AssertFinalExponentiationIsOne checks that a Miller function output x lies in the -// same equivalence class as the reduced pairing. This replaces the final -// exponentiation step in-circuit. -// The method follows Section 4 of [On Proving Pairings] paper by A. Novakovic and L. Eagen. -// -// [On Proving Pairings]: https://eprint.iacr.org/2024/640.pdf -func (pr Pairing) AssertFinalExponentiationIsOne(a *GTEl) { - tower := pr.Ext12.ToTower(a) + // performed in torus compressed form + t0 = pr.ExptTorus(c) + t0 = pr.InverseTorus(t0) + t0 = pr.SquareTorus(t0) + t1 := pr.SquareTorus(t0) + t1 = pr.MulTorus(t0, t1) + t2 := pr.ExptTorus(t1) + t2 = pr.InverseTorus(t2) + t3 := pr.InverseTorus(t1) + t1 = pr.MulTorus(t2, t3) + t3 = pr.SquareTorus(t2) + t4 := pr.ExptTorus(t3) + t4 = pr.MulTorus(t1, t4) + t3 = pr.MulTorus(t0, t4) + t0 = pr.MulTorus(t2, t4) + t0 = pr.MulTorus(c, t0) + t2 = pr.FrobeniusTorus(t3) + t0 = pr.MulTorus(t2, t0) + t2 = pr.FrobeniusSquareTorus(t4) + t0 = pr.MulTorus(t2, t0) + t2 = pr.InverseTorus(c) + t2 = pr.MulTorus(t2, t3) + t2 = pr.FrobeniusCubeTorus(t2) + + var result GTEl + // MulTorus(t0, t2) requires t0 ≠ -t2. When t0 = -t2, it means the + // product is 1 in the torus. + if unsafe { + // For a single pairing, this does not happen because the pairing is non-degenerate. + result = *pr.DecompressTorus(pr.MulTorus(t2, t0)) + } else { + // For a product of pairings this might happen when the result is expected to be 1. + // We assign a dummy value (1) to t0 and proceed further. + // Finally we do a select on both edge cases: + // - Only if seletor1=0 and selector2=0, we return MulTorus(t2, t0) decompressed. + // - Otherwise, we return 1. + _sum := pr.Ext6.Add(t0, t2) + selector2 = pr.Ext6.IsZero(_sum) + t0 = pr.Ext6.Select(selector2, _dummy, t0) + selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) + result = *pr.Select(selector, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One()) + } + + return &result +} - res, err := pr.curveF.NewHint(finalExpHint, 24, tower[0], tower[1], tower[2], tower[3], tower[4], tower[5], tower[6], tower[7], tower[8], tower[9], tower[10], tower[11]) +// Pair calculates the reduced pairing for a set of points +// ∏ᵢ e(Pᵢ, Qᵢ). +// +// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2. +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { + res, err := pr.MillerLoop(P, Q) if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) + return nil, fmt.Errorf("miller loop: %w", err) } - - nine := big.NewInt(9) - residueWitness := pr.Ext12.FromTower([12]*baseEl{res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7], res[8], res[9], res[10], res[11]}) - - // constrain cubicNonResiduePower to be in Fp6 - // that is: a100=a101=a110=a111=a120=a121=0 - // or - // A0 = a000 - 9 * a001 - // A1 = 0 - // A2 = a010 - 9 * a011 - // A3 = 0 - // A4 = a020 - 9 * a021 - // A5 = 0 - // A6 = a001 - // A7 = 0 - // A8 = a011 - // A9 = 0 - // A10 = a021 - // A11 = 0 - cubicNonResiduePower := GTEl{ - A0: *pr.curveF.Sub(res[12], pr.curveF.MulConst(res[13], nine)), - A1: *pr.curveF.Zero(), - A2: *pr.curveF.Sub(res[14], pr.curveF.MulConst(res[15], nine)), - A3: *pr.curveF.Zero(), - A4: *pr.curveF.Sub(res[16], pr.curveF.MulConst(res[17], nine)), - A5: *pr.curveF.Zero(), - A6: *res[13], - A7: *pr.curveF.Zero(), - A8: *res[15], - A9: *pr.curveF.Zero(), - A10: *res[17], - A11: *pr.curveF.Zero(), - } - - // Check that x * cubicNonResiduePower == residueWitness^λ - // where λ = 6u + 2 + q^3 - q^2 + q, with u the BN254 seed - // and residueWitness, cubicNonResiduePower from the hint. - t2 := pr.Ext12.Mul(&cubicNonResiduePower, a) - - t1 := pr.Ext12.FrobeniusCube(residueWitness) - t0 := pr.Ext12.FrobeniusSquare(residueWitness) - t1 = pr.Ext12.DivUnchecked(t1, t0) - t0 = pr.Ext12.Frobenius(residueWitness) - t1 = pr.Ext12.Mul(t1, t0) - - // exponentiation by U=6u+2 - t0 = pr.Ext12.ExpByU(residueWitness) - - t0 = pr.Ext12.Mul(t0, t1) - - pr.AssertIsEqual(t0, t2) + res = pr.finalExponentiation(res, len(P) == 1) + return res, nil } // PairingCheck calculates the reduced pairing for a set of points and asserts if the result is One @@ -216,6 +247,15 @@ func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error { return err } + // We perform the easy part of the final exp to push f to the cyclotomic + // subgroup so that AssertFinalExponentiationIsOne is carried with optimized + // cyclotomic squaring (e.g. Karabina12345). + // + // f = f^(p⁶-1)(p²+1) + buf := pr.Conjugate(f) + buf = pr.DivUnchecked(buf, f) + f = pr.FrobeniusSquare(buf) + f = pr.Mul(f, buf) pr.AssertFinalExponentiationIsOne(f) @@ -357,7 +397,8 @@ func (pr Pairing) computeTwistEquation(Q *G2Affine) (left, right *fields_bn254.E b := pr.Ext2.Select(selector, pr.Ext2.Zero(), pr.bTwist) left = pr.Ext2.Square(&Q.P.Y) - right = pr.Ext2.Cube(&Q.P.X) + right = pr.Ext2.Square(&Q.P.X) + right = pr.Ext2.Mul(right, &Q.P.X) right = pr.Ext2.Add(right, b) return left, right } @@ -463,8 +504,8 @@ func (pr Pairing) millerLoopLines(P []*G1Affine, lines []lineEvaluations) (*GTEl } // precomputations - yInv := make([]*baseEl, n) - xNegOverY := make([]*baseEl, n) + yInv := make([]*emulated.Element[BaseField], n) + xNegOverY := make([]*emulated.Element[BaseField], n) for k := 0; k < n; k++ { // P are supposed to be on G1 respectively of prime order r. @@ -475,89 +516,114 @@ func (pr Pairing) millerLoopLines(P []*G1Affine, lines []lineEvaluations) (*GTEl xNegOverY[k] = pr.curveF.Neg(xNegOverY[k]) } - var prodLines [10]*baseEl + var prodLines [5]*fields_bn254.E2 + res := pr.Ext12.One() // Compute f_{6x₀+2,Q}(P) - // i = 64 - // - // k = 0 - c3 := pr.Ext2.MulByElement(&lines[0][0][64].R0, xNegOverY[0]) - c4 := pr.Ext2.MulByElement(&lines[0][0][64].R1, yInv[0]) - nine := big.NewInt(9) - res := >El{ - A0: *pr.curveF.One(), - A1: *pr.curveF.Sub(&c3.A0, pr.curveF.MulConst(&c3.A1, nine)), - A2: *pr.curveF.Zero(), - A3: *pr.curveF.Sub(&c4.A0, pr.curveF.MulConst(&c4.A1, nine)), - A4: *pr.curveF.Zero(), - A5: *pr.curveF.Zero(), - A6: *pr.curveF.Zero(), - A7: c3.A1, - A8: *pr.curveF.Zero(), - A9: c4.A1, - A10: *pr.curveF.Zero(), - A11: *pr.curveF.Zero(), + // i = 64, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + // line evaluation at P[0] + res = &fields_bn254.E12{ + C0: res.C0, + C1: fields_bn254.E6{ + B0: *pr.MulByElement(&lines[0][0][64].R0, xNegOverY[0]), + B1: *pr.MulByElement(&lines[0][0][64].R1, yInv[0]), + B2: res.C1.B2, + }, } if n >= 2 { - // k = 1, separately to avoid MulBy01379 (res × ℓ) - // (res is also a line at this point, so we use Mul01379By01379 ℓ × ℓ) + // k = 1, separately to avoid MulBy034 (res × ℓ) + // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) // line evaluation at P[1] - prodLines = pr.Mul01379By01379( - pr.Ext2.MulByElement(&lines[1][0][64].R0, xNegOverY[1]), - pr.Ext2.MulByElement(&lines[1][0][64].R1, yInv[1]), - c3, - c4, + // ℓ × res + prodLines = pr.Mul034By034( + pr.MulByElement(&lines[1][0][64].R0, xNegOverY[1]), + pr.MulByElement(&lines[1][0][64].R1, yInv[1]), + &res.C1.B0, + &res.C1.B1, ) - res = >El{ - A0: *prodLines[0], - A1: *prodLines[1], - A2: *prodLines[2], - A3: *prodLines[3], - A4: *prodLines[4], - A5: *pr.curveF.Zero(), - A6: *prodLines[5], - A7: *prodLines[6], - A8: *prodLines[7], - A9: *prodLines[8], - A10: *prodLines[9], - A11: *pr.curveF.Zero(), + res = &fields_bn254.E12{ + C0: fields_bn254.E6{ + B0: *prodLines[0], + B1: *prodLines[1], + B2: *prodLines[2], + }, + C1: fields_bn254.E6{ + B0: *prodLines[3], + B1: *prodLines[4], + B2: res.C1.B2, + }, } } if n >= 3 { - // k >= 2 - for k := 2; k < n; k++ { + // k = 2, separately to avoid MulBy034 (res × ℓ) + // (res has a zero E2 element, so we use Mul01234By034) + // line evaluation at P[1] + // ℓ × res + res = pr.Mul01234By034( + prodLines, + pr.MulByElement(&lines[2][0][64].R0, xNegOverY[2]), + pr.MulByElement(&lines[2][0][64].R1, yInv[2]), + ) + + // k >= 3 + for k := 3; k < n; k++ { // line evaluation at P[k] // ℓ × res - res = pr.MulBy01379( + res = pr.MulBy034( res, - pr.Ext2.MulByElement(&lines[k][0][64].R0, xNegOverY[k]), - pr.Ext2.MulByElement(&lines[k][0][64].R1, yInv[k]), + pr.MulByElement(&lines[k][0][64].R0, xNegOverY[k]), + pr.MulByElement(&lines[k][0][64].R1, yInv[k]), ) } } for i := 63; i >= 0; i-- { - res = pr.Ext12.Square(res) - - for k := 0; k < n; k++ { - if loopCounter[i] == 0 { - res = pr.MulBy01379( + res = pr.Square(res) + + if loopCounter[i] == 0 { + // if number of lines is odd, mul last line by res + // works for n=1 as well + if n%2 != 0 { + // ℓ × res + res = pr.MulBy034( res, - pr.Ext2.MulByElement(&lines[k][0][i].R0, xNegOverY[k]), - pr.Ext2.MulByElement(&lines[k][0][i].R1, yInv[k]), + pr.MulByElement(&lines[n-1][0][i].R0, xNegOverY[n-1]), + pr.MulByElement(&lines[n-1][0][i].R1, yInv[n-1]), ) - } else { + } + + // mul lines 2-by-2 + for k := 1; k < n; k += 2 { // ℓ × ℓ - prodLines = pr.Mul01379By01379( - pr.Ext2.MulByElement(&lines[k][0][i].R0, xNegOverY[k]), - pr.Ext2.MulByElement(&lines[k][0][i].R1, yInv[k]), - pr.Ext2.MulByElement(&lines[k][1][i].R0, xNegOverY[k]), - pr.Ext2.MulByElement(&lines[k][1][i].R1, yInv[k]), + prodLines = pr.Mul034By034( + pr.MulByElement(&lines[k][0][i].R0, xNegOverY[k]), + pr.MulByElement(&lines[k][0][i].R1, yInv[k]), + pr.MulByElement(&lines[k-1][0][i].R0, xNegOverY[k-1]), + pr.MulByElement(&lines[k-1][0][i].R1, yInv[k-1]), + ) + // (ℓ × ℓ) × res + res = pr.MulBy01234(res, prodLines) + } + + } else { + for k := 0; k < n; k++ { + // lines evaluations at P + // and ℓ × ℓ + prodLines := pr.Mul034By034( + pr.MulByElement(&lines[k][0][i].R0, xNegOverY[k]), + pr.MulByElement(&lines[k][0][i].R1, yInv[k]), + pr.MulByElement(&lines[k][1][i].R0, xNegOverY[k]), + pr.MulByElement(&lines[k][1][i].R1, yInv[k]), ) // (ℓ × ℓ) × res - res = pr.Ext12.MulBy012346789(res, prodLines) + res = pr.MulBy01234(res, prodLines) + } } } @@ -566,13 +632,14 @@ func (pr Pairing) millerLoopLines(P []*G1Affine, lines []lineEvaluations) (*GTEl // lines evaluations at P // and ℓ × ℓ for k := 0; k < n; k++ { - prodLines = pr.Mul01379By01379( - pr.Ext2.MulByElement(&lines[k][0][65].R0, xNegOverY[k]), - pr.Ext2.MulByElement(&lines[k][0][65].R1, yInv[k]), - pr.Ext2.MulByElement(&lines[k][1][65].R0, xNegOverY[k]), - pr.Ext2.MulByElement(&lines[k][1][65].R1, yInv[k]), + prodLines := pr.Mul034By034( + pr.MulByElement(&lines[k][0][65].R0, xNegOverY[k]), + pr.MulByElement(&lines[k][0][65].R1, yInv[k]), + pr.MulByElement(&lines[k][1][65].R0, xNegOverY[k]), + pr.MulByElement(&lines[k][1][65].R1, yInv[k]), ) - res = pr.Ext12.MulBy012346789(res, prodLines) + // (ℓ × ℓ) × res + res = pr.MulBy01234(res, prodLines) } return res, nil @@ -585,7 +652,6 @@ func (pr Pairing) doubleAndAddStep(p1, p2 *g2AffP, isSub bool) (*g2AffP, *lineEv var line1, line2 lineEvaluation var p g2AffP - mone := pr.curveF.NewElement(-1) // compute λ1 = (y1-y2)/(x1-x2) or λ1 = (y1+y2)/(x1-x2) if isSub is true var n *fields_bn254.E2 @@ -598,16 +664,15 @@ func (pr Pairing) doubleAndAddStep(p1, p2 *g2AffP, isSub bool) (*g2AffP, *lineEv λ1 := pr.Ext2.DivUnchecked(n, d) // compute x3 =λ1²-x1-x2 - x30 := pr.curveF.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p1.X.A0}, {mone, &p2.X.A0}}, []int{1, 1, 1, 1}) - x31 := pr.curveF.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p1.X.A1}, {mone, &p2.X.A1}}, []int{2, 1, 1}) - x3 := &fields_bn254.E2{A0: *x30, A1: *x31} + x3 := pr.Ext2.Square(λ1) + x3 = pr.Ext2.Sub(x3, pr.Ext2.Add(&p1.X, &p2.X)) // omit y3 computation // compute line1 line1.R0 = *λ1 - line1.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ1.A0, &p1.X.A0}, {mone, &λ1.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line1.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ1.A0, &p1.X.A1}, {&λ1.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line1.R1 = *pr.Ext2.Mul(λ1, &p1.X) + line1.R1 = *pr.Ext2.Sub(&line1.R1, &p1.Y) // compute λ2 = -λ1-2y1/(x3-x1) n = pr.Ext2.MulByConstElement(&p1.Y, big.NewInt(2)) @@ -617,23 +682,21 @@ func (pr Pairing) doubleAndAddStep(p1, p2 *g2AffP, isSub bool) (*g2AffP, *lineEv λ2 = pr.Ext2.Neg(λ2) // compute x4 = λ2²-x1-x3 - x40 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p1.X.A0}, {mone, x30}}, []int{1, 1, 1, 1}) - x41 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p1.X.A1}, {mone, x31}}, []int{2, 1, 1}) - x4 := &fields_bn254.E2{A0: *x40, A1: *x41} + x4 := pr.Ext2.Square(λ2) + x4 = pr.Ext2.Sub(x4, pr.Ext2.Add(&p1.X, x3)) // compute y4 = λ2(x1 - x4)-y1 y4 := pr.Ext2.Sub(&p1.X, x4) - y40 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &y4.A0}, {mone, &λ2.A1, &y4.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - y41 := pr.curveF.Eval([][]*baseEl{{&λ2.A0, &y4.A1}, {&λ2.A1, &y4.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) - y4 = &fields_bn254.E2{A0: *y40, A1: *y41} + y4 = pr.Ext2.Mul(λ2, y4) + y4 = pr.Ext2.Sub(y4, &p1.Y) p.X = *x4 p.Y = *y4 // compute line2 line2.R0 = *λ2 - line2.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ2.A0, &p1.X.A0}, {mone, &λ2.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line2.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ2.A0, &p1.X.A1}, {&λ2.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line2.R1 = *pr.Ext2.Mul(λ2, &p1.X) + line2.R1 = *pr.Ext2.Sub(&line2.R1, &p1.Y) return &p, &line1, &line2 } @@ -644,7 +707,6 @@ func (pr Pairing) doubleStep(p1 *g2AffP) (*g2AffP, *lineEvaluation) { var p g2AffP var line lineEvaluation - mone := pr.curveF.NewElement(-1) // λ = 3x²/2y n := pr.Ext2.Square(&p1.X) @@ -653,22 +715,20 @@ func (pr Pairing) doubleStep(p1 *g2AffP) (*g2AffP, *lineEvaluation) { λ := pr.Ext2.DivUnchecked(n, d) // xr = λ²-2x - xr0 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p1.X.A0}}, []int{1, 1, 2}) - xr1 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p1.X.A1}}, []int{2, 2}) - xr := &fields_bn254.E2{A0: *xr0, A1: *xr1} + xr := pr.Ext2.Square(λ) + xr = pr.Ext2.Sub(xr, pr.Ext2.MulByConstElement(&p1.X, big.NewInt(2))) // yr = λ(x-xr)-y yr := pr.Ext2.Sub(&p1.X, xr) - yr0 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - yr1 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bn254.E2{A0: *yr0, A1: *yr1} + yr = pr.Ext2.Mul(λ, yr) + yr = pr.Ext2.Sub(yr, &p1.Y) p.X = *xr p.Y = *yr line.R0 = *λ - line.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A0}, {mone, &λ.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A1}, {&λ.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &p, &line @@ -678,23 +738,19 @@ func (pr Pairing) doubleStep(p1 *g2AffP) (*g2AffP, *lineEvaluation) { // https://eprint.iacr.org/2022/1162 (Section 6.1) func (pr Pairing) addStep(p1, p2 *g2AffP) (*g2AffP, *lineEvaluation) { - mone := pr.curveF.NewElement(-1) - // compute λ = (y2-y1)/(x2-x1) p2ypy := pr.Ext2.Sub(&p2.Y, &p1.Y) p2xpx := pr.Ext2.Sub(&p2.X, &p1.X) λ := pr.Ext2.DivUnchecked(p2ypy, p2xpx) // xr = λ²-x1-x2 - xr0 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p1.X.A0}, {mone, &p2.X.A0}}, []int{1, 1, 1, 1}) - xr1 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p1.X.A1}, {mone, &p2.X.A1}}, []int{2, 1, 1}) - xr := &fields_bn254.E2{A0: *xr0, A1: *xr1} + xr := pr.Ext2.Square(λ) + xr = pr.Ext2.Sub(xr, pr.Ext2.Add(&p1.X, &p2.X)) // yr = λ(x1-xr) - y1 - yr := pr.Ext2.Sub(&p1.X, xr) - yr0 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - yr1 := pr.curveF.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) - yr = &fields_bn254.E2{A0: *yr0, A1: *yr1} + pxrx := pr.Ext2.Sub(&p1.X, xr) + λpxrx := pr.Ext2.Mul(λ, pxrx) + yr := pr.Ext2.Sub(λpxrx, &p1.Y) var res g2AffP res.X = *xr @@ -702,8 +758,8 @@ func (pr Pairing) addStep(p1, p2 *g2AffP) (*g2AffP, *lineEvaluation) { var line lineEvaluation line.R0 = *λ - line.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A0}, {mone, &λ.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A1}, {&λ.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &res, &line @@ -712,8 +768,6 @@ func (pr Pairing) addStep(p1, p2 *g2AffP) (*g2AffP, *lineEvaluation) { // lineCompute computes the line through p1 and p2, but does not compute p1+p2. func (pr Pairing) lineCompute(p1, p2 *g2AffP) *lineEvaluation { - mone := pr.curveF.NewElement(-1) - // compute λ = (y2+y1)/(x2-x1) qypy := pr.Ext2.Add(&p1.Y, &p2.Y) qxpx := pr.Ext2.Sub(&p1.X, &p2.X) @@ -721,8 +775,8 @@ func (pr Pairing) lineCompute(p1, p2 *g2AffP) *lineEvaluation { var line lineEvaluation line.R0 = *λ - line.R1.A0 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A0}, {mone, &λ.A1, &p1.X.A1}, {mone, &p1.Y.A0}}, []int{1, 1, 1}) - line.R1.A1 = *pr.curveF.Eval([][]*baseEl{{&λ.A0, &p1.X.A1}, {&λ.A1, &p1.X.A0}, {mone, &p1.Y.A1}}, []int{1, 1, 1}) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &line @@ -737,56 +791,42 @@ func (pr Pairing) MillerLoopAndMul(P *G1Affine, Q *G2Affine, previous *GTEl) (*G if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.Ext12.Mul(res, previous) + res = pr.Mul(res, previous) return res, err } // millerLoopAndFinalExpResult computes the Miller loop between P and Q, // multiplies it in 𝔽p¹² by previous and returns the result. func (pr Pairing) millerLoopAndFinalExpResult(P *G1Affine, Q *G2Affine, previous *GTEl) *GTEl { - tower := pr.ToTower(previous) // hint the non-residue witness - hint, err := pr.curveF.NewHint(millerLoopAndCheckFinalExpHint, 18, &P.X, &P.Y, &Q.P.X.A0, &Q.P.X.A1, &Q.P.Y.A0, &Q.P.Y.A1, tower[0], tower[1], tower[2], tower[3], tower[4], tower[5], tower[6], tower[7], tower[8], tower[9], tower[10], tower[11]) + hint, err := pr.curveF.NewHint(millerLoopAndCheckFinalExpHint, 18, &P.X, &P.Y, &Q.P.X.A0, &Q.P.X.A1, &Q.P.Y.A0, &Q.P.Y.A1, &previous.C0.B0.A0, &previous.C0.B0.A1, &previous.C0.B1.A0, &previous.C0.B1.A1, &previous.C0.B2.A0, &previous.C0.B2.A1, &previous.C1.B0.A0, &previous.C1.B0.A1, &previous.C1.B1.A0, &previous.C1.B1.A1, &previous.C1.B2.A0, &previous.C1.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) } - residueWitness := pr.FromTower([12]*baseEl{hint[0], hint[1], hint[2], hint[3], hint[4], hint[5], hint[6], hint[7], hint[8], hint[9], hint[10], hint[11]}) + residueWitness := fields_bn254.E12{ + C0: fields_bn254.E6{ + B0: fields_bn254.E2{A0: *hint[0], A1: *hint[1]}, + B1: fields_bn254.E2{A0: *hint[2], A1: *hint[3]}, + B2: fields_bn254.E2{A0: *hint[4], A1: *hint[5]}, + }, + C1: fields_bn254.E6{ + B0: fields_bn254.E2{A0: *hint[6], A1: *hint[7]}, + B1: fields_bn254.E2{A0: *hint[8], A1: *hint[9]}, + B2: fields_bn254.E2{A0: *hint[10], A1: *hint[11]}, + }, + } // constrain cubicNonResiduePower to be in Fp6 - // that is: a100=a101=a110=a111=a120=a121=0 - // or - // A0 = a000 - 9 * a001 - // A1 = 0 - // A2 = a010 - 9 * a011 - // A3 = 0 - // A4 = a020 - 9 * a021 - // A5 = 0 - // A6 = a001 - // A7 = 0 - // A8 = a011 - // A9 = 0 - // A10 = a021 - // A11 = 0 - nine := big.NewInt(9) - cubicNonResiduePower := GTEl{ - A0: *pr.curveF.Sub(hint[12], pr.curveF.MulConst(hint[13], nine)), - A1: *pr.curveF.Zero(), - A2: *pr.curveF.Sub(hint[14], pr.curveF.MulConst(hint[15], nine)), - A3: *pr.curveF.Zero(), - A4: *pr.curveF.Sub(hint[16], pr.curveF.MulConst(hint[17], nine)), - A5: *pr.curveF.Zero(), - A6: *hint[13], - A7: *pr.curveF.Zero(), - A8: *hint[15], - A9: *pr.curveF.Zero(), - A10: *hint[17], - A11: *pr.curveF.Zero(), + cubicNonResiduePower := fields_bn254.E6{ + B0: fields_bn254.E2{A0: *hint[12], A1: *hint[13]}, + B1: fields_bn254.E2{A0: *hint[14], A1: *hint[15]}, + B2: fields_bn254.E2{A0: *hint[16], A1: *hint[17]}, } // residueWitnessInv = 1 / residueWitness - residueWitnessInv := pr.Ext12.Inverse(residueWitness) + residueWitnessInv := pr.Inverse(&residueWitness) if Q.Lines == nil { Qlines := pr.computeLines(&Q.P) @@ -805,42 +845,42 @@ func (pr Pairing) millerLoopAndFinalExpResult(P *G1Affine, Q *G2Affine, previous // Compute f_{6x₀+2,Q}(P) for i := 64; i >= 0; i-- { - res = pr.Ext12.Square(res) + res = pr.Square(res) switch loopCounter[i] { case 0: // ℓ × res - res = pr.MulBy01379( + res = pr.MulBy034( res, - pr.Ext2.MulByElement(&lines[0][i].R0, xNegOverY), - pr.Ext2.MulByElement(&lines[0][i].R1, yInv), + pr.MulByElement(&lines[0][i].R0, xNegOverY), + pr.MulByElement(&lines[0][i].R1, yInv), ) case 1: // multiply by residueWitnessInv when bit=1 - res = pr.Ext12.Mul(res, residueWitnessInv) + res = pr.Mul(res, residueWitnessInv) // lines evaluations at P // and ℓ × ℓ - prodLines := pr.Mul01379By01379( - pr.Ext2.MulByElement(&lines[0][i].R0, xNegOverY), - pr.Ext2.MulByElement(&lines[0][i].R1, yInv), - pr.Ext2.MulByElement(&lines[1][i].R0, xNegOverY), - pr.Ext2.MulByElement(&lines[1][i].R1, yInv), + prodLines := pr.Mul034By034( + pr.MulByElement(&lines[0][i].R0, xNegOverY), + pr.MulByElement(&lines[0][i].R1, yInv), + pr.MulByElement(&lines[1][i].R0, xNegOverY), + pr.MulByElement(&lines[1][i].R1, yInv), ) // (ℓ × ℓ) × res - res = pr.Ext12.MulBy012346789(res, prodLines) + res = pr.MulBy01234(res, prodLines) case -1: // multiply by residueWitness when bit=-1 - res = pr.Ext12.Mul(res, residueWitness) + res = pr.Mul(res, &residueWitness) // lines evaluations at P // and ℓ × ℓ - prodLines := pr.Mul01379By01379( - pr.Ext2.MulByElement(&lines[0][i].R0, xNegOverY), - pr.Ext2.MulByElement(&lines[0][i].R1, yInv), - pr.Ext2.MulByElement(&lines[1][i].R0, xNegOverY), - pr.Ext2.MulByElement(&lines[1][i].R1, yInv), + prodLines := pr.Mul034By034( + pr.MulByElement(&lines[0][i].R0, xNegOverY), + pr.MulByElement(&lines[0][i].R1, yInv), + pr.MulByElement(&lines[1][i].R0, xNegOverY), + pr.MulByElement(&lines[1][i].R1, yInv), ) // (ℓ × ℓ) × res - res = pr.Ext12.MulBy012346789(res, prodLines) + res = pr.MulBy01234(res, prodLines) default: panic(fmt.Sprintf("invalid loop counter value %d", loopCounter[i])) } @@ -848,31 +888,36 @@ func (pr Pairing) millerLoopAndFinalExpResult(P *G1Affine, Q *G2Affine, previous // Compute ℓ_{[6x₀+2]Q,π(Q)}(P) · ℓ_{[6x₀+2]Q+π(Q),-π²(Q)}(P) // lines evaluations at P - prodLines := pr.Mul01379By01379( - pr.Ext2.MulByElement(&lines[0][65].R0, xNegOverY), - pr.Ext2.MulByElement(&lines[0][65].R1, yInv), - pr.Ext2.MulByElement(&lines[1][65].R0, xNegOverY), - pr.Ext2.MulByElement(&lines[1][65].R1, yInv), + // and ℓ × ℓ + prodLines := pr.Mul034By034( + pr.MulByElement(&lines[0][65].R0, xNegOverY), + pr.MulByElement(&lines[0][65].R1, yInv), + pr.MulByElement(&lines[1][65].R0, xNegOverY), + pr.MulByElement(&lines[1][65].R1, yInv), ) - res = pr.Ext12.MulBy012346789(res, prodLines) + // (ℓ × ℓ) × res + res = pr.MulBy01234(res, prodLines) // multiply by previous multi-Miller function - res = pr.Ext12.Mul(res, previous) + res = pr.Mul(res, previous) // Check that res * cubicNonResiduePower * residueWitnessInv^λ' == 1 // where λ' = q^3 - q^2 + q, with u the BN254 seed // and residueWitnessInv, cubicNonResiduePower from the hint. // Note that res is already MillerLoop(P,Q) * residueWitnessInv^{6x₀+2} since // we initialized the Miller loop accumulator with residueWitnessInv. - t2 := pr.Ext12.Mul(&cubicNonResiduePower, res) + t2 := &fields_bn254.E12{ + C0: *pr.Ext6.Mul(&res.C0, &cubicNonResiduePower), + C1: *pr.Ext6.Mul(&res.C1, &cubicNonResiduePower), + } t1 := pr.FrobeniusCube(residueWitnessInv) - t0 := pr.FrobeniusSquare(residueWitness) - t1 = pr.Ext12.Mul(t1, t0) + t0 := pr.FrobeniusSquare(residueWitnessInv) + t1 = pr.DivUnchecked(t1, t0) t0 = pr.Frobenius(residueWitnessInv) - t1 = pr.Ext12.Mul(t1, t0) + t1 = pr.Mul(t1, t0) - t2 = pr.Ext12.Mul(t2, t1) + t2 = pr.Mul(t2, t1) return t2 } @@ -890,7 +935,7 @@ func (pr Pairing) millerLoopAndFinalExpResult(P *G1Affine, Q *G2Affine, previous func (pr Pairing) IsMillerLoopAndFinalExpOne(P *G1Affine, Q *G2Affine, previous *GTEl) frontend.Variable { t2 := pr.millerLoopAndFinalExpResult(P, Q, previous) - res := pr.IsEqual(t2, pr.Ext12.One()) + res := pr.IsEqual(t2, pr.One()) return res } @@ -905,5 +950,5 @@ func (pr Pairing) IsMillerLoopAndFinalExpOne(P *G1Affine, Q *G2Affine, previous // [On Proving Pairings]: https://eprint.iacr.org/2024/640.pdf func (pr Pairing) AssertMillerLoopAndFinalExpIsOne(P *G1Affine, Q *G2Affine, previous *GTEl) { t2 := pr.millerLoopAndFinalExpResult(P, Q, previous) - pr.AssertIsEqual(t2, pr.Ext12.One()) + pr.AssertIsEqual(t2, pr.One()) } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index ae2fe87e80..eb84bf9b98 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -33,18 +33,20 @@ func randomG1G2Affines() (bn254.G1Affine, bn254.G2Affine) { return p, q } -type FinalExponentiation struct { +type FinalExponentiationCircuit struct { InGt GTEl Res GTEl } -func (c *FinalExponentiation) Define(api frontend.API) error { +func (c *FinalExponentiationCircuit) Define(api frontend.API) error { pairing, err := NewPairing(api) if err != nil { return fmt.Errorf("new pairing: %w", err) } - expected := pairing.FinalExponentiation(&c.InGt) - pairing.AssertIsEqual(expected, &c.Res) + res1 := pairing.FinalExponentiation(&c.InGt) + pairing.AssertIsEqual(res1, &c.Res) + res2 := pairing.FinalExponentiationUnsafe(&c.InGt) + pairing.AssertIsEqual(res2, &c.Res) return nil } @@ -53,45 +55,93 @@ func TestFinalExponentiationTestSolve(t *testing.T) { var gt bn254.GT gt.SetRandom() res := bn254.FinalExponentiation(>) - witness := FinalExponentiation{ + witness := FinalExponentiationCircuit{ InGt: NewGTEl(gt), Res: NewGTEl(res), } - err := test.IsSolved(&FinalExponentiation{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type FinalExponentiationIsOne struct { - InGt GTEl +type MillerLoopCircuit struct { + InG1 G1Affine + InG2 G2Affine + Res GTEl } -func (c *FinalExponentiationIsOne) Define(api frontend.API) error { +func (c *MillerLoopCircuit) Define(api frontend.API) error { pairing, err := NewPairing(api) if err != nil { return fmt.Errorf("new pairing: %w", err) } - pairing.AssertFinalExponentiationIsOne(&c.InGt) + res, err := pairing.MillerLoop([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Res) return nil } -func TestFinalExponentiationIsOneTestSolve(t *testing.T) { +func TestMillerLoopTestSolve(t *testing.T) { assert := test.NewAssert(t) - // e(a,2b) * e(-2a,b) == 1 - p1, q1 := randomG1G2Affines() - var p2 bn254.G1Affine - p2.Double(&p1).Neg(&p2) - var q2 bn254.G2Affine - q2.Set(&q1) - q1.Double(&q1) - ml, err := bn254.MillerLoop( - []bn254.G1Affine{p1, p2}, - []bn254.G2Affine{q1, q2}, + p, q := randomG1G2Affines() + lines := bn254.PrecomputeLines(q) + res, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{p}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, ) assert.NoError(err) - witness := FinalExponentiationIsOne{ - InGt: NewGTEl(ml), + witness := MillerLoopCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + Res: NewGTEl(res), } - err = test.IsSolved(&FinalExponentiationIsOne{}, &witness, ecc.BN254.ScalarField()) + err = test.IsSolved(&MillerLoopCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type MillerLoopAndMulCircuit struct { + Prev GTEl + P G1Affine + Q G2Affine + Current GTEl +} + +func (c *MillerLoopAndMulCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.MillerLoopAndMul(&c.P, &c.Q, &c.Prev) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Current) + return nil + +} + +func TestMillerLoopAndMulTestSolve(t *testing.T) { + assert := test.NewAssert(t) + var prev, curr bn254.GT + prev.SetRandom() + p, q := randomG1G2Affines() + lines := bn254.PrecomputeLines(q) + // need to use ML with precomputed lines. Otherwise, the result will be different + mlres, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{p}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, + ) + assert.NoError(err) + curr.Mul(&prev, &mlres) + + witness := MillerLoopAndMulCircuit{ + Prev: NewGTEl(prev), + P: NewG1Affine(p), + Q: NewG2Affine(q), + Current: NewGTEl(curr), + } + err = test.IsSolved(&MillerLoopAndMulCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -106,6 +156,8 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -492,3 +544,65 @@ func BenchmarkPairing(b *testing.B) { } }) } + +// bench +func BenchmarkFinalExponentiation(b *testing.B) { + // e(a,2b) * e(-2a,b) == 1 + var gt bn254.GT + gt.SetRandom() + res := bn254.FinalExponentiation(>) + witness := FinalExponentiationCircuit{ + InGt: NewGTEl(gt), + Res: NewGTEl(res), + } + w, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + b.Fatal(err) + } + var ccs constraint.ConstraintSystem + b.Run("compile scs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ccs, err = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &FinalExponentiationCircuit{}); err != nil { + b.Fatal(err) + } + } + }) + var buf bytes.Buffer + _, err = ccs.WriteTo(&buf) + if err != nil { + b.Fatal(err) + } + b.Logf("scs size: %d (bytes), nb constraints %d, nbInstructions: %d", buf.Len(), ccs.GetNbConstraints(), ccs.GetNbInstructions()) + b.Run("solve scs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := ccs.Solve(w); err != nil { + b.Fatal(err) + } + } + }) + b.Run("compile r1cs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ccs, err = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &FinalExponentiationCircuit{}); err != nil { + b.Fatal(err) + } + } + }) + buf.Reset() + _, err = ccs.WriteTo(&buf) + if err != nil { + b.Fatal(err) + } + b.Logf("r1cs size: %d (bytes), nb constraints %d, nbInstructions: %d", buf.Len(), ccs.GetNbConstraints(), ccs.GetNbInstructions()) + + b.Run("solve r1cs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := ccs.Solve(w); err != nil { + b.Fatal(err) + } + } + }) +} diff --git a/std/algebra/emulated/sw_bw6761/g1.go b/std/algebra/emulated/sw_bw6761/g1.go index 0c97334a0d..02278f42be 100644 --- a/std/algebra/emulated/sw_bw6761/g1.go +++ b/std/algebra/emulated/sw_bw6761/g1.go @@ -137,17 +137,18 @@ func (g1 G1) doubleAndAdd(p, q *G1Affine) *G1Affine { x2 := g1.curveF.Eval([][]*baseEl{{λ1, λ1}, {mone, &p.X}, {mone, &q.X}}, []int{1, 1, 1}) // omit y1 computation - // compute -λ1 = λ1+2*p.y/(x1-p.x) + // compute λ1 = -λ1-1*p.y/(x1-p.x) ypyp := g1.curveF.Add(&p.Y, &p.Y) x2xp := g1.curveF.Sub(x2, &p.X) λ2 := g1.curveF.Div(ypyp, x2xp) λ2 = g1.curveF.Add(λ1, λ2) + λ2 = g1.curveF.Neg(λ2) - // compute x3 = (-λ2)²-p.x-x3 + // compute x3 =λ2²-p.x-x3 x3 := g1.curveF.Eval([][]*baseEl{{λ2, λ2}, {mone, &p.X}, {mone, x2}}, []int{1, 1, 1}) - // compute y3 = -λ2*(x3 - p.x)-p.y - y3 := g1.curveF.Eval([][]*baseEl{{mone, λ2, &p.X}, {λ2, x3}, {mone, &p.Y}}, []int{1, 1, 1}) + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g1.curveF.Eval([][]*baseEl{{λ2, &p.X}, {mone, λ2, x3}, {mone, &p.Y}}, []int{1, 1, 1}) return &G1Affine{ X: *x3, diff --git a/std/algebra/emulated/sw_emulated/hints.go b/std/algebra/emulated/sw_emulated/hints.go index f00ba4c804..f19bfeef0f 100644 --- a/std/algebra/emulated/sw_emulated/hints.go +++ b/std/algebra/emulated/sw_emulated/hints.go @@ -2,7 +2,6 @@ package sw_emulated import ( "crypto/elliptic" - "errors" "fmt" "math/big" @@ -43,10 +42,10 @@ func GetHints() []solver.Hint { func decomposeScalarG1Subscalars(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return emulated.UnwrapHint(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error { if len(inputs) != 2 { - return errors.New("expecting two inputs") + return fmt.Errorf("expecting two inputs") } if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } glvBasis := new(ecc.Lattice) ecc.PrecomputeLattice(field, inputs[1], glvBasis) @@ -72,10 +71,10 @@ func decomposeScalarG1Subscalars(mod *big.Int, inputs []*big.Int, outputs []*big func decomposeScalarG1Signs(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return emulated.UnwrapHintWithNativeOutput(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error { if len(inputs) != 2 { - return errors.New("expecting two inputs") + return fmt.Errorf("expecting two inputs") } if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } glvBasis := new(ecc.Lattice) ecc.PrecomputeLattice(field, inputs[1], glvBasis) @@ -98,10 +97,10 @@ func decomposeScalarG1Signs(mod *big.Int, inputs []*big.Int, outputs []*big.Int) func scalarMulHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { return emulated.UnwrapHintWithNativeInput(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error { if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } if field.Cmp(elliptic.P256().Params().P) == 0 { var fp emparams.P256Fp @@ -283,7 +282,7 @@ func scalarMulHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { P.Y.BigInt(outputs[1]) } else { - return errors.New("unsupported curve") + return fmt.Errorf("unsupported curve") } return nil @@ -340,8 +339,8 @@ func halfGCDEisensteinSigns(mod *big.Int, inputs, outputs []*big.Int) error { if len(inputs) != 2 { return fmt.Errorf("expecting two input") } - if len(outputs) != 4 { - return fmt.Errorf("expecting four outputs") + if len(outputs) != 5 { + return fmt.Errorf("expecting five outputs") } glvBasis := new(ecc.Lattice) ecc.PrecomputeLattice(field, inputs[1], glvBasis) @@ -362,7 +361,15 @@ func halfGCDEisensteinSigns(mod *big.Int, inputs, outputs []*big.Int) error { outputs[1].SetUint64(0) outputs[2].SetUint64(0) outputs[3].SetUint64(0) + outputs[4].SetUint64(0) res := eisenstein.HalfGCD(&r, &s) + s.A1.Mul(res[1].A1, inputs[1]). + Add(s.A1, res[1].A0). + Mul(s.A1, inputs[0]). + Add(s.A1, res[0].A0) + s.A0.Mul(res[0].A1, inputs[1]) + s.A1.Add(s.A1, s.A0). + Div(s.A1, field) if res[0].A0.Sign() == -1 { outputs[0].SetUint64(1) @@ -376,6 +383,9 @@ func halfGCDEisensteinSigns(mod *big.Int, inputs, outputs []*big.Int) error { if res[1].A1.Sign() == -1 { outputs[3].SetUint64(1) } + if s.A1.Sign() == -1 { + outputs[4].SetUint64(1) + } return nil }) } @@ -385,8 +395,8 @@ func halfGCDEisenstein(mod *big.Int, inputs []*big.Int, outputs []*big.Int) erro if len(inputs) != 2 { return fmt.Errorf("expecting two input") } - if len(outputs) != 4 { - return fmt.Errorf("expecting four outputs") + if len(outputs) != 5 { + return fmt.Errorf("expecting five outputs") } glvBasis := new(ecc.Lattice) ecc.PrecomputeLattice(field, inputs[1], glvBasis) @@ -407,6 +417,13 @@ func halfGCDEisenstein(mod *big.Int, inputs []*big.Int, outputs []*big.Int) erro outputs[1].Set(res[0].A1) outputs[2].Set(res[1].A0) outputs[3].Set(res[1].A1) + outputs[4].Mul(res[1].A1, inputs[1]). + Add(outputs[4], res[1].A0). + Mul(outputs[4], inputs[0]). + Add(outputs[4], res[0].A0) + s.A0.Mul(res[0].A1, inputs[1]) + outputs[4].Add(outputs[4], s.A0). + Div(outputs[4], field) if outputs[0].Sign() == -1 { outputs[0].Neg(outputs[0]) @@ -420,6 +437,9 @@ func halfGCDEisenstein(mod *big.Int, inputs []*big.Int, outputs []*big.Int) erro if outputs[3].Sign() == -1 { outputs[3].Neg(outputs[3]) } + if outputs[4].Sign() == -1 { + outputs[4].Neg(outputs[4]) + } return nil }) } diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 6defe337e3..2cd9e71a6c 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -214,15 +214,14 @@ func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { selector := c.api.And(c.baseApi.IsZero(&p.X), c.baseApi.IsZero(&p.Y)) b := c.baseApi.Select(selector, c.baseApi.Zero(), &c.b) - mone := c.baseApi.NewElement(-1) - - var check *emulated.Element[B] - if !c.addA { - check = c.baseApi.Eval([][]*emulated.Element[B]{{&p.X, &p.X, &p.X}, {b}, {mone, &p.Y, &p.Y}}, []int{1, 1, 1}) - } else { - check = c.baseApi.Eval([][]*emulated.Element[B]{{&p.X, &p.X, &p.X}, {&c.a, &p.X}, {b}, {mone, &p.Y, &p.Y}}, []int{1, 1, 1, 1}) + left := c.baseApi.Mul(&p.Y, &p.Y) + right := c.baseApi.Mul(&p.X, c.baseApi.Mul(&p.X, &p.X)) + right = c.baseApi.Add(right, b) + if c.addA { + ax := c.baseApi.Mul(&c.a, &p.X) + right = c.baseApi.Add(right, ax) } - c.baseApi.AssertIsEqual(check, c.baseApi.Zero()) + c.baseApi.AssertIsEqual(left, right) } // AddUnified adds p and q and returns it. It doesn't modify p nor q. @@ -383,17 +382,16 @@ func (c *Curve[B, S]) doubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { x2 := c.baseApi.Eval([][]*emulated.Element[B]{{λ1, λ1}, {mone, c.baseApi.Add(&p.X, &q.X)}}, []int{1, 1}) // omit y2 computation - - // compute -λ2 = λ1+2*p.y/(x2-p.x) + // compute λ2 = λ1+2*p.y/(x2-p.x) ypyp := c.baseApi.MulConst(&p.Y, big.NewInt(2)) x2xp := c.baseApi.Sub(x2, &p.X) λ2 := c.baseApi.Div(ypyp, x2xp) λ2 = c.baseApi.Add(λ1, λ2) - // compute x3 = (-λ2)²-p.x-x2 + // compute x3 =λ2²-p.x-x2 x3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, λ2}, {mone, &p.X}, {mone, x2}}, []int{1, 1, 1}) - // compute y3 = -λ2*(x3 - p.x)-p.y + // compute y3 = λ2*(-p.x + x3)-p.y y3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, c.baseApi.Sub(x3, &p.X)}, {mone, &p.Y}}, []int{1, 1}) return &AffinePoint[B]{ @@ -426,16 +424,16 @@ func (c *Curve[B, S]) doubleAndAddSelect(b frontend.Variable, p, q *AffinePoint[ // conditional second addition t := c.Select(b, p, q) - // compute -λ2 = λ1+2*t.y/(x2-t.x) + // compute λ2 = λ1+2*t.y/(x2-t.x) ypyp := c.baseApi.MulConst(&t.Y, big.NewInt(2)) x2xp := c.baseApi.Sub(x2, &t.X) λ2 := c.baseApi.Div(ypyp, x2xp) λ2 = c.baseApi.Add(λ1, λ2) - // compute x3 = (-λ2)²-t.x-x2 + // compute x3 =λ2²-t.x-x2 x3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, λ2}, {mone, &t.X}, {mone, x2}}, []int{1, 1, 1}) - // compute y3 = -λ2*(x3 - t.x)-t.y + // compute y3 = -λ2*(t.x - x3)-t.y y3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, x3}, {mone, λ2, &t.X}, {mone, &t.Y}}, []int{1, 1, 1}) return &AffinePoint[B]{ @@ -1564,7 +1562,7 @@ func (c *Curve[B, S]) scalarMulGLVAndFakeGLV(P *AffinePoint[B], s *emulated.Elem // // The hint returns u1, u2, v1, v2. // In-circuit we check that (v1 + λ*v2)*s = (u1 + λ*u2) mod r - sd, err := c.scalarApi.NewHint(halfGCDEisenstein, 4, _s, c.eigenvalue) + sd, err := c.scalarApi.NewHint(halfGCDEisenstein, 5, _s, c.eigenvalue) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -1574,7 +1572,7 @@ func (c *Curve[B, S]) scalarMulGLVAndFakeGLV(P *AffinePoint[B], s *emulated.Elem // Eisenstein integers real and imaginary parts can be negative. So we // return the absolute value in the hint and negate the corresponding // points here when needed. - signs, err := c.scalarApi.NewHintWithNativeOutput(halfGCDEisensteinSigns, 4, _s, c.eigenvalue) + signs, err := c.scalarApi.NewHintWithNativeOutput(halfGCDEisensteinSigns, 5, _s, c.eigenvalue) if err != nil { panic(fmt.Sprintf("halfGCDSigns hint: %v", err)) } diff --git a/std/algebra/native/sw_bls12377/hints.go b/std/algebra/native/sw_bls12377/hints.go index 6a993b9095..9c0c86333d 100644 --- a/std/algebra/native/sw_bls12377/hints.go +++ b/std/algebra/native/sw_bls12377/hints.go @@ -1,7 +1,7 @@ package sw_bls12377 import ( - "errors" + "fmt" "math/big" "github.com/consensys/gnark-crypto/ecc" @@ -27,10 +27,10 @@ func init() { func decomposeScalarG1Simple(scalarField *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 1 { - return errors.New("expecting one input") + return fmt.Errorf("expecting one input") } if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } cc := getInnerCurveConfig(scalarField) sp := ecc.SplitScalar(inputs[0], cc.glvBasis) @@ -42,10 +42,10 @@ func decomposeScalarG1Simple(scalarField *big.Int, inputs []*big.Int, outputs [] func decomposeScalarG1(scalarField *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 1 { - return errors.New("expecting one input") + return fmt.Errorf("expecting one input") } if len(outputs) != 3 { - return errors.New("expecting three outputs") + return fmt.Errorf("expecting three outputs") } cc := getInnerCurveConfig(scalarField) sp := ecc.SplitScalar(inputs[0], cc.glvBasis) @@ -69,10 +69,10 @@ func decomposeScalarG1(scalarField *big.Int, inputs []*big.Int, outputs []*big.I func decomposeScalarG2(scalarField *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 1 { - return errors.New("expecting one input") + return fmt.Errorf("expecting one input") } if len(outputs) != 3 { - return errors.New("expecting three outputs") + return fmt.Errorf("expecting three outputs") } cc := getInnerCurveConfig(scalarField) sp := ecc.SplitScalar(inputs[0], cc.glvBasis) @@ -96,10 +96,10 @@ func decomposeScalarG2(scalarField *big.Int, inputs []*big.Int, outputs []*big.I func scalarMulGLVG1Hint(scalarField *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 3 { - return errors.New("expecting three inputs") + return fmt.Errorf("expecting three inputs") } if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } // compute the resulting point [s]Q @@ -114,10 +114,10 @@ func scalarMulGLVG1Hint(scalarField *big.Int, inputs []*big.Int, outputs []*big. func halfGCDEisenstein(scalarField *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 2 { - return errors.New("expecting two input") + return fmt.Errorf("expecting two input") } if len(outputs) != 5 { - return errors.New("expecting five outputs") + return fmt.Errorf("expecting five outputs") } cc := getInnerCurveConfig(scalarField) glvBasis := new(ecc.Lattice) @@ -168,10 +168,10 @@ func halfGCDEisenstein(scalarField *big.Int, inputs []*big.Int, outputs []*big.I func halfGCDEisensteinSigns(scalarField *big.Int, inputs, outputs []*big.Int) error { if len(inputs) != 2 { - return errors.New("expecting two input") + return fmt.Errorf("expecting two input") } if len(outputs) != 5 { - return errors.New("expecting five outputs") + return fmt.Errorf("expecting five outputs") } cc := getInnerCurveConfig(scalarField) glvBasis := new(ecc.Lattice) diff --git a/std/algebra/native/sw_bls12377/pairing2.go b/std/algebra/native/sw_bls12377/pairing2.go index 072e2707bc..67989e5dfd 100644 --- a/std/algebra/native/sw_bls12377/pairing2.go +++ b/std/algebra/native/sw_bls12377/pairing2.go @@ -1,7 +1,6 @@ package sw_bls12377 import ( - "errors" "fmt" "math/big" "slices" @@ -29,7 +28,7 @@ type Curve struct { func NewCurve(api frontend.API) (*Curve, error) { f, err := emulated.NewField[ScalarField](api) if err != nil { - return nil, errors.New("scalar field") + return nil, fmt.Errorf("scalar field") } return &Curve{ api: api, @@ -167,7 +166,7 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar, opts ...algopts } if !cfg.FoldMulti { if len(P) != len(scalars) { - return nil, errors.New("mismatching points and scalars slice lengths") + return nil, fmt.Errorf("mismatching points and scalars slice lengths") } // points and scalars must be non-zero n := len(P) @@ -185,7 +184,7 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar, opts ...algopts } else { // scalars are powers if len(scalars) == 0 { - return nil, errors.New("need scalar for folding") + return nil, fmt.Errorf("need scalar for folding") } gamma := c.packScalarToVar(scalars[0]) // decompose gamma in the endomorphism eigenvalue basis and bit-decompose the sub-scalars diff --git a/std/algebra/native/sw_bls24315/hints.go b/std/algebra/native/sw_bls24315/hints.go index 98517cc4a8..d20fac537c 100644 --- a/std/algebra/native/sw_bls24315/hints.go +++ b/std/algebra/native/sw_bls24315/hints.go @@ -1,7 +1,7 @@ package sw_bls24315 import ( - "errors" + "fmt" "math/big" "github.com/consensys/gnark-crypto/ecc" @@ -26,10 +26,10 @@ func init() { func decomposeScalarSimple(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHintWithNativeInput(nativeInputs, nativeOutputs, func(nnMod *big.Int, nninputs, nnOutputs []*big.Int) error { if len(nninputs) != 1 { - return errors.New("expecting one input") + return fmt.Errorf("expecting one input") } if len(nnOutputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } cc := getInnerCurveConfig(nativeMod) sp := ecc.SplitScalar(nninputs[0], cc.glvBasis) @@ -43,10 +43,10 @@ func decomposeScalarSimple(nativeMod *big.Int, nativeInputs, nativeOutputs []*bi func decomposeScalar(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHintWithNativeInput(nativeInputs, nativeOutputs, func(nnMod *big.Int, nninputs, nnOutputs []*big.Int) error { if len(nninputs) != 1 { - return errors.New("expecting one input") + return fmt.Errorf("expecting one input") } if len(nnOutputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } cc := getInnerCurveConfig(nativeMod) sp := ecc.SplitScalar(nninputs[0], cc.glvBasis) @@ -115,7 +115,7 @@ func callDecomposeScalar(api frontend.API, s frontend.Variable, simple bool) (s1 func decompose(mod *big.Int, inputs, outputs []*big.Int) error { if len(inputs) != 1 && len(outputs) != 4 { - return errors.New("input/output length mismatch") + return fmt.Errorf("input/output length mismatch") } tmp := new(big.Int).Set(inputs[0]) mask := new(big.Int).SetUint64(^uint64(0)) diff --git a/std/algebra/native/sw_bls24315/pairing2.go b/std/algebra/native/sw_bls24315/pairing2.go index 09da07d6dc..295845eab8 100644 --- a/std/algebra/native/sw_bls24315/pairing2.go +++ b/std/algebra/native/sw_bls24315/pairing2.go @@ -1,7 +1,6 @@ package sw_bls24315 import ( - "errors" "fmt" "math/big" "slices" @@ -29,7 +28,7 @@ type Curve struct { func NewCurve(api frontend.API) (*Curve, error) { f, err := emulated.NewField[ScalarField](api) if err != nil { - return nil, errors.New("scalar field") + return nil, fmt.Errorf("scalar field") } return &Curve{ api: api, @@ -167,7 +166,7 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar, opts ...algopts } if !cfg.FoldMulti { if len(P) != len(scalars) { - return nil, errors.New("mismatching points and scalars slice lengths") + return nil, fmt.Errorf("mismatching points and scalars slice lengths") } // points and scalars must be non-zero n := len(P) @@ -185,7 +184,7 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar, opts ...algopts } else { // scalars are powers if len(scalars) == 0 { - return nil, errors.New("need scalar for folding") + return nil, fmt.Errorf("need scalar for folding") } gamma := c.packScalarToVar(scalars[0]) // decompose gamma in the endomorphism eigenvalue basis and bit-decompose the sub-scalars diff --git a/std/algebra/native/twistededwards/hints.go b/std/algebra/native/twistededwards/hints.go index c9c4f7c78d..90a59619cd 100644 --- a/std/algebra/native/twistededwards/hints.go +++ b/std/algebra/native/twistededwards/hints.go @@ -2,6 +2,7 @@ package twistededwards import ( "errors" + "fmt" "math/big" "sync" @@ -68,10 +69,10 @@ func decomposeScalar(scalarField *big.Int, inputs []*big.Int, res []*big.Int) er func halfGCD(mod *big.Int, inputs, outputs []*big.Int) error { if len(inputs) != 2 { - return errors.New("expecting two inputs") + return fmt.Errorf("expecting two inputs") } if len(outputs) != 4 { - return errors.New("expecting four outputs") + return fmt.Errorf("expecting four outputs") } glvBasis := new(ecc.Lattice) ecc.PrecomputeLattice(inputs[1], inputs[0], glvBasis) @@ -95,10 +96,10 @@ func halfGCD(mod *big.Int, inputs, outputs []*big.Int) error { func scalarMulHint(field *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 4 { - return errors.New("expecting four inputs") + return fmt.Errorf("expecting four inputs") } if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } // compute the resulting point [s]Q if field.Cmp(ecc.BLS12_381.ScalarField()) == 0 { @@ -161,7 +162,7 @@ func scalarMulHint(field *big.Int, inputs []*big.Int, outputs []*big.Int) error P.X.BigInt(outputs[0]) P.Y.BigInt(outputs[1]) } else { - return errors.New("scalarMulHint: unknown curve") + return fmt.Errorf("scalarMulHint: unknown curve") } return nil } diff --git a/std/commitments/fri/fri.go b/std/commitments/fri/fri.go index 8b4bad94c0..cf91d6e826 100644 --- a/std/commitments/fri/fri.go +++ b/std/commitments/fri/fri.go @@ -43,7 +43,7 @@ type ProofOfProximity struct { Rounds []Round } -// RadixTwoFri empty structs implementing compressionFunction for +// radixTwoFri empty structs implementing compressionFunction for // the squaring function. type RadixTwoFri struct { diff --git a/std/evmprecompiles/08-bnpairing.go b/std/evmprecompiles/08-bnpairing.go index 25ab396b0c..4a31e1f058 100644 --- a/std/evmprecompiles/08-bnpairing.go +++ b/std/evmprecompiles/08-bnpairing.go @@ -47,7 +47,7 @@ func ECPair(api frontend.API, P []*sw_bn254.G1Affine, Q []*sw_bn254.G2Affine) { } // 3- Check that ∏ᵢ e(Pᵢ, Qᵢ) == 1 - ml := pair.Ext12.One() + ml := pair.One() for i := 0; i < n-1; i++ { // fixed circuit 1 ml, err = pair.MillerLoopAndMul(P[i], Q[i], ml) diff --git a/std/evmprecompiles/hints.go b/std/evmprecompiles/hints.go index fb3665f332..1ff0021ebe 100644 --- a/std/evmprecompiles/hints.go +++ b/std/evmprecompiles/hints.go @@ -42,7 +42,7 @@ func recoverPublicKeyHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) err return fmt.Errorf("expected %d limbs got %d", emfr.NbLimbs()*3+1, len(inputs)) } if !inputs[emfr.NbLimbs()].IsInt64() { - return fmt.Errorf("second input must be in [0,3]") + return fmt.Errorf("second input input must be in [0,3]") } if len(outputs) != 2*int(emfp.NbLimbs())+1 { return fmt.Errorf("expected output %d limbs got %d", 2*emfp.NbLimbs(), len(outputs)) diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 50cf5b42e6..31a790c56d 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -1,7 +1,7 @@ package gkr import ( - "errors" + "fmt" "math/bits" "github.com/consensys/gnark/constraint" @@ -71,11 +71,11 @@ func (api *API) Import(assignment []frontend.Variable) (constraint.GkrVariable, nbInstances := len(assignment) logNbInstances := log2(uint(nbInstances)) if logNbInstances == -1 { - return -1, errors.New("number of assignments must be a power of 2") + return -1, fmt.Errorf("number of assignments must be a power of 2") } if currentNbInstances := api.nbInstances(); currentNbInstances != -1 && currentNbInstances != nbInstances { - return -1, errors.New("number of assignments must be consistent across all variables") + return -1, fmt.Errorf("number of assignments must be consistent across all variables") } newVar := api.toStore.NewInputVariable() api.assignments = append(api.assignments, assignment) diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index 0da52730a9..a715a9d98e 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -1,7 +1,6 @@ package gkr import ( - "errors" "fmt" "strconv" @@ -191,7 +190,7 @@ func setup(api frontend.API, c Circuit, assignment WireAssignment, transcriptSet o.nbVars = assignment.NumVars() nbInstances := assignment.NumInstances() if 1< 0 { - return errors.New("the hasher is not in an initial state") - } - - if len(newState) != 1 { - return errors.New("the MiMC hasher expects a single field element to represent the state") - } - - h.h = newState[0] - h.data = nil - return nil -} - -// State returns the inner-state of the hasher. In the context of MiMC only a -// single field element is returned. -func (h *MiMC) State() []frontend.Variable { - h.Sum() // this flushes the unsummed data - return []frontend.Variable{h.h} -} - // Sum hash using [Miyaguchi–Preneel] where the XOR operation is replaced by // field addition. // diff --git a/std/hash/mimc/mimc_test.go b/std/hash/mimc/mimc_test.go index 8efc7cdc87..e698a95f62 100644 --- a/std/hash/mimc/mimc_test.go +++ b/std/hash/mimc/mimc_test.go @@ -4,9 +4,6 @@ package mimc import ( - "crypto/rand" - "errors" - "fmt" "math/big" "testing" @@ -83,128 +80,3 @@ func TestMimcAll(t *testing.T) { } } - -// stateStoreTestCircuit checks that SetState works as expected. The circuit, however -// does not check the correctness of the hashes returned by the MiMC function -// as there is another test already testing this property. -type stateStoreTestCircuit struct { - X frontend.Variable -} - -func (s *stateStoreTestCircuit) Define(api frontend.API) error { - - hsh1, err1 := NewMiMC(api) - hsh2, err2 := NewMiMC(api) - - if err1 != nil || err2 != nil { - return fmt.Errorf("could not instantiate the MIMC hasher: %w", errors.Join(err1, err2)) - } - - // This pre-shuffle the hasher state so that the test does not start from - // a zero state. - hsh1.Write(s.X) - - state := hsh1.State() - hsh2.SetState(state) - - hsh1.Write(s.X) - hsh2.Write(s.X) - - var ( - dig1 = hsh1.Sum() - dig2 = hsh2.Sum() - newState1 = hsh1.State() - newState2 = hsh2.State() - ) - - api.AssertIsEqual(dig1, dig2) - - for i := range newState1 { - api.AssertIsEqual(newState1[i], newState2[i]) - } - - return nil -} - -func TestStateStoreMiMC(t *testing.T) { - - assert := test.NewAssert(t) - - curves := map[ecc.ID]hash.Hash{ - ecc.BN254: hash.MIMC_BN254, - ecc.BLS12_381: hash.MIMC_BLS12_381, - ecc.BLS12_377: hash.MIMC_BLS12_377, - ecc.BW6_761: hash.MIMC_BW6_761, - ecc.BW6_633: hash.MIMC_BW6_633, - ecc.BLS24_315: hash.MIMC_BLS24_315, - ecc.BLS24_317: hash.MIMC_BLS24_317, - } - - for curve := range curves { - - // minimal cs res = hash(data) - var ( - circuit = &stateStoreTestCircuit{} - assignment = &stateStoreTestCircuit{X: 2} - ) - - assert.CheckCircuit(circuit, - test.WithValidAssignment(assignment), - test.WithCurves(curve)) - } -} - -type recoveredStateTestCircuit struct { - State []frontend.Variable - Input frontend.Variable - Expected frontend.Variable `gnark:",public"` -} - -func (c *recoveredStateTestCircuit) Define(api frontend.API) error { - h, err := NewMiMC(api) - if err != nil { - return fmt.Errorf("initialize hash: %w", err) - } - if err = h.SetState(c.State); err != nil { - return fmt.Errorf("set state: %w", err) - } - h.Write(c.Input) - res := h.Sum() - api.AssertIsEqual(res, c.Expected) - return nil -} - -func TestHasherFromState(t *testing.T) { - assert := test.NewAssert(t) - - hashes := map[ecc.ID]hash.Hash{ - ecc.BN254: hash.MIMC_BN254, - ecc.BLS12_381: hash.MIMC_BLS12_381, - ecc.BLS12_377: hash.MIMC_BLS12_377, - ecc.BW6_761: hash.MIMC_BW6_761, - ecc.BW6_633: hash.MIMC_BW6_633, - ecc.BLS24_315: hash.MIMC_BLS24_315, - ecc.BLS24_317: hash.MIMC_BLS24_317, - } - - for cc, hh := range hashes { - hasher := hh.New() - ss, ok := hasher.(hash.StateStorer) - assert.True(ok) - _, err := ss.Write([]byte("hello world")) - assert.NoError(err) - state := ss.State() - nbBytes := cc.ScalarField().BitLen() / 8 - buf := make([]byte, nbBytes) - _, err = rand.Read(buf) - assert.NoError(err) - ss.Write(buf) - expected := ss.Sum(nil) - bstate := new(big.Int).SetBytes(state) - binput := new(big.Int).SetBytes(buf) - assert.CheckCircuit( - &recoveredStateTestCircuit{State: make([]frontend.Variable, 1)}, - test.WithValidAssignment(&recoveredStateTestCircuit{State: []frontend.Variable{bstate}, Input: binput, Expected: expected}), - test.WithCurves(cc)) - } -} diff --git a/std/permutation/poseidon2/poseidon2.go b/std/hash/poseidon2/poseidon2.go similarity index 99% rename from std/permutation/poseidon2/poseidon2.go rename to std/hash/poseidon2/poseidon2.go index 00fb9306fd..0e403e15da 100644 --- a/std/permutation/poseidon2/poseidon2.go +++ b/std/hash/poseidon2/poseidon2.go @@ -147,7 +147,7 @@ func (h *Hash) sBox(api frontend.API, index int, input []frontend.Variable) { // (4 6 1 1) // (1 3 5 7) // (1 1 4 6) -// on chunks of 4 elements on each part of the buffer +// on chunks of 4 elemts on each part of the buffer // see https://eprint.iacr.org/2023/323.pdf appendix B for the addition chain func (h *Hash) matMulM4InPlace(api frontend.API, s []frontend.Variable) { c := len(s) / 4 diff --git a/std/permutation/poseidon2/poseidon2_test.go b/std/hash/poseidon2/poseidon2_test.go similarity index 100% rename from std/permutation/poseidon2/poseidon2_test.go rename to std/hash/poseidon2/poseidon2_test.go diff --git a/std/hash/ripemd160/ripemd160_test.go b/std/hash/ripemd160/ripemd160_test.go index 87db38d626..83f37cbd04 100644 --- a/std/hash/ripemd160/ripemd160_test.go +++ b/std/hash/ripemd160/ripemd160_test.go @@ -8,7 +8,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/uints" "github.com/consensys/gnark/test" - "golang.org/x/crypto/ripemd160" //nolint staticcheck, backwards compatibility + "golang.org/x/crypto/ripemd160" //nolint staticcheck, backwards compatiblity ) type ripemd160Circuit struct { diff --git a/std/internal/limbcomposition/composition.go b/std/internal/limbcomposition/composition.go index 348f34deee..b2d3211c75 100644 --- a/std/internal/limbcomposition/composition.go +++ b/std/internal/limbcomposition/composition.go @@ -1,7 +1,7 @@ package limbs import ( - "errors" + "fmt" "math/big" ) @@ -13,7 +13,7 @@ import ( // res = \sum_{i=0}^{len(inputs)} inputs[i] * 2^{nbBits * i} func Recompose(inputs []*big.Int, nbBits uint, res *big.Int) error { if res == nil { - return errors.New("result not initialized") + return fmt.Errorf("result not initialized") } res.SetUint64(0) for i := range inputs { @@ -34,11 +34,11 @@ func Recompose(inputs []*big.Int, nbBits uint, res *big.Int) error { func Decompose(input *big.Int, nbBits uint, res []*big.Int) error { // limb modulus if input.BitLen() > len(res)*int(nbBits) { - return errors.New("decomposed integer does not fit into res") + return fmt.Errorf("decomposed integer does not fit into res") } for _, r := range res { if r == nil { - return errors.New("result slice element uninitialized") + return fmt.Errorf("result slice element uninitialized") } } base := new(big.Int).Lsh(big.NewInt(1), nbBits) diff --git a/std/internal/logderivarg/logderivarg.go b/std/internal/logderivarg/logderivarg.go index a52961410d..4dcc559331 100644 --- a/std/internal/logderivarg/logderivarg.go +++ b/std/internal/logderivarg/logderivarg.go @@ -39,7 +39,6 @@ package logderivarg // we have to show that all sorted values ara monotonically increasing. import ( - "errors" "fmt" "math/big" @@ -75,14 +74,14 @@ func AsTable(vector []frontend.Variable) Table { // linear combinations. func Build(api frontend.API, table Table, queries Table) error { if len(table) == 0 { - return errors.New("table empty") + return fmt.Errorf("table empty") } nbRow := len(table[0]) constTable := true countInputs := []frontend.Variable{len(table), nbRow} for i := range table { if len(table[i]) != nbRow { - return errors.New("table row length mismatch") + return fmt.Errorf("table row length mismatch") } if constTable { for j := range table[i] { @@ -95,7 +94,7 @@ func Build(api frontend.API, table Table, queries Table) error { } for i := range queries { if len(queries[i]) != nbRow { - return errors.New("query row length mismatch") + return fmt.Errorf("query row length mismatch") } countInputs = append(countInputs, queries[i]...) } diff --git a/std/internal/logderivprecomp/logderivprecomp.go b/std/internal/logderivprecomp/logderivprecomp.go index 36493391b5..d768c10a32 100644 --- a/std/internal/logderivprecomp/logderivprecomp.go +++ b/std/internal/logderivprecomp/logderivprecomp.go @@ -13,7 +13,7 @@ package logderivprecomp import ( - "errors" + "fmt" "math/big" "reflect" @@ -53,7 +53,7 @@ func New(api frontend.API, fn solver.Hint, rets []uint) (*Precomputed, error) { s += v } if s >= uint(api.Compiler().FieldBitLen()) { - return nil, errors.New("result doesn't fit into field element") + return nil, fmt.Errorf("result doesn't fit into field element") } t := &Precomputed{ api: api, diff --git a/std/math/bitslice/hints.go b/std/math/bitslice/hints.go index 0ec8f298d7..d9797c6a9a 100644 --- a/std/math/bitslice/hints.go +++ b/std/math/bitslice/hints.go @@ -1,7 +1,7 @@ package bitslice import ( - "errors" + "fmt" "math/big" "github.com/consensys/gnark/constraint/solver" @@ -19,13 +19,13 @@ func GetHints() []solver.Hint { func partitionHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 2 { - return errors.New("expecting two inputs") + return fmt.Errorf("expecting two inputs") } if len(outputs) != 2 { - return errors.New("expecting two outputs") + return fmt.Errorf("expecting two outputs") } if !inputs[0].IsUint64() { - return errors.New("split location must be int") + return fmt.Errorf("split location must be int") } split := uint(inputs[0].Uint64()) div := new(big.Int).Lsh(big.NewInt(1), split) diff --git a/std/math/bitslice/partition.go b/std/math/bitslice/partition.go index 17987eecd4..7b07c3f983 100644 --- a/std/math/bitslice/partition.go +++ b/std/math/bitslice/partition.go @@ -9,7 +9,7 @@ import ( "github.com/consensys/gnark/std/rangecheck" ) -// Partition partitions v into two parts split at bit numbered split. The +// Partition partitions v into two parts splitted at bit numbered split. The // following holds // // v = lower + 2^split * upper. diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index d5a6901086..510d3d6a96 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -1482,7 +1482,7 @@ func (c *FastPathsCircuit[T]) Define(api frontend.API) error { return nil } -func TestFastPaths(t *testing.T) { +func TestFasthPaths(t *testing.T) { testFastPaths[Goldilocks](t) testFastPaths[BN254Fr](t) testFastPaths[emparams.Mod1e512](t) diff --git a/std/math/emulated/emparams/emparams.go b/std/math/emulated/emparams/emparams.go index 51e3ed8c2e..b6ac1ce9ab 100644 --- a/std/math/emulated/emparams/emparams.go +++ b/std/math/emulated/emparams/emparams.go @@ -313,7 +313,7 @@ type STARKCurveFr struct{ fourLimbPrimeField } func (fp STARKCurveFr) Modulus() *big.Int { return ecc.STARK_CURVE.ScalarField() } -// Mod1e4096 provides type parametrization for emulated arithmetic: +// Mod1e4096 provides type parametrization for emulated aritmetic: // - limbs: 64 // - limb width: 64 bits // diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 7dca5383e1..d7087974c6 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -1,7 +1,6 @@ package emulated import ( - "errors" "fmt" "math/big" "sync" @@ -55,7 +54,9 @@ type ctxKey[T FieldParams] struct{} // NewField returns an object to be used in-circuit to perform emulated // arithmetic over the field defined by type parameter [FieldParams]. The -// operations on this type are defined on [Element]. +// operations on this type are defined on [Element]. There is also another type +// [FieldAPI] implementing [frontend.API] which can be used in place of native +// API for existing circuits. // // This is an experimental feature and performing emulated arithmetic in-circuit // is extremely costly. See package doc for more info. @@ -76,17 +77,17 @@ func NewField[T FieldParams](native frontend.API) (*Field[T], error) { // ensure prime is correctly set if f.fParams.IsPrime() { if !f.fParams.Modulus().ProbablyPrime(20) { - return nil, errors.New("invalid parametrization: modulus is not prime") + return nil, fmt.Errorf("invalid parametrization: modulus is not prime") } } if f.fParams.BitsPerLimb() < 3 { // even three is way too small, but it should probably work. - return nil, errors.New("nbBits must be at least 3") + return nil, fmt.Errorf("nbBits must be at least 3") } if f.fParams.Modulus().Cmp(big.NewInt(1)) < 1 { - return nil, errors.New("n must be at least 2") + return nil, fmt.Errorf("n must be at least 2") } nbLimbs := (uint(f.fParams.Modulus().BitLen()) + f.fParams.BitsPerLimb() - 1) / f.fParams.BitsPerLimb() @@ -95,7 +96,7 @@ func NewField[T FieldParams](native frontend.API) (*Field[T], error) { } if f.api == nil { - return f, errors.New("missing api") + return f, fmt.Errorf("missing api") } if uint(f.api.Compiler().FieldBitLen()) < 2*f.fParams.BitsPerLimb()+1 { diff --git a/std/math/emulated/field_assert.go b/std/math/emulated/field_assert.go index e33409e4bc..3cac83ea2c 100644 --- a/std/math/emulated/field_assert.go +++ b/std/math/emulated/field_assert.go @@ -108,7 +108,7 @@ func (f *Field[T]) IsZero(a *Element[T]) frontend.Variable { // in this case the result can be either 0 or p (if it is zero). // // so we check that the reduced value limbs are either all zeros or - // correspond to the modulus limbs. + // corrspond to the modulus limbs. ca := f.Reduce(a) p := f.Modulus() diff --git a/std/math/emulated/field_hint.go b/std/math/emulated/field_hint.go index ac47768903..826f33c075 100644 --- a/std/math/emulated/field_hint.go +++ b/std/math/emulated/field_hint.go @@ -1,7 +1,6 @@ package emulated import ( - "errors" "fmt" "math/big" @@ -51,15 +50,15 @@ func UnwrapHintWithNativeInput(nativeInputs, nativeOutputs []*big.Int, nonnative func unwrapHint(isEmulatedInput, isEmulatedOutput bool, nativeInputs, nativeOutputs []*big.Int, nonnativeHint solver.Hint) error { if len(nativeInputs) < 2 { - return errors.New("hint wrapper header is 2 elements") + return fmt.Errorf("hint wrapper header is 2 elements") } if !nativeInputs[0].IsInt64() || !nativeInputs[1].IsInt64() { - return errors.New("header must be castable to int64") + return fmt.Errorf("header must be castable to int64") } nbBits := int(nativeInputs[0].Int64()) nbLimbs := int(nativeInputs[1].Int64()) if len(nativeInputs) < 2+nbLimbs { - return errors.New("hint wrapper header is 2+nbLimbs elements") + return fmt.Errorf("hint wrapper header is 2+nbLimbs elements") } nonnativeMod := new(big.Int) if err := limbs.Recompose(nativeInputs[2:2+nbLimbs], uint(nbBits), nonnativeMod); err != nil { @@ -68,7 +67,7 @@ func unwrapHint(isEmulatedInput, isEmulatedOutput bool, nativeInputs, nativeOutp var nonnativeInputs []*big.Int if isEmulatedInput { if !nativeInputs[2+nbLimbs].IsInt64() { - return errors.New("number of nonnative elements must be castable to int64") + return fmt.Errorf("number of nonnative elements must be castable to int64") } nbInputs := int(nativeInputs[2+nbLimbs].Int64()) readPtr := 3 + nbLimbs @@ -102,7 +101,7 @@ func unwrapHint(isEmulatedInput, isEmulatedOutput bool, nativeInputs, nativeOutp var nonnativeOutputs []*big.Int if isEmulatedOutput { if len(nativeOutputs)%nbLimbs != 0 { - return errors.New("output count doesn't divide limb count") + return fmt.Errorf("output count doesn't divide limb count") } nonnativeOutputs = make([]*big.Int, len(nativeOutputs)/nbLimbs) } else { diff --git a/std/math/emulated/field_mul.go b/std/math/emulated/field_mul.go index 6d7e697eac..1d44483d56 100644 --- a/std/math/emulated/field_mul.go +++ b/std/math/emulated/field_mul.go @@ -1,7 +1,6 @@ package emulated import ( - "errors" "fmt" "math/big" "math/bits" @@ -263,7 +262,7 @@ func (f *Field[T]) evalWithChallenge(a *Element[T], at []frontend.Variable) *Ele return a } -// performDeferredChecks should be deferred to actually perform all the +// performMulChecks should be deferred to actually perform all the // multiplication checks. func (f *Field[T]) performDeferredChecks(api frontend.API) error { // use given api. We are in defer and API may be different to what we have @@ -890,7 +889,7 @@ func (f *Field[T]) polyMvEvalQuoSize(mv *multivariate[T], at []*Element[T]) (quo // handles the input packing and output unpacking. func polyMvHint(mod *big.Int, inputs, outputs []*big.Int) error { if len(inputs) < 7 { - return errors.New("not enough inputs") + return fmt.Errorf("not enough inputs") } var ( nbBits = int(inputs[0].Int64()) @@ -902,7 +901,7 @@ func polyMvHint(mod *big.Int, inputs, outputs []*big.Int) error { nbCarryLimbs = int(inputs[5].Int64()) ) if len(outputs) != nbQuoLimbs+nbRemLimbs+nbCarryLimbs { - return errors.New("output length mismatch") + return fmt.Errorf("output length mismatch") } outPtr := 0 quoLimbs := outputs[outPtr : outPtr+nbQuoLimbs] @@ -944,7 +943,7 @@ func polyMvHint(mod *big.Int, inputs, outputs []*big.Int) error { } } if ptr != len(inputs) { - return errors.New("inputs not exhausted") + return fmt.Errorf("inputs not exhausted") } // recompose the inputs in limb-form to *big.Int form vars := make([]*big.Int, nbVars) diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 1a2205121d..28a84b9a84 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -1,7 +1,6 @@ package emulated import ( - "errors" "fmt" "math/big" @@ -55,15 +54,15 @@ func (f *Field[T]) computeInverseHint(inLimbs []frontend.Variable) (inverseLimbs // InverseHint computes the inverse x^-1 for the input x and stores it in outputs. func InverseHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) < 2 { - return errors.New("input must be at least two elements") + return fmt.Errorf("input must be at least two elements") } nbBits := uint(inputs[0].Uint64()) nbLimbs := int(inputs[1].Int64()) if len(inputs[2:]) < 2*nbLimbs { - return errors.New("inputs missing") + return fmt.Errorf("inputs missing") } if len(outputs) != nbLimbs { - return errors.New("result does not fit into output") + return fmt.Errorf("result does not fit into output") } p := new(big.Int) if err := limbs.Recompose(inputs[2:2+nbLimbs], nbBits, p); err != nil { @@ -74,7 +73,7 @@ func InverseHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return fmt.Errorf("recompose value: %w", err) } if x.ModInverse(x, p) == nil { - return errors.New("input and modulus not relatively primes") + return fmt.Errorf("input and modulus not relatively primes") } if err := limbs.Decompose(x, nbBits, outputs); err != nil { return fmt.Errorf("decompose: %w", err) @@ -102,7 +101,7 @@ func (f *Field[T]) computeDivisionHint(nomLimbs, denomLimbs []frontend.Variable) // outputs. func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) < 3 { - return errors.New("input must be at least three elements") + return fmt.Errorf("input must be at least three elements") } nbBits := uint(inputs[0].Uint64()) nbLimbs := int(inputs[1].Int64()) @@ -111,10 +110,10 @@ func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { // Denominator and order have to be nbLimbs long. nbNomLimbs := int(inputs[3].Int64()) if len(inputs[4:]) != nbLimbs+nbNomLimbs+nbDenomLimbs { - return errors.New("input length mismatch") + return fmt.Errorf("input length mismatch") } if len(outputs) != nbLimbs { - return errors.New("result does not fit into output") + return fmt.Errorf("result does not fit into output") } p := new(big.Int) if err := limbs.Recompose(inputs[4:4+nbLimbs], nbBits, p); err != nil { @@ -130,7 +129,7 @@ func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { } res := new(big.Int).ModInverse(denominator, p) if res == nil { - return errors.New("no modular inverse") + return fmt.Errorf("no modular inverse") } res.Mul(res, nominator) res.Mod(res, p) @@ -144,14 +143,14 @@ func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { func SqrtHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return UnwrapHint(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error { if len(inputs) != 1 { - return errors.New("expecting single input") + return fmt.Errorf("expecting single input") } if len(outputs) != 1 { - return errors.New("expecting single output") + return fmt.Errorf("expecting single output") } res := new(big.Int) if res.ModSqrt(inputs[0], field) == nil { - return errors.New("no square root") + return fmt.Errorf("no square root") } outputs[0].Set(res) return nil diff --git a/std/math/emulated/subtraction_padding.go b/std/math/emulated/subtraction_padding.go index 454827796c..ae4ff8ddc6 100644 --- a/std/math/emulated/subtraction_padding.go +++ b/std/math/emulated/subtraction_padding.go @@ -1,7 +1,6 @@ package emulated import ( - "errors" "fmt" "math/big" @@ -73,17 +72,17 @@ func subPadding(modulus *big.Int, bitsPerLimbs uint, overflow uint, nbLimbs uint // In case of fixed modulus use subPadding instead. func subPaddingHint(mod *big.Int, inputs, outputs []*big.Int) error { if len(inputs) < 4 { - return errors.New("input must be at least four elements") + return fmt.Errorf("input must be at least four elements") } nbLimbs := int(inputs[0].Int64()) bitsPerLimbs := uint(inputs[1].Uint64()) overflow := uint(inputs[2].Uint64()) retLimbs := int(inputs[3].Int64()) if len(inputs[4:]) != nbLimbs { - return errors.New("input length mismatch") + return fmt.Errorf("input length mismatch") } if len(outputs) != retLimbs { - return errors.New("result does not fit into output") + return fmt.Errorf("result does not fit into output") } pLimbs := inputs[4 : 4+nbLimbs] p := new(big.Int) diff --git a/std/math/polynomial/polynomial.go b/std/math/polynomial/polynomial.go index aa763cbe88..59be7084f5 100644 --- a/std/math/polynomial/polynomial.go +++ b/std/math/polynomial/polynomial.go @@ -1,7 +1,6 @@ package polynomial import ( - "errors" "fmt" "math/big" "math/bits" @@ -121,7 +120,7 @@ func (p *Polynomial[FR]) EvalMultilinearMany(at []*emulated.Element[FR], M ...Mu lenM := len(M[0]) for i := range M { if len(M[i]) != lenM { - return nil, errors.New("incompatible multilinear polynomial sizes") + return nil, fmt.Errorf("incompatible multilinear polynomial sizes") } } mlelems := make([][]*emulated.Element[FR], len(M)) @@ -129,11 +128,11 @@ func (p *Polynomial[FR]) EvalMultilinearMany(at []*emulated.Element[FR], M ...Mu mlelems[i] = FromSlice(M[i]) } if bits.OnesCount(uint(lenM)) != 1 { - return nil, errors.New("multilinear polynomial length must be a power of 2") + return nil, fmt.Errorf("multilinear polynomial length must be a power of 2") } nbExpvars := bits.Len(uint(lenM)) - 1 if len(at) != nbExpvars { - return nil, errors.New("incompatible evaluation vector size") + return nil, fmt.Errorf("incompatible evaluation vector size") } split1 := nbExpvars / 2 nbSplit1Elems := 1 << split1 diff --git a/std/math/uints/hints.go b/std/math/uints/hints.go index 6e230ed8cf..58edf9fd51 100644 --- a/std/math/uints/hints.go +++ b/std/math/uints/hints.go @@ -1,7 +1,7 @@ package uints import ( - "errors" + "fmt" "math/big" "github.com/consensys/gnark/constraint/solver" @@ -37,17 +37,17 @@ func orHint(_ *big.Int, inputs, outputs []*big.Int) error { func toBytes(m *big.Int, inputs []*big.Int, outputs []*big.Int) error { if len(inputs) != 2 { - return errors.New("input must be 2 elements") + return fmt.Errorf("input must be 2 elements") } if !inputs[0].IsUint64() { - return errors.New("first input must be uint64") + return fmt.Errorf("first input must be uint64") } nbLimbs := int(inputs[0].Uint64()) if len(outputs) != nbLimbs { - return errors.New("output must be 8 elements") + return fmt.Errorf("output must be 8 elements") } if !inputs[1].IsUint64() { - return errors.New("input must be 64 bits") + return fmt.Errorf("input must be 64 bits") } base := new(big.Int).Lsh(big.NewInt(1), uint(8)) tmp := new(big.Int).Set(inputs[1]) diff --git a/std/multicommit/doc_test.go b/std/multicommit/doc_test.go index b7ed380847..b7860932b3 100644 --- a/std/multicommit/doc_test.go +++ b/std/multicommit/doc_test.go @@ -10,7 +10,7 @@ import ( "github.com/consensys/gnark/std/multicommit" ) -// MultipleCommitmentsCircuit is an example circuit showing usage of multiple +// MultipleCommitmentCircuit is an example circuit showing usage of multiple // independent commitments in-circuit. type MultipleCommitmentsCircuit struct { Secrets [4]frontend.Variable diff --git a/std/signature/ecdsa/ecdsa.go b/std/signature/ecdsa/ecdsa.go index 201a802323..066e6e15a5 100644 --- a/std/signature/ecdsa/ecdsa.go +++ b/std/signature/ecdsa/ecdsa.go @@ -32,8 +32,9 @@ func (pk PublicKey[T, S]) Verify(api frontend.API, params sw_emulated.CurveParam panic(err) } pkpt := sw_emulated.AffinePoint[T](pk) - msInv := scalarApi.Div(msg, &sig.S) - rsInv := scalarApi.Div(&sig.R, &sig.S) + sInv := scalarApi.Inverse(&sig.S) + msInv := scalarApi.MulMod(msg, sInv) + rsInv := scalarApi.MulMod(&sig.R, sInv) // q = [rsInv]pkpt + [msInv]g q := cr.JointScalarMulBase(&pkpt, rsInv, msInv) diff --git a/std/signature/ecdsa/ecdsa_secpr_test.go b/std/signature/ecdsa/ecdsa_secpr_test.go index 55233bc112..139865e48b 100644 --- a/std/signature/ecdsa/ecdsa_secpr_test.go +++ b/std/signature/ecdsa/ecdsa_secpr_test.go @@ -10,10 +10,6 @@ import ( "testing" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" "golang.org/x/crypto/cryptobyte" @@ -113,26 +109,3 @@ func TestEcdsaP384PreHashed(t *testing.T) { assert.NoError(err) } - -var ccsBench constraint.ConstraintSystem - -func BenchmarkCompile(b *testing.B) { - // create an empty cs - var circuit EcdsaCircuit[emulated.P384Fp, emulated.P384Fr] - - var ccs constraint.ConstraintSystem - b.ResetTimer() - for i := 0; i < b.N; i++ { - ccs, _ = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &circuit) - } - b.Log("scs constraints", ccs.GetNbConstraints()) - - b.Run("groth16", func(b *testing.B) { - for i := 0; i < b.N; i++ { - ccsBench, _ = frontend.Compile(ecc.BW6_633.ScalarField(), r1cs.NewBuilder, &circuit) - } - - }) - b.Log("r1cs constraints", ccsBench.GetNbConstraints()) - -} diff --git a/std/sumcheck/sumcheck.go b/std/sumcheck/sumcheck.go index ad96621c96..de3689cbb8 100644 --- a/std/sumcheck/sumcheck.go +++ b/std/sumcheck/sumcheck.go @@ -1,7 +1,7 @@ package sumcheck import ( - "errors" + "fmt" "strconv" "github.com/consensys/gnark/frontend" @@ -87,7 +87,7 @@ func Verify(api frontend.API, claims LazyClaims, proof Proof, transcriptSettings for j := 0; j < claims.VarsNum(); j++ { partialSumPoly := proof.PartialSumPolys[j] //proof.PartialSumPolys(j) if len(partialSumPoly) != claims.Degree(j) { - return errors.New("malformed proof") //Malformed proof + return fmt.Errorf("malformed proof") //Malformed proof } copy(gJ[1:], partialSumPoly) gJ[0] = api.Sub(gJR, partialSumPoly[0]) // Requirement that gⱼ(0) + gⱼ(1) = gⱼ₋₁(r) diff --git a/test/unsafekzg/options.go b/test/unsafekzg/options.go index b4a7323050..120e17079e 100644 --- a/test/unsafekzg/options.go +++ b/test/unsafekzg/options.go @@ -13,7 +13,7 @@ import ( // Option allows changing the behaviour of the unsafe KZG SRS generation. type Option func(*config) error -// WithFSCache enables the filesystem cache and sets the cache directory +// WithCacheDir enables the filesystem cache and sets the cache directory // to ~/.gnark/kzg by default. func WithFSCache() Option { return func(opt *config) error {