Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: fixed-argument emulated pairing #708

Merged
merged 21 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5da68fd
feat(emulated/bn254): fixed-argument pairing
yelhousni May 30, 2023
9d6155e
feat(emulated/bls12-381): fixed-argument pairing
yelhousni May 30, 2023
d639d22
feat(emulated/bn254): double ML for fixed-argument pairing
yelhousni May 30, 2023
94a38a0
perf(bn254/fixed-pair): isolate first iteration
yelhousni May 30, 2023
f11d757
perf(bn254/fixed-pair): use double-and-add for variable argument
yelhousni May 30, 2023
57a1dd2
perf(bls12-381/pairing): mul lines 2-by-2
yelhousni May 31, 2023
d0895dc
perf(bls12-381/fixed-pairing): isolate last iteration
yelhousni May 31, 2023
4de2ce1
fix: test double fixed pairing
yelhousni May 31, 2023
72bc177
fix(bls12-381/fixed-pairing): fix last iteration computation
yelhousni May 31, 2023
9b24466
perf(bn254/fixed-pair): mul precomputed lines 2-by-2
yelhousni May 31, 2023
d2f8f2d
refactor: remove profiler code
yelhousni May 31, 2023
c6de6f8
docs(fixed-emulated-pairing): add some comments
yelhousni May 31, 2023
dd6c7f1
feat(native/bls12-377): fixed-argument pairing
yelhousni Jun 1, 2023
215f19b
feat(native/bls24-315): fixed-argument pairing
yelhousni Jun 1, 2023
270dc19
docs: comment fixed pairing
yelhousni Jun 1, 2023
8b0aba7
feat: define precomputed lines only if initalising
ivokub Jun 1, 2023
f2a8748
feat: lazy line initialising
ivokub Jun 1, 2023
ea3e180
refactor: make native precomputed lines private
ivokub Jun 1, 2023
c8664c2
refactor(native/pairing): no need to isolate last iteration in fixed 1ML
yelhousni Jun 2, 2023
e24c520
perf(bn254-pairing): some missed small optims
yelhousni Jun 2, 2023
07a87ed
refactor(native/pairing): no need to switch -1/1 when lines precomputed
yelhousni Jun 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions std/algebra/emulated/sw_bls12381/g2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ func (c *addG2Circuit) Define(api frontend.API) error {

func TestAddG2TestSolve(t *testing.T) {
assert := test.NewAssert(t)
_, in1 := randomG1G2Affines(assert)
_, in2 := randomG1G2Affines(assert)
_, in1 := randomG1G2Affines()
_, in2 := randomG1G2Affines()
var res bls12381.G2Affine
res.Add(&in1, &in2)
witness := addG2Circuit{
Expand All @@ -51,7 +51,7 @@ func (c *doubleG2Circuit) Define(api frontend.API) error {

func TestDoubleG2TestSolve(t *testing.T) {
assert := test.NewAssert(t)
_, in1 := randomG1G2Affines(assert)
_, in1 := randomG1G2Affines()
var res bls12381.G2Affine
var in1Jac, resJac bls12381.G2Jac
in1Jac.FromAffine(&in1)
Expand Down Expand Up @@ -79,8 +79,8 @@ func (c *doubleAndAddG2Circuit) Define(api frontend.API) error {

func TestDoubleAndAddG2TestSolve(t *testing.T) {
assert := test.NewAssert(t)
_, in1 := randomG1G2Affines(assert)
_, in2 := randomG1G2Affines(assert)
_, in1 := randomG1G2Affines()
_, in2 := randomG1G2Affines()
var res bls12381.G2Affine
res.Double(&in1).
Add(&res, &in2)
Expand All @@ -107,7 +107,7 @@ func (c *scalarMulG2BySeedCircuit) Define(api frontend.API) error {

func TestScalarMulG2BySeedTestSolve(t *testing.T) {
assert := test.NewAssert(t)
_, in1 := randomG1G2Affines(assert)
_, in1 := randomG1G2Affines()
var res bls12381.G2Affine
x0, _ := new(big.Int).SetString("15132376222941642752", 10)
res.ScalarMultiplication(&in1, x0).Neg(&res)
Expand Down
228 changes: 220 additions & 8 deletions std/algebra/emulated/sw_bls12381/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Pairing struct {
g1 *G1
curve *sw_emulated.Curve[emulated.BLS12381Fp, emulated.BLS12381Fr]
bTwist *fields_bls12381.E2
lines [4][63]fields_bls12381.E2
}

type GTEl = fields_bls12381.E12
Expand Down Expand Up @@ -82,6 +83,7 @@ func NewPairing(api frontend.API) (*Pairing, error) {
g1: g1,
g2: NewG2(api),
bTwist: &bTwist,
lines: getPrecomputedLines(),
}, nil
}

Expand Down Expand Up @@ -373,13 +375,14 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) {
// line evaluation at P[k]
l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k])
l1.R1 = *pr.MulByElement(&l1.R1, yInv[k])
// ℓ × res
res = pr.MulBy014(res, &l1.R1, &l1.R0)
// line evaluation at P[k]
l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k])
l2.R1 = *pr.MulByElement(&l2.R1, yInv[k])
// ℓ × res
res = pr.MulBy014(res, &l2.R1, &l2.R0)
// ℓ × ℓ
prodLines = *pr.Mul014By014(&l1.R1, &l1.R0, &l2.R1, &l2.R0)
// (ℓ × ℓ) × res
res = pr.MulBy01245(res, &prodLines)

}

// Compute ∏ᵢ { fᵢ_{u,Q}(P) }
Expand Down Expand Up @@ -410,10 +413,10 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) {
// line evaluation at P[k]
l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k])
l2.R1 = *pr.MulByElement(&l2.R1, yInv[k])
// ℓ × res
res = pr.MulBy014(res, &l1.R1, &l1.R0)
// × res
res = pr.MulBy014(res, &l2.R1, &l2.R0)
// ℓ ×
prodLines = *pr.Mul014By014(&l1.R1, &l1.R0, &l2.R1, &l2.R0)
// (ℓ × ℓ) × res
res = pr.MulBy01245(res, &prodLines)
}
}
}
Expand Down Expand Up @@ -623,3 +626,212 @@ func (pr Pairing) tangentCompute(p1 *G2Affine) *lineEvaluation {
return &line

}

