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

ecc/bls12381: Ensures pairing operations don't overwrite their input #494

Merged
merged 2 commits into from Apr 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 6 additions & 4 deletions ecc/bls12381/g1.go

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is G2 really not affected at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For points in G2, the Miller's loop only uses the points in read-only mode.

Expand Up @@ -392,7 +392,8 @@ func G1Generator() *G1 {
}

// affinize converts an entire slice to affine at once
func affinize(points []*G1) {
func affinize(points []*G1) (out []G1) {
armfazh marked this conversation as resolved.
Show resolved Hide resolved
out = make([]G1, len(points))
if len(points) == 0 {
return
}
Expand All @@ -410,8 +411,9 @@ func affinize(points []*G1) {
zinv.Mul(w, &ws[i])
w.Mul(w, &points[i].z)

points[i].x.Mul(&points[i].x, zinv)
points[i].y.Mul(&points[i].y, zinv)
points[i].z.SetOne()
out[i].x.Mul(&points[i].x, zinv)
out[i].y.Mul(&points[i].y, zinv)
out[i].z.SetOne()
}
return
}
7 changes: 2 additions & 5 deletions ecc/bls12381/g1_test.go
Expand Up @@ -218,17 +218,14 @@ func TestG1Affinize(t *testing.T) {
N := 20
testTimes := 1 << 6
g1 := make([]*G1, N)
g2 := make([]*G1, N)
for i := 0; i < testTimes; i++ {
for j := 0; j < N; j++ {
g1[j] = randomG1(t)
g2[j] = &G1{}
*g2[j] = *g1[j]
}
affinize(g2)
g2 := affinize(g1)
for j := 0; j < N; j++ {
g1[j].toAffine()
if !g1[j].IsEqual(g2[j]) {
if !g1[j].IsEqual(&g2[j]) {
t.Fatal("failure to preserve points")
}
if g2[j].z.IsEqual(&g1[j].z) != 1 {
Expand Down
20 changes: 10 additions & 10 deletions ecc/bls12381/pair.go
Expand Up @@ -4,9 +4,10 @@ import "github.com/cloudflare/circl/ecc/bls12381/ff"

// Pair calculates the ate-pairing of P and Q.
func Pair(P *G1, Q *G2) *Gt {
P.toAffine()
affP := *P
affP.toAffine()
mi := &ff.Fp12{}
miller(mi, P, Q)
miller(mi, &affP, Q)
e := &Gt{}
finalExp(e, mi)
return e
Expand Down Expand Up @@ -82,9 +83,9 @@ func ProdPair(P []*G1, Q []*G2, n []*Scalar) *Gt {
out := new(ff.Fp12)
out.SetOne()

affinize(P)
for i := range P {
miller(mi, P[i], Q[i])
affineP := affinize(P)
for i := range affineP {
miller(mi, &affineP[i], Q[i])
nb, _ := n[i].MarshalBinary()
ei.Exp(mi, nb)
out.Mul(out, ei)
Expand All @@ -105,13 +106,12 @@ func ProdPairFrac(P []*G1, Q []*G2, signs []int) *Gt {
out := new(ff.Fp12)
out.SetOne()

affinize(P)
for i := range P {
g := *P[i]
affineP := affinize(P)
for i := range affineP {
if signs[i] == -1 {
g.Neg()
affineP[i].Neg()
}
miller(mi, &g, Q[i])
miller(mi, &affineP[i], Q[i])
out.Mul(mi, out)
}

Expand Down
46 changes: 46 additions & 0 deletions ecc/bls12381/pair_test.go
Expand Up @@ -79,6 +79,52 @@ func TestProdPairFrac(t *testing.T) {
}
}

func TestInputs(t *testing.T) {
t.Run("Pair", func(t *testing.T) {
P := *randomG1(t)
Q := *randomG2(t)
oldP := P
oldQ := Q
_ = Pair(&P, &Q)
test.CheckOk(P == oldP, "the point P was overwritten", t)
test.CheckOk(Q == oldQ, "the point Q was overwritten", t)
})

t.Run("ProdPair", func(t *testing.T) {
P0, P1 := *randomG1(t), *randomG1(t)
Q0, Q1 := *randomG2(t), *randomG2(t)
n0, n1 := *randomScalar(t), *randomScalar(t)

oldP0, oldP1 := P0, P1
oldQ0, oldQ1 := Q0, Q1
oldn0, oldn1 := n0, n1

_ = ProdPair([]*G1{&P0, &P1}, []*G2{&Q0, &Q1}, []*Scalar{&n0, &n1})

test.CheckOk(P0 == oldP0, "the point P0 was overwritten", t)
test.CheckOk(P1 == oldP1, "the point P1 was overwritten", t)
test.CheckOk(Q0 == oldQ0, "the point Q0 was overwritten", t)
test.CheckOk(Q1 == oldQ1, "the point Q1 was overwritten", t)
test.CheckOk(n0 == oldn0, "the scalar n0 was overwritten", t)
test.CheckOk(n1 == oldn1, "the scalar n1 was overwritten", t)
})

t.Run("ProdPairFrac", func(t *testing.T) {
P0, P1 := *randomG1(t), *randomG1(t)
Q0, Q1 := *randomG2(t), *randomG2(t)

oldP0, oldP1 := P0, P1
oldQ0, oldQ1 := Q0, Q1

_ = ProdPairFrac([]*G1{&P0, &P1}, []*G2{&Q0, &Q1}, []int{1, -1})

test.CheckOk(P0 == oldP0, "the point P0 was overwritten", t)
test.CheckOk(P1 == oldP1, "the point P1 was overwritten", t)
test.CheckOk(Q0 == oldQ0, "the point Q0 was overwritten", t)
test.CheckOk(Q1 == oldQ1, "the point Q1 was overwritten", t)
})
}

func TestPairBilinear(t *testing.T) {
testTimes := 1 << 5
for i := 0; i < testTimes; i++ {
Expand Down