go-ethereum/crypto/bn256/curve.go
Matthew Di Ferrante 80c6dfc19f crypto/bn256: fix generator on G1 (#15591)
Generator in the current lib uses -2 as the y point when doing
ScalarBaseMult, this makes it so that points/signatures generated
from libs like py_ecc don't match/validate as pretty much all
other libs (including libsnark) have (1, 2) as the standard
generator.

This does not affect consensus as the generator is never used in
the VM, points are always explicitly defined and there is not
ScalarBaseMult op - it only makes it so that doing "import
github.com/ethereum/go-ethereum/crypto/bn256" doesn't generate
bad points in userland tools.
2017-12-01 13:03:39 +01:00

279 lines
5.4 KiB
Go

// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"math/big"
)
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in
// Jacobian form and t=z² when valid. G₁ is the set of points of this curve on
// GF(p).
type curvePoint struct {
x, y, z, t *big.Int
}
var curveB = new(big.Int).SetInt64(3)
// curveGen is the generator of G₁.
var curveGen = &curvePoint{
new(big.Int).SetInt64(1),
new(big.Int).SetInt64(2),
new(big.Int).SetInt64(1),
new(big.Int).SetInt64(1),
}
func newCurvePoint(pool *bnPool) *curvePoint {
return &curvePoint{
pool.Get(),
pool.Get(),
pool.Get(),
pool.Get(),
}
}
func (c *curvePoint) String() string {
c.MakeAffine(new(bnPool))
return "(" + c.x.String() + ", " + c.y.String() + ")"
}
func (c *curvePoint) Put(pool *bnPool) {
pool.Put(c.x)
pool.Put(c.y)
pool.Put(c.z)
pool.Put(c.t)
}
func (c *curvePoint) Set(a *curvePoint) {
c.x.Set(a.x)
c.y.Set(a.y)
c.z.Set(a.z)
c.t.Set(a.t)
}
// IsOnCurve returns true iff c is on the curve where c must be in affine form.
func (c *curvePoint) IsOnCurve() bool {
yy := new(big.Int).Mul(c.y, c.y)
xxx := new(big.Int).Mul(c.x, c.x)
xxx.Mul(xxx, c.x)
yy.Sub(yy, xxx)
yy.Sub(yy, curveB)
if yy.Sign() < 0 || yy.Cmp(P) >= 0 {
yy.Mod(yy, P)
}
return yy.Sign() == 0
}
func (c *curvePoint) SetInfinity() {
c.z.SetInt64(0)
}
func (c *curvePoint) IsInfinity() bool {
return c.z.Sign() == 0
}
func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
if a.IsInfinity() {
c.Set(b)
return
}
if b.IsInfinity() {
c.Set(a)
return
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
z1z1 := pool.Get().Mul(a.z, a.z)
z1z1.Mod(z1z1, P)
z2z2 := pool.Get().Mul(b.z, b.z)
z2z2.Mod(z2z2, P)
u1 := pool.Get().Mul(a.x, z2z2)
u1.Mod(u1, P)
u2 := pool.Get().Mul(b.x, z1z1)
u2.Mod(u2, P)
t := pool.Get().Mul(b.z, z2z2)
t.Mod(t, P)
s1 := pool.Get().Mul(a.y, t)
s1.Mod(s1, P)
t.Mul(a.z, z1z1)
t.Mod(t, P)
s2 := pool.Get().Mul(b.y, t)
s2.Mod(s2, P)
// Compute x = (2h)²(s²-u1-u2)
// where s = (s2-s1)/(u2-u1) is the slope of the line through
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
// This is also:
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
// = r² - j - 2v
// with the notations below.
h := pool.Get().Sub(u2, u1)
xEqual := h.Sign() == 0
t.Add(h, h)
// i = 4h²
i := pool.Get().Mul(t, t)
i.Mod(i, P)
// j = 4h³
j := pool.Get().Mul(h, i)
j.Mod(j, P)
t.Sub(s2, s1)
yEqual := t.Sign() == 0
if xEqual && yEqual {
c.Double(a, pool)
return
}
r := pool.Get().Add(t, t)
v := pool.Get().Mul(u1, i)
v.Mod(v, P)
// t4 = 4(s2-s1)²
t4 := pool.Get().Mul(r, r)
t4.Mod(t4, P)
t.Add(v, v)
t6 := pool.Get().Sub(t4, j)
c.x.Sub(t6, t)
// Set y = -(2h)³(s1 + s*(x/4h²-u1))
// This is also
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
t.Sub(v, c.x) // t7
t4.Mul(s1, j) // t8
t4.Mod(t4, P)
t6.Add(t4, t4) // t9
t4.Mul(r, t) // t10
t4.Mod(t4, P)
c.y.Sub(t4, t6)
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
t.Add(a.z, b.z) // t11
t4.Mul(t, t) // t12
t4.Mod(t4, P)
t.Sub(t4, z1z1) // t13
t4.Sub(t, z2z2) // t14
c.z.Mul(t4, h)
c.z.Mod(c.z, P)
pool.Put(z1z1)
pool.Put(z2z2)
pool.Put(u1)
pool.Put(u2)
pool.Put(t)
pool.Put(s1)
pool.Put(s2)
pool.Put(h)
pool.Put(i)
pool.Put(j)
pool.Put(r)
pool.Put(v)
pool.Put(t4)
pool.Put(t6)
}
func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := pool.Get().Mul(a.x, a.x)
A.Mod(A, P)
B := pool.Get().Mul(a.y, a.y)
B.Mod(B, P)
C_ := pool.Get().Mul(B, B)
C_.Mod(C_, P)
t := pool.Get().Add(a.x, B)
t2 := pool.Get().Mul(t, t)
t2.Mod(t2, P)
t.Sub(t2, A)
t2.Sub(t, C_)
d := pool.Get().Add(t2, t2)
t.Add(A, A)
e := pool.Get().Add(t, A)
f := pool.Get().Mul(e, e)
f.Mod(f, P)
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C_, C_)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
t2.Mul(e, c.y)
t2.Mod(t2, P)
c.y.Sub(t2, t)
t.Mul(a.y, a.z)
t.Mod(t, P)
c.z.Add(t, t)
pool.Put(A)
pool.Put(B)
pool.Put(C_)
pool.Put(t)
pool.Put(t2)
pool.Put(d)
pool.Put(e)
pool.Put(f)
}
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint {
sum := newCurvePoint(pool)
sum.SetInfinity()
t := newCurvePoint(pool)
for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum, pool)
if scalar.Bit(i) != 0 {
sum.Add(t, a, pool)
} else {
sum.Set(t)
}
}
c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
}
func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
return c
}
zInv := pool.Get().ModInverse(c.z, P)
t := pool.Get().Mul(c.y, zInv)
t.Mod(t, P)
zInv2 := pool.Get().Mul(zInv, zInv)
zInv2.Mod(zInv2, P)
c.y.Mul(t, zInv2)
c.y.Mod(c.y, P)
t.Mul(c.x, zInv2)
t.Mod(t, P)
c.x.Set(t)
c.z.SetInt64(1)
c.t.SetInt64(1)
pool.Put(zInv)
pool.Put(t)
pool.Put(zInv2)
return c
}
func (c *curvePoint) Negative(a *curvePoint) {
c.x.Set(a.x)
c.y.Neg(a.y)
c.z.Set(a.z)
c.t.SetInt64(0)
}