Skip to content

Commit

Permalink
perf(bw6): implement a variant of Karabina cyclo square
Browse files Browse the repository at this point in the history
  • Loading branch information
yelhousni committed Nov 23, 2023
1 parent ec07217 commit d7e8d78
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 55 deletions.
103 changes: 98 additions & 5 deletions std/algebra/emulated/fields_bw6761/e6.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,103 @@ func (e Ext6) Square(x *E6) *E6 {
}
}

// Karabina's compressed cyclotomic square
// Karabina's compressed cyclotomic square SQR12345
// https://eprint.iacr.org/2010/542.pdf
// Sec. 5.6 with minor modifications to fit our tower
func (e Ext6) CyclotomicSquareKarabina12345(x *E6) *E6 {
x = e.Reduce(x)

// h4 = -g4 + 3((g3+g5)(g1+c*g2)-g1g5-c*g3g2)
g1g5 := e.fp.Mul(&x.B0.A1, &x.B1.A2)
g3g2 := e.fp.Mul(&x.B1.A0, &x.B0.A2)
h4 := mulFpByNonResidue(e.fp, &x.B0.A2)
h4 = e.fp.Add(h4, &x.B0.A1)
t := e.fp.Add(&x.B1.A0, &x.B1.A2)
h4 = e.fp.Mul(h4, t)
h4 = e.fp.Sub(h4, g1g5)
t = mulFpByNonResidue(e.fp, g3g2)
h4 = e.fp.Sub(h4, t)
h4 = e.fp.MulConst(h4, big.NewInt(3))
h4 = e.fp.Sub(h4, &x.B1.A1)

// h3 = 2(g3+3c*g1g5)
h3 := mulFpByNonResidue(e.fp, g1g5)
h3 = e.fp.MulConst(h3, big.NewInt(3))
h3 = e.fp.Add(h3, &x.B1.A0)
h3 = e.fp.MulConst(h3, big.NewInt(2))

// h2 = 3((g1+g5)(g1+c*g5)-c*g1g5-g1g5)-2g2
t = mulFpByNonResidue(e.fp, &x.B1.A2)
t = e.fp.Add(t, &x.B0.A1)
h2 := e.fp.Add(&x.B1.A2, &x.B0.A1)
h2 = e.fp.Mul(h2, t)
h2 = e.fp.Sub(h2, g1g5)
t = mulFpByNonResidue(e.fp, g1g5)
h2 = e.fp.Sub(h2, t)
h2 = e.fp.MulConst(h2, big.NewInt(3))
t = e.fp.MulConst(&x.B0.A2, big.NewInt(2))
h2 = e.fp.Sub(h2, t)

// h1 = 3((g3+g2)(g3+c*g2)-c*g3g2-g3g2)-2g1
t = mulFpByNonResidue(e.fp, &x.B0.A2)
t = e.fp.Add(t, &x.B1.A0)
h1 := e.fp.Add(&x.B0.A2, &x.B1.A0)
h1 = e.fp.Mul(h1, t)
h1 = e.fp.Sub(h1, g3g2)
t = mulFpByNonResidue(e.fp, g3g2)
h1 = e.fp.Sub(h1, t)
h1 = e.fp.MulConst(h1, big.NewInt(3))
t = e.fp.MulConst(&x.B0.A1, big.NewInt(2))
h1 = e.fp.Sub(h1, t)

// h5 = 2(g5+3g3g2)
h5 := e.fp.MulConst(g3g2, big.NewInt(3))
h5 = e.fp.Add(h5, &x.B1.A2)
h5 = e.fp.MulConst(h5, big.NewInt(2))

return &E6{
B0: E3{
A0: x.B0.A0,
A1: *h1,
A2: *h2,
},
B1: E3{
A0: *h3,
A1: *h4,
A2: *h5,
},
}
}

// DecompressKarabina12345 decompresses Karabina's cyclotomic square result SQR12345
func (e Ext6) DecompressKarabina12345(x *E6) *E6 {
x = e.Reduce(x)

// h0 = (2g4^2 + g3g5 - 3g2g1)*c + 1
t0 := e.fp.Mul(&x.B0.A1, &x.B0.A2)
t0 = e.fp.MulConst(t0, big.NewInt(3))
t1 := e.fp.Mul(&x.B1.A0, &x.B1.A2)
h0 := e.fp.Mul(&x.B1.A1, &x.B1.A1)
h0 = e.fp.MulConst(h0, big.NewInt(2))
h0 = e.fp.Add(h0, t1)
h0 = e.fp.Sub(h0, t0)
h0 = mulFpByNonResidue(e.fp, h0)
h0 = e.fp.Add(h0, e.fp.One())

return &E6{
B0: E3{
A0: *h0,
A1: x.B0.A1,
A2: x.B0.A2,
},
B1: x.B1,
}
}

