From 8ed586e5f1c7791a1135ed9e4486fae53ea80a25 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 8 Mar 2023 03:59:57 +0100 Subject: [PATCH] Refactor: std/algebra (#526) * feat: add BN254 pairing using field emulation * refactor: make methods private * feat: add equality assertion for GT elements * docs: add package documentation and example * refactor: algebra into native (2-chain) and emulated * fix: remove pairing_bn254 * fix: use sw_emulated instead of weierstrass * fix: update path to algebra/native * fix: update path to algebra/native * fix: update path to algebra/native/twistededwards * docs: add documentation to std/algebra packages * style(std/fields_*): separate Fpk ops specific to choice of pairing * style: apply suggested edits --------- Co-authored-by: Ivo Kubjas --- examples/rollup/circuit.go | 2 +- internal/stats/snippet.go | 4 +- std/algebra/doc.go | 14 + std/algebra/emulated/fields_bn254/doc.go | 7 + std/algebra/emulated/fields_bn254/e12.go | 226 +++++ .../emulated/fields_bn254/e12_pairing.go | 96 ++ std/algebra/emulated/fields_bn254/e2.go | 312 +++++++ std/algebra/emulated/fields_bn254/e6.go | 201 +++++ .../sw_bn254}/doc.go | 4 +- .../sw_bn254}/doc_test.go | 20 +- .../sw_bn254}/g1.go | 6 +- .../sw_bn254}/g2.go | 13 +- std/algebra/emulated/sw_bn254/pairing.go | 319 +++++++ .../sw_bn254}/pairing_test.go | 12 +- .../sw_emulated}/doc.go | 8 +- .../sw_emulated}/doc_test.go | 10 +- .../sw_emulated}/params.go | 2 +- .../sw_emulated}/params_compute.go | 2 +- .../sw_emulated}/point.go | 2 +- .../sw_emulated}/point_test.go | 2 +- std/algebra/native/fields_bls12377/doc.go | 9 + .../{ => native}/fields_bls12377/e12.go | 74 -- .../native/fields_bls12377/e12_pairing.go | 77 ++ .../{ => native}/fields_bls12377/e12_test.go | 0 .../{ => native}/fields_bls12377/e2.go | 0 .../{ => native}/fields_bls12377/e2_test.go | 0 .../{ => native}/fields_bls12377/e6.go | 0 .../{ => native}/fields_bls12377/e6_test.go | 0 std/algebra/native/fields_bls24315/doc.go | 10 + .../{ => native}/fields_bls24315/e12.go | 0 .../{ => native}/fields_bls24315/e12_test.go | 0 .../{ => native}/fields_bls24315/e2.go | 0 .../{ => native}/fields_bls24315/e24.go | 72 -- .../native/fields_bls24315/e24_pairing.go | 75 ++ .../{ => native}/fields_bls24315/e24_test.go | 0 .../{ => native}/fields_bls24315/e2_test.go | 0 .../{ => native}/fields_bls24315/e4.go | 0 .../{ => native}/fields_bls24315/e4_test.go | 0 std/algebra/native/sw_bls12377/doc.go | 8 + std/algebra/{ => native}/sw_bls12377/g1.go | 0 .../{ => native}/sw_bls12377/g1_test.go | 0 std/algebra/{ => native}/sw_bls12377/g2.go | 2 +- .../{ => native}/sw_bls12377/g2_test.go | 0 std/algebra/{ => native}/sw_bls12377/inner.go | 0 .../{ => native}/sw_bls12377/inner_compute.go | 0 .../{ => native}/sw_bls12377/pairing.go | 2 +- .../{ => native}/sw_bls12377/pairing_test.go | 2 +- std/algebra/native/sw_bls24315/doc.go | 8 + std/algebra/{ => native}/sw_bls24315/g1.go | 0 .../{ => native}/sw_bls24315/g1_test.go | 0 std/algebra/{ => native}/sw_bls24315/g2.go | 2 +- .../{ => native}/sw_bls24315/g2_test.go | 0 std/algebra/{ => native}/sw_bls24315/inner.go | 0 .../{ => native}/sw_bls24315/inner_compute.go | 0 .../{ => native}/sw_bls24315/pairing.go | 2 +- .../{ => native}/sw_bls24315/pairing_test.go | 2 +- .../{ => native}/twistededwards/curve.go | 0 .../{ => native}/twistededwards/curve_test.go | 0 std/algebra/native/twistededwards/doc.go | 8 + .../{ => native}/twistededwards/point.go | 0 .../twistededwards/scalarmul_glv.go | 0 .../twistededwards/twistededwards.go | 0 std/algebra/pairing_bn254/gt.go | 41 - std/algebra/pairing_bn254/pairing.go | 282 ------ std/algebra/pairing_bn254/tower.go | 833 ------------------ std/algebra/sw_bls12377/doc.go | 18 - std/algebra/sw_bls24315/doc.go | 18 - std/commitments/kzg_bls12377/verifier.go | 4 +- std/commitments/kzg_bls24315/verifier.go | 4 +- std/groth16_bls12377/verifier.go | 4 +- std/groth16_bls12377/verifier_test.go | 2 +- std/groth16_bls24315/verifier.go | 4 +- std/groth16_bls24315/verifier_test.go | 2 +- std/hints.go | 4 +- std/math/emulated/field_test.go | 2 +- std/signature/ecdsa/ecdsa.go | 12 +- std/signature/ecdsa/ecdsa_test.go | 6 +- std/signature/eddsa/eddsa.go | 2 +- std/signature/eddsa/eddsa_test.go | 2 +- 79 files changed, 1443 insertions(+), 1412 deletions(-) create mode 100644 std/algebra/doc.go create mode 100644 std/algebra/emulated/fields_bn254/doc.go create mode 100644 std/algebra/emulated/fields_bn254/e12.go create mode 100644 std/algebra/emulated/fields_bn254/e12_pairing.go create mode 100644 std/algebra/emulated/fields_bn254/e2.go create mode 100644 std/algebra/emulated/fields_bn254/e6.go rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/doc.go (64%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/doc_test.go (81%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/g1.go (66%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/g2.go (70%) create mode 100644 std/algebra/emulated/sw_bn254/pairing.go rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/pairing_test.go (90%) rename std/algebra/{weierstrass => emulated/sw_emulated}/doc.go (83%) rename std/algebra/{weierstrass => emulated/sw_emulated}/doc_test.go (89%) rename std/algebra/{weierstrass => emulated/sw_emulated}/params.go (99%) rename std/algebra/{weierstrass => emulated/sw_emulated}/params_compute.go (98%) rename std/algebra/{weierstrass => emulated/sw_emulated}/point.go (99%) rename std/algebra/{weierstrass => emulated/sw_emulated}/point_test.go (99%) create mode 100644 std/algebra/native/fields_bls12377/doc.go rename std/algebra/{ => native}/fields_bls12377/e12.go (91%) create mode 100644 std/algebra/native/fields_bls12377/e12_pairing.go rename std/algebra/{ => native}/fields_bls12377/e12_test.go (100%) rename std/algebra/{ => native}/fields_bls12377/e2.go (100%) rename std/algebra/{ => native}/fields_bls12377/e2_test.go (100%) rename std/algebra/{ => native}/fields_bls12377/e6.go (100%) rename std/algebra/{ => native}/fields_bls12377/e6_test.go (100%) create mode 100644 std/algebra/native/fields_bls24315/doc.go rename std/algebra/{ => native}/fields_bls24315/e12.go (100%) rename std/algebra/{ => native}/fields_bls24315/e12_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e2.go (100%) rename std/algebra/{ => native}/fields_bls24315/e24.go (92%) create mode 100644 std/algebra/native/fields_bls24315/e24_pairing.go rename std/algebra/{ => native}/fields_bls24315/e24_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e2_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e4.go (100%) rename std/algebra/{ => native}/fields_bls24315/e4_test.go (100%) create mode 100644 std/algebra/native/sw_bls12377/doc.go rename std/algebra/{ => native}/sw_bls12377/g1.go (100%) rename std/algebra/{ => native}/sw_bls12377/g1_test.go (100%) rename std/algebra/{ => native}/sw_bls12377/g2.go (99%) rename std/algebra/{ => native}/sw_bls12377/g2_test.go (100%) rename std/algebra/{ => native}/sw_bls12377/inner.go (100%) rename std/algebra/{ => native}/sw_bls12377/inner_compute.go (100%) rename std/algebra/{ => native}/sw_bls12377/pairing.go (98%) rename std/algebra/{ => native}/sw_bls12377/pairing_test.go (98%) create mode 100644 std/algebra/native/sw_bls24315/doc.go rename std/algebra/{ => native}/sw_bls24315/g1.go (100%) rename std/algebra/{ => native}/sw_bls24315/g1_test.go (100%) rename std/algebra/{ => native}/sw_bls24315/g2.go (99%) rename std/algebra/{ => native}/sw_bls24315/g2_test.go (100%) rename std/algebra/{ => native}/sw_bls24315/inner.go (100%) rename std/algebra/{ => native}/sw_bls24315/inner_compute.go (100%) rename std/algebra/{ => native}/sw_bls24315/pairing.go (98%) rename std/algebra/{ => native}/sw_bls24315/pairing_test.go (98%) rename std/algebra/{ => native}/twistededwards/curve.go (100%) rename std/algebra/{ => native}/twistededwards/curve_test.go (100%) create mode 100644 std/algebra/native/twistededwards/doc.go rename std/algebra/{ => native}/twistededwards/point.go (100%) rename std/algebra/{ => native}/twistededwards/scalarmul_glv.go (100%) rename std/algebra/{ => native}/twistededwards/twistededwards.go (100%) delete mode 100644 std/algebra/pairing_bn254/gt.go delete mode 100644 std/algebra/pairing_bn254/pairing.go delete mode 100644 std/algebra/pairing_bn254/tower.go delete mode 100644 std/algebra/sw_bls12377/doc.go delete mode 100644 std/algebra/sw_bls24315/doc.go diff --git a/examples/rollup/circuit.go b/examples/rollup/circuit.go index 0b3b5000ba..27b47f4fda 100644 --- a/examples/rollup/circuit.go +++ b/examples/rollup/circuit.go @@ -20,7 +20,7 @@ import ( tedwards "github.com/consensys/gnark-crypto/ecc/twistededwards" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/accumulator/merkle" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/signature/eddsa" ) diff --git a/internal/stats/snippet.go b/internal/stats/snippet.go index 1f6ed7764c..a166bb849c 100644 --- a/internal/stats/snippet.go +++ b/internal/stats/snippet.go @@ -7,8 +7,8 @@ import ( "github.com/consensys/gnark" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/sw_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" diff --git a/std/algebra/doc.go b/std/algebra/doc.go new file mode 100644 index 0000000000..18e70aeac5 --- /dev/null +++ b/std/algebra/doc.go @@ -0,0 +1,14 @@ +// Package algebra implements: +// - base finite field 𝔽p arithmetic, +// - extension finite fields arithmetic (𝔽p², 𝔽p⁴, 𝔽p⁶, 𝔽p¹², 𝔽p²⁴), +// - short Weierstrass curve arithmetic over G1 (E/𝔽p) and G2 (Eₜ/𝔽p² or Eₜ/𝔽p⁴) +// - twisted Edwards curve arithmetic +// +// These arithmetic operations are implemented +// - using native field via the 2-chains BLS12-377/BW6-761 and BLS24-315/BW-633 +// (`native/`) or associated twisted Edwards (e.g. Jubjub/BLS12-381) and +// - using nonnative field via field emulation (`emulated/`). This allows to +// use any curve over any (SNARK) field (e.g. secp256k1 curve arithmetic over +// BN254 SNARK field or BN254 pairing over BN254 SNARK field). The drawback +// of this approach is the extreme cost of the operations. +package algebra diff --git a/std/algebra/emulated/fields_bn254/doc.go b/std/algebra/emulated/fields_bn254/doc.go new file mode 100644 index 0000000000..ae94b3c243 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/doc.go @@ -0,0 +1,7 @@ +// Package fields_bn254 implements the fields arithmetic of the Fp12 tower +// used to compute the pairing over the BN254 curve. +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-9-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +package fields_bn254 diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go new file mode 100644 index 0000000000..f8492ee5f0 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -0,0 +1,226 @@ +package fields_bn254 + +type E12 struct { + C0, C1 E6 +} + +type Ext12 struct { + *Ext6 +} + +func NewExt12(baseField *curveF) *Ext12 { + return &Ext12{Ext6: NewExt6(baseField)} +} +func (e Ext12) Conjugate(x *E12) *E12 { + z1 := e.Ext6.Neg(&x.C1) // z.C1.Neg(&z.C1) + return &E12{ // return z + C0: x.C0, + C1: *z1, + } +} + +func (e Ext12) Inverse(x *E12) *E12 { + // var t0, t1, tmp E6 + t0 := e.Ext6.Square(&x.C0) // t0.Square(&x.C0) + t1 := e.Ext6.Square(&x.C1) // t1.Square(&x.C1) + tmp := e.Ext6.MulByNonResidue(t1) // tmp.MulByNonResidue(&t1) + t0 = e.Ext6.Sub(t0, tmp) // t0.Sub(&t0, &tmp) + t1 = e.Ext6.Inverse(t0) // t1.Inverse(&t0) + z0 := e.Ext6.Mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) + z1 := e.Ext6.Mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). + z1 = e.Ext6.Neg(z1) // Neg(&z.C1) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) Mul(x, y *E12) *E12 { + // var a, b, c E6 + a := e.Ext6.Add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) + b := e.Ext6.Add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) + a = e.Ext6.Mul(a, b) // a.Mul(&a, &b) + b = e.Ext6.Mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) + c := e.Ext6.Mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) + z1 := e.Ext6.Sub(a, b) // z.C1.Sub(&a, &b). + z1 = e.Ext6.Sub(z1, c) // Sub(&z.C1, &c) + z0 := e.Ext6.MulByNonResidue(c) // z.C0.MulByNonResidue(&c). + z0 = e.Ext6.Add(z0, b) // Add(&z.C0, &b) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) CyclotomicSquare(x *E12) *E12 { + // var t [9]E2 + t0 := e.Ext2.Square(&x.C1.B1) // t[0].Square(&x.C1.B1) + t1 := e.Ext2.Square(&x.C0.B0) // t[1].Square(&x.C0.B0) + t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). + t6 = e.Ext2.Square(t6) // Square(&t[6]). + t6 = e.Ext2.Sub(t6, t0) // Sub(&t[6], &t[0]). + t6 = e.Ext2.Sub(t6, t1) // Sub(&t[6], &t[1]) + t2 := e.Ext2.Square(&x.C0.B2) // t[2].Square(&x.C0.B2) + t3 := e.Ext2.Square(&x.C1.B0) // t[3].Square(&x.C1.B0) + t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). + t7 = e.Ext2.Square(t7) // Square(&t[7]). + t7 = e.Ext2.Sub(t7, t2) // Sub(&t[7], &t[2]). + t7 = e.Ext2.Sub(t7, t3) // Sub(&t[7], &t[3]) + t4 := e.Ext2.Square(&x.C1.B2) // t[4].Square(&x.C1.B2) + t5 := e.Ext2.Square(&x.C0.B1) // t[5].Square(&x.C0.B1) + t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). + t8 = e.Ext2.Square(t8) // Square(&t[8]). + t8 = e.Ext2.Sub(t8, t4) // Sub(&t[8], &t[4]). + t8 = e.Ext2.Sub(t8, t5) // Sub(&t[8], &t[5]). + t8 = e.Ext2.MulByNonResidue(t8) // MulByNonResidue(&t[8]) + t0 = e.Ext2.MulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). + t0 = e.Ext2.Add(t0, t1) // Add(&t[0], &t[1]) + t2 = e.Ext2.MulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). + t2 = e.Ext2.Add(t2, t3) // Add(&t[2], &t[3]) + t4 = e.Ext2.MulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). + t4 = e.Ext2.Add(t4, t5) // Add(&t[4], &t[5]) + z00 := e.Ext2.Sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). + z00 = e.Ext2.Double(z00) // Double(&z.C0.B0). + z00 = e.Ext2.Add(z00, t0) // Add(&z.C0.B0, &t[0]) + z01 := e.Ext2.Sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). + z01 = e.Ext2.Double(z01) // Double(&z.C0.B1). + z01 = e.Ext2.Add(z01, t2) // Add(&z.C0.B1, &t[2]) + z02 := e.Ext2.Sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). + z02 = e.Ext2.Double(z02) // Double(&z.C0.B2). + z02 = e.Ext2.Add(z02, t4) // Add(&z.C0.B2, &t[4]) + z10 := e.Ext2.Add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). + z10 = e.Ext2.Double(z10) // Double(&z.C1.B0). + z10 = e.Ext2.Add(z10, t8) // Add(&z.C1.B0, &t[8]) + z11 := e.Ext2.Add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). + z11 = e.Ext2.Double(z11) // Double(&z.C1.B1). + z11 = e.Ext2.Add(z11, t6) // Add(&z.C1.B1, &t[6]) + z12 := e.Ext2.Add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). + z12 = e.Ext2.Double(z12) // Double(&z.C1.B2). + z12 = e.Ext2.Add(z12, t7) // Add(&z.C1.B2, &t[7]) + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +func (e Ext12) NCycloSquare(z *E12, n int) *E12 { + for i := 0; i < n; i++ { + z = e.CyclotomicSquare(z) + } + return z +} + +func (e Ext12) Frobenius(x *E12) *E12 { + // var t [6]E2 + t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) + t2 = e.Ext2.MulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) + t3 = e.Ext2.MulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) + t4 = e.Ext2.MulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) + t5 = e.Ext2.MulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e Ext12) FrobeniusSquare(x *E12) *E12 { + z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 + z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) + return &E12{ // return z + C0: E6{B0: *z00, B1: *z01, B2: *z02}, + C1: E6{B0: *z10, B1: *z11, B2: *z12}, + } +} + +func (e Ext12) FrobeniusCube(x *E12) *E12 { + // var t [6]E2 + t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) + t2 = e.Ext2.MulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) + t3 = e.Ext2.MulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) + t4 = e.Ext2.MulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) + t5 = e.Ext2.MulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e Ext12) One() *E12 { + z000 := e.fp.One() + zero := e.fp.Zero() + return &E12{ + 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) Square(x *E12) *E12 { + // var c0, c2, c3 E6 + c0 := e.Ext6.Sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) + c3 := e.Ext6.MulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). + c3 = e.Ext6.Neg(c3) // Neg(&c3). + c3 = e.Ext6.Add(&x.C0, c3) // Add(&x.C0, &c3) + c2 := e.Ext6.Mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) + c0 = e.Ext6.Mul(c0, c3) // c0.Mul(&c0, &c3). + c0 = e.Ext6.Add(c0, c2) // Add(&c0, &c2) + z1 := e.Ext6.double(c2) // z.C1.Double(&c2) + c2 = e.Ext6.MulByNonResidue(c2) // c2.MulByNonResidue(&c2) + z0 := e.Ext6.Add(c0, c2) // z.C0.Add(&c0, &c2) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) AssertIsEqual(x, y *E12) { + e.Ext6.AssertIsEqual(&x.C0, &y.C0) + e.Ext6.AssertIsEqual(&x.C1, &y.C1) +} diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go new file mode 100644 index 0000000000..59de7433e0 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -0,0 +1,96 @@ +package fields_bn254 + +func (e Ext12) Expt(x *E12) *E12 { + // var result, t0, t1, t2, t3, t4, t5, t6 E12 + t3 := e.CyclotomicSquare(x) // t3.CyclotomicSquare(x) + t5 := e.CyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) + result := e.CyclotomicSquare(t5) // result.CyclotomicSquare(&t5) + t0 := e.CyclotomicSquare(result) // t0.CyclotomicSquare(&result) + t2 := e.Mul(x, t0) // t2.Mul(x, &t0) + t0 = e.Mul(t3, t2) // t0.Mul(&t3, &t2) + t1 := e.Mul(x, t0) // t1.Mul(x, &t0) + t4 := e.Mul(result, t2) // t4.Mul(&result, &t2) + t6 := e.CyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) + t1 = e.Mul(t0, t1) // t1.Mul(&t0, &t1) + t0 = e.Mul(t3, t1) // t0.Mul(&t3, &t1) + t6 = e.NCycloSquare(t6, 6) // t6.NCycloSquare(6) + t5 = e.Mul(t5, t6) // t5.Mul(&t5, &t6) + t5 = e.Mul(t4, t5) // t5.Mul(&t4, &t5) + t5 = e.NCycloSquare(t5, 7) // t5.NCycloSquare(7) + t4 = e.Mul(t4, t5) // t4.Mul(&t4, &t5) + t4 = e.NCycloSquare(t4, 8) // t4.NCycloSquare(8) + t4 = e.Mul(t0, t4) // t4.Mul(&t0, &t4) + t3 = e.Mul(t3, t4) // t3.Mul(&t3, &t4) + t3 = e.NCycloSquare(t3, 6) // t3.NCycloSquare(6) + t2 = e.Mul(t2, t3) // t2.Mul(&t2, &t3) + t2 = e.NCycloSquare(t2, 8) // t2.NCycloSquare(8) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.NCycloSquare(t2, 6) // t2.NCycloSquare(6) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.NCycloSquare(t2, 10) // t2.NCycloSquare(10) + t1 = e.Mul(t1, t2) // t1.Mul(&t1, &t2) + t1 = e.NCycloSquare(t1, 6) // t1.NCycloSquare(6) + t0 = e.Mul(t0, t1) // t0.Mul(&t0, &t1) + z := e.Mul(result, t0) // z.Mul(&result, &t0) + return z // return z +} + +func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { + // var a, b, d E6 + a := e.Ext6.MulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) + // b.Set(&z.C1) + b := e.Ext6.MulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) + c0 = e.Ext2.Add(c0, c3) // c0.Add(c0, c3) + d := e.Ext6.Add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) + d = e.Ext6.MulBy01(d, c0, c4) // d.MulBy01(c0, c4) + z1 := e.Add(a, b) // z.C1.Add(&a, &b). + z1 = e.Neg(z1) // Neg(&z.C1). + z1 = e.Add(z1, d) // Add(&z.C1, &d) + z0 := e.MulByNonResidue(b) // z.C0.MulByNonResidue(&b). + z0 = e.Add(z0, a) // Add(&z.C0, &a) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { + // var tmp, x0, x3, x4, x04, x03, x34 E2 + x0 := e.Ext2.Mul(c0, d0) // x0.Mul(c0, d0) + x3 := e.Ext2.Mul(c3, d3) // x3.Mul(c3, d3) + x4 := e.Ext2.Mul(c4, d4) // x4.Mul(c4, d4) + tmp := e.Ext2.Add(c0, c4) // tmp.Add(c0, c4) + x04 := e.Ext2.Add(d0, d4) // x04.Add(d0, d4). + x04 = e.Ext2.Mul(x04, tmp) // Mul(&x04, &tmp). + x04 = e.Ext2.Sub(x04, x0) // Sub(&x04, &x0). + x04 = e.Ext2.Sub(x04, x4) // Sub(&x04, &x4) + tmp = e.Ext2.Add(c0, c3) // tmp.Add(c0, c3) + x03 := e.Ext2.Add(d0, d3) // x03.Add(d0, d3). + x03 = e.Ext2.Mul(x03, tmp) // Mul(&x03, &tmp). + x03 = e.Ext2.Sub(x03, x0) // Sub(&x03, &x0). + x03 = e.Ext2.Sub(x03, x3) // Sub(&x03, &x3) + tmp = e.Ext2.Add(c3, c4) // tmp.Add(c3, c4) + x34 := e.Ext2.Add(d3, d4) // x34.Add(d3, d4). + x34 = e.Ext2.Mul(x34, tmp) // Mul(&x34, &tmp). + x34 = e.Ext2.Sub(x34, x3) // Sub(&x34, &x3). + x34 = e.Ext2.Sub(x34, x4) // Sub(&x34, &x4) + z00 := e.Ext2.MulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). + z00 = e.Ext2.Add(z00, x0) // Add(&z.C0.B0, &x0) + z01 := x3 // z.C0.B1.Set(&x3) + z02 := x34 // z.C0.B2.Set(&x34) + z10 := x03 // z.C1.B0.Set(&x03) + z11 := x04 // z.C1.B1.Set(&x04) + z12 := e.Ext2.Zero() // z.C1.B2.SetZero() + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go new file mode 100644 index 0000000000..8ba71003c7 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -0,0 +1,312 @@ +package fields_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark/std/math/emulated" +) + +type curveF = emulated.Field[emulated.BN254Fp] +type baseEl = emulated.Element[emulated.BN254Fp] + +type E2 struct { + A0, A1 baseEl +} + +type Ext2 struct { + fp *curveF + nonResidues map[int]map[int]*E2 +} + +func NewExt2(baseField *curveF) *Ext2 { + pwrs := map[int]map[int]struct { + A0 string + A1 string + }{ + 0: { + -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, + 1: {"9", "1"}, + }, + 1: { + 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, + 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, + 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, + 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, + 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, + }, + 2: { + 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, + 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, + 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, + 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, + 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, + }, + 3: { + 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, + 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, + 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, + 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, + 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, + }, + } + nonResidues := make(map[int]map[int]*E2) + for pwr, v := range pwrs { + for coeff, v := range v { + el := E2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} + if nonResidues[pwr] == nil { + nonResidues[pwr] = make(map[int]*E2) + } + nonResidues[pwr][coeff] = &el + } + } + return &Ext2{fp: baseField, nonResidues: nonResidues} +} + +// TODO: check where to use Mod and where ModMul. + +func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { + // var yCopy fp.Element + // yCopy.Set(y) + z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) + z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Conjugate(x *E2) *E2 { + z0 := x.A0 // z.A0 = x.A0 + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ // return z + A0: z0, + A1: *z1, + } +} + +func (e Ext2) MulByNonResidueGeneric(x *E2, power, coef int) *E2 { + y := e.nonResidues[power][coef] + z := e.Mul(x, y) + return z +} + +func (e Ext2) MulByNonResidue(x *E2) *E2 { + /* + // below is the direct transliteration of the gnark-crypto code. Now only, + // for simplicity and debugging purposes, we do the non residue operations + // without optimisations. + + nine := big.NewInt(9) + // var a, b fp.Element + a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). + a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) + b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). + b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } // return z + */ + // TODO: inline non-residue Multiplication + return e.MulByNonResidueGeneric(x, 0, 1) +} + +func (e Ext2) MulByNonResidueInv(x *E2) *E2 { + // TODO: to optimise with constant non-residue inverse + /* + // from gnark-crypto + // z.Mul(x, &nonResInverse) + // return z + */ + return e.MulByNonResidueGeneric(x, 0, -1) +} + +func (e Ext2) MulByNonResidue1Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 1) +} + +func (e Ext2) MulByNonResidue1Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 2) +} + +func (e Ext2) MulByNonResidue1Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 3) +} + +func (e Ext2) MulByNonResidue1Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 4) +} + +func (e Ext2) MulByNonResidue1Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 5) +} + +func (e Ext2) MulByNonResidue2Power1(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 1) +} +func (e Ext2) MulByNonResidue2Power2(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 2) +} + +func (e Ext2) MulByNonResidue2Power3(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 3) +} + +func (e Ext2) MulByNonResidue2Power4(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 4) +} + +func (e Ext2) MulByNonResidue2Power5(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 5) +} + +func (e Ext2) MulByNonResidue3Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 1) +} + +func (e Ext2) MulByNonResidue3Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 2) +} + +func (e Ext2) MulByNonResidue3Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 3) +} + +func (e Ext2) MulByNonResidue3Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 4) +} + +func (e Ext2) MulByNonResidue3Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 5) +} + +func (e Ext2) Mul(x, y *E2) *E2 { + // var a, b, c fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) + c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) + z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). + z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) + z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Add(x, y *E2) *E2 { + z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) + z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Sub(x, y *E2) *E2 { + z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) + z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Neg(x *E2) *E2 { + z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) One() *E2 { + z0 := e.fp.One() // z.A0.SetOne() + z1 := e.fp.Zero() // z.A1.SetZero() + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Zero() *E2 { + z0 := e.fp.Zero() + z1 := e.fp.Zero() + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Square(x *E2) *E2 { + // var a, b fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). + b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } +} + +func (e Ext2) Double(x *E2) *E2 { + two := big.NewInt(2) + z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) + z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Halve(x *E2) *E2 { + // I'm trying to avoid hard-coding modulus here in case want to make generic + // for different curves. + // TODO: if implemented Half in field emulation, then replace with it. + one := e.fp.One() + two := e.fp.MulConst(one, big.NewInt(2)) + z0 := e.fp.Div(&x.A0, two) + z1 := e.fp.Div(&x.A1, two) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) MulBybTwistCurveCoeff(x *E2) *E2 { + // var res E2 + res := e.MulByNonResidueInv(x) // res.MulByNonResidueInv(x) + z := e.Double(res) // z.Double(&res). + z = e.Add(z, res) // Add(&res, z) + return z // return z +} + +func (e Ext2) Inverse(x *E2) *E2 { + // var t0, t1 fp.Element + t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) + t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) + t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) + t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) + z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) + z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). + z1 = e.fp.Neg(z1) // Neg(&z.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) AssertIsEqual(x, y *E2) { + e.fp.AssertIsEqual(&x.A0, &y.A0) + e.fp.AssertIsEqual(&x.A1, &y.A1) +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go new file mode 100644 index 0000000000..a07d04d015 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -0,0 +1,201 @@ +package fields_bn254 + +type E6 struct { + B0, B1, B2 E2 +} + +type Ext6 struct { + *Ext2 +} + +func NewExt6(baseField *curveF) *Ext6 { + return &Ext6{Ext2: NewExt2(baseField)} +} + +func (e Ext6) Add(x, y *E6) *E6 { + z0 := e.Ext2.Add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) + z1 := e.Ext2.Add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) + z2 := e.Ext2.Add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Neg(x *E6) *E6 { + z0 := e.Ext2.Neg(&x.B0) // z.B0.Neg(&x.B0) + z1 := e.Ext2.Neg(&x.B1) // z.B1.Neg(&x.B1) + z2 := e.Ext2.Neg(&x.B2) // z.B2.Neg(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Sub(x, y *E6) *E6 { + z0 := e.Ext2.Sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) + z1 := e.Ext2.Sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) + z2 := e.Ext2.Sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Mul(x, y *E6) *E6 { + // var t0, t1, t2, c0, c1, c2, tmp E2 + t0 := e.Ext2.Mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) + t1 := e.Ext2.Mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) + t2 := e.Ext2.Mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) + c0 := e.Ext2.Add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) + c0 = e.Ext2.Mul(c0, tmp) // c0.Mul(&c0, &tmp). + c0 = e.Ext2.Sub(c0, t1) // Sub(&c0, &t1). + c0 = e.Ext2.Sub(c0, t2) // Sub(&c0, &t2). + c0 = e.Ext2.MulByNonResidue(c0) // MulByNonResidue(&c0). + c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.Ext2.Add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) + tmp = e.Ext2.Add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) + c1 = e.Ext2.Mul(c1, tmp) // c1.Mul(&c1, &tmp). + c1 = e.Ext2.Sub(c1, t0) // Sub(&c1, &t0). + c1 = e.Ext2.Sub(c1, t1) // Sub(&c1, &t1) + tmp = e.Ext2.MulByNonResidue(t2) // tmp.MulByNonResidue(&t2) + c1 = e.Ext2.Add(c1, tmp) // c1.Add(&c1, &tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) + c2 := e.Ext2.Add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). + c2 = e.Ext2.Mul(c2, tmp) // Mul(&c2, &tmp). + c2 = e.Ext2.Sub(c2, t0) // Sub(&c2, &t0). + c2 = e.Ext2.Sub(c2, t2) // Sub(&c2, &t2). + c2 = e.Ext2.Add(c2, t1) // Add(&c2, &t1) + return &E6{ + B0: *c0, // z.B0.Set(&c0) + B1: *c1, // z.B1.Set(&c1) + B2: *c2, // z.B2.Set(&c2) + } // return z +} + +func (e Ext6) double(x *E6) *E6 { + z0 := e.Ext2.Double(&x.B0) // z.B0.Double(&x.B0) + z1 := e.Ext2.Double(&x.B1) // z.B1.Double(&x.B1) + z2 := e.Ext2.Double(&x.B2) // z.B2.Double(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Square(x *E6) *E6 { + // var c4, c5, c1, c2, c3, c0 E2 + c4 := e.Ext2.Mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). + c4 = e.Ext2.Double(c4) // Double(&c4) + c5 := e.Ext2.Square(&x.B2) // c5.Square(&x.B2) + c1 := e.Ext2.MulByNonResidue(c5) // c1.MulByNonResidue(&c5). + c1 = e.Ext2.Add(c1, c4) // Add(&c1, &c4) + c2 := e.Ext2.Sub(c4, c5) // c2.Sub(&c4, &c5) + c3 := e.Ext2.Square(&x.B0) // c3.Square(&x.B0) + c4 = e.Ext2.Sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). + c4 = e.Ext2.Add(c4, &x.B2) // Add(&c4, &x.B2) + c5 = e.Ext2.Mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). + c5 = e.Ext2.Double(c5) // Double(&c5) + c4 = e.Ext2.Square(c4) // c4.Square(&c4) + c0 := e.Ext2.MulByNonResidue(c5) // c0.MulByNonResidue(&c5). + c0 = e.Ext2.Add(c0, c3) // Add(&c0, &c3) + z2 := e.Ext2.Add(c2, c4) // z.B2.Add(&c2, &c4). + z2 = e.Ext2.Add(z2, c5) // Add(&z.B2, &c5). + z2 = e.Ext2.Sub(z2, c3) // Sub(&z.B2, &c3) + z0 := c0 // z.B0.Set(&c0) + z1 := c1 // z.B1.Set(&c1) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Inverse(x *E6) *E6 { + // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0 := e.Ext2.Square(&x.B0) // t0.Square(&x.B0) + t1 := e.Ext2.Square(&x.B1) // t1.Square(&x.B1) + t2 := e.Ext2.Square(&x.B2) // t2.Square(&x.B2) + t3 := e.Ext2.Mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) + t4 := e.Ext2.Mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) + t5 := e.Ext2.Mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) + c0 := e.Ext2.MulByNonResidue(t5) // c0.MulByNonResidue(&t5). + c0 = e.Ext2.Neg(c0) // Neg(&c0). + c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.Ext2.MulByNonResidue(t2) // c1.MulByNonResidue(&t2). + c1 = e.Ext2.Sub(c1, t3) // Sub(&c1, &t3) + c2 := e.Ext2.Sub(t1, t4) // c2.Sub(&t1, &t4) + t6 := e.Ext2.Mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) + d1 := e.Ext2.Mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) + d2 := e.Ext2.Mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) + d1 = e.Ext2.Add(d1, d2) // d1.Add(&d1, &d2). + d1 = e.Ext2.MulByNonResidue(d1) // MulByNonResidue(&d1) + t6 = e.Ext2.Add(t6, d1) // t6.Add(&t6, &d1) + t6 = e.Ext2.Inverse(t6) // t6.Inverse(&t6) + z0 := e.Ext2.Mul(c0, t6) // z.B0.Mul(&c0, &t6) + z1 := e.Ext2.Mul(c1, t6) // z.B1.Mul(&c1, &t6) + z2 := e.Ext2.Mul(c2, t6) // z.B2.Mul(&c2, &t6) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} +func (e Ext6) MulByE2(x *E6, y *E2) *E6 { + // var yCopy E2 + // yCopy.Set(y) + z0 := e.Ext2.Mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) + z1 := e.Ext2.Mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) + z2 := e.Ext2.Mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + // var a, b, tmp, t0, t1, t2 E2 + a := e.Ext2.Mul(&z.B0, c0) // a.Mul(&z.B0, c0) + b := e.Ext2.Mul(&z.B1, c1) // b.Mul(&z.B1, c1) + tmp := e.Ext2.Add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) // t0.Mul(c1, &tmp) + t0 = e.Ext2.Sub(t0, b) // t0.Sub(&t0, &b) + t0 = e.Ext2.MulByNonResidue(t0) // t0.MulByNonResidue(&t0) + t0 = e.Ext2.Add(t0, a) // t0.Add(&t0, &a) + tmp = e.Ext2.Add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) // t2.Mul(c0, &tmp) + t2 = e.Ext2.Sub(t2, a) // t2.Sub(&t2, &a) + t2 = e.Ext2.Add(t2, b) // t2.Add(&t2, &b) + t1 := e.Ext2.Add(c0, c1) // t1.Add(c0, c1) + tmp = e.Ext2.Add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) + t1 = e.Ext2.Mul(t1, tmp) // t1.Mul(&t1, &tmp) + t1 = e.Ext2.Sub(t1, a) // t1.Sub(&t1, &a) + t1 = e.Ext2.Sub(t1, b) // t1.Sub(&t1, &b) + return &E6{ + B0: *t0, // z.B0.Set(&t0) + B1: *t1, // z.B1.Set(&t1) + B2: *t2, // z.B2.Set(&t2) + } // return z +} + +func (e Ext6) MulByNonResidue(x *E6) *E6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z0 = e.Ext2.MulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) + return &E6{ // return z + 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) +} diff --git a/std/algebra/pairing_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go similarity index 64% rename from std/algebra/pairing_bn254/doc.go rename to std/algebra/emulated/sw_bn254/doc.go index 5f04a7dd72..60bfca6876 100644 --- a/std/algebra/pairing_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,7 +1,7 @@ -// Package pairing_bn254 implements pairing over BN254 curve. +// Package sw_bn254 implements G1 and G2 arithmetics and pairing computation over BN254 curve. // // The implementation follows very closely the implementation of its out-circuit // counterpart in [gnark-crypto]. // // [gnark-crypto]: https://github.com/ConsenSys/gnark-crypto/tree/master/ecc/bn254 -package pairing_bn254 +package sw_bn254 diff --git a/std/algebra/pairing_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go similarity index 81% rename from std/algebra/pairing_bn254/doc_test.go rename to std/algebra/emulated/sw_bn254/doc_test.go index 8481c45361..db095a0210 100644 --- a/std/algebra/pairing_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -1,4 +1,4 @@ -package pairing_bn254_test +package sw_bn254_test import ( "crypto/rand" @@ -9,21 +9,21 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/pairing_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" ) type PairCircuit struct { - InG1 pairing_bn254.G1Affine - InG2 pairing_bn254.G2Affine - Res pairing_bn254.GTEl + InG1 sw_bn254.G1Affine + InG2 sw_bn254.G2Affine + Res sw_bn254.GTEl } func (c *PairCircuit) Define(api frontend.API) error { - pairing, err := pairing_bn254.NewPairing(api) + pairing, err := sw_bn254.NewPairing(api) if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*pairing_bn254.G1Affine{&c.InG1}, []*pairing_bn254.G2Affine{&c.InG2}) + res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -42,9 +42,9 @@ func ExamplePairing() { } circuit := PairCircuit{} witness := PairCircuit{ - InG1: pairing_bn254.NewG1Affine(p), - InG2: pairing_bn254.NewG2Affine(q), - Res: pairing_bn254.NewGTEl(res), + InG1: sw_bn254.NewG1Affine(p), + InG2: sw_bn254.NewG2Affine(q), + Res: sw_bn254.NewGTEl(res), } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { diff --git a/std/algebra/pairing_bn254/g1.go b/std/algebra/emulated/sw_bn254/g1.go similarity index 66% rename from std/algebra/pairing_bn254/g1.go rename to std/algebra/emulated/sw_bn254/g1.go index 4f1fa5d2c4..69ce54898c 100644 --- a/std/algebra/pairing_bn254/g1.go +++ b/std/algebra/emulated/sw_bn254/g1.go @@ -1,12 +1,12 @@ -package pairing_bn254 +package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) -type G1Affine = weierstrass.AffinePoint[emulated.BN254Fp] +type G1Affine = sw_emulated.AffinePoint[emulated.BN254Fp] func NewG1Affine(v bn254.G1Affine) G1Affine { return G1Affine{ diff --git a/std/algebra/pairing_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go similarity index 70% rename from std/algebra/pairing_bn254/g2.go rename to std/algebra/emulated/sw_bn254/g2.go index ace3b00efe..1ba7d154a6 100644 --- a/std/algebra/pairing_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -1,29 +1,30 @@ -package pairing_bn254 +package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) type G2Affine struct { - X, Y e2 + X, Y fields_bn254.E2 } type g2Jacobian struct { - X, Y, Z e2 + X, Y, Z fields_bn254.E2 } type g2Projective struct { - X, Y, Z e2 + X, Y, Z fields_bn254.E2 } func NewG2Affine(v bn254.G2Affine) G2Affine { return G2Affine{ - X: e2{ + X: fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1), }, - Y: e2{ + Y: fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1), }, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go new file mode 100644 index 0000000000..8aceb63f2e --- /dev/null +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -0,0 +1,319 @@ +package sw_bn254 + +import ( + "fmt" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type Pairing struct { + *fields_bn254.Ext12 +} + +type GTEl = fields_bn254.E12 + +func NewGTEl(v bn254.GT) GTEl { + return GTEl{ + C0: fields_bn254.E6{ + B0: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), + }, + B1: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), + }, + B2: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), + }, + }, + C1: fields_bn254.E6{ + B0: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), + }, + B1: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), + }, + B2: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), + }, + }, + } +} + +func NewPairing(api frontend.API) (*Pairing, error) { + ba, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + return &Pairing{ + Ext12: fields_bn254.NewExt12(ba), + }, nil +} + +func (pr Pairing) DoubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { + // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A := pr.Ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) + A = pr.Ext2.Halve(A) // A.Halve() + B := pr.Ext2.Square(&p.Y) // B.Square(&p.y) + C := pr.Ext2.Square(&p.Z) // C.Square(&p.z) + D := pr.Ext2.Double(C) // D.Double(&C). + D = pr.Ext2.Add(D, C) // Add(&D, &C) + E := pr.Ext2.MulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) + F := pr.Ext2.Double(E) // F.Double(&E). + F = pr.Ext2.Add(F, E) // Add(&F, &E) + G := pr.Ext2.Add(B, F) // G.Add(&B, &F) + G = pr.Ext2.Halve(G) // G.Halve() + H := pr.Ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). + H = pr.Ext2.Square(H) // Square(&H) + t1 := pr.Ext2.Add(B, C) // t1.Add(&B, &C) + H = pr.Ext2.Sub(H, t1) // H.Sub(&H, &t1) + I := pr.Ext2.Sub(E, B) // I.Sub(&E, &B) + J := pr.Ext2.Square(&p.X) // J.Square(&p.x) + EE := pr.Ext2.Square(E) // EE.Square(&E) + K := pr.Ext2.Double(EE) // K.Double(&EE). + K = pr.Ext2.Add(K, EE) // Add(&K, &EE) + px := pr.Ext2.Sub(B, F) // p.x.Sub(&B, &F). + px = pr.Ext2.Mul(px, A) // Mul(&p.x, &A) + py := pr.Ext2.Square(G) // p.y.Square(&G). + py = pr.Ext2.Sub(py, K) // Sub(&p.y, &K) + pz := pr.Ext2.Mul(B, H) // p.z.Mul(&B, &H) + ev0 := pr.Ext2.Neg(H) // evaluations.r0.Neg(&H) + ev1 := pr.Ext2.Double(J) // evaluations.r1.Double(&J). + ev1 = pr.Ext2.Add(ev1, J) // Add(&evaluations.r1, &J) + ev2 := I // evaluations.r2.Set(&I) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, + &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { + // TODO: check point at infinity? We do not filter them in the Miller Loop neither. + // if Q.X.IsZero() && Q.Y.IsZero() { + // p.z.SetZero() + // p.x.SetOne() + // p.y.SetOne() + // return p + // } + pz := pr.Ext2.One() // p.z.SetOne() + px := &Q.X // p.x.Set(&Q.X) + py := &Q.Y // p.y.Set(&Q.Y) + return &g2Projective{ // return p + X: *px, + Y: *py, + Z: *pz, + } +} + +func (pr Pairing) NegAffine(a *G2Affine) *G2Affine { + px := &a.X // p.X = a.X + py := pr.Ext2.Neg(&a.Y) // p.Y.Neg(&a.Y) + return &G2Affine{ // return p + X: *px, + Y: *py, + } +} + +func (pr Pairing) AddStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { + // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1 := pr.Ext2.Mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) + O := pr.Ext2.Sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) + X2Z1 := pr.Ext2.Mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) + L := pr.Ext2.Sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) + C := pr.Ext2.Square(O) // C.Square(&O) + D := pr.Ext2.Square(L) // D.Square(&L) + E := pr.Ext2.Mul(L, D) // E.Mul(&L, &D) + F := pr.Ext2.Mul(&p.Z, C) // F.Mul(&p.z, &C) + G := pr.Ext2.Mul(&p.X, D) // G.Mul(&p.x, &D) + t0 := pr.Ext2.Double(G) // t0.Double(&G) + H := pr.Ext2.Add(E, F) // H.Add(&E, &F). + H = pr.Ext2.Sub(H, t0) // Sub(&H, &t0) + t1 := pr.Ext2.Mul(&p.Y, E) // t1.Mul(&p.y, &E) + px := pr.Ext2.Mul(L, H) // p.x.Mul(&L, &H) + py := pr.Ext2.Sub(G, H) // p.y.Sub(&G, &H). + py = pr.Ext2.Mul(py, O) // Mul(&p.y, &O). + py = pr.Ext2.Sub(py, t1) // Sub(&p.y, &t1) + pz := pr.Ext2.Mul(E, &p.Z) // p.z.Mul(&E, &p.z) + t2 := pr.Ext2.Mul(L, &a.Y) // t2.Mul(&L, &a.Y) + J := pr.Ext2.Mul(&a.X, O) // J.Mul(&a.X, &O). + J = pr.Ext2.Sub(J, t2) // Sub(&J, &t2) + ev0 := L // evaluations.r0.Set(&L) + ev1 := pr.Ext2.Neg(O) // evaluations.r1.Neg(&O) + ev2 := J // evaluations.r2.Set(&J) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +type lineEvaluation struct { + r0 fields_bn254.E2 + r1 fields_bn254.E2 + r2 fields_bn254.E2 +} + +var loopCounter = [66]int8{ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, + 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, + 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, + -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, + -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, +} + +func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { + n := len(p) + if n == 0 || n != len(q) { + return nil, fmt.Errorf("invalid inputs sizes") + } + + // TODO: we have omitted filtering for infinity points. + + // projective points for Q + qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) + qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) + for k := 0; k < n; k++ { + qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) + qNeg[k] = pr.NegAffine(q[k]) // qNeg[k].Neg(&q[k]) + } + + var l, l0 *lineEvaluation + result := pr.Ext12.One() // var tmp, result GTEl + + // i == len(loopCounter) - 2 + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + + for i := len(loopCounter) - 3; i >= 0; i-- { + result = pr.Ext12.Square(result) // result.Square(&result) + + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + + if loopCounter[i] == 1 { + qProj[k], l0 = pr.AddStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } else if loopCounter[i] == -1 { + qProj[k], l0 = pr.AddStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) //result.Mul(&result, &tmp) + } else { + result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + } + } + + Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine + for k := 0; k < n; k++ { + //Q1 = π(Q) + // TODO(ivokub): define phi(Q) in G2 instead of doing manually? + Q1.X = *pr.Ext12.Ext2.Conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.Ext12.Ext2.Conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + + // Q2 = -π²(Q) + Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidufields_bn254.E2Power2(&q[k].X) + Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) + Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) + + qProj[k], l0 = pr.AddStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + + qProj[k], l = pr.AddStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } + + return result, nil +} + +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + // var result GT + // result.Set(z) + var t [4]*GTEl // var t [4]GT + + // easy part + t[0] = pr.Ext12.Conjugate(e) // t[0].Conjugate(&result) + result := pr.Ext12.Inverse(e) // result.Inverse(&result) + t[0] = pr.Ext12.Mul(t[0], result) // t[0].Mul(&t[0], &result) + result = pr.Ext12.FrobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). + result = pr.Ext12.Mul(result, t[0]) // Mul(&result, &t[0]) + + //hard part + t[0] = pr.Ext12.Expt(result) // t[0].Expt(&result). + t[0] = pr.Ext12.Conjugate(t[0]) // Conjugate(&t[0]) + t[0] = pr.Ext12.CyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) + t[2] = pr.Ext12.Expt(t[0]) // t[2].Expt(&t[0]). + t[2] = pr.Ext12.Conjugate(t[2]) // Conjugate(&t[2]) + t[1] = pr.Ext12.CyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[2] = pr.Ext12.Mul(t[2], result) // t[2].Mul(&t[2], &result) + t[1] = pr.Ext12.Expt(t[2]) // t[1].Expt(&t[2]). + t[1] = pr.Ext12.CyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). + t[1] = pr.Ext12.Mul(t[1], t[2]) // Mul(&t[1], &t[2]). + t[1] = pr.Ext12.Conjugate(t[1]) // Conjugate(&t[1]) + t[3] = pr.Ext12.Conjugate(t[1]) // t[3].Conjugate(&t[1]) + t[1] = pr.Ext12.CyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) + t[1] = pr.Ext12.Mul(t[1], result) // t[1].Mul(&t[1], &result) + t[1] = pr.Ext12.Conjugate(t[1]) // t[1].Conjugate(&t[1]) + t[1] = pr.Ext12.Mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) + t[0] = pr.Ext12.Mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[3] = pr.Ext12.FrobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) + t[2] = pr.Ext12.Mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) + t[3] = pr.Ext12.Conjugate(result) // t[3].Conjugate(&result) + t[3] = pr.Ext12.Mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) + t[1] = pr.Ext12.FrobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[1] = pr.Ext12.Frobenius(t[0]) // t[1].Frobenius(&t[0]) + t[1] = pr.Ext12.Mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) + // result.Set(&t[1]) + return t[1] // return result +} + +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) + } + res = pr.FinalExponentiation(res) + return res, nil +} + +func (pr Pairing) AssertIsEqual(x, y *GTEl) { + pr.Ext12.AssertIsEqual(x, y) +} diff --git a/std/algebra/pairing_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go similarity index 90% rename from std/algebra/pairing_bn254/pairing_test.go rename to std/algebra/emulated/sw_bn254/pairing_test.go index 30fddc1829..5de8a3bc89 100644 --- a/std/algebra/pairing_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -1,4 +1,4 @@ -package pairing_bn254 +package sw_bn254 import ( "crypto/rand" @@ -8,8 +8,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" - "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -28,7 +26,7 @@ func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { } type MillerLoopCircuit struct { - InG1 weierstrass.AffinePoint[emulated.BN254Fp] + InG1 G1Affine InG2 G2Affine Res GTEl } @@ -42,7 +40,7 @@ func (c *MillerLoopCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.AssertIsEqual(res, &c.Res) return nil } @@ -71,7 +69,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { return fmt.Errorf("new pairing: %w", err) } res := pairing.FinalExponentiation(&c.InGt) - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.AssertIsEqual(res, &c.Res) return nil } @@ -103,7 +101,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.AssertIsEqual(res, &c.Res) return nil } diff --git a/std/algebra/weierstrass/doc.go b/std/algebra/emulated/sw_emulated/doc.go similarity index 83% rename from std/algebra/weierstrass/doc.go rename to std/algebra/emulated/sw_emulated/doc.go index dfcb647fe5..5ff58f9467 100644 --- a/std/algebra/weierstrass/doc.go +++ b/std/algebra/emulated/sw_emulated/doc.go @@ -1,5 +1,5 @@ /* -Package weierstrass implements elliptic curve group operations in (short) +Package sw_emulated implements elliptic curve group operations in (short) Weierstrass form. The elliptic curve is the set of points (X,Y) satisfying the equation: @@ -22,9 +22,9 @@ field. For now, we only have a single curve defined on every base field, but this may change in the future with the addition of additional curves. This package uses field emulation (unlike packages -[github.com/consensys/gnark/std/algebra/sw_bls12377] and -[github.com/consensys/gnark/std/algebra/sw_bls24315], which use 2-chains). This +[github.com/consensys/gnark/std/algebra/native/sw_bls12377] and +[github.com/consensys/gnark/std/algebra/native/sw_bls24315], which use 2-chains). This allows to use any curve over any native (SNARK) field. The drawback of this approach is the extreme cost of the operations. */ -package weierstrass +package sw_emulated diff --git a/std/algebra/weierstrass/doc_test.go b/std/algebra/emulated/sw_emulated/doc_test.go similarity index 89% rename from std/algebra/weierstrass/doc_test.go rename to std/algebra/emulated/sw_emulated/doc_test.go index cfa81a1fe0..bf939bfd3d 100644 --- a/std/algebra/weierstrass/doc_test.go +++ b/std/algebra/emulated/sw_emulated/doc_test.go @@ -1,4 +1,4 @@ -package weierstrass_test +package sw_emulated_test import ( "fmt" @@ -9,16 +9,16 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) type ExampleCurveCircuit[Base, Scalar emulated.FieldParams] struct { - Res weierstrass.AffinePoint[Base] + Res sw_emulated.AffinePoint[Base] } func (c *ExampleCurveCircuit[B, S]) Define(api frontend.API) error { - curve, err := weierstrass.New[B, S](api, weierstrass.GetCurveParams[emulated.BN254Fp]()) + curve, err := sw_emulated.New[B, S](api, sw_emulated.GetCurveParams[emulated.BN254Fp]()) if err != nil { panic("initalize new curve") } @@ -41,7 +41,7 @@ func ExampleCurve() { circuit := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - Res: weierstrass.AffinePoint[emulated.Secp256k1Fp]{ + Res: sw_emulated.AffinePoint[emulated.Secp256k1Fp]{ X: emulated.ValueOf[emulated.Secp256k1Fp](g.X), Y: emulated.ValueOf[emulated.Secp256k1Fp](g.Y), }, diff --git a/std/algebra/weierstrass/params.go b/std/algebra/emulated/sw_emulated/params.go similarity index 99% rename from std/algebra/weierstrass/params.go rename to std/algebra/emulated/sw_emulated/params.go index 32cd8812e8..b9f00ec707 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/emulated/sw_emulated/params.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/weierstrass/params_compute.go b/std/algebra/emulated/sw_emulated/params_compute.go similarity index 98% rename from std/algebra/weierstrass/params_compute.go rename to std/algebra/emulated/sw_emulated/params_compute.go index 0edf3f78b4..fbdabea300 100644 --- a/std/algebra/weierstrass/params_compute.go +++ b/std/algebra/emulated/sw_emulated/params_compute.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/weierstrass/point.go b/std/algebra/emulated/sw_emulated/point.go similarity index 99% rename from std/algebra/weierstrass/point.go rename to std/algebra/emulated/sw_emulated/point.go index c40f45a0cd..414b011de2 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "fmt" diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go similarity index 99% rename from std/algebra/weierstrass/point_test.go rename to std/algebra/emulated/sw_emulated/point_test.go index 86a9295e7c..6703970c1a 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/native/fields_bls12377/doc.go b/std/algebra/native/fields_bls12377/doc.go new file mode 100644 index 0000000000..69308f8280 --- /dev/null +++ b/std/algebra/native/fields_bls12377/doc.go @@ -0,0 +1,9 @@ +// Package fields_bls12377 implements the fields arithmetic of the Fp12 tower +// used to compute the pairing over the BLS12-377 curve. +// +// 𝔽p²[u] = 𝔽p/u²+5 +// 𝔽p⁶[v] = 𝔽p²/v³-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +// +// Reference: https://eprint.iacr.org/2022/1162 +package fields_bls12377 diff --git a/std/algebra/fields_bls12377/e12.go b/std/algebra/native/fields_bls12377/e12.go similarity index 91% rename from std/algebra/fields_bls12377/e12.go rename to std/algebra/native/fields_bls12377/e12.go index 9ae3ff02c7..f51413348b 100644 --- a/std/algebra/fields_bls12377/e12.go +++ b/std/algebra/native/fields_bls12377/e12.go @@ -345,51 +345,6 @@ func (e *E12) Conjugate(api frontend.API, e1 E12) *E12 { return e } -// MulBy034 multiplication by sparse element -func (e *E12) MulBy034(api frontend.API, c3, c4 E2) *E12 { - - var d E6 - - a := e.C0 - b := e.C1 - - b.MulBy01(api, c3, c4) - - c3.Add(api, E2{A0: 1, A1: 0}, c3) - d.Add(api, e.C0, e.C1) - d.MulBy01(api, c3, c4) - - e.C1.Add(api, a, b).Neg(api, e.C1).Add(api, e.C1, d) - e.C0.MulByNonResidue(api, b).Add(api, e.C0, a) - - return e -} - -// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) -func (e *E12) Mul034By034(api frontend.API, d3, d4, c3, c4 E2) *E12 { - var one, tmp, x3, x4, x04, x03, x34 E2 - one.SetOne() - x3.Mul(api, c3, d3) - x4.Mul(api, c4, d4) - x04.Add(api, c4, d4) - x03.Add(api, c3, d3) - tmp.Add(api, c3, c4) - x34.Add(api, d3, d4). - Mul(api, x34, tmp). - Sub(api, x34, x3). - Sub(api, x34, x4) - - e.C0.B0.MulByNonResidue(api, x4). - Add(api, e.C0.B0, one) - e.C0.B1 = x3 - e.C0.B2 = x34 - e.C1.B0 = x03 - e.C1.B1 = x04 - e.C1.B2.SetZero() - - return e -} - // Frobenius applies frob to an fp12 elmt func (e *E12) Frobenius(api frontend.API, e1 E12) *E12 { @@ -588,35 +543,6 @@ func (e *E12) nSquareCompressed(api frontend.API, n int) { } } -// Expt compute e1**exponent, where the exponent is hardcoded -// This function is only used for the final expo of the pairing for bls12377, so the exponent is supposed to be hardcoded -// and on 64 bits. -func (e *E12) Expt(api frontend.API, e1 E12, exponent uint64) *E12 { - - res := e1 - - res.nSquareCompressed(api, 5) - res.Decompress(api, res) - res.Mul(api, res, e1) - x33 := res - res.nSquareCompressed(api, 7) - res.Decompress(api, res) - res.Mul(api, res, x33) - res.nSquareCompressed(api, 4) - res.Decompress(api, res) - res.Mul(api, res, e1) - res.CyclotomicSquare(api, res) - res.Mul(api, res, e1) - res.nSquareCompressed(api, 46) - res.Decompress(api, res) - res.Mul(api, res, e1) - - *e = res - - return e - -} - // Assign a value to self (witness assignment) func (e *E12) Assign(a *bls12377.E12) { e.C0.Assign(&a.C0) diff --git a/std/algebra/native/fields_bls12377/e12_pairing.go b/std/algebra/native/fields_bls12377/e12_pairing.go new file mode 100644 index 0000000000..5021d12ed2 --- /dev/null +++ b/std/algebra/native/fields_bls12377/e12_pairing.go @@ -0,0 +1,77 @@ +package fields_bls12377 + +import "github.com/consensys/gnark/frontend" + +// MulBy034 multiplication by sparse element +func (e *E12) MulBy034(api frontend.API, c3, c4 E2) *E12 { + + var d E6 + + a := e.C0 + b := e.C1 + + b.MulBy01(api, c3, c4) + + c3.Add(api, E2{A0: 1, A1: 0}, c3) + d.Add(api, e.C0, e.C1) + d.MulBy01(api, c3, c4) + + e.C1.Add(api, a, b).Neg(api, e.C1).Add(api, e.C1, d) + e.C0.MulByNonResidue(api, b).Add(api, e.C0, a) + + return e +} + +// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) +func (e *E12) Mul034By034(api frontend.API, d3, d4, c3, c4 E2) *E12 { + var one, tmp, x3, x4, x04, x03, x34 E2 + one.SetOne() + x3.Mul(api, c3, d3) + x4.Mul(api, c4, d4) + x04.Add(api, c4, d4) + x03.Add(api, c3, d3) + tmp.Add(api, c3, c4) + x34.Add(api, d3, d4). + Mul(api, x34, tmp). + Sub(api, x34, x3). + Sub(api, x34, x4) + + e.C0.B0.MulByNonResidue(api, x4). + Add(api, e.C0.B0, one) + e.C0.B1 = x3 + e.C0.B2 = x34 + e.C1.B0 = x03 + e.C1.B1 = x04 + e.C1.B2.SetZero() + + return e +} + +// Expt compute e1**exponent, where the exponent is hardcoded +// This function is only used for the final expo of the pairing for bls12377, so the exponent is supposed to be hardcoded +// and on 64 bits. +func (e *E12) Expt(api frontend.API, e1 E12, exponent uint64) *E12 { + + res := e1 + + res.nSquareCompressed(api, 5) + res.Decompress(api, res) + res.Mul(api, res, e1) + x33 := res + res.nSquareCompressed(api, 7) + res.Decompress(api, res) + res.Mul(api, res, x33) + res.nSquareCompressed(api, 4) + res.Decompress(api, res) + res.Mul(api, res, e1) + res.CyclotomicSquare(api, res) + res.Mul(api, res, e1) + res.nSquareCompressed(api, 46) + res.Decompress(api, res) + res.Mul(api, res, e1) + + *e = res + + return e + +} diff --git a/std/algebra/fields_bls12377/e12_test.go b/std/algebra/native/fields_bls12377/e12_test.go similarity index 100% rename from std/algebra/fields_bls12377/e12_test.go rename to std/algebra/native/fields_bls12377/e12_test.go diff --git a/std/algebra/fields_bls12377/e2.go b/std/algebra/native/fields_bls12377/e2.go similarity index 100% rename from std/algebra/fields_bls12377/e2.go rename to std/algebra/native/fields_bls12377/e2.go diff --git a/std/algebra/fields_bls12377/e2_test.go b/std/algebra/native/fields_bls12377/e2_test.go similarity index 100% rename from std/algebra/fields_bls12377/e2_test.go rename to std/algebra/native/fields_bls12377/e2_test.go diff --git a/std/algebra/fields_bls12377/e6.go b/std/algebra/native/fields_bls12377/e6.go similarity index 100% rename from std/algebra/fields_bls12377/e6.go rename to std/algebra/native/fields_bls12377/e6.go diff --git a/std/algebra/fields_bls12377/e6_test.go b/std/algebra/native/fields_bls12377/e6_test.go similarity index 100% rename from std/algebra/fields_bls12377/e6_test.go rename to std/algebra/native/fields_bls12377/e6_test.go diff --git a/std/algebra/native/fields_bls24315/doc.go b/std/algebra/native/fields_bls24315/doc.go new file mode 100644 index 0000000000..8b669480b7 --- /dev/null +++ b/std/algebra/native/fields_bls24315/doc.go @@ -0,0 +1,10 @@ +// Package fields_bls24315 implements the fields arithmetic of the Fp24 tower +// used to compute the pairing over the BLS24-315 curve. +// +// 𝔽p²[u] = 𝔽p/u²-13 +// 𝔽p⁴[v] = 𝔽p²/v²-u +// 𝔽p¹²[w] = 𝔽p⁴/w³-v +// 𝔽p²⁴[i] = 𝔽p¹²/i²-w +// +// Reference: https://eprint.iacr.org/2022/1162 +package fields_bls24315 diff --git a/std/algebra/fields_bls24315/e12.go b/std/algebra/native/fields_bls24315/e12.go similarity index 100% rename from std/algebra/fields_bls24315/e12.go rename to std/algebra/native/fields_bls24315/e12.go diff --git a/std/algebra/fields_bls24315/e12_test.go b/std/algebra/native/fields_bls24315/e12_test.go similarity index 100% rename from std/algebra/fields_bls24315/e12_test.go rename to std/algebra/native/fields_bls24315/e12_test.go diff --git a/std/algebra/fields_bls24315/e2.go b/std/algebra/native/fields_bls24315/e2.go similarity index 100% rename from std/algebra/fields_bls24315/e2.go rename to std/algebra/native/fields_bls24315/e2.go diff --git a/std/algebra/fields_bls24315/e24.go b/std/algebra/native/fields_bls24315/e24.go similarity index 92% rename from std/algebra/fields_bls24315/e24.go rename to std/algebra/native/fields_bls24315/e24.go index 7394f86374..ea21cf09c5 100644 --- a/std/algebra/fields_bls24315/e24.go +++ b/std/algebra/native/fields_bls24315/e24.go @@ -341,53 +341,6 @@ func (e *E24) Conjugate(api frontend.API, e1 E24) *E24 { return e } -// MulBy034 multiplication by sparse element -func (e *E24) MulBy034(api frontend.API, c3, c4 E4) *E24 { - - var d E12 - var one E4 - one.SetOne() - - a := e.D0 - b := e.D1 - - b.MulBy01(api, c3, c4) - - c3.Add(api, one, c3) - d.Add(api, e.D0, e.D1) - d.MulBy01(api, c3, c4) - - e.D1.Add(api, a, b).Neg(api, e.D1).Add(api, e.D1, d) - e.D0.MulByNonResidue(api, b).Add(api, e.D0, a) - - return e -} - -// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) -func (e *E24) Mul034By034(api frontend.API, d3, d4, c3, c4 E4) *E24 { - var one, tmp, x3, x4, x04, x03, x34 E4 - one.SetOne() - x3.Mul(api, c3, d3) - x4.Mul(api, c4, d4) - x04.Add(api, c4, d4) - x03.Add(api, c3, d3) - tmp.Add(api, c3, c4) - x34.Add(api, d3, d4). - Mul(api, x34, tmp). - Sub(api, x34, x3). - Sub(api, x34, x4) - - e.D0.C0.MulByNonResidue(api, x4). - Add(api, e.D0.C0, one) - e.D0.C1 = x3 - e.D0.C2 = x34 - e.D1.C0 = x03 - e.D1.C1 = x04 - e.D1.C2.SetZero() - - return e -} - var InverseE24Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { var a, c bls24315.E24 @@ -595,31 +548,6 @@ func (e *E24) nSquare(api frontend.API, n int) { } } -// Expt compute e1**exponent, where the exponent is hardcoded -// This function is only used for the final expo of the pairing for bls24315, so the exponent is supposed to be hardcoded and on 32 bits. -func (e *E24) Expt(api frontend.API, x E24, exponent uint64) *E24 { - - xInv := E24{} - res := x - xInv.Conjugate(api, x) - - res.nSquare(api, 2) - res.Mul(api, res, xInv) - res.nSquareCompressed(api, 8) - res.Decompress(api, res) - res.Mul(api, res, xInv) - res.nSquare(api, 2) - res.Mul(api, res, x) - res.nSquareCompressed(api, 20) - res.Decompress(api, res) - res.Mul(api, res, xInv) - res.Conjugate(api, res) - - *e = res - - return e -} - // AssertIsEqual constraint self to be equal to other into the given constraint system func (e *E24) AssertIsEqual(api frontend.API, other E24) { e.D0.AssertIsEqual(api, other.D0) diff --git a/std/algebra/native/fields_bls24315/e24_pairing.go b/std/algebra/native/fields_bls24315/e24_pairing.go new file mode 100644 index 0000000000..b087eb8138 --- /dev/null +++ b/std/algebra/native/fields_bls24315/e24_pairing.go @@ -0,0 +1,75 @@ +package fields_bls24315 + +import "github.com/consensys/gnark/frontend" + +// MulBy034 multiplication by sparse element +func (e *E24) MulBy034(api frontend.API, c3, c4 E4) *E24 { + + var d E12 + var one E4 + one.SetOne() + + a := e.D0 + b := e.D1 + + b.MulBy01(api, c3, c4) + + c3.Add(api, one, c3) + d.Add(api, e.D0, e.D1) + d.MulBy01(api, c3, c4) + + e.D1.Add(api, a, b).Neg(api, e.D1).Add(api, e.D1, d) + e.D0.MulByNonResidue(api, b).Add(api, e.D0, a) + + return e +} + +// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) +func (e *E24) Mul034By034(api frontend.API, d3, d4, c3, c4 E4) *E24 { + var one, tmp, x3, x4, x04, x03, x34 E4 + one.SetOne() + x3.Mul(api, c3, d3) + x4.Mul(api, c4, d4) + x04.Add(api, c4, d4) + x03.Add(api, c3, d3) + tmp.Add(api, c3, c4) + x34.Add(api, d3, d4). + Mul(api, x34, tmp). + Sub(api, x34, x3). + Sub(api, x34, x4) + + e.D0.C0.MulByNonResidue(api, x4). + Add(api, e.D0.C0, one) + e.D0.C1 = x3 + e.D0.C2 = x34 + e.D1.C0 = x03 + e.D1.C1 = x04 + e.D1.C2.SetZero() + + return e +} + +// Expt compute e1**exponent, where the exponent is hardcoded +// This function is only used for the final expo of the pairing for bls24315, so the exponent is supposed to be hardcoded and on 32 bits. +func (e *E24) Expt(api frontend.API, x E24, exponent uint64) *E24 { + + xInv := E24{} + res := x + xInv.Conjugate(api, x) + + res.nSquare(api, 2) + res.Mul(api, res, xInv) + res.nSquareCompressed(api, 8) + res.Decompress(api, res) + res.Mul(api, res, xInv) + res.nSquare(api, 2) + res.Mul(api, res, x) + res.nSquareCompressed(api, 20) + res.Decompress(api, res) + res.Mul(api, res, xInv) + res.Conjugate(api, res) + + *e = res + + return e +} diff --git a/std/algebra/fields_bls24315/e24_test.go b/std/algebra/native/fields_bls24315/e24_test.go similarity index 100% rename from std/algebra/fields_bls24315/e24_test.go rename to std/algebra/native/fields_bls24315/e24_test.go diff --git a/std/algebra/fields_bls24315/e2_test.go b/std/algebra/native/fields_bls24315/e2_test.go similarity index 100% rename from std/algebra/fields_bls24315/e2_test.go rename to std/algebra/native/fields_bls24315/e2_test.go diff --git a/std/algebra/fields_bls24315/e4.go b/std/algebra/native/fields_bls24315/e4.go similarity index 100% rename from std/algebra/fields_bls24315/e4.go rename to std/algebra/native/fields_bls24315/e4.go diff --git a/std/algebra/fields_bls24315/e4_test.go b/std/algebra/native/fields_bls24315/e4_test.go similarity index 100% rename from std/algebra/fields_bls24315/e4_test.go rename to std/algebra/native/fields_bls24315/e4_test.go diff --git a/std/algebra/native/sw_bls12377/doc.go b/std/algebra/native/sw_bls12377/doc.go new file mode 100644 index 0000000000..3888dba835 --- /dev/null +++ b/std/algebra/native/sw_bls12377/doc.go @@ -0,0 +1,8 @@ +// Package sw_bls12377 implements the arithmetics of G1, G2 and the pairing +// computation on BLS12-377 as a SNARK circuit over BW6-761. These two curves +// form a 2-chain so the operations use native field arithmetic. +// +// References: +// BW6-761: https://eprint.iacr.org/2020/351 +// Pairings in R1CS: https://eprint.iacr.org/2022/1162 +package sw_bls12377 diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/native/sw_bls12377/g1.go similarity index 100% rename from std/algebra/sw_bls12377/g1.go rename to std/algebra/native/sw_bls12377/g1.go diff --git a/std/algebra/sw_bls12377/g1_test.go b/std/algebra/native/sw_bls12377/g1_test.go similarity index 100% rename from std/algebra/sw_bls12377/g1_test.go rename to std/algebra/native/sw_bls12377/g1_test.go diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/native/sw_bls12377/g2.go similarity index 99% rename from std/algebra/sw_bls12377/g2.go rename to std/algebra/native/sw_bls12377/g2.go index 3674196b98..7d0152f753 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/native/sw_bls12377/g2.go @@ -24,7 +24,7 @@ import ( "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" ) // G2Jac point in Jacobian coords diff --git a/std/algebra/sw_bls12377/g2_test.go b/std/algebra/native/sw_bls12377/g2_test.go similarity index 100% rename from std/algebra/sw_bls12377/g2_test.go rename to std/algebra/native/sw_bls12377/g2_test.go diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/native/sw_bls12377/inner.go similarity index 100% rename from std/algebra/sw_bls12377/inner.go rename to std/algebra/native/sw_bls12377/inner.go diff --git a/std/algebra/sw_bls12377/inner_compute.go b/std/algebra/native/sw_bls12377/inner_compute.go similarity index 100% rename from std/algebra/sw_bls12377/inner_compute.go rename to std/algebra/native/sw_bls12377/inner_compute.go diff --git a/std/algebra/sw_bls12377/pairing.go b/std/algebra/native/sw_bls12377/pairing.go similarity index 98% rename from std/algebra/sw_bls12377/pairing.go rename to std/algebra/native/sw_bls12377/pairing.go index 7ca86131e7..c0e4bfef68 100644 --- a/std/algebra/sw_bls12377/pairing.go +++ b/std/algebra/native/sw_bls12377/pairing.go @@ -21,7 +21,7 @@ import ( "math/big" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" ) // GT target group of the pairing diff --git a/std/algebra/sw_bls12377/pairing_test.go b/std/algebra/native/sw_bls12377/pairing_test.go similarity index 98% rename from std/algebra/sw_bls12377/pairing_test.go rename to std/algebra/native/sw_bls12377/pairing_test.go index bf09b6efad..dbe5639919 100644 --- a/std/algebra/sw_bls12377/pairing_test.go +++ b/std/algebra/native/sw_bls12377/pairing_test.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" "github.com/consensys/gnark/test" ) diff --git a/std/algebra/native/sw_bls24315/doc.go b/std/algebra/native/sw_bls24315/doc.go new file mode 100644 index 0000000000..9a13dd4769 --- /dev/null +++ b/std/algebra/native/sw_bls24315/doc.go @@ -0,0 +1,8 @@ +// Package sw_bls24315 implements the arithmetics of G1, G2 and the pairing +// computation on BLS24-315 as a SNARK circuit over BW6-633. These two curves +// form a 2-chain so the operations use native field arithmetic. +// +// References: +// BLS24-315/BW6-633: https://eprint.iacr.org/2021/1359 +// Pairings in R1CS: https://eprint.iacr.org/2022/1162 +package sw_bls24315 diff --git a/std/algebra/sw_bls24315/g1.go b/std/algebra/native/sw_bls24315/g1.go similarity index 100% rename from std/algebra/sw_bls24315/g1.go rename to std/algebra/native/sw_bls24315/g1.go diff --git a/std/algebra/sw_bls24315/g1_test.go b/std/algebra/native/sw_bls24315/g1_test.go similarity index 100% rename from std/algebra/sw_bls24315/g1_test.go rename to std/algebra/native/sw_bls24315/g1_test.go diff --git a/std/algebra/sw_bls24315/g2.go b/std/algebra/native/sw_bls24315/g2.go similarity index 99% rename from std/algebra/sw_bls24315/g2.go rename to std/algebra/native/sw_bls24315/g2.go index 06be5d9fe4..7997060144 100644 --- a/std/algebra/sw_bls24315/g2.go +++ b/std/algebra/native/sw_bls24315/g2.go @@ -23,7 +23,7 @@ import ( bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" ) // G2Jac point in Jacobian coords diff --git a/std/algebra/sw_bls24315/g2_test.go b/std/algebra/native/sw_bls24315/g2_test.go similarity index 100% rename from std/algebra/sw_bls24315/g2_test.go rename to std/algebra/native/sw_bls24315/g2_test.go diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/native/sw_bls24315/inner.go similarity index 100% rename from std/algebra/sw_bls24315/inner.go rename to std/algebra/native/sw_bls24315/inner.go diff --git a/std/algebra/sw_bls24315/inner_compute.go b/std/algebra/native/sw_bls24315/inner_compute.go similarity index 100% rename from std/algebra/sw_bls24315/inner_compute.go rename to std/algebra/native/sw_bls24315/inner_compute.go diff --git a/std/algebra/sw_bls24315/pairing.go b/std/algebra/native/sw_bls24315/pairing.go similarity index 98% rename from std/algebra/sw_bls24315/pairing.go rename to std/algebra/native/sw_bls24315/pairing.go index b1e1fb11e0..57b4b8e928 100644 --- a/std/algebra/sw_bls24315/pairing.go +++ b/std/algebra/native/sw_bls24315/pairing.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" ) // GT target group of the pairing diff --git a/std/algebra/sw_bls24315/pairing_test.go b/std/algebra/native/sw_bls24315/pairing_test.go similarity index 98% rename from std/algebra/sw_bls24315/pairing_test.go rename to std/algebra/native/sw_bls24315/pairing_test.go index c7bb53b4a5..44233d888d 100644 --- a/std/algebra/sw_bls24315/pairing_test.go +++ b/std/algebra/native/sw_bls24315/pairing_test.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" "github.com/consensys/gnark/test" ) diff --git a/std/algebra/twistededwards/curve.go b/std/algebra/native/twistededwards/curve.go similarity index 100% rename from std/algebra/twistededwards/curve.go rename to std/algebra/native/twistededwards/curve.go diff --git a/std/algebra/twistededwards/curve_test.go b/std/algebra/native/twistededwards/curve_test.go similarity index 100% rename from std/algebra/twistededwards/curve_test.go rename to std/algebra/native/twistededwards/curve_test.go diff --git a/std/algebra/native/twistededwards/doc.go b/std/algebra/native/twistededwards/doc.go new file mode 100644 index 0000000000..95b1486681 --- /dev/null +++ b/std/algebra/native/twistededwards/doc.go @@ -0,0 +1,8 @@ +// Package twistededwards implements the arithmetic of twisted Edwards curves +// in native fields. This uses associated twisted Edwards curves defined over +// the scalar field of the SNARK curves. +// +// Examples: +// Jubjub, Bandersnatch (a twisted Edwards) is defined over BLS12-381's scalar field +// Baby-Jubjub (a twisted Edwards) is defined over BN254's salar fields +package twistededwards diff --git a/std/algebra/twistededwards/point.go b/std/algebra/native/twistededwards/point.go similarity index 100% rename from std/algebra/twistededwards/point.go rename to std/algebra/native/twistededwards/point.go diff --git a/std/algebra/twistededwards/scalarmul_glv.go b/std/algebra/native/twistededwards/scalarmul_glv.go similarity index 100% rename from std/algebra/twistededwards/scalarmul_glv.go rename to std/algebra/native/twistededwards/scalarmul_glv.go diff --git a/std/algebra/twistededwards/twistededwards.go b/std/algebra/native/twistededwards/twistededwards.go similarity index 100% rename from std/algebra/twistededwards/twistededwards.go rename to std/algebra/native/twistededwards/twistededwards.go diff --git a/std/algebra/pairing_bn254/gt.go b/std/algebra/pairing_bn254/gt.go deleted file mode 100644 index 2b84c9f0ed..0000000000 --- a/std/algebra/pairing_bn254/gt.go +++ /dev/null @@ -1,41 +0,0 @@ -package pairing_bn254 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/math/emulated" -) - -type GTEl = e12 - -func NewGTEl(v bn254.GT) GTEl { - return GTEl{ - C0: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), - }, - }, - C1: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), - }, - }, - } -} diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go deleted file mode 100644 index ec0baa633b..0000000000 --- a/std/algebra/pairing_bn254/pairing.go +++ /dev/null @@ -1,282 +0,0 @@ -package pairing_bn254 - -import ( - "fmt" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" -) - -type Pairing struct { - *ext12 -} - -func NewPairing(api frontend.API) (*Pairing, error) { - ba, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - return nil, fmt.Errorf("new base api: %w", err) - } - return &Pairing{ - ext12: newExt12(ba), - }, nil -} - -func (pr Pairing) doubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { - // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 - A := pr.ext2.mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.ext2.halve(A) // A.Halve() - B := pr.ext2.square(&p.Y) // B.Square(&p.y) - C := pr.ext2.square(&p.Z) // C.Square(&p.z) - D := pr.ext2.double(C) // D.Double(&C). - D = pr.ext2.add(D, C) // Add(&D, &C) - E := pr.ext2.mulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) - F := pr.ext2.double(E) // F.Double(&E). - F = pr.ext2.add(F, E) // Add(&F, &E) - G := pr.ext2.add(B, F) // G.Add(&B, &F) - G = pr.ext2.halve(G) // G.Halve() - H := pr.ext2.add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). - H = pr.ext2.square(H) // Square(&H) - t1 := pr.ext2.add(B, C) // t1.Add(&B, &C) - H = pr.ext2.sub(H, t1) // H.Sub(&H, &t1) - I := pr.ext2.sub(E, B) // I.Sub(&E, &B) - J := pr.ext2.square(&p.X) // J.Square(&p.x) - EE := pr.ext2.square(E) // EE.Square(&E) - K := pr.ext2.double(EE) // K.Double(&EE). - K = pr.ext2.add(K, EE) // Add(&K, &EE) - px := pr.ext2.sub(B, F) // p.x.Sub(&B, &F). - px = pr.ext2.mul(px, A) // Mul(&p.x, &A) - py := pr.ext2.square(G) // p.y.Square(&G). - py = pr.ext2.sub(py, K) // Sub(&p.y, &K) - pz := pr.ext2.mul(B, H) // p.z.Mul(&B, &H) - ev0 := pr.ext2.neg(H) // evaluations.r0.Neg(&H) - ev1 := pr.ext2.double(J) // evaluations.r1.Double(&J). - ev1 = pr.ext2.add(ev1, J) // Add(&evaluations.r1, &J) - ev2 := I // evaluations.r2.Set(&I) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, - &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { - // TODO: check point at infinity? We do not filter them in the Miller Loop neither. - // if Q.X.IsZero() && Q.Y.IsZero() { - // p.z.SetZero() - // p.x.SetOne() - // p.y.SetOne() - // return p - // } - pz := pr.ext2.one() // p.z.SetOne() - px := &Q.X // p.x.Set(&Q.X) - py := &Q.Y // p.y.Set(&Q.Y) - return &g2Projective{ // return p - X: *px, - Y: *py, - Z: *pz, - } -} - -func (pr Pairing) negAffine(a *G2Affine) *G2Affine { - px := &a.X // p.X = a.X - py := pr.ext2.neg(&a.Y) // p.Y.Neg(&a.Y) - return &G2Affine{ // return p - X: *px, - Y: *py, - } -} - -func (pr Pairing) addStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { - // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 - Y2Z1 := pr.ext2.mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) - O := pr.ext2.sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) - X2Z1 := pr.ext2.mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) - L := pr.ext2.sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) - C := pr.ext2.square(O) // C.Square(&O) - D := pr.ext2.square(L) // D.Square(&L) - E := pr.ext2.mul(L, D) // E.Mul(&L, &D) - F := pr.ext2.mul(&p.Z, C) // F.Mul(&p.z, &C) - G := pr.ext2.mul(&p.X, D) // G.Mul(&p.x, &D) - t0 := pr.ext2.double(G) // t0.Double(&G) - H := pr.ext2.add(E, F) // H.Add(&E, &F). - H = pr.ext2.sub(H, t0) // Sub(&H, &t0) - t1 := pr.ext2.mul(&p.Y, E) // t1.Mul(&p.y, &E) - px := pr.ext2.mul(L, H) // p.x.Mul(&L, &H) - py := pr.ext2.sub(G, H) // p.y.Sub(&G, &H). - py = pr.ext2.mul(py, O) // Mul(&p.y, &O). - py = pr.ext2.sub(py, t1) // Sub(&p.y, &t1) - pz := pr.ext2.mul(E, &p.Z) // p.z.Mul(&E, &p.z) - t2 := pr.ext2.mul(L, &a.Y) // t2.Mul(&L, &a.Y) - J := pr.ext2.mul(&a.X, O) // J.Mul(&a.X, &O). - J = pr.ext2.sub(J, t2) // Sub(&J, &t2) - ev0 := L // evaluations.r0.Set(&L) - ev1 := pr.ext2.neg(O) // evaluations.r1.Neg(&O) - ev2 := J // evaluations.r2.Set(&J) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -type lineEvaluation struct { - r0 e2 - r1 e2 - r2 e2 -} - -var loopCounter = [66]int8{ - 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, - 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, - 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, - 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, - -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, - -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, -} - -func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { - n := len(p) - if n == 0 || n != len(q) { - return nil, fmt.Errorf("invalid inputs sizes") - } - - // TODO: we have omitted filtering for infinity points. - - // projective points for Q - qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) - qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) - for k := 0; k < n; k++ { - qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) - qNeg[k] = pr.negAffine(q[k]) // qNeg[k].Neg(&q[k]) - } - - var l, l0 *lineEvaluation - result := pr.ext12.one() // var tmp, result GTEl - - // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - - for i := len(loopCounter) - 3; i >= 0; i-- { - result = pr.ext12.square(result) // result.Square(&result) - - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - - if loopCounter[i] == 1 { - qProj[k], l0 = pr.addStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } else if loopCounter[i] == -1 { - qProj[k], l0 = pr.addStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) //result.Mul(&result, &tmp) - } else { - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - } - } - - Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine - for k := 0; k < n; k++ { - //Q1 = π(Q) - // TODO(ivokub): define phi(Q) in G2 instead of doing manually? - Q1.X = *pr.ext12.ext2.conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.X = *pr.ext12.ext2.mulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.ext12.ext2.conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - Q1.Y = *pr.ext12.ext2.mulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - - // Q2 = -π²(Q) - Q2.X = *pr.ext12.ext2.mulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) - Q2.Y = *pr.ext12.ext2.mulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - Q2.Y = *pr.ext12.ext2.neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - - qProj[k], l0 = pr.addStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - - qProj[k], l = pr.addStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } - - return result, nil -} - -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - // var result GT - // result.Set(z) - var t [4]*GTEl // var t [4]GT - - // easy part - t[0] = pr.ext12.conjugate(e) // t[0].Conjugate(&result) - result := pr.ext12.inverse(e) // result.Inverse(&result) - t[0] = pr.ext12.mul(t[0], result) // t[0].Mul(&t[0], &result) - result = pr.ext12.frobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). - result = pr.ext12.mul(result, t[0]) // Mul(&result, &t[0]) - - //hard part - t[0] = pr.ext12.expt(result) // t[0].Expt(&result). - t[0] = pr.ext12.conjugate(t[0]) // Conjugate(&t[0]) - t[0] = pr.ext12.cyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) - t[2] = pr.ext12.expt(t[0]) // t[2].Expt(&t[0]). - t[2] = pr.ext12.conjugate(t[2]) // Conjugate(&t[2]) - t[1] = pr.ext12.cyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[2] = pr.ext12.mul(t[2], result) // t[2].Mul(&t[2], &result) - t[1] = pr.ext12.expt(t[2]) // t[1].Expt(&t[2]). - t[1] = pr.ext12.cyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). - t[1] = pr.ext12.mul(t[1], t[2]) // Mul(&t[1], &t[2]). - t[1] = pr.ext12.conjugate(t[1]) // Conjugate(&t[1]) - t[3] = pr.ext12.conjugate(t[1]) // t[3].Conjugate(&t[1]) - t[1] = pr.ext12.cyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) - t[1] = pr.ext12.mul(t[1], result) // t[1].Mul(&t[1], &result) - t[1] = pr.ext12.conjugate(t[1]) // t[1].Conjugate(&t[1]) - t[1] = pr.ext12.mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) - t[0] = pr.ext12.mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[3] = pr.ext12.frobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) - t[2] = pr.ext12.mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) - t[3] = pr.ext12.conjugate(result) // t[3].Conjugate(&result) - t[3] = pr.ext12.mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) - t[1] = pr.ext12.frobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[1] = pr.ext12.frobenius(t[0]) // t[1].Frobenius(&t[0]) - t[1] = pr.ext12.mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) - // result.Set(&t[1]) - return t[1] // return result -} - -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) - } - res = pr.FinalExponentiation(res) - return res, nil -} - -func (pr Pairing) AssertIsEqual(x, y *GTEl) { - pr.ext12.assertIsEqual(x, y) -} diff --git a/std/algebra/pairing_bn254/tower.go b/std/algebra/pairing_bn254/tower.go deleted file mode 100644 index c555680885..0000000000 --- a/std/algebra/pairing_bn254/tower.go +++ /dev/null @@ -1,833 +0,0 @@ -package pairing_bn254 - -import ( - "math/big" - - "github.com/consensys/gnark/std/math/emulated" -) - -type curveF = emulated.Field[emulated.BN254Fp] -type baseEl = emulated.Element[emulated.BN254Fp] - -type e2 struct { - A0, A1 baseEl -} - -type e6 struct { - B0, B1, B2 e2 -} - -type e12 struct { - C0, C1 e6 -} - -type ext2 struct { - fp *curveF - nonResidues map[int]map[int]*e2 -} - -func newExt2(baseField *curveF) *ext2 { - pwrs := map[int]map[int]struct { - A0 string - A1 string - }{ - 0: { - -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, - 1: {"9", "1"}, - }, - 1: { - 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, - 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, - 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, - 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, - 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, - }, - 2: { - 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, - 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, - 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, - 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, - 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, - }, - 3: { - 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, - 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, - 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, - 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, - 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, - }, - } - nonResidues := make(map[int]map[int]*e2) - for pwr, v := range pwrs { - for coeff, v := range v { - el := e2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} - if nonResidues[pwr] == nil { - nonResidues[pwr] = make(map[int]*e2) - } - nonResidues[pwr][coeff] = &el - } - } - return &ext2{fp: baseField, nonResidues: nonResidues} -} - -type ext6 struct { - *ext2 -} - -func newExt6(baseField *curveF) *ext6 { - return &ext6{ext2: newExt2(baseField)} -} - -type ext12 struct { - *ext6 -} - -func newExt12(baseField *curveF) *ext12 { - return &ext12{ext6: newExt6(baseField)} -} - -// TODO: check where to use Mod and where ModMul. - -func (e ext2) mulByElement(x *e2, y *baseEl) *e2 { - // var yCopy fp.Element - // yCopy.Set(y) - z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) - z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) conjugate(x *e2) *e2 { - z0 := x.A0 // z.A0 = x.A0 - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ // return z - A0: z0, - A1: *z1, - } -} - -func (e ext2) mulByNonResidueGeneric(x *e2, power, coef int) *e2 { - y := e.nonResidues[power][coef] - z := e.mul(x, y) - return z -} - -func (e ext2) mulByNonResidue(x *e2) *e2 { - /* - // below is the direct transliteration of the gnark-crypto code. Now only, - // for simplicity and debugging purposes, we do the non residue operations - // without optimisations. - - nine := big.NewInt(9) - // var a, b fp.Element - a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). - a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) - b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). - b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) - return &E2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } // return z - */ - // TODO: inline non-residue multiplication - return e.mulByNonResidueGeneric(x, 0, 1) -} - -func (e ext2) mulByNonResidueInv(x *e2) *e2 { - // TODO: to optimise with constant non-residue inverse - /* - // from gnark-crypto - // z.Mul(x, &nonResInverse) - // return z - */ - return e.mulByNonResidueGeneric(x, 0, -1) -} - -func (e ext2) mulByNonResidue1Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 1) -} - -func (e ext2) mulByNonResidue1Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 2) -} - -func (e ext2) mulByNonResidue1Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 3) -} - -func (e ext2) mulByNonResidue1Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 4) -} - -func (e ext2) mulByNonResidue1Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 5) -} - -func (e ext2) mulByNonResidue2Power1(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 1) -} -func (e ext2) mulByNonResidue2Power2(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 2) -} - -func (e ext2) mulByNonResidue2Power3(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 3) -} - -func (e ext2) mulByNonResidue2Power4(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 4) -} - -func (e ext2) mulByNonResidue2Power5(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 5) -} - -func (e ext2) mulByNonResidue3Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 1) -} - -func (e ext2) mulByNonResidue3Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 2) -} - -func (e ext2) mulByNonResidue3Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 3) -} - -func (e ext2) mulByNonResidue3Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 4) -} - -func (e ext2) mulByNonResidue3Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 5) -} - -func (e ext2) mul(x, y *e2) *e2 { - // var a, b, c fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) - c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) - z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). - z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) - z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) add(x, y *e2) *e2 { - z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) - z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) sub(x, y *e2) *e2 { - z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) - z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) neg(x *e2) *e2 { - z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) one() *e2 { - z0 := e.fp.One() // z.A0.SetOne() - z1 := e.fp.Zero() // z.A1.SetZero() - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) zero() *e2 { - z0 := e.fp.Zero() - z1 := e.fp.Zero() - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) square(x *e2) *e2 { - // var a, b fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). - b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) - return &e2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } -} - -func (e ext2) double(x *e2) *e2 { - two := big.NewInt(2) - z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) - z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) halve(x *e2) *e2 { - // I'm trying to avoid hard-coding modulus here in case want to make generic - // for different curves. - // TODO: if implemented Half in field emulation, then replace with it. - one := e.fp.One() - two := e.fp.MulConst(one, big.NewInt(2)) - z0 := e.fp.Div(&x.A0, two) - z1 := e.fp.Div(&x.A1, two) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) mulBybTwistCurveCoeff(x *e2) *e2 { - // var res E2 - res := e.mulByNonResidueInv(x) // res.MulByNonResidueInv(x) - z := e.double(res) // z.Double(&res). - z = e.add(z, res) // Add(&res, z) - return z // return z -} - -func (e ext2) inverse(x *e2) *e2 { - // var t0, t1 fp.Element - t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) - t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) - t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) - t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) - z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) - z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). - z1 = e.fp.Neg(z1) // Neg(&z.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) assertIsEqual(x, y *e2) { - e.fp.AssertIsEqual(&x.A0, &y.A0) - e.fp.AssertIsEqual(&x.A1, &y.A1) -} - -func (e ext6) add(x, y *e6) *e6 { - z0 := e.ext2.add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) - z1 := e.ext2.add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) - z2 := e.ext2.add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) neg(x *e6) *e6 { - z0 := e.ext2.neg(&x.B0) // z.B0.Neg(&x.B0) - z1 := e.ext2.neg(&x.B1) // z.B1.Neg(&x.B1) - z2 := e.ext2.neg(&x.B2) // z.B2.Neg(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) sub(x, y *e6) *e6 { - z0 := e.ext2.sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) - z1 := e.ext2.sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) - z2 := e.ext2.sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mul(x, y *e6) *e6 { - // var t0, t1, t2, c0, c1, c2, tmp E2 - t0 := e.ext2.mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) - t1 := e.ext2.mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) - t2 := e.ext2.mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) - c0 := e.ext2.add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) - tmp := e.ext2.add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) - c0 = e.ext2.mul(c0, tmp) // c0.Mul(&c0, &tmp). - c0 = e.ext2.sub(c0, t1) // Sub(&c0, &t1). - c0 = e.ext2.sub(c0, t2) // Sub(&c0, &t2). - c0 = e.ext2.mulByNonResidue(c0) // MulByNonResidue(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) - tmp = e.ext2.add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) - c1 = e.ext2.mul(c1, tmp) // c1.Mul(&c1, &tmp). - c1 = e.ext2.sub(c1, t0) // Sub(&c1, &t0). - c1 = e.ext2.sub(c1, t1) // Sub(&c1, &t1) - tmp = e.ext2.mulByNonResidue(t2) // tmp.MulByNonResidue(&t2) - c1 = e.ext2.add(c1, tmp) // c1.Add(&c1, &tmp) - tmp = e.ext2.add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) - c2 := e.ext2.add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). - c2 = e.ext2.mul(c2, tmp) // Mul(&c2, &tmp). - c2 = e.ext2.sub(c2, t0) // Sub(&c2, &t0). - c2 = e.ext2.sub(c2, t2) // Sub(&c2, &t2). - c2 = e.ext2.add(c2, t1) // Add(&c2, &t1) - return &e6{ - B0: *c0, // z.B0.Set(&c0) - B1: *c1, // z.B1.Set(&c1) - B2: *c2, // z.B2.Set(&c2) - } // return z -} - -func (e ext6) double(x *e6) *e6 { - z0 := e.ext2.double(&x.B0) // z.B0.Double(&x.B0) - z1 := e.ext2.double(&x.B1) // z.B1.Double(&x.B1) - z2 := e.ext2.double(&x.B2) // z.B2.Double(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) square(x *e6) *e6 { - // var c4, c5, c1, c2, c3, c0 E2 - c4 := e.ext2.mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). - c4 = e.ext2.double(c4) // Double(&c4) - c5 := e.ext2.square(&x.B2) // c5.Square(&x.B2) - c1 := e.ext2.mulByNonResidue(c5) // c1.MulByNonResidue(&c5). - c1 = e.ext2.add(c1, c4) // Add(&c1, &c4) - c2 := e.ext2.sub(c4, c5) // c2.Sub(&c4, &c5) - c3 := e.ext2.square(&x.B0) // c3.Square(&x.B0) - c4 = e.ext2.sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). - c4 = e.ext2.add(c4, &x.B2) // Add(&c4, &x.B2) - c5 = e.ext2.mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). - c5 = e.ext2.double(c5) // Double(&c5) - c4 = e.ext2.square(c4) // c4.Square(&c4) - c0 := e.ext2.mulByNonResidue(c5) // c0.MulByNonResidue(&c5). - c0 = e.ext2.add(c0, c3) // Add(&c0, &c3) - z2 := e.ext2.add(c2, c4) // z.B2.Add(&c2, &c4). - z2 = e.ext2.add(z2, c5) // Add(&z.B2, &c5). - z2 = e.ext2.sub(z2, c3) // Sub(&z.B2, &c3) - z0 := c0 // z.B0.Set(&c0) - z1 := c1 // z.B1.Set(&c1) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) inverse(x *e6) *e6 { - // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 - t0 := e.ext2.square(&x.B0) // t0.Square(&x.B0) - t1 := e.ext2.square(&x.B1) // t1.Square(&x.B1) - t2 := e.ext2.square(&x.B2) // t2.Square(&x.B2) - t3 := e.ext2.mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) - t4 := e.ext2.mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) - t5 := e.ext2.mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) - c0 := e.ext2.mulByNonResidue(t5) // c0.MulByNonResidue(&t5). - c0 = e.ext2.neg(c0) // Neg(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.mulByNonResidue(t2) // c1.MulByNonResidue(&t2). - c1 = e.ext2.sub(c1, t3) // Sub(&c1, &t3) - c2 := e.ext2.sub(t1, t4) // c2.Sub(&t1, &t4) - t6 := e.ext2.mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) - d1 := e.ext2.mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) - d2 := e.ext2.mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) - d1 = e.ext2.add(d1, d2) // d1.Add(&d1, &d2). - d1 = e.ext2.mulByNonResidue(d1) // MulByNonResidue(&d1) - t6 = e.ext2.add(t6, d1) // t6.Add(&t6, &d1) - t6 = e.ext2.inverse(t6) // t6.Inverse(&t6) - z0 := e.ext2.mul(c0, t6) // z.B0.Mul(&c0, &t6) - z1 := e.ext2.mul(c1, t6) // z.B1.Mul(&c1, &t6) - z2 := e.ext2.mul(c2, t6) // z.B2.Mul(&c2, &t6) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} -func (e ext6) mulByE2(x *e6, y *e2) *e6 { - // var yCopy E2 - // yCopy.Set(y) - z0 := e.ext2.mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) - z1 := e.ext2.mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) - z2 := e.ext2.mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mulBy01(z *e6, c0, c1 *e2) *e6 { - // var a, b, tmp, t0, t1, t2 E2 - a := e.ext2.mul(&z.B0, c0) // a.Mul(&z.B0, c0) - b := e.ext2.mul(&z.B1, c1) // b.Mul(&z.B1, c1) - tmp := e.ext2.add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) - t0 := e.ext2.mul(c1, tmp) // t0.Mul(c1, &tmp) - t0 = e.ext2.sub(t0, b) // t0.Sub(&t0, &b) - t0 = e.ext2.mulByNonResidue(t0) // t0.MulByNonResidue(&t0) - t0 = e.ext2.add(t0, a) // t0.Add(&t0, &a) - tmp = e.ext2.add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) - t2 := e.ext2.mul(c0, tmp) // t2.Mul(c0, &tmp) - t2 = e.ext2.sub(t2, a) // t2.Sub(&t2, &a) - t2 = e.ext2.add(t2, b) // t2.Add(&t2, &b) - t1 := e.ext2.add(c0, c1) // t1.Add(c0, c1) - tmp = e.ext2.add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) - t1 = e.ext2.mul(t1, tmp) // t1.Mul(&t1, &tmp) - t1 = e.ext2.sub(t1, a) // t1.Sub(&t1, &a) - t1 = e.ext2.sub(t1, b) // t1.Sub(&t1, &b) - return &e6{ - B0: *t0, // z.B0.Set(&t0) - B1: *t1, // z.B1.Set(&t1) - B2: *t2, // z.B2.Set(&t2) - } // return z -} - -func (e ext6) mulByNonResidue(x *e6) *e6 { - z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 - z0 = e.ext2.mulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) - return &e6{ // return z - 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 (e ext12) conjugate(x *e12) *e12 { - z1 := e.ext6.neg(&x.C1) // z.C1.Neg(&z.C1) - return &e12{ // return z - C0: x.C0, - C1: *z1, - } -} - -func (e ext12) inverse(x *e12) *e12 { - // var t0, t1, tmp E6 - t0 := e.ext6.square(&x.C0) // t0.Square(&x.C0) - t1 := e.ext6.square(&x.C1) // t1.Square(&x.C1) - tmp := e.ext6.mulByNonResidue(t1) // tmp.MulByNonResidue(&t1) - t0 = e.ext6.sub(t0, tmp) // t0.Sub(&t0, &tmp) - t1 = e.ext6.inverse(t0) // t1.Inverse(&t0) - z0 := e.ext6.mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) - z1 := e.ext6.mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). - z1 = e.ext6.neg(z1) // Neg(&z.C1) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mul(x, y *e12) *e12 { - // var a, b, c E6 - a := e.ext6.add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) - b := e.ext6.add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) - a = e.ext6.mul(a, b) // a.Mul(&a, &b) - b = e.ext6.mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) - c := e.ext6.mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) - z1 := e.ext6.sub(a, b) // z.C1.Sub(&a, &b). - z1 = e.ext6.sub(z1, c) // Sub(&z.C1, &c) - z0 := e.ext6.mulByNonResidue(c) // z.C0.MulByNonResidue(&c). - z0 = e.ext6.add(z0, b) // Add(&z.C0, &b) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) cyclotomicSquare(x *e12) *e12 { - // var t [9]E2 - t0 := e.ext2.square(&x.C1.B1) // t[0].Square(&x.C1.B1) - t1 := e.ext2.square(&x.C0.B0) // t[1].Square(&x.C0.B0) - t6 := e.ext2.add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). - t6 = e.ext2.square(t6) // Square(&t[6]). - t6 = e.ext2.sub(t6, t0) // Sub(&t[6], &t[0]). - t6 = e.ext2.sub(t6, t1) // Sub(&t[6], &t[1]) - t2 := e.ext2.square(&x.C0.B2) // t[2].Square(&x.C0.B2) - t3 := e.ext2.square(&x.C1.B0) // t[3].Square(&x.C1.B0) - t7 := e.ext2.add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). - t7 = e.ext2.square(t7) // Square(&t[7]). - t7 = e.ext2.sub(t7, t2) // Sub(&t[7], &t[2]). - t7 = e.ext2.sub(t7, t3) // Sub(&t[7], &t[3]) - t4 := e.ext2.square(&x.C1.B2) // t[4].Square(&x.C1.B2) - t5 := e.ext2.square(&x.C0.B1) // t[5].Square(&x.C0.B1) - t8 := e.ext2.add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). - t8 = e.ext2.square(t8) // Square(&t[8]). - t8 = e.ext2.sub(t8, t4) // Sub(&t[8], &t[4]). - t8 = e.ext2.sub(t8, t5) // Sub(&t[8], &t[5]). - t8 = e.ext2.mulByNonResidue(t8) // MulByNonResidue(&t[8]) - t0 = e.ext2.mulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). - t0 = e.ext2.add(t0, t1) // Add(&t[0], &t[1]) - t2 = e.ext2.mulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). - t2 = e.ext2.add(t2, t3) // Add(&t[2], &t[3]) - t4 = e.ext2.mulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). - t4 = e.ext2.add(t4, t5) // Add(&t[4], &t[5]) - z00 := e.ext2.sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). - z00 = e.ext2.double(z00) // Double(&z.C0.B0). - z00 = e.ext2.add(z00, t0) // Add(&z.C0.B0, &t[0]) - z01 := e.ext2.sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). - z01 = e.ext2.double(z01) // Double(&z.C0.B1). - z01 = e.ext2.add(z01, t2) // Add(&z.C0.B1, &t[2]) - z02 := e.ext2.sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). - z02 = e.ext2.double(z02) // Double(&z.C0.B2). - z02 = e.ext2.add(z02, t4) // Add(&z.C0.B2, &t[4]) - z10 := e.ext2.add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). - z10 = e.ext2.double(z10) // Double(&z.C1.B0). - z10 = e.ext2.add(z10, t8) // Add(&z.C1.B0, &t[8]) - z11 := e.ext2.add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). - z11 = e.ext2.double(z11) // Double(&z.C1.B1). - z11 = e.ext2.add(z11, t6) // Add(&z.C1.B1, &t[6]) - z12 := e.ext2.add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). - z12 = e.ext2.double(z12) // Double(&z.C1.B2). - z12 = e.ext2.add(z12, t7) // Add(&z.C1.B2, &t[7]) - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) frobenius(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) - t2 = e.ext2.mulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) - t3 = e.ext2.mulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) - t4 = e.ext2.mulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) - t5 = e.ext2.mulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) frobeniusSquare(x *e12) *e12 { - z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 - z01 := e.ext2.mulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.ext2.mulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.ext2.mulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.ext2.mulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.ext2.mulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) - return &e12{ // return z - C0: e6{B0: *z00, B1: *z01, B2: *z02}, - C1: e6{B0: *z10, B1: *z11, B2: *z12}, - } -} - -func (e ext12) frobeniusCube(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) - t2 = e.ext2.mulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) - t3 = e.ext2.mulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) - t4 = e.ext2.mulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) - t5 = e.ext2.mulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) expt(x *e12) *e12 { - // var result, t0, t1, t2, t3, t4, t5, t6 E12 - t3 := e.cyclotomicSquare(x) // t3.CyclotomicSquare(x) - t5 := e.cyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) - result := e.cyclotomicSquare(t5) // result.CyclotomicSquare(&t5) - t0 := e.cyclotomicSquare(result) // t0.CyclotomicSquare(&result) - t2 := e.mul(x, t0) // t2.Mul(x, &t0) - t0 = e.mul(t3, t2) // t0.Mul(&t3, &t2) - t1 := e.mul(x, t0) // t1.Mul(x, &t0) - t4 := e.mul(result, t2) // t4.Mul(&result, &t2) - t6 := e.cyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) - t1 = e.mul(t0, t1) // t1.Mul(&t0, &t1) - t0 = e.mul(t3, t1) // t0.Mul(&t3, &t1) - t6 = e.nSquare(t6, 6) // t6.nSquare(6) - t5 = e.mul(t5, t6) // t5.Mul(&t5, &t6) - t5 = e.mul(t4, t5) // t5.Mul(&t4, &t5) - t5 = e.nSquare(t5, 7) // t5.nSquare(7) - t4 = e.mul(t4, t5) // t4.Mul(&t4, &t5) - t4 = e.nSquare(t4, 8) // t4.nSquare(8) - t4 = e.mul(t0, t4) // t4.Mul(&t0, &t4) - t3 = e.mul(t3, t4) // t3.Mul(&t3, &t4) - t3 = e.nSquare(t3, 6) // t3.nSquare(6) - t2 = e.mul(t2, t3) // t2.Mul(&t2, &t3) - t2 = e.nSquare(t2, 8) // t2.nSquare(8) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 6) // t2.nSquare(6) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 10) // t2.nSquare(10) - t1 = e.mul(t1, t2) // t1.Mul(&t1, &t2) - t1 = e.nSquare(t1, 6) // t1.nSquare(6) - t0 = e.mul(t0, t1) // t0.Mul(&t0, &t1) - z := e.mul(result, t0) // z.Mul(&result, &t0) - return z // return z -} - -func (e ext12) one() *e12 { - z000 := e.fp.One() - zero := e.fp.Zero() - return &e12{ - 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) mulBy034(z *e12, c0, c3, c4 *e2) *e12 { - // var a, b, d E6 - a := e.ext6.mulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) - // b.Set(&z.C1) - b := e.ext6.mulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) - c0 = e.ext2.add(c0, c3) // c0.Add(c0, c3) - d := e.ext6.add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) - d = e.ext6.mulBy01(d, c0, c4) // d.MulBy01(c0, c4) - z1 := e.add(a, b) // z.C1.Add(&a, &b). - z1 = e.neg(z1) // Neg(&z.C1). - z1 = e.add(z1, d) // Add(&z.C1, &d) - z0 := e.mulByNonResidue(b) // z.C0.MulByNonResidue(&b). - z0 = e.add(z0, a) // Add(&z.C0, &a) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) square(x *e12) *e12 { - // var c0, c2, c3 E6 - c0 := e.ext6.sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) - c3 := e.ext6.mulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). - c3 = e.ext6.neg(c3) // Neg(&c3). - c3 = e.ext6.add(&x.C0, c3) // Add(&x.C0, &c3) - c2 := e.ext6.mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) - c0 = e.ext6.mul(c0, c3) // c0.Mul(&c0, &c3). - c0 = e.ext6.add(c0, c2) // Add(&c0, &c2) - z1 := e.ext6.double(c2) // z.C1.Double(&c2) - c2 = e.ext6.mulByNonResidue(c2) // c2.MulByNonResidue(&c2) - z0 := e.ext6.add(c0, c2) // z.C0.Add(&c0, &c2) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mulBy034by034(d0, d3, d4, c0, c3, c4 *e2) *e12 { - // var tmp, x0, x3, x4, x04, x03, x34 E2 - x0 := e.ext2.mul(c0, d0) // x0.Mul(c0, d0) - x3 := e.ext2.mul(c3, d3) // x3.Mul(c3, d3) - x4 := e.ext2.mul(c4, d4) // x4.Mul(c4, d4) - tmp := e.ext2.add(c0, c4) // tmp.Add(c0, c4) - x04 := e.ext2.add(d0, d4) // x04.Add(d0, d4). - x04 = e.ext2.mul(x04, tmp) // Mul(&x04, &tmp). - x04 = e.ext2.sub(x04, x0) // Sub(&x04, &x0). - x04 = e.ext2.sub(x04, x4) // Sub(&x04, &x4) - tmp = e.ext2.add(c0, c3) // tmp.Add(c0, c3) - x03 := e.ext2.add(d0, d3) // x03.Add(d0, d3). - x03 = e.ext2.mul(x03, tmp) // Mul(&x03, &tmp). - x03 = e.ext2.sub(x03, x0) // Sub(&x03, &x0). - x03 = e.ext2.sub(x03, x3) // Sub(&x03, &x3) - tmp = e.ext2.add(c3, c4) // tmp.Add(c3, c4) - x34 := e.ext2.add(d3, d4) // x34.Add(d3, d4). - x34 = e.ext2.mul(x34, tmp) // Mul(&x34, &tmp). - x34 = e.ext2.sub(x34, x3) // Sub(&x34, &x3). - x34 = e.ext2.sub(x34, x4) // Sub(&x34, &x4) - z00 := e.ext2.mulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). - z00 = e.ext2.add(z00, x0) // Add(&z.C0.B0, &x0) - z01 := x3 // z.C0.B1.Set(&x3) - z02 := x34 // z.C0.B2.Set(&x34) - z10 := x03 // z.C1.B0.Set(&x03) - z11 := x04 // z.C1.B1.Set(&x04) - z12 := e.ext2.zero() // z.C1.B2.SetZero() - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) assertIsEqual(x, y *e12) { - e.ext6.assertIsEqual(&x.C0, &y.C0) - e.ext6.assertIsEqual(&x.C1, &y.C1) -} - -func (e ext12) nSquare(z *e12, n int) *e12 { - for i := 0; i < n; i++ { - z = e.cyclotomicSquare(z) - } - return z -} diff --git a/std/algebra/sw_bls12377/doc.go b/std/algebra/sw_bls12377/doc.go deleted file mode 100644 index c9270127e8..0000000000 --- a/std/algebra/sw_bls12377/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright © 2020 ConsenSys - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package sw (short weierstrass) -package sw_bls12377 diff --git a/std/algebra/sw_bls24315/doc.go b/std/algebra/sw_bls24315/doc.go deleted file mode 100644 index 279e09879b..0000000000 --- a/std/algebra/sw_bls24315/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright © 2020 ConsenSys - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package sw (short weierstrass) -package sw_bls24315 diff --git a/std/commitments/kzg_bls12377/verifier.go b/std/commitments/kzg_bls12377/verifier.go index d999e6396e..43dd15a83a 100644 --- a/std/commitments/kzg_bls12377/verifier.go +++ b/std/commitments/kzg_bls12377/verifier.go @@ -19,8 +19,8 @@ package kzg_bls12377 import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) // Digest commitment of a polynomial. diff --git a/std/commitments/kzg_bls24315/verifier.go b/std/commitments/kzg_bls24315/verifier.go index e5704525f8..4d6680c072 100644 --- a/std/commitments/kzg_bls24315/verifier.go +++ b/std/commitments/kzg_bls24315/verifier.go @@ -19,8 +19,8 @@ package kzg_bls24315 import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) // Digest commitment of a polynomial. diff --git a/std/groth16_bls12377/verifier.go b/std/groth16_bls12377/verifier.go index 6a43e585a8..8316d20479 100644 --- a/std/groth16_bls12377/verifier.go +++ b/std/groth16_bls12377/verifier.go @@ -24,8 +24,8 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - "github.com/consensys/gnark/std/algebra/fields_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) // Proof represents a Groth16 proof diff --git a/std/groth16_bls12377/verifier_test.go b/std/groth16_bls12377/verifier_test.go index 61bc403ca5..beab2de62b 100644 --- a/std/groth16_bls12377/verifier_test.go +++ b/std/groth16_bls12377/verifier_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) diff --git a/std/groth16_bls24315/verifier.go b/std/groth16_bls24315/verifier.go index 09487acbb3..836c20d33b 100644 --- a/std/groth16_bls24315/verifier.go +++ b/std/groth16_bls24315/verifier.go @@ -24,8 +24,8 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - "github.com/consensys/gnark/std/algebra/fields_bls24315" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) // Proof represents a Groth16 proof diff --git a/std/groth16_bls24315/verifier_test.go b/std/groth16_bls24315/verifier_test.go index 18da40b4b4..73bb075d19 100644 --- a/std/groth16_bls24315/verifier_test.go +++ b/std/groth16_bls24315/verifier_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) diff --git a/std/hints.go b/std/hints.go index c3bdc3713b..f9b85d3266 100644 --- a/std/hints.go +++ b/std/hints.go @@ -4,8 +4,8 @@ import ( "sync" "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/algebra/sw_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/selector" diff --git a/std/math/emulated/field_test.go b/std/math/emulated/field_test.go index 927b23bc59..d1124f4e82 100644 --- a/std/math/emulated/field_test.go +++ b/std/math/emulated/field_test.go @@ -8,7 +8,7 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/test" ) diff --git a/std/signature/ecdsa/ecdsa.go b/std/signature/ecdsa/ecdsa.go index acf7286dcd..86bdb5bac7 100644 --- a/std/signature/ecdsa/ecdsa.go +++ b/std/signature/ecdsa/ecdsa.go @@ -1,7 +1,7 @@ /* Package ecdsa implements ECDSA signature verification over any elliptic curve. -The package depends on the [weierstrass] package for elliptic curve group +The package depends on the [emulated/sw_emulated] package for elliptic curve group operations using non-native arithmetic. Thus we can verify ECDSA signatures over any curve. The cost for a single secp256k1 signature verification is approximately 4M constraints in R1CS and 10M constraints in PLONKish. @@ -15,7 +15,7 @@ package ecdsa import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -25,14 +25,14 @@ type Signature[Scalar emulated.FieldParams] struct { } // PublicKey represents the public key to verify the signature for. -type PublicKey[Base, Scalar emulated.FieldParams] weierstrass.AffinePoint[Base] +type PublicKey[Base, Scalar emulated.FieldParams] sw_emulated.AffinePoint[Base] // Verify asserts that the signature sig verifies for the message msg and public // key pk. The curve parameters params define the elliptic curve. // // We assume that the message msg is already hashed to the scalar field. -func (pk PublicKey[T, S]) Verify(api frontend.API, params weierstrass.CurveParams, msg *emulated.Element[S], sig *Signature[S]) { - cr, err := weierstrass.New[T, S](api, params) +func (pk PublicKey[T, S]) Verify(api frontend.API, params sw_emulated.CurveParams, msg *emulated.Element[S], sig *Signature[S]) { + cr, err := sw_emulated.New[T, S](api, params) if err != nil { // TODO: softer handling. panic(err) @@ -45,7 +45,7 @@ func (pk PublicKey[T, S]) Verify(api frontend.API, params weierstrass.CurveParam if err != nil { panic(err) } - pkpt := weierstrass.AffinePoint[T](pk) + pkpt := sw_emulated.AffinePoint[T](pk) sInv := scalarApi.Inverse(&sig.S) msInv := scalarApi.MulMod(msg, sInv) rsInv := scalarApi.MulMod(&sig.R, sInv) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index 711ec69554..57ff1a4406 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -9,7 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -21,7 +21,7 @@ type EcdsaCircuit[T, S emulated.FieldParams] struct { } func (c *EcdsaCircuit[T, S]) Define(api frontend.API) error { - c.Pub.Verify(api, weierstrass.GetCurveParams[T](), &c.Msg, &c.Sig) + c.Pub.Verify(api, sw_emulated.GetCurveParams[T](), &c.Msg, &c.Sig) return nil } @@ -134,7 +134,7 @@ func ExamplePublicKey_Verify() { Y: emulated.ValueOf[emulated.Secp256k1Fp](puby), } // signature verification assertion is done in-circuit - Pub.Verify(api, weierstrass.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) + Pub.Verify(api, sw_emulated.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) } // Example how to create a valid signature for secp256k1 diff --git a/std/signature/eddsa/eddsa.go b/std/signature/eddsa/eddsa.go index e285f00496..dcfcfc2870 100644 --- a/std/signature/eddsa/eddsa.go +++ b/std/signature/eddsa/eddsa.go @@ -24,7 +24,7 @@ import ( "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" tedwards "github.com/consensys/gnark-crypto/ecc/twistededwards" diff --git a/std/signature/eddsa/eddsa_test.go b/std/signature/eddsa/eddsa_test.go index 657d337010..762bfb5ef0 100644 --- a/std/signature/eddsa/eddsa_test.go +++ b/std/signature/eddsa/eddsa_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark-crypto/signature/eddsa" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/utils" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" )