Skip to content

Commit

Permalink
Refactor: std/algebra (#526)
Browse files Browse the repository at this point in the history
* 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 <ivo.kubjas@consensys.net>
  • Loading branch information
yelhousni and ivokub authored Mar 8, 2023
1 parent 73896a7 commit 8ed586e
Show file tree
Hide file tree
Showing 79 changed files with 1,443 additions and 1,412 deletions.
2 changes: 1 addition & 1 deletion examples/rollup/circuit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down
4 changes: 2 additions & 2 deletions internal/stats/snippet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
14 changes: 14 additions & 0 deletions std/algebra/doc.go
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions std/algebra/emulated/fields_bn254/doc.go
Original file line number Diff line number Diff line change
@@ -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
226 changes: 226 additions & 0 deletions std/algebra/emulated/fields_bn254/e12.go
Original file line number Diff line number Diff line change
@@ -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)
}
96 changes: 96 additions & 0 deletions std/algebra/emulated/fields_bn254/e12_pairing.go
Original file line number Diff line number Diff line change
@@ -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,
},
}
}
Loading

0 comments on commit 8ed586e

Please sign in to comment.