Skip to content

Commit

Permalink
feat: BN254 pairing (Consensys#411)
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
  • Loading branch information
ivokub authored Mar 6, 2023
1 parent ba7ef6b commit db76d9e
Show file tree
Hide file tree
Showing 8 changed files with 1,433 additions and 0 deletions.
7 changes: 7 additions & 0 deletions std/algebra/pairing_bn254/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Package pairing_bn254 implements pairing 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
101 changes: 101 additions & 0 deletions std/algebra/pairing_bn254/doc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package pairing_bn254_test

import (
"crypto/rand"
"fmt"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/ecc/bn254"
"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"
)

type PairCircuit struct {
InG1 pairing_bn254.G1Affine
InG2 pairing_bn254.G2Affine
Res pairing_bn254.GTEl
}

func (c *PairCircuit) Define(api frontend.API) error {
pairing, err := pairing_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})
if err != nil {
return fmt.Errorf("pair: %w", err)
}
pairing.AssertIsEqual(res, &c.Res)
return nil
}

func ExamplePairing() {
p, q, err := randomG1G2Affines()
if err != nil {
panic(err)
}
res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q})
if err != nil {
panic(err)
}
circuit := PairCircuit{}
witness := PairCircuit{
InG1: pairing_bn254.NewG1Affine(p),
InG2: pairing_bn254.NewG2Affine(q),
Res: pairing_bn254.NewGTEl(res),
}
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
panic(err)
} else {
fmt.Println("compiled")
}
pk, vk, err := groth16.Setup(ccs)
if err != nil {
panic(err)
} else {
fmt.Println("setup done")
}
secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField())
if err != nil {
panic(err)
} else {
fmt.Println("secret witness")
}
publicWitness, err := secretWitness.Public()
if err != nil {
panic(err)
} else {
fmt.Println("public witness")
}
proof, err := groth16.Prove(ccs, pk, secretWitness)
if err != nil {
panic(err)
} else {
fmt.Println("proof")
}
err = groth16.Verify(proof, vk, publicWitness)
if err != nil {
panic(err)
} else {
fmt.Println("verify")
}
}

func randomG1G2Affines() (p bn254.G1Affine, q bn254.G2Affine, err error) {
_, _, G1AffGen, G2AffGen := bn254.Generators()
mod := bn254.ID.ScalarField()
s1, err := rand.Int(rand.Reader, mod)
if err != nil {
return p, q, err
}
s2, err := rand.Int(rand.Reader, mod)
if err != nil {
return p, q, err
}
p.ScalarMultiplication(&G1AffGen, s1)
q.ScalarMultiplication(&G2AffGen, s2)
return
}
16 changes: 16 additions & 0 deletions std/algebra/pairing_bn254/g1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package pairing_bn254

import (
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark/std/algebra/weierstrass"
"github.com/consensys/gnark/std/math/emulated"
)

type G1Affine = weierstrass.AffinePoint[emulated.BN254Fp]

func NewG1Affine(v bn254.G1Affine) G1Affine {
return G1Affine{
X: emulated.ValueOf[emulated.BN254Fp](v.X),
Y: emulated.ValueOf[emulated.BN254Fp](v.Y),
}
}
31 changes: 31 additions & 0 deletions std/algebra/pairing_bn254/g2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package pairing_bn254

import (
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark/std/math/emulated"
)

type G2Affine struct {
X, Y e2
}

type g2Jacobian struct {
X, Y, Z e2
}

type g2Projective struct {
X, Y, Z e2
}

func NewG2Affine(v bn254.G2Affine) G2Affine {
return G2Affine{
X: e2{
A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0),
A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1),
},
Y: e2{
A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0),
A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1),
},
}
}
41 changes: 41 additions & 0 deletions std/algebra/pairing_bn254/gt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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),
},
},
}
}
Loading

0 comments on commit db76d9e

Please sign in to comment.