// ----------------------------
// Fixed-argument pairing
// ----------------------------
//
// The second argument Q is g2 the fixed canonical generator of G2.
//
// g2.X.A0 = 0x24aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
// g2.X.A1 = 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e
// g2.Y.A0 = 0xce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801
// g2.Y.A1 = 0x606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be

// MillerLoopFixed computes the single Miller loop
// fᵢ_{u,g2}(P), where g2 is fixed.
func (pr Pairing) MillerLoopFixedQ(P *G1Affine) (*GTEl, error) {

res := pr.Ext12.One()

var yInv, xOverY *emulated.Element[emulated.BLS12381Fp]

// P and Q are supposed to be on G1 and G2 respectively of prime order r.
// The point (x,0) is of order 2. But this function does not check
// subgroup membership.
// Anyway (x,0) cannot be on BLS12-381 because -4 is a cubic non-residue in Fp.
// so, 1/y is well defined for all points P's
yInv = pr.curveF.Inverse(&P.Y)
xOverY = pr.curveF.MulMod(&P.X, yInv)

// Compute ∏ᵢ { fᵢ_{x₀,Q}(P) }

// i = 62, separately to avoid an E12 Square
// (Square(res) = 1² = 1)
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[1][62], yInv),
pr.MulByElement(&pr.lines[0][62], xOverY),
)
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[3][62], yInv),
pr.MulByElement(&pr.lines[2][62], xOverY),
)

// Compute ∏ᵢ { fᵢ_{u,Q}(P) }
for i := 61; i >= 0; i-- {
// mutualize the square among n Miller loops
// (∏ᵢfᵢ)²
res = pr.Square(res)

if loopCounter[i] == 0 {
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[1][i], yInv),
pr.MulByElement(&pr.lines[0][i], xOverY),
)
} else {
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[1][i], yInv),
pr.MulByElement(&pr.lines[0][i], xOverY),
)
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[3][i], yInv),
pr.MulByElement(&pr.lines[2][i], xOverY),
)
}
}

// negative x₀
res = pr.Ext12.Conjugate(res)

return res, nil
}

// DoubleMillerLoopFixedQ computes the double Miller loop
// fᵢ_{u,g2}(T) * fᵢ_{u,Q}(P), where g2 is fixed.
func (pr Pairing) DoubleMillerLoopFixedQ(P, T *G1Affine, Q *G2Affine) (*GTEl, error) {
res := pr.Ext12.One()

var l1, l2 *lineEvaluation
var Qacc *G2Affine
Qacc = Q
var yInv, xOverY, y2Inv, x2OverY2 *emulated.Element[emulated.BLS12381Fp]
yInv = pr.curveF.Inverse(&P.Y)
xOverY = pr.curveF.MulMod(&P.X, yInv)
y2Inv = pr.curveF.Inverse(&T.Y)
x2OverY2 = pr.curveF.MulMod(&T.X, y2Inv)

// i = 62, separately to avoid an E12 Square
// (Square(res) = 1² = 1)

// Qacc ← 3Qacc,
// l1 the tangent ℓ to 2Q
// l2 the line ℓ passing 2Q and Q
Qacc, l1, l2 = pr.tripleStep(Qacc)
// line evaluation at P
// and assign line to res (R1, R0, 0, 0, 1, 0)
res.C0.B1 = *pr.MulByElement(&l1.R0, xOverY)
res.C0.B0 = *pr.MulByElement(&l1.R1, yInv)
res.C1.B1 = *pr.Ext2.One()
// line evaluation at P
l2.R0 = *pr.MulByElement(&l2.R0, xOverY)
l2.R1 = *pr.MulByElement(&l2.R1, yInv)
// res = ℓ × ℓ
prodLines := *pr.Mul014By014(&l2.R1, &l2.R0, &res.C0.B0, &res.C0.B1)
res.C0.B0 = prodLines[0]
res.C0.B1 = prodLines[1]
res.C0.B2 = prodLines[2]
res.C1.B1 = prodLines[3]
res.C1.B2 = prodLines[4]

res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[1][62], y2Inv),
pr.MulByElement(&pr.lines[0][62], x2OverY2),
)
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[3][62], y2Inv),
pr.MulByElement(&pr.lines[2][62], x2OverY2),
)

