github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/bn256/google/curve.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library is free software: you can redistribute it and/or modify
     6  //  it under the terms of the GNU Lesser General Public License as published by
     7  //  the Free Software Foundation, either version 3 of the License, or
     8  //  (at your option) any later version.
     9  //
    10  //  The go-aigar library is distributed in the hope that it will be useful,
    11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  //  GNU Lesser General Public License for more details.
    14  //
    15  //  You should have received a copy of the GNU Lesser General Public License
    16  //  along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package bn256
    19  
    20  import (
    21  	"math/big"
    22  )
    23  
    24  // curvePoint implements the elliptic curve y²=x³+3. Points are kept in
    25  // Jacobian form and t=z² when valid. G₁ is the set of points of this curve on
    26  // GF(p).
    27  type curvePoint struct {
    28  	x, y, z, t *big.Int
    29  }
    30  
    31  var curveB = new(big.Int).SetInt64(3)
    32  
    33  // curveGen is the generator of G₁.
    34  var curveGen = &curvePoint{
    35  	new(big.Int).SetInt64(1),
    36  	new(big.Int).SetInt64(2),
    37  	new(big.Int).SetInt64(1),
    38  	new(big.Int).SetInt64(1),
    39  }
    40  
    41  func newCurvePoint(pool *bnPool) *curvePoint {
    42  	return &curvePoint{
    43  		pool.Get(),
    44  		pool.Get(),
    45  		pool.Get(),
    46  		pool.Get(),
    47  	}
    48  }
    49  
    50  func (c *curvePoint) String() string {
    51  	c.MakeAffine(new(bnPool))
    52  	return "(" + c.x.String() + ", " + c.y.String() + ")"
    53  }
    54  
    55  func (c *curvePoint) Put(pool *bnPool) {
    56  	pool.Put(c.x)
    57  	pool.Put(c.y)
    58  	pool.Put(c.z)
    59  	pool.Put(c.t)
    60  }
    61  
    62  func (c *curvePoint) Set(a *curvePoint) {
    63  	c.x.Set(a.x)
    64  	c.y.Set(a.y)
    65  	c.z.Set(a.z)
    66  	c.t.Set(a.t)
    67  }
    68  
    69  // IsOnCurve returns true iff c is on the curve where c must be in affine form.
    70  func (c *curvePoint) IsOnCurve() bool {
    71  	yy := new(big.Int).Mul(c.y, c.y)
    72  	xxx := new(big.Int).Mul(c.x, c.x)
    73  	xxx.Mul(xxx, c.x)
    74  	yy.Sub(yy, xxx)
    75  	yy.Sub(yy, curveB)
    76  	if yy.Sign() < 0 || yy.Cmp(P) >= 0 {
    77  		yy.Mod(yy, P)
    78  	}
    79  	return yy.Sign() == 0
    80  }
    81  
    82  func (c *curvePoint) SetInfinity() {
    83  	c.z.SetInt64(0)
    84  }
    85  
    86  func (c *curvePoint) IsInfinity() bool {
    87  	return c.z.Sign() == 0
    88  }
    89  
    90  func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
    91  	if a.IsInfinity() {
    92  		c.Set(b)
    93  		return
    94  	}
    95  	if b.IsInfinity() {
    96  		c.Set(a)
    97  		return
    98  	}
    99  
   100  	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
   101  
   102  	// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
   103  	// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
   104  	// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
   105  	z1z1 := pool.Get().Mul(a.z, a.z)
   106  	z1z1.Mod(z1z1, P)
   107  	z2z2 := pool.Get().Mul(b.z, b.z)
   108  	z2z2.Mod(z2z2, P)
   109  	u1 := pool.Get().Mul(a.x, z2z2)
   110  	u1.Mod(u1, P)
   111  	u2 := pool.Get().Mul(b.x, z1z1)
   112  	u2.Mod(u2, P)
   113  
   114  	t := pool.Get().Mul(b.z, z2z2)
   115  	t.Mod(t, P)
   116  	s1 := pool.Get().Mul(a.y, t)
   117  	s1.Mod(s1, P)
   118  
   119  	t.Mul(a.z, z1z1)
   120  	t.Mod(t, P)
   121  	s2 := pool.Get().Mul(b.y, t)
   122  	s2.Mod(s2, P)
   123  
   124  	// Compute x = (2h)²(s²-u1-u2)
   125  	// where s = (s2-s1)/(u2-u1) is the slope of the line through
   126  	// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
   127  	// This is also:
   128  	// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
   129  	//                        = r² - j - 2v
   130  	// with the notations below.
   131  	h := pool.Get().Sub(u2, u1)
   132  	xEqual := h.Sign() == 0
   133  
   134  	t.Add(h, h)
   135  	// i = 4h²
   136  	i := pool.Get().Mul(t, t)
   137  	i.Mod(i, P)
   138  	// j = 4h³
   139  	j := pool.Get().Mul(h, i)
   140  	j.Mod(j, P)
   141  
   142  	t.Sub(s2, s1)
   143  	yEqual := t.Sign() == 0
   144  	if xEqual && yEqual {
   145  		c.Double(a, pool)
   146  		return
   147  	}
   148  	r := pool.Get().Add(t, t)
   149  
   150  	v := pool.Get().Mul(u1, i)
   151  	v.Mod(v, P)
   152  
   153  	// t4 = 4(s2-s1)²
   154  	t4 := pool.Get().Mul(r, r)
   155  	t4.Mod(t4, P)
   156  	t.Add(v, v)
   157  	t6 := pool.Get().Sub(t4, j)
   158  	c.x.Sub(t6, t)
   159  
   160  	// Set y = -(2h)³(s1 + s*(x/4h²-u1))
   161  	// This is also
   162  	// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
   163  	t.Sub(v, c.x) // t7
   164  	t4.Mul(s1, j) // t8
   165  	t4.Mod(t4, P)
   166  	t6.Add(t4, t4) // t9
   167  	t4.Mul(r, t)   // t10
   168  	t4.Mod(t4, P)
   169  	c.y.Sub(t4, t6)
   170  
   171  	// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
   172  	t.Add(a.z, b.z) // t11
   173  	t4.Mul(t, t)    // t12
   174  	t4.Mod(t4, P)
   175  	t.Sub(t4, z1z1) // t13
   176  	t4.Sub(t, z2z2) // t14
   177  	c.z.Mul(t4, h)
   178  	c.z.Mod(c.z, P)
   179  
   180  	pool.Put(z1z1)
   181  	pool.Put(z2z2)
   182  	pool.Put(u1)
   183  	pool.Put(u2)
   184  	pool.Put(t)
   185  	pool.Put(s1)
   186  	pool.Put(s2)
   187  	pool.Put(h)
   188  	pool.Put(i)
   189  	pool.Put(j)
   190  	pool.Put(r)
   191  	pool.Put(v)
   192  	pool.Put(t4)
   193  	pool.Put(t6)
   194  }
   195  
   196  func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
   197  	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
   198  	A := pool.Get().Mul(a.x, a.x)
   199  	A.Mod(A, P)
   200  	B := pool.Get().Mul(a.y, a.y)
   201  	B.Mod(B, P)
   202  	C_ := pool.Get().Mul(B, B)
   203  	C_.Mod(C_, P)
   204  
   205  	t := pool.Get().Add(a.x, B)
   206  	t2 := pool.Get().Mul(t, t)
   207  	t2.Mod(t2, P)
   208  	t.Sub(t2, A)
   209  	t2.Sub(t, C_)
   210  	d := pool.Get().Add(t2, t2)
   211  	t.Add(A, A)
   212  	e := pool.Get().Add(t, A)
   213  	f := pool.Get().Mul(e, e)
   214  	f.Mod(f, P)
   215  
   216  	t.Add(d, d)
   217  	c.x.Sub(f, t)
   218  
   219  	t.Add(C_, C_)
   220  	t2.Add(t, t)
   221  	t.Add(t2, t2)
   222  	c.y.Sub(d, c.x)
   223  	t2.Mul(e, c.y)
   224  	t2.Mod(t2, P)
   225  	c.y.Sub(t2, t)
   226  
   227  	t.Mul(a.y, a.z)
   228  	t.Mod(t, P)
   229  	c.z.Add(t, t)
   230  
   231  	pool.Put(A)
   232  	pool.Put(B)
   233  	pool.Put(C_)
   234  	pool.Put(t)
   235  	pool.Put(t2)
   236  	pool.Put(d)
   237  	pool.Put(e)
   238  	pool.Put(f)
   239  }
   240  
   241  func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint {
   242  	sum := newCurvePoint(pool)
   243  	sum.SetInfinity()
   244  	t := newCurvePoint(pool)
   245  
   246  	for i := scalar.BitLen(); i >= 0; i-- {
   247  		t.Double(sum, pool)
   248  		if scalar.Bit(i) != 0 {
   249  			sum.Add(t, a, pool)
   250  		} else {
   251  			sum.Set(t)
   252  		}
   253  	}
   254  
   255  	c.Set(sum)
   256  	sum.Put(pool)
   257  	t.Put(pool)
   258  	return c
   259  }
   260  
   261  // MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
   262  // c to 0 : 1 : 0.
   263  func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
   264  	if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
   265  		return c
   266  	}
   267  	if c.IsInfinity() {
   268  		c.x.SetInt64(0)
   269  		c.y.SetInt64(1)
   270  		c.z.SetInt64(0)
   271  		c.t.SetInt64(0)
   272  		return c
   273  	}
   274  	zInv := pool.Get().ModInverse(c.z, P)
   275  	t := pool.Get().Mul(c.y, zInv)
   276  	t.Mod(t, P)
   277  	zInv2 := pool.Get().Mul(zInv, zInv)
   278  	zInv2.Mod(zInv2, P)
   279  	c.y.Mul(t, zInv2)
   280  	c.y.Mod(c.y, P)
   281  	t.Mul(c.x, zInv2)
   282  	t.Mod(t, P)
   283  	c.x.Set(t)
   284  	c.z.SetInt64(1)
   285  	c.t.SetInt64(1)
   286  
   287  	pool.Put(zInv)
   288  	pool.Put(t)
   289  	pool.Put(zInv2)
   290  
   291  	return c
   292  }
   293  
   294  func (c *curvePoint) Negative(a *curvePoint) {
   295  	c.x.Set(a.x)
   296  	c.y.Neg(a.y)
   297  	c.z.Set(a.z)
   298  	c.t.SetInt64(0)
   299  }