Browse Source

bn256: explicitly fix MakeAffine for ∞

When c = ∞, z = 0 and 0 does not have a modular inverse, triggering
undefined behavior (recently changed to returning nil) in ModInverse.

Unclear how this used to work anyway. Looks like ModInverse was
leaving the receiver untouched, making zInv = 0 when pool = nil.

Fixes golang/go#25199

Change-Id: Ib39abf59f0e71cf43cdb5836142ebdd3b206fb3f
Reviewed-on: https://go-review.googlesource.com/110695
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Filippo Valsorda 7 years ago
parent
commit
8b1d31080a
3 changed files with 32 additions and 4 deletions
  1. 14 4
      bn256/bn256.go
  2. 9 0
      bn256/curve.go
  3. 9 0
      bn256/twist.go

+ 14 - 4
bn256/bn256.go

@@ -97,13 +97,18 @@ func (e *G1) Neg(a *G1) *G1 {
 
 
 // Marshal converts n to a byte slice.
 // Marshal converts n to a byte slice.
 func (e *G1) Marshal() []byte {
 func (e *G1) Marshal() []byte {
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	if e.p.IsInfinity() {
+		return make([]byte, numBytes*2)
+	}
+
 	e.p.MakeAffine(nil)
 	e.p.MakeAffine(nil)
 
 
 	xBytes := new(big.Int).Mod(e.p.x, p).Bytes()
 	xBytes := new(big.Int).Mod(e.p.x, p).Bytes()
 	yBytes := new(big.Int).Mod(e.p.y, p).Bytes()
 	yBytes := new(big.Int).Mod(e.p.y, p).Bytes()
 
 
-	// Each value is a 256-bit number.
-	const numBytes = 256 / 8
 
 
 	ret := make([]byte, numBytes*2)
 	ret := make([]byte, numBytes*2)
 	copy(ret[1*numBytes-len(xBytes):], xBytes)
 	copy(ret[1*numBytes-len(xBytes):], xBytes)
@@ -205,6 +210,13 @@ func (e *G2) Add(a, b *G2) *G2 {
 
 
 // Marshal converts n into a byte slice.
 // Marshal converts n into a byte slice.
 func (n *G2) Marshal() []byte {
 func (n *G2) Marshal() []byte {
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	if n.p.IsInfinity() {
+		return make([]byte, numBytes*4)
+	}
+
 	n.p.MakeAffine(nil)
 	n.p.MakeAffine(nil)
 
 
 	xxBytes := new(big.Int).Mod(n.p.x.x, p).Bytes()
 	xxBytes := new(big.Int).Mod(n.p.x.x, p).Bytes()
@@ -212,8 +224,6 @@ func (n *G2) Marshal() []byte {
 	yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes()
 	yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes()
 	yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes()
 	yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes()
 
 
-	// Each value is a 256-bit number.
-	const numBytes = 256 / 8
 
 
 	ret := make([]byte, numBytes*4)
 	ret := make([]byte, numBytes*4)
 	copy(ret[1*numBytes-len(xxBytes):], xxBytes)
 	copy(ret[1*numBytes-len(xxBytes):], xxBytes)

+ 9 - 0
bn256/curve.go

@@ -245,10 +245,19 @@ func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoi
 	return c
 	return c
 }
 }
 
 
+// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
+// c to 0 : 1 : 0.
 func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
 func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
 	if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
 	if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
 		return c
 		return c
 	}
 	}
+	if c.IsInfinity() {
+		c.x.SetInt64(0)
+		c.y.SetInt64(1)
+		c.z.SetInt64(0)
+		c.t.SetInt64(0)
+		return c
+	}
 
 
 	zInv := pool.Get().ModInverse(c.z, p)
 	zInv := pool.Get().ModInverse(c.z, p)
 	t := pool.Get().Mul(c.y, zInv)
 	t := pool.Get().Mul(c.y, zInv)

+ 9 - 0
bn256/twist.go

@@ -219,10 +219,19 @@ func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoi
 	return c
 	return c
 }
 }
 
 
+// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
+// c to 0 : 1 : 0.
 func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint {
 func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint {
 	if c.z.IsOne() {
 	if c.z.IsOne() {
 		return c
 		return c
 	}
 	}
+	if c.IsInfinity() {
+		c.x.SetZero()
+		c.y.SetOne()
+		c.z.SetZero()
+		c.t.SetZero()
+		return c
+	}
 
 
 	zInv := newGFp2(pool).Invert(c.z, pool)
 	zInv := newGFp2(pool).Invert(c.z, pool)
 	t := newGFp2(pool).Mul(c.y, zInv, pool)
 	t := newGFp2(pool).Mul(c.y, zInv, pool)