github.com/emmansun/gmsm@v0.29.1/sm9/bn256/curve.go (about)

     1  package bn256
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"math/big"
     6  )
     7  
     8  // curvePoint implements the elliptic curve y²=x³+5. Points are kept in Jacobian
     9  // form and t=z² when valid. G₁ is the set of points of this curve on GF(p).
    10  type curvePoint struct {
    11  	x, y, z, t gfP
    12  }
    13  
    14  var curveB = newGFp(5)
    15  var threeCurveB = newGFp(3 * 5)
    16  
    17  // curveGen is the generator of G₁.
    18  var curveGen = &curvePoint{
    19  	x: *fromBigInt(bigFromHex("93DE051D62BF718FF5ED0704487D01D6E1E4086909DC3280E8C4E4817C66DDDD")),
    20  	y: *fromBigInt(bigFromHex("21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616")),
    21  	z: *one,
    22  	t: *one,
    23  }
    24  
    25  func (c *curvePoint) String() string {
    26  	c.MakeAffine()
    27  	x, y := &gfP{}, &gfP{}
    28  	montDecode(x, &c.x)
    29  	montDecode(y, &c.y)
    30  	return "(" + x.String() + ", " + y.String() + ")"
    31  }
    32  
    33  func (c *curvePoint) Set(a *curvePoint) {
    34  	c.x.Set(&a.x)
    35  	c.y.Set(&a.y)
    36  	c.z.Set(&a.z)
    37  	c.t.Set(&a.t)
    38  }
    39  
    40  func (c *curvePoint) polynomial(x *gfP) *gfP {
    41  	x3 := &gfP{}
    42  	gfpSqr(x3, x, 1)
    43  	gfpMul(x3, x3, x)
    44  	gfpAdd(x3, x3, curveB)
    45  	return x3
    46  }
    47  
    48  // IsOnCurve returns true if c is on the curve.
    49  func (c *curvePoint) IsOnCurve() bool {
    50  	c.MakeAffine()
    51  	if c.IsInfinity() { // TBC: This is not same as golang elliptic
    52  		return true
    53  	}
    54  
    55  	y2 := &gfP{}
    56  	gfpSqr(y2, &c.y, 1)
    57  
    58  	x3 := c.polynomial(&c.x)
    59  
    60  	return y2.Equal(x3) == 1
    61  }
    62  
    63  func NewCurvePoint() *curvePoint {
    64  	c := &curvePoint{}
    65  	c.SetInfinity()
    66  	return c
    67  }
    68  
    69  func NewCurveGenerator() *curvePoint {
    70  	c := &curvePoint{}
    71  	c.Set(curveGen)
    72  	return c
    73  }
    74  
    75  func (c *curvePoint) SetInfinity() {
    76  	c.x.Set(zero)
    77  	c.y.Set(one)
    78  	c.z.Set(zero)
    79  	c.t.Set(zero)
    80  }
    81  
    82  func (c *curvePoint) IsInfinity() bool {
    83  	return c.z.Equal(zero) == 1
    84  }
    85  
    86  func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
    87  	sum, t := &curvePoint{}, &curvePoint{}
    88  	sum.SetInfinity()
    89  
    90  	for i := scalar.BitLen(); i >= 0; i-- {
    91  		t.Double(sum)
    92  		if scalar.Bit(i) != 0 {
    93  			sum.Add(t, a)
    94  		} else {
    95  			sum.Set(t)
    96  		}
    97  	}
    98  
    99  	c.Set(sum)
   100  }
   101  
   102  // MakeAffine reverses the Jacobian transform.
   103  // the Jacobian coordinates are (x1, y1, z1)
   104  // where x = x1/z1² and y = y1/z1³.
   105  func (c *curvePoint) AffineFromJacobian() {
   106  	if c.z.Equal(one) == 1 {
   107  		return
   108  	} else if c.z.Equal(zero) == 1 {
   109  		c.x.Set(zero)
   110  		c.y.Set(one)
   111  		c.t.Set(zero)
   112  		return
   113  	}
   114  
   115  	zInv := &gfP{}
   116  	zInv.Invert(&c.z)
   117  
   118  	t, zInv2 := &gfP{}, &gfP{}
   119  	gfpMul(t, &c.y, zInv) // t = y/z
   120  	gfpSqr(zInv2, zInv, 1)
   121  
   122  	gfpMul(&c.x, &c.x, zInv2) // x = x / z^2
   123  	gfpMul(&c.y, t, zInv2)    // y = y / z^3
   124  
   125  	c.z.Set(one)
   126  	c.t.Set(one)
   127  }
   128  
   129  func (c *curvePoint) Neg(a *curvePoint) {
   130  	c.x.Set(&a.x)
   131  	gfpNeg(&c.y, &a.y)
   132  	c.z.Set(&a.z)
   133  	c.t.Set(zero)
   134  }
   135  
   136  // A curvePointTable holds the first 15 multiples of a point at offset -1, so [1]P
   137  // is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
   138  // point.
   139  type curvePointTable [15]*curvePoint
   140  
   141  // Select selects the n-th multiple of the table base point into p. It works in
   142  // constant time by iterating over every entry of the table. n must be in [0, 15].
   143  func (table *curvePointTable) Select(p *curvePoint, n uint8) {
   144  	if n >= 16 {
   145  		panic("sm9: internal error: curvePointTable called with out-of-bounds value")
   146  	}
   147  	p.SetInfinity()
   148  	for i, f := range table {
   149  		cond := subtle.ConstantTimeByteEq(uint8(i+1), n)
   150  		curvePointMovCond(p, f, p, cond)
   151  	}
   152  }
   153  
   154  // Equal compare e and other
   155  func (e *curvePoint) Equal(other *curvePoint) bool {
   156  	return e.x.Equal(&other.x) == 1 &&
   157  		e.y.Equal(&other.y) == 1 &&
   158  		e.z.Equal(&other.z) == 1 &&
   159  		e.t.Equal(&other.t) == 1
   160  }
   161  
   162  // Below methods are POC yet, the line add/double functions are still based on
   163  // Jacobian coordination.
   164  func (c *curvePoint) Add(p1, p2 *curvePoint) {
   165  	curvePointAddComplete(c, p1, p2)
   166  }
   167  
   168  func (c *curvePoint) AddComplete(p1, p2 *curvePoint) {
   169  	curvePointAddComplete(c, p1, p2)
   170  }
   171  
   172  func (c *curvePoint) Double(p *curvePoint) {
   173  	curvePointDoubleComplete(c, p)
   174  }
   175  
   176  func (c *curvePoint) DoubleComplete(p *curvePoint) {
   177  	curvePointDoubleComplete(c, p)
   178  }
   179  
   180  // MakeAffine reverses the Projective transform.
   181  // A = 1/Z1
   182  // X3 = A*X1
   183  // Y3 = A*Y1
   184  // Z3 = 1
   185  func (c *curvePoint) MakeAffine() {
   186  	// TODO: do we need to change it to constant-time implementation?
   187  	if c.z.Equal(one) == 1 {
   188  		return
   189  	} else if c.z.Equal(zero) == 1 {
   190  		c.x.Set(zero)
   191  		c.y.Set(one)
   192  		c.t.Set(zero)
   193  		return
   194  	}
   195  	zInv := &gfP{}
   196  	zInv.Invert(&c.z)
   197  	gfpMul(&c.x, &c.x, zInv)
   198  	gfpMul(&c.y, &c.y, zInv)
   199  	c.z.Set(one)
   200  	c.t.Set(one)
   201  }
   202  
   203  func (c *curvePoint) AffineFromProjective() {
   204  	c.MakeAffine()
   205  }
   206  
   207  func curvePointDouble(c, a *curvePoint) {
   208  	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
   209  	A, B, C := &gfP{}, &gfP{}, &gfP{}
   210  	gfpSqr(A, &a.x, 1)
   211  	gfpSqr(B, &a.y, 1)
   212  	gfpSqr(C, B, 1)
   213  
   214  	t := &gfP{}
   215  	gfpAdd(B, &a.x, B)
   216  	gfpSqr(t, B, 1)
   217  	gfpSub(B, t, A)
   218  	gfpSub(t, B, C)
   219  
   220  	d, e := &gfP{}, &gfP{}
   221  	gfpDouble(d, t)
   222  	gfpDouble(B, A)
   223  	gfpAdd(e, B, A)
   224  	gfpSqr(A, e, 1)
   225  
   226  	gfpDouble(B, d)
   227  	gfpSub(&c.x, A, B)
   228  
   229  	gfpMul(&c.z, &a.y, &a.z)
   230  	gfpDouble(&c.z, &c.z)
   231  
   232  	gfpDouble(B, C)
   233  	gfpDouble(t, B)
   234  	gfpDouble(B, t)
   235  	gfpSub(&c.y, d, &c.x)
   236  	gfpMul(t, e, &c.y)
   237  	gfpSub(&c.y, t, B)
   238  }
   239  
   240  func curvePointAdd(c, a, b *curvePoint) int {
   241  	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
   242  	var pointEq int
   243  	// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
   244  	// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
   245  	// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
   246  	z12, z22 := &gfP{}, &gfP{}
   247  	gfpSqr(z12, &a.z, 1)
   248  	gfpSqr(z22, &b.z, 1)
   249  
   250  	u1, u2 := &gfP{}, &gfP{}
   251  	gfpMul(u1, &a.x, z22)
   252  	gfpMul(u2, &b.x, z12)
   253  
   254  	t, s1 := &gfP{}, &gfP{}
   255  	gfpMul(t, &b.z, z22)
   256  	gfpMul(s1, &a.y, t)
   257  
   258  	s2 := &gfP{}
   259  	gfpMul(t, &a.z, z12)
   260  	gfpMul(s2, &b.y, t)
   261  
   262  	// Compute x = (2h)²(s²-u1-u2)
   263  	// where s = (s2-s1)/(u2-u1) is the slope of the line through
   264  	// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
   265  	// This is also:
   266  	// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
   267  	//                        = r² - j - 2v
   268  	// with the notations below.
   269  	h := &gfP{}
   270  	gfpSub(h, u2, u1)
   271  
   272  	gfpDouble(t, h)
   273  	// i = 4h²
   274  	i := &gfP{}
   275  	gfpSqr(i, t, 1)
   276  	// j = 4h³
   277  	j := &gfP{}
   278  	gfpMul(j, h, i)
   279  
   280  	gfpSub(t, s2, s1)
   281  
   282  	pointEq = h.Equal(zero) & t.Equal(zero)
   283  
   284  	r := &gfP{}
   285  	gfpDouble(r, t)
   286  
   287  	v := &gfP{}
   288  	gfpMul(v, u1, i)
   289  
   290  	// t4 = 4(s2-s1)²
   291  	t4, t6 := &gfP{}, &gfP{}
   292  	gfpSqr(t4, r, 1)
   293  	gfpDouble(t, v)
   294  	gfpSub(t6, t4, j)
   295  
   296  	gfpSub(&c.x, t6, t)
   297  
   298  	// Set y = -(2h)³(s1 + s*(x/4h²-u1))
   299  	// This is also
   300  	// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
   301  	gfpSub(t, v, &c.x) // t7
   302  	gfpMul(t4, s1, j)  // t8
   303  	gfpDouble(t6, t4)  // t9
   304  	gfpMul(t4, r, t)   // t10
   305  	gfpSub(&c.y, t4, t6)
   306  
   307  	// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
   308  	gfpAdd(t, &a.z, &b.z) // t11
   309  	gfpSqr(t4, t, 1)      // t12
   310  	gfpSub(t, t4, z12)    // t13
   311  	gfpSub(t4, t, z22)    // t14
   312  	gfpMul(&c.z, t4, h)
   313  
   314  	return pointEq
   315  }