Skip to content

Commit

Permalink
fix(emulated/JointScalarMul): edge case where P+Q is maliciously crafted
Browse files Browse the repository at this point in the history
  • Loading branch information
yelhousni committed Mar 7, 2024
1 parent c7d831d commit 2f2fadc
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 11 deletions.
47 changes: 36 additions & 11 deletions std/algebra/emulated/sw_emulated/point.go
Original file line number Diff line number Diff line change
Expand Up @@ -943,14 +943,30 @@ func (c *Curve[B, S]) jointScalarMulGLVUnsafe(Q, R *AffinePoint[B], s, t *emulat
// Acc = Q + R + Φ(Q) + Φ(R)
Acc := c.Add(tableS[1], tablePhiS[1])
B1 := Acc
// and then add the base point G to it to avoid incomplete additions in the
// loop, because when doing doubleAndAdd(Acc, Bi) as (Acc+Bi)+Acc it might
// happen that Acc==Bi or -Bi. But now we force Acc to be different than
// the stored Bi. However we need at the end to subtract [2^nbits]G
// (harcoded) from the result.
// then conditionally add to Acc either Φ²(G) or G (if Acc==-Φ²(G)) where G is
// the base point to avoid incomplete additions in the loop, because when
// doing doubleAndAdd(Acc, Bi) as (Acc+Bi)+Acc it might happen that Acc==Bi
// or Acc==-Bi. But now we force Acc to be different than the stored Bi.
// However we need at the end to subtract [2^nbits]Φ²(G) (or conditionally
// [2^nbits]G) from the result.
//
// Acc = Q + R + Φ(Q) + Φ(R) + G
Acc = c.Add(Acc, c.Generator())
// Acc = Q + R + Φ(Q) + Φ(R) + Φ²(G) or Q + R + Φ(Q) + Φ(R) + G ( = -Φ²(G)+G )
g0 := c.Generator()
selector0 := c.baseApi.IsZero(
c.baseApi.Add(&Acc.Y, &c.Generator().Y),
)
g := c.Select(
selector0,
// G
g0,
// Φ²(G)
&AffinePoint[B]{
X: *c.baseApi.Mul(
c.baseApi.Mul(&g0.X, c.thirdRootOne), c.thirdRootOne),
Y: g0.Y,
},
)
Acc = c.Add(Acc, g)

s1bits := c.scalarApi.ToBits(s1)
s2bits := c.scalarApi.ToBits(s2)
Expand Down Expand Up @@ -990,8 +1006,6 @@ func (c *Curve[B, S]) jointScalarMulGLVUnsafe(Q, R *AffinePoint[B], s, t *emulat
B15 := c.Neg(B2)
// B16 = -Q - R - Φ(Q) - Φ(R)
B16 := c.Neg(B1)
// and compute [2]Acc+P. We don't use doubleAndAdd as it involves edge cases.
// Note: half of the Bi points have the same X coordinates.

var P *AffinePoint[B]
for i := nbits - 1; i > 0; i-- {
Expand Down Expand Up @@ -1034,9 +1048,20 @@ func (c *Curve[B, S]) jointScalarMulGLVUnsafe(Q, R *AffinePoint[B], s, t *emulat
tablePhiR[0] = c.Add(tablePhiR[0], Acc)
Acc = c.Select(t2bits[0], Acc, tablePhiR[0])

// subtract [2^nbits]G since we added G at the beginning
// subtract [2^nbits]Φ²(G) (or conditionally [2^nbits]G)
gm := c.GeneratorMultiples()[nbits-1]
Acc = c.Add(Acc, c.Neg(&gm))
g = c.Select(
selector0,
// [2^nbits]G
&gm,
// [2^nbits]Φ²(G)
&AffinePoint[B]{
X: *c.baseApi.Mul(
c.baseApi.Mul(&gm.X, c.thirdRootOne), c.thirdRootOne),
Y: gm.Y,
},
)
Acc = c.Add(Acc, c.Neg(g))

return Acc

Expand Down
42 changes: 42 additions & 0 deletions std/algebra/emulated/sw_emulated/point_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1532,6 +1532,48 @@ func TestJointScalarMul4(t *testing.T) {
assert.NoError(err)
}

// We explicitly choose here P1 and P2 s.t. P1+P2 = G (the base point). This
// triggers the edge case where Q + R + Φ(Q) + Φ(R) + Φ²(G) == inf
func TestJointScalarMulSpecial6(t *testing.T) {
assert := test.NewAssert(t)
var r1, r2 fr_bw6761.Element
_, _ = r1.SetRandom()
_, _ = r2.SetRandom()
s1 := new(big.Int)
s2 := new(big.Int)
r1.BigInt(s1)
r2.BigInt(s2)
var res, tmp, p1, p2 bw6761.G1Affine
// P1
p1.ScalarMultiplicationBase(s1)
// P2 = G-P1
_, _, g, _ := bw6761.Generators()
p2.Sub(&g, &p1)
tmp.ScalarMultiplication(&p1, s1)
res.ScalarMultiplication(&p2, s2)
res.Add(&res, &tmp)

circuit := JointScalarMulTest[emulated.BW6761Fp, emulated.BW6761Fr]{}
witness := JointScalarMulTest[emulated.BW6761Fp, emulated.BW6761Fr]{
S1: emulated.ValueOf[emulated.BW6761Fr](s1),
S2: emulated.ValueOf[emulated.BW6761Fr](s2),
P1: AffinePoint[emulated.BW6761Fp]{
X: emulated.ValueOf[emulated.BW6761Fp](p1.X),
Y: emulated.ValueOf[emulated.BW6761Fp](p1.Y),
},
P2: AffinePoint[emulated.BW6761Fp]{
X: emulated.ValueOf[emulated.BW6761Fp](p2.X),
Y: emulated.ValueOf[emulated.BW6761Fp](p2.Y),
},
Q: AffinePoint[emulated.BW6761Fp]{
X: emulated.ValueOf[emulated.BW6761Fp](res.X),
Y: emulated.ValueOf[emulated.BW6761Fp](res.Y),
},
}
err := test.IsSolved(&circuit, &witness, testCurve.ScalarField())
assert.NoError(err)
}

type JointScalarMulEdgeCasesTest[T, S emulated.FieldParams] struct {
P1, P2, Q AffinePoint[T]
S1, S2 emulated.Element[S]
Expand Down

0 comments on commit 2f2fadc

Please sign in to comment.