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

     1  package bn256
     2  
     3  import "math/big"
     4  
     5  // CurveParams contains the parameters of an elliptic curve and also provides
     6  // a generic, non-constant time implementation of Curve.
     7  type CurveParams struct {
     8  	P       *big.Int // the order of the underlying field
     9  	N       *big.Int // the order of the base point
    10  	B       *big.Int // the constant of the curve equation
    11  	Gx, Gy  *big.Int // (x,y) of the base point
    12  	BitSize int      // the size of the underlying field
    13  	Name    string   // the canonical name of the curve
    14  }
    15  
    16  func (curve *CurveParams) Params() *CurveParams {
    17  	return curve
    18  }
    19  
    20  // CurveParams operates, internally, on Jacobian coordinates. For a given
    21  // (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
    22  // where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
    23  // calculation can be performed within the transform (as in ScalarMult and
    24  // ScalarBaseMult). But even for Add and Double, it's faster to apply and
    25  // reverse the transform than to operate in affine coordinates.
    26  
    27  // polynomial returns x³ + b.
    28  func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
    29  	x3 := new(big.Int).Mul(x, x)
    30  	x3.Mul(x3, x)
    31  
    32  	x3.Add(x3, curve.B)
    33  	x3.Mod(x3, curve.P)
    34  
    35  	return x3
    36  }
    37  
    38  func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
    39  	if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
    40  		y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
    41  		return false
    42  	}
    43  
    44  	// y² = x³ + b
    45  	y2 := new(big.Int).Mul(y, y)
    46  	y2.Mod(y2, curve.P)
    47  
    48  	return curve.polynomial(x).Cmp(y2) == 0
    49  }
    50  
    51  // zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
    52  // y are zero, it assumes that they represent the point at infinity because (0,
    53  // 0) is not on the any of the curves handled here.
    54  func zForAffine(x, y *big.Int) *big.Int {
    55  	z := new(big.Int)
    56  	if x.Sign() != 0 || y.Sign() != 0 {
    57  		z.SetInt64(1)
    58  	}
    59  	return z
    60  }
    61  
    62  // affineFromJacobian reverses the Jacobian transform. See the comment at the
    63  // top of the file. If the point is ∞ it returns 0, 0.
    64  func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
    65  	if z.Sign() == 0 {
    66  		return new(big.Int), new(big.Int)
    67  	}
    68  
    69  	zinv := new(big.Int).ModInverse(z, curve.P)
    70  	zinvsq := new(big.Int).Mul(zinv, zinv)
    71  
    72  	xOut = new(big.Int).Mul(x, zinvsq)
    73  	xOut.Mod(xOut, curve.P)
    74  	zinvsq.Mul(zinvsq, zinv)
    75  	yOut = new(big.Int).Mul(y, zinvsq)
    76  	yOut.Mod(yOut, curve.P)
    77  	return
    78  }
    79  
    80  func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
    81  	z1 := zForAffine(x1, y1)
    82  	z2 := zForAffine(x2, y2)
    83  	return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
    84  }
    85  
    86  // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
    87  // (x2, y2, z2) and returns their sum, also in Jacobian form.
    88  func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
    89  	// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
    90  	x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
    91  	if z1.Sign() == 0 {
    92  		x3.Set(x2)
    93  		y3.Set(y2)
    94  		z3.Set(z2)
    95  		return x3, y3, z3
    96  	}
    97  	if z2.Sign() == 0 {
    98  		x3.Set(x1)
    99  		y3.Set(y1)
   100  		z3.Set(z1)
   101  		return x3, y3, z3
   102  	}
   103  
   104  	z1z1 := new(big.Int).Mul(z1, z1)
   105  	z1z1.Mod(z1z1, curve.P)
   106  	z2z2 := new(big.Int).Mul(z2, z2)
   107  	z2z2.Mod(z2z2, curve.P)
   108  
   109  	u1 := new(big.Int).Mul(x1, z2z2)
   110  	u1.Mod(u1, curve.P)
   111  	u2 := new(big.Int).Mul(x2, z1z1)
   112  	u2.Mod(u2, curve.P)
   113  	h := new(big.Int).Sub(u2, u1)
   114  	xEqual := h.Sign() == 0
   115  	if h.Sign() == -1 {
   116  		h.Add(h, curve.P)
   117  	}
   118  	i := new(big.Int).Lsh(h, 1)
   119  	i.Mul(i, i)
   120  	j := new(big.Int).Mul(h, i)
   121  
   122  	s1 := new(big.Int).Mul(y1, z2)
   123  	s1.Mul(s1, z2z2)
   124  	s1.Mod(s1, curve.P)
   125  	s2 := new(big.Int).Mul(y2, z1)
   126  	s2.Mul(s2, z1z1)
   127  	s2.Mod(s2, curve.P)
   128  	r := new(big.Int).Sub(s2, s1)
   129  	if r.Sign() == -1 {
   130  		r.Add(r, curve.P)
   131  	}
   132  	yEqual := r.Sign() == 0
   133  	if xEqual && yEqual {
   134  		return curve.doubleJacobian(x1, y1, z1)
   135  	}
   136  	r.Lsh(r, 1)
   137  	v := new(big.Int).Mul(u1, i)
   138  
   139  	x3.Set(r)
   140  	x3.Mul(x3, x3)
   141  	x3.Sub(x3, j)
   142  	x3.Sub(x3, v)
   143  	x3.Sub(x3, v)
   144  	x3.Mod(x3, curve.P)
   145  
   146  	y3.Set(r)
   147  	v.Sub(v, x3)
   148  	y3.Mul(y3, v)
   149  	s1.Mul(s1, j)
   150  	s1.Lsh(s1, 1)
   151  	y3.Sub(y3, s1)
   152  	y3.Mod(y3, curve.P)
   153  
   154  	z3.Add(z1, z2)
   155  	z3.Mul(z3, z3)
   156  	z3.Sub(z3, z1z1)
   157  	z3.Sub(z3, z2z2)
   158  	z3.Mul(z3, h)
   159  	z3.Mod(z3, curve.P)
   160  
   161  	return x3, y3, z3
   162  }
   163  
   164  func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
   165  	z1 := zForAffine(x1, y1)
   166  	return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
   167  }
   168  
   169  // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
   170  // returns its double, also in Jacobian form.
   171  func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
   172  	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
   173  	a := new(big.Int).Mul(x, x)
   174  	a.Mod(a, curve.P)
   175  	b := new(big.Int).Mul(y, y)
   176  	b.Mod(b, curve.P)
   177  	c := new(big.Int).Mul(b, b)
   178  	c.Mod(c, curve.P)
   179  
   180  	d := new(big.Int).Add(x, b)
   181  	d.Mul(d, d)
   182  	d.Sub(d, a)
   183  	d.Sub(d, c)
   184  	d.Lsh(d, 1)
   185  	if d.Sign() < 0 {
   186  		d.Add(d, curve.P)
   187  	} else {
   188  		d.Mod(d, curve.P)
   189  	}
   190  
   191  	e := new(big.Int).Lsh(a, 1)
   192  	e.Add(e, a)
   193  	f := new(big.Int).Mul(e, e)
   194  	x3 := new(big.Int).Lsh(d, 1)
   195  	x3.Sub(f, x3)
   196  	if x3.Sign() < 0 {
   197  		x3.Add(x3, curve.P)
   198  	} else {
   199  		x3.Mod(x3, curve.P)
   200  	}
   201  
   202  	y3 := new(big.Int).Sub(d, x3)
   203  	y3.Mul(y3, e)
   204  	c.Lsh(c, 3)
   205  	y3.Sub(y3, c)
   206  	if y3.Sign() < 0 {
   207  		y3.Add(y3, curve.P)
   208  	} else {
   209  		y3.Mod(y3, curve.P)
   210  	}
   211  
   212  	z3 := new(big.Int).Mul(y, z)
   213  	z3.Lsh(z3, 1)
   214  	z3.Mod(z3, curve.P)
   215  
   216  	return x3, y3, z3
   217  }
   218  
   219  func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
   220  	Bz := new(big.Int).SetInt64(1)
   221  	x, y, z := new(big.Int), new(big.Int), new(big.Int)
   222  
   223  	for _, byte := range k {
   224  		for bitNum := 0; bitNum < 8; bitNum++ {
   225  			x, y, z = curve.doubleJacobian(x, y, z)
   226  			if byte&0x80 == 0x80 {
   227  				x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
   228  			}
   229  			byte <<= 1
   230  		}
   231  	}
   232  
   233  	return curve.affineFromJacobian(x, y, z)
   234  }
   235  
   236  func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
   237  	return curve.ScalarMult(curve.Gx, curve.Gy, k)
   238  }