// Karabina's compressed cyclotomic square SQR2345
// https://eprint.iacr.org/2010/542.pdf
// Th. 3.2 with minor modifications to fit our tower
func (e Ext6) CyclotomicSquareCompressed(x *E6) *E6 {
func (e Ext6) CyclotomicSquareKarabina2345(x *E6) *E6 {
x = e.Reduce(x)
z := e.Copy(x)

Expand Down Expand Up @@ -183,7 +276,7 @@ func (e Ext6) CyclotomicSquareCompressed(x *E6) *E6 {
return z
}

// DecompressKarabina Karabina's cyclotomic square result
// DecompressKarabina2345 decompresses Karabina's cyclotomic square result SQR2345
// if g3 != 0
//
// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3
Expand All @@ -194,7 +287,7 @@ func (e Ext6) CyclotomicSquareCompressed(x *E6) *E6 {
//
// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1)
// Theorem 3.1 is well-defined for all x in Gϕₙ\{1}
func (e Ext6) DecompressKarabina(x *E6) *E6 {
func (e Ext6) DecompressKarabina2345(x *E6) *E6 {

x = e.Reduce(x)

Expand Down Expand Up @@ -246,7 +339,7 @@ func (e Ext6) DecompressKarabina(x *E6) *E6 {
t[2] = e.fp.Sub(t[2], t[1])
// t1 = g3 * g5 (g3 can be 0)
t[1] = e.fp.Mul(&x.B1.A0, &x.B1.A2)
// c₀ = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1
// g0 = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1
t[2] = e.fp.Add(t[2], t[1])

z.B0.A0 = *mulFpByNonResidue(e.fp, t[2])
Expand Down
83 changes: 45 additions & 38 deletions std/algebra/emulated/fields_bw6761/e6_pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ import (
"github.com/consensys/gnark/std/math/emulated"
)

func (e Ext6) nSquareCompressed(z *E6, n int) *E6 {
func (e Ext6) nSquareKarabina2345(z *E6, n int) *E6 {
for i := 0; i < n; i++ {
z = e.CyclotomicSquareCompressed(z)
z = e.CyclotomicSquareKarabina2345(z)
}
return z
}

func (e Ext6) nSquareKarabina12345(z *E6, n int) *E6 {
for i := 0; i < n; i++ {
z = e.CyclotomicSquareKarabina12345(z)
}
return z
}
Expand All @@ -18,20 +25,20 @@ func (e Ext6) nSquareCompressed(z *E6, n int) *E6 {
func (e Ext6) ExpX0Minus1(z *E6) *E6 {
z = e.Reduce(z)
result := e.Copy(z)
result = e.nSquareCompressed(result, 5)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 5)
result = e.DecompressKarabina12345(result)
result = e.Mul(result, z)
z33 := e.Copy(result)
result = e.nSquareCompressed(result, 7)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 7)
result = e.DecompressKarabina12345(result)
result = e.Mul(result, z33)
result = e.nSquareCompressed(result, 4)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 4)
result = e.DecompressKarabina12345(result)
result = e.Mul(result, z)
result = e.CyclotomicSquare(result)
result = e.Mul(result, z)
result = e.nSquareCompressed(result, 46)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina2345(result, 46)
result = e.DecompressKarabina2345(result)

return result
}
Expand All @@ -41,29 +48,29 @@ func (e Ext6) ExpX0Minus1(z *E6) *E6 {
func (e Ext6) ExpX0Minus1Square(z *E6) *E6 {
z = e.Reduce(z)
result := e.Copy(z)
result = e.nSquareCompressed(result, 3)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 3)
result = e.DecompressKarabina12345(result)
t0 := e.CyclotomicSquare(result)
t2 := e.Mul(z, t0)
result = e.Mul(result, t2)
t0 = e.Mul(z, result)
t1 := e.CyclotomicSquare(t0)
t1 = e.Mul(t2, t1)
t3 := e.nSquareCompressed(t1, 7)
t3 = e.DecompressKarabina(t3)
t3 := e.nSquareKarabina12345(t1, 7)
t3 = e.DecompressKarabina12345(t3)
t2 = e.Mul(t2, t3)
t2 = e.nSquareCompressed(t2, 11)
t2 = e.DecompressKarabina(t2)
t2 = e.nSquareKarabina12345(t2, 11)
t2 = e.DecompressKarabina12345(t2)
t1 = e.Mul(t1, t2)
t0 = e.Mul(t0, t1)
t0 = e.nSquareCompressed(t0, 7)
t0 = e.DecompressKarabina(t0)
t0 = e.nSquareKarabina12345(t0, 7)
t0 = e.DecompressKarabina12345(t0)
result = e.Mul(result, t0)
result = e.nSquareCompressed(result, 3)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 3)
result = e.DecompressKarabina12345(result)
result = e.Mul(z, result)
result = e.nSquareCompressed(result, 92)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina2345(result, 92)
result = e.DecompressKarabina2345(result)

return result

Expand All @@ -75,20 +82,20 @@ func (e Ext6) ExpX0Plus1(z *E6) *E6 {
z = e.Reduce(z)
result := e.Copy(z)
t := e.CyclotomicSquare(result)
result = e.nSquareCompressed(t, 4)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(t, 4)
result = e.DecompressKarabina12345(result)
result = e.Mul(result, z)
z33 := e.Copy(result)
result = e.nSquareCompressed(result, 7)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 7)
result = e.DecompressKarabina12345(result)
result = e.Mul(result, z33)
result = e.nSquareCompressed(result, 4)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 4)
result = e.DecompressKarabina12345(result)
result = e.Mul(result, z)
result = e.CyclotomicSquare(result)
result = e.Mul(result, z)
result = e.nSquareCompressed(result, 46)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina2345(result, 46)
result = e.DecompressKarabina2345(result)
result = e.Mul(result, t)

return result
Expand All @@ -104,14 +111,14 @@ func (e Ext6) ExptMinus1Div3(z *E6) *E6 {
result = e.Mul(result, z)
result = e.CyclotomicSquare(result)
result = e.Mul(result, z)
t0 := e.nSquareCompressed(result, 7)
t0 = e.DecompressKarabina(t0)
t0 := e.nSquareKarabina12345(result, 7)
t0 = e.DecompressKarabina2345(t0)
result = e.Mul(result, t0)
result = e.nSquareCompressed(result, 5)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina12345(result, 5)
result = e.DecompressKarabina12345(result)
result = e.Mul(result, z)
result = e.nSquareCompressed(result, 46)
result = e.DecompressKarabina(result)
result = e.nSquareKarabina2345(result, 46)
result = e.DecompressKarabina2345(result)

return result
}
Expand All @@ -138,8 +145,8 @@ func (e Ext6) ExpC2(z *E6) *E6 {
z = e.Reduce(z)
result := e.CyclotomicSquare(z)
result = e.Mul(result, z)
t0 := e.nSquareCompressed(result, 4)
t0 = e.DecompressKarabina(t0)
t0 := e.nSquareKarabina12345(result, 4)
t0 = e.DecompressKarabina12345(t0)
result = e.Mul(result, t0)
result = e.CyclotomicSquare(result)
result = e.Mul(result, z)
Expand Down
24 changes: 12 additions & 12 deletions std/algebra/emulated/fields_bw6761/e6_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,59 +245,59 @@ func TestConjugateFp6(t *testing.T) {
assert.NoError(err)
}

type e6CyclotomicSquareCompressed struct {
type e6CyclotomicSquareKarabina2345 struct {
A, B E6
}

func (circuit *e6CyclotomicSquareCompressed) Define(api frontend.API) error {
func (circuit *e6CyclotomicSquareKarabina2345) Define(api frontend.API) error {
e := NewExt6(api)
expected := e.CyclotomicSquareCompressed(&circuit.A)
expected := e.CyclotomicSquareKarabina2345(&circuit.A)
e.AssertIsEqual(expected, &circuit.B)
return nil
}

func TestCyclotomicSquareCompressedFp6(t *testing.T) {
func TestCyclotomicSquareKarabina2345Fp6(t *testing.T) {
assert := test.NewAssert(t)
// witness values
var a, b bw6761.E6
_, _ = a.SetRandom()
b.Set(&a)
b.CyclotomicSquareCompressed(&a)

witness := e6CyclotomicSquareCompressed{
witness := e6CyclotomicSquareKarabina2345{
A: FromE6(&a),
B: FromE6(&b),
}

err := test.IsSolved(&e6CyclotomicSquareCompressed{}, &witness, ecc.BN254.ScalarField())
err := test.IsSolved(&e6CyclotomicSquareKarabina2345{}, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}

type e6DecompressKarabina struct {
type e6DecompressKarabina2345 struct {
A, B E6
}

func (circuit *e6DecompressKarabina) Define(api frontend.API) error {
func (circuit *e6DecompressKarabina2345) Define(api frontend.API) error {
e := NewExt6(api)
expected := e.DecompressKarabina(&circuit.A)
expected := e.DecompressKarabina2345(&circuit.A)
e.AssertIsEqual(expected, &circuit.B)
return nil
}

func TestDecompressKarabinaFp6(t *testing.T) {
func TestDecompressKarabina2345Fp6(t *testing.T) {
assert := test.NewAssert(t)
// witness values
var a, b bw6761.E6
_, _ = a.SetRandom()
b.Set(&a)
a.DecompressKarabina(&a)

witness := e6DecompressKarabina{
witness := e6DecompressKarabina2345{
A: FromE6(&b),
B: FromE6(&a),
}

err := test.IsSolved(&e6DecompressKarabina{}, &witness, ecc.BN254.ScalarField())
err := test.IsSolved(&e6DecompressKarabina2345{}, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}

Expand Down

0 comments on commit d7e8d78

Please sign in to comment.