github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/crypto/elliptic/elliptic.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package elliptic implements several standard elliptic curves over prime
     6  // fields.
     7  package elliptic
     8  
     9  // This package operates, internally, on Jacobian coordinates. For a given
    10  // (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
    11  // where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
    12  // calculation can be performed within the transform (as in ScalarMult and
    13  // ScalarBaseMult). But even for Add and Double, it's faster to apply and
    14  // reverse the transform than to operate in affine coordinates.
    15  
    16  import (
    17  	"io"
    18  	"math/big"
    19  	"sync"
    20  )
    21  
    22  // A Curve represents a short-form Weierstrass curve with a=-3.
    23  //
    24  // Note that the point at infinity (0, 0) is not considered on the curve, and
    25  // although it can be returned by Add, Double, ScalarMult, or ScalarBaseMult, it
    26  // can't be marshaled or unmarshaled, and IsOnCurve will return false for it.
    27  type Curve interface {
    28  	// Params returns the parameters for the curve.
    29  	Params() *CurveParams
    30  	// IsOnCurve reports whether the given (x,y) lies on the curve.
    31  	IsOnCurve(x, y *big.Int) bool
    32  	// Add returns the sum of (x1,y1) and (x2,y2)
    33  	Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
    34  	// Double returns 2*(x,y)
    35  	Double(x1, y1 *big.Int) (x, y *big.Int)
    36  	// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
    37  	ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int)
    38  	// ScalarBaseMult returns k*G, where G is the base point of the group
    39  	// and k is an integer in big-endian form.
    40  	ScalarBaseMult(k []byte) (x, y *big.Int)
    41  }
    42  
    43  func matchesSpecificCurve(params *CurveParams, available ...Curve) (Curve, bool) {
    44  	for _, c := range available {
    45  		if params == c.Params() {
    46  			return c, true
    47  		}
    48  	}
    49  	return nil, false
    50  }
    51  
    52  // CurveParams contains the parameters of an elliptic curve and also provides
    53  // a generic, non-constant time implementation of Curve.
    54  type CurveParams struct {
    55  	P       *big.Int // the order of the underlying field
    56  	N       *big.Int // the order of the base point
    57  	B       *big.Int // the constant of the curve equation
    58  	Gx, Gy  *big.Int // (x,y) of the base point
    59  	BitSize int      // the size of the underlying field
    60  	Name    string   // the canonical name of the curve
    61  }
    62  
    63  func (curve *CurveParams) Params() *CurveParams {
    64  	return curve
    65  }
    66  
    67  // polynomial returns x³ - 3x + b.
    68  func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
    69  	x3 := new(big.Int).Mul(x, x)
    70  	x3.Mul(x3, x)
    71  
    72  	threeX := new(big.Int).Lsh(x, 1)
    73  	threeX.Add(threeX, x)
    74  
    75  	x3.Sub(x3, threeX)
    76  	x3.Add(x3, curve.B)
    77  	x3.Mod(x3, curve.P)
    78  
    79  	return x3
    80  }
    81  
    82  func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
    83  	// If there is a dedicated constant-time implementation for this curve operation,
    84  	// use that instead of the generic one.
    85  	if specific, ok := matchesSpecificCurve(curve, p224, p521); ok {
    86  		return specific.IsOnCurve(x, y)
    87  	}
    88  
    89  	if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
    90  		y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
    91  		return false
    92  	}
    93  
    94  	// y² = x³ - 3x + b
    95  	y2 := new(big.Int).Mul(y, y)
    96  	y2.Mod(y2, curve.P)
    97  
    98  	return curve.polynomial(x).Cmp(y2) == 0
    99  }
   100  
   101  // zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
   102  // y are zero, it assumes that they represent the point at infinity because (0,
   103  // 0) is not on the any of the curves handled here.
   104  func zForAffine(x, y *big.Int) *big.Int {
   105  	z := new(big.Int)
   106  	if x.Sign() != 0 || y.Sign() != 0 {
   107  		z.SetInt64(1)
   108  	}
   109  	return z
   110  }
   111  
   112  // affineFromJacobian reverses the Jacobian transform. See the comment at the
   113  // top of the file. If the point is ∞ it returns 0, 0.
   114  func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
   115  	if z.Sign() == 0 {
   116  		return new(big.Int), new(big.Int)
   117  	}
   118  
   119  	zinv := new(big.Int).ModInverse(z, curve.P)
   120  	zinvsq := new(big.Int).Mul(zinv, zinv)
   121  
   122  	xOut = new(big.Int).Mul(x, zinvsq)
   123  	xOut.Mod(xOut, curve.P)
   124  	zinvsq.Mul(zinvsq, zinv)
   125  	yOut = new(big.Int).Mul(y, zinvsq)
   126  	yOut.Mod(yOut, curve.P)
   127  	return
   128  }
   129  
   130  func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
   131  	// If there is a dedicated constant-time implementation for this curve operation,
   132  	// use that instead of the generic one.
   133  	if specific, ok := matchesSpecificCurve(curve, p224, p521); ok {
   134  		return specific.Add(x1, y1, x2, y2)
   135  	}
   136  
   137  	z1 := zForAffine(x1, y1)
   138  	z2 := zForAffine(x2, y2)
   139  	return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
   140  }
   141  
   142  // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
   143  // (x2, y2, z2) and returns their sum, also in Jacobian form.
   144  func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
   145  	// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
   146  	x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
   147  	if z1.Sign() == 0 {
   148  		x3.Set(x2)
   149  		y3.Set(y2)
   150  		z3.Set(z2)
   151  		return x3, y3, z3
   152  	}
   153  	if z2.Sign() == 0 {
   154  		x3.Set(x1)
   155  		y3.Set(y1)
   156  		z3.Set(z1)
   157  		return x3, y3, z3
   158  	}
   159  
   160  	z1z1 := new(big.Int).Mul(z1, z1)
   161  	z1z1.Mod(z1z1, curve.P)
   162  	z2z2 := new(big.Int).Mul(z2, z2)
   163  	z2z2.Mod(z2z2, curve.P)
   164  
   165  	u1 := new(big.Int).Mul(x1, z2z2)
   166  	u1.Mod(u1, curve.P)
   167  	u2 := new(big.Int).Mul(x2, z1z1)
   168  	u2.Mod(u2, curve.P)
   169  	h := new(big.Int).Sub(u2, u1)
   170  	xEqual := h.Sign() == 0
   171  	if h.Sign() == -1 {
   172  		h.Add(h, curve.P)
   173  	}
   174  	i := new(big.Int).Lsh(h, 1)
   175  	i.Mul(i, i)
   176  	j := new(big.Int).Mul(h, i)
   177  
   178  	s1 := new(big.Int).Mul(y1, z2)
   179  	s1.Mul(s1, z2z2)
   180  	s1.Mod(s1, curve.P)
   181  	s2 := new(big.Int).Mul(y2, z1)
   182  	s2.Mul(s2, z1z1)
   183  	s2.Mod(s2, curve.P)
   184  	r := new(big.Int).Sub(s2, s1)
   185  	if r.Sign() == -1 {
   186  		r.Add(r, curve.P)
   187  	}
   188  	yEqual := r.Sign() == 0
   189  	if xEqual && yEqual {
   190  		return curve.doubleJacobian(x1, y1, z1)
   191  	}
   192  	r.Lsh(r, 1)
   193  	v := new(big.Int).Mul(u1, i)
   194  
   195  	x3.Set(r)
   196  	x3.Mul(x3, x3)
   197  	x3.Sub(x3, j)
   198  	x3.Sub(x3, v)
   199  	x3.Sub(x3, v)
   200  	x3.Mod(x3, curve.P)
   201  
   202  	y3.Set(r)
   203  	v.Sub(v, x3)
   204  	y3.Mul(y3, v)
   205  	s1.Mul(s1, j)
   206  	s1.Lsh(s1, 1)
   207  	y3.Sub(y3, s1)
   208  	y3.Mod(y3, curve.P)
   209  
   210  	z3.Add(z1, z2)
   211  	z3.Mul(z3, z3)
   212  	z3.Sub(z3, z1z1)
   213  	z3.Sub(z3, z2z2)
   214  	z3.Mul(z3, h)
   215  	z3.Mod(z3, curve.P)
   216  
   217  	return x3, y3, z3
   218  }
   219  
   220  func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
   221  	// If there is a dedicated constant-time implementation for this curve operation,
   222  	// use that instead of the generic one.
   223  	if specific, ok := matchesSpecificCurve(curve, p224, p521); ok {
   224  		return specific.Double(x1, y1)
   225  	}
   226  
   227  	z1 := zForAffine(x1, y1)
   228  	return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
   229  }
   230  
   231  // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
   232  // returns its double, also in Jacobian form.
   233  func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
   234  	// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
   235  	delta := new(big.Int).Mul(z, z)
   236  	delta.Mod(delta, curve.P)
   237  	gamma := new(big.Int).Mul(y, y)
   238  	gamma.Mod(gamma, curve.P)
   239  	alpha := new(big.Int).Sub(x, delta)
   240  	if alpha.Sign() == -1 {
   241  		alpha.Add(alpha, curve.P)
   242  	}
   243  	alpha2 := new(big.Int).Add(x, delta)
   244  	alpha.Mul(alpha, alpha2)
   245  	alpha2.Set(alpha)
   246  	alpha.Lsh(alpha, 1)
   247  	alpha.Add(alpha, alpha2)
   248  
   249  	beta := alpha2.Mul(x, gamma)
   250  
   251  	x3 := new(big.Int).Mul(alpha, alpha)
   252  	beta8 := new(big.Int).Lsh(beta, 3)
   253  	beta8.Mod(beta8, curve.P)
   254  	x3.Sub(x3, beta8)
   255  	if x3.Sign() == -1 {
   256  		x3.Add(x3, curve.P)
   257  	}
   258  	x3.Mod(x3, curve.P)
   259  
   260  	z3 := new(big.Int).Add(y, z)
   261  	z3.Mul(z3, z3)
   262  	z3.Sub(z3, gamma)
   263  	if z3.Sign() == -1 {
   264  		z3.Add(z3, curve.P)
   265  	}
   266  	z3.Sub(z3, delta)
   267  	if z3.Sign() == -1 {
   268  		z3.Add(z3, curve.P)
   269  	}
   270  	z3.Mod(z3, curve.P)
   271  
   272  	beta.Lsh(beta, 2)
   273  	beta.Sub(beta, x3)
   274  	if beta.Sign() == -1 {
   275  		beta.Add(beta, curve.P)
   276  	}
   277  	y3 := alpha.Mul(alpha, beta)
   278  
   279  	gamma.Mul(gamma, gamma)
   280  	gamma.Lsh(gamma, 3)
   281  	gamma.Mod(gamma, curve.P)
   282  
   283  	y3.Sub(y3, gamma)
   284  	if y3.Sign() == -1 {
   285  		y3.Add(y3, curve.P)
   286  	}
   287  	y3.Mod(y3, curve.P)
   288  
   289  	return x3, y3, z3
   290  }
   291  
   292  func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
   293  	// If there is a dedicated constant-time implementation for this curve operation,
   294  	// use that instead of the generic one.
   295  	if specific, ok := matchesSpecificCurve(curve, p224, p256, p521); ok {
   296  		return specific.ScalarMult(Bx, By, k)
   297  	}
   298  
   299  	Bz := new(big.Int).SetInt64(1)
   300  	x, y, z := new(big.Int), new(big.Int), new(big.Int)
   301  
   302  	for _, byte := range k {
   303  		for bitNum := 0; bitNum < 8; bitNum++ {
   304  			x, y, z = curve.doubleJacobian(x, y, z)
   305  			if byte&0x80 == 0x80 {
   306  				x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
   307  			}
   308  			byte <<= 1
   309  		}
   310  	}
   311  
   312  	return curve.affineFromJacobian(x, y, z)
   313  }
   314  
   315  func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
   316  	// If there is a dedicated constant-time implementation for this curve operation,
   317  	// use that instead of the generic one.
   318  	if specific, ok := matchesSpecificCurve(curve, p224, p256, p521); ok {
   319  		return specific.ScalarBaseMult(k)
   320  	}
   321  
   322  	return curve.ScalarMult(curve.Gx, curve.Gy, k)
   323  }
   324  
   325  var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
   326  
   327  // GenerateKey returns a public/private key pair. The private key is
   328  // generated using the given reader, which must return random data.
   329  func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) {
   330  	N := curve.Params().N
   331  	bitSize := N.BitLen()
   332  	byteLen := (bitSize + 7) / 8
   333  	priv = make([]byte, byteLen)
   334  
   335  	for x == nil {
   336  		_, err = io.ReadFull(rand, priv)
   337  		if err != nil {
   338  			return
   339  		}
   340  		// We have to mask off any excess bits in the case that the size of the
   341  		// underlying field is not a whole number of bytes.
   342  		priv[0] &= mask[bitSize%8]
   343  		// This is because, in tests, rand will return all zeros and we don't
   344  		// want to get the point at infinity and loop forever.
   345  		priv[1] ^= 0x42
   346  
   347  		// If the scalar is out of range, sample another random number.
   348  		if new(big.Int).SetBytes(priv).Cmp(N) >= 0 {
   349  			continue
   350  		}
   351  
   352  		x, y = curve.ScalarBaseMult(priv)
   353  	}
   354  	return
   355  }
   356  
   357  // Marshal converts a point on the curve into the uncompressed form specified in
   358  // section 4.3.6 of ANSI X9.62.
   359  func Marshal(curve Curve, x, y *big.Int) []byte {
   360  	byteLen := (curve.Params().BitSize + 7) / 8
   361  
   362  	ret := make([]byte, 1+2*byteLen)
   363  	ret[0] = 4 // uncompressed point
   364  
   365  	x.FillBytes(ret[1 : 1+byteLen])
   366  	y.FillBytes(ret[1+byteLen : 1+2*byteLen])
   367  
   368  	return ret
   369  }
   370  
   371  // MarshalCompressed converts a point on the curve into the compressed form
   372  // specified in section 4.3.6 of ANSI X9.62.
   373  func MarshalCompressed(curve Curve, x, y *big.Int) []byte {
   374  	byteLen := (curve.Params().BitSize + 7) / 8
   375  	compressed := make([]byte, 1+byteLen)
   376  	compressed[0] = byte(y.Bit(0)) | 2
   377  	x.FillBytes(compressed[1:])
   378  	return compressed
   379  }
   380  
   381  // Unmarshal converts a point, serialized by Marshal, into an x, y pair.
   382  // It is an error if the point is not in uncompressed form or is not on the curve.
   383  // On error, x = nil.
   384  func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
   385  	byteLen := (curve.Params().BitSize + 7) / 8
   386  	if len(data) != 1+2*byteLen {
   387  		return nil, nil
   388  	}
   389  	if data[0] != 4 { // uncompressed form
   390  		return nil, nil
   391  	}
   392  	p := curve.Params().P
   393  	x = new(big.Int).SetBytes(data[1 : 1+byteLen])
   394  	y = new(big.Int).SetBytes(data[1+byteLen:])
   395  	if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 {
   396  		return nil, nil
   397  	}
   398  	if !curve.IsOnCurve(x, y) {
   399  		return nil, nil
   400  	}
   401  	return
   402  }
   403  
   404  // UnmarshalCompressed converts a point, serialized by MarshalCompressed, into an x, y pair.
   405  // It is an error if the point is not in compressed form or is not on the curve.
   406  // On error, x = nil.
   407  func UnmarshalCompressed(curve Curve, data []byte) (x, y *big.Int) {
   408  	byteLen := (curve.Params().BitSize + 7) / 8
   409  	if len(data) != 1+byteLen {
   410  		return nil, nil
   411  	}
   412  	if data[0] != 2 && data[0] != 3 { // compressed form
   413  		return nil, nil
   414  	}
   415  	p := curve.Params().P
   416  	x = new(big.Int).SetBytes(data[1:])
   417  	if x.Cmp(p) >= 0 {
   418  		return nil, nil
   419  	}
   420  	// y² = x³ - 3x + b
   421  	y = curve.Params().polynomial(x)
   422  	y = y.ModSqrt(y, p)
   423  	if y == nil {
   424  		return nil, nil
   425  	}
   426  	if byte(y.Bit(0)) != data[0]&1 {
   427  		y.Neg(y).Mod(y, p)
   428  	}
   429  	if !curve.IsOnCurve(x, y) {
   430  		return nil, nil
   431  	}
   432  	return
   433  }
   434  
   435  var initonce sync.Once
   436  var p384 *CurveParams
   437  
   438  func initAll() {
   439  	initP224()
   440  	initP256()
   441  	initP384()
   442  	initP521()
   443  }
   444  
   445  func initP384() {
   446  	// See FIPS 186-3, section D.2.4
   447  	p384 = &CurveParams{Name: "P-384"}
   448  	p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
   449  	p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10)
   450  	p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
   451  	p384.Gx, _ = new(big.Int).SetString("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", 16)
   452  	p384.Gy, _ = new(big.Int).SetString("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", 16)
   453  	p384.BitSize = 384
   454  }
   455  
   456  // P256 returns a Curve which implements NIST P-256 (FIPS 186-3, section D.2.3),
   457  // also known as secp256r1 or prime256v1. The CurveParams.Name of this Curve is
   458  // "P-256".
   459  //
   460  // Multiple invocations of this function will return the same value, so it can
   461  // be used for equality checks and switch statements.
   462  //
   463  // ScalarMult and ScalarBaseMult are implemented using constant-time algorithms.
   464  func P256() Curve {
   465  	initonce.Do(initAll)
   466  	return p256
   467  }
   468  
   469  // P384 returns a Curve which implements NIST P-384 (FIPS 186-3, section D.2.4),
   470  // also known as secp384r1. The CurveParams.Name of this Curve is "P-384".
   471  //
   472  // Multiple invocations of this function will return the same value, so it can
   473  // be used for equality checks and switch statements.
   474  //
   475  // The cryptographic operations do not use constant-time algorithms.
   476  func P384() Curve {
   477  	initonce.Do(initAll)
   478  	return p384
   479  }
   480  
   481  // P521 returns a Curve which implements NIST P-521 (FIPS 186-3, section D.2.5),
   482  // also known as secp521r1. The CurveParams.Name of this Curve is "P-521".
   483  //
   484  // Multiple invocations of this function will return the same value, so it can
   485  // be used for equality checks and switch statements.
   486  //
   487  // The cryptographic operations are implemented using constant-time algorithms.
   488  func P521() Curve {
   489  	initonce.Do(initAll)
   490  	return p521
   491  }