// Compute ∏ᵢ { fᵢ_{u,G2}(T) }
for i := 61; i >= 1; i-- {
// mutualize the square among n Miller loops
// (∏ᵢfᵢ)²
res = pr.Square(res)

if loopCounter[i] == 0 {
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[1][i], y2Inv),
pr.MulByElement(&pr.lines[0][i], x2OverY2),
)
// Qacc ← 2Qacc and l1 the tangent ℓ passing 2Qacc
Qacc, l1 = pr.doubleStep(Qacc)
// line evaluation at P
l1.R0 = *pr.MulByElement(&l1.R0, xOverY)
l1.R1 = *pr.MulByElement(&l1.R1, yInv)
// ℓ × res
res = pr.MulBy014(res, &l1.R1, &l1.R0)
} else {
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[1][i], y2Inv),
pr.MulByElement(&pr.lines[0][i], x2OverY2),
)
res = pr.MulBy014(res,
pr.MulByElement(&pr.lines[3][i], y2Inv),
pr.MulByElement(&pr.lines[2][i], x2OverY2),
)
// Qacc ← 2Qacc+Q,
// l1 the line ℓ passing Qacc and Q
// l2 the line ℓ passing (Qacc+Q) and Qacc
Qacc, l1, l2 = pr.doubleAndAddStep(Qacc, Q)
// line evaluation at P
l1.R0 = *pr.MulByElement(&l1.R0, xOverY)
l1.R1 = *pr.MulByElement(&l1.R1, yInv)
// line evaluation at P
l2.R0 = *pr.MulByElement(&l2.R0, xOverY)
l2.R1 = *pr.MulByElement(&l2.R1, yInv)
// ℓ × ℓ
prodLines = *pr.Mul014By014(&l1.R1, &l1.R0, &l2.R1, &l2.R0)
// (ℓ × ℓ) × res
res = pr.MulBy01245(res, &prodLines)

}
}

// i = 0, separately to avoid a point doubling
res = pr.Square(res)
// l1 the tangent ℓ passing 2Qacc
l1 = pr.tangentCompute(Qacc)
// line evaluation at P
l1.R0 = *pr.MulByElement(&l1.R0, xOverY)
l1.R1 = *pr.MulByElement(&l1.R1, yInv)
// ℓ × ℓ
prodLines = *pr.Mul014By014(
&l1.R1,
&l1.R0,
pr.MulByElement(&pr.lines[1][0], y2Inv),
pr.MulByElement(&pr.lines[0][0], x2OverY2),
)
// (ℓ × ℓ) × res
res = pr.MulBy01245(res, &prodLines)

// negative x₀
res = pr.Ext12.Conjugate(res)

return res, nil
}

// PairFixedQ calculates the reduced pairing for a set of points
// e(P, g2), where g2 is fixed.
//
// This function doesn't check that the inputs are in the correct subgroups.
func (pr Pairing) PairFixedQ(P *G1Affine) (*GTEl, error) {
res, err := pr.MillerLoopFixedQ(P)
if err != nil {
return nil, fmt.Errorf("miller loop: %w", err)
}
res = pr.finalExponentiation(res, true)
return res, nil
}

// DoublePairFixedQ calculates the reduced pairing for a set of points
// e(P, Q) * e(T, g2), where g2 is fixed.
//
// This function doesn't check that the inputs are in the correct subgroups.
func (pr Pairing) DoublePairFixedQ(P, T *G1Affine, Q *G2Affine) (*GTEl, error) {
res, err := pr.DoubleMillerLoopFixedQ(P, T, Q)
if err != nil {
return nil, fmt.Errorf("double miller loop: %w", err)
}
res = pr.finalExponentiation(res, false)
return res, nil
}
Loading