Source file src/crypto/elliptic/params.go

     1  // Copyright 2021 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
     6  
     7  import "math/big"
     8  
     9  // CurveParams contains the parameters of an elliptic curve and also provides
    10  // a generic, non-constant time implementation of [Curve].
    11  //
    12  // The generic Curve implementation is deprecated, and using custom curves
    13  // (those not returned by [P224], [P256], [P384], and [P521]) is not guaranteed
    14  // to provide any security property.
    15  type CurveParams struct {
    16  	P       *big.Int // the order of the underlying field
    17  	N       *big.Int // the order of the base point
    18  	B       *big.Int // the constant of the curve equation
    19  	Gx, Gy  *big.Int // (x,y) of the base point
    20  	BitSize int      // the size of the underlying field
    21  	Name    string   // the canonical name of the curve
    22  }
    23  
    24  func (curve *CurveParams) Params() *CurveParams {
    25  	return curve
    26  }
    27  
    28  // CurveParams operates, internally, on Jacobian coordinates. For a given
    29  // (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
    30  // where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
    31  // calculation can be performed within the transform (as in ScalarMult and
    32  // ScalarBaseMult). But even for Add and Double, it's faster to apply and
    33  // reverse the transform than to operate in affine coordinates.
    34  
    35  // polynomial returns x³ - 3x + b.
    36  func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
    37  	x3 := new(big.Int).Mul(x, x)
    38  	x3.Mul(x3, x)
    39  
    40  	threeX := new(big.Int).Lsh(x, 1)
    41  	threeX.Add(threeX, x)
    42  
    43  	x3.Sub(x3, threeX)
    44  	x3.Add(x3, curve.B)
    45  	x3.Mod(x3, curve.P)
    46  
    47  	return x3
    48  }
    49  
    50  // IsOnCurve implements [Curve.IsOnCurve].
    51  //
    52  // Deprecated: the [CurveParams] methods are deprecated and are not guaranteed to
    53  // provide any security property. For ECDH, use the [crypto/ecdh] package.
    54  // For ECDSA, use the [crypto/ecdsa] package with a [Curve] value returned directly
    55  // from [P224], [P256], [P384], or [P521].
    56  func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
    57  	// If there is a dedicated constant-time implementation for this curve operation,
    58  	// use that instead of the generic one.
    59  	if specific, ok := matchesSpecificCurve(curve); ok {
    60  		return specific.IsOnCurve(x, y)
    61  	}
    62  
    63  	if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
    64  		y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
    65  		return false
    66  	}
    67  
    68  	// y² = x³ - 3x + b
    69  	y2 := new(big.Int).Mul(y, y)
    70  	y2.Mod(y2, curve.P)
    71  
    72  	return curve.polynomial(x).Cmp(y2) == 0
    73  }
    74  
    75  // zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
    76  // y are zero, it assumes that they represent the point at infinity because (0,
    77  // 0) is not on the any of the curves handled here.
    78  func zForAffine(x, y *big.Int) *big.Int {
    79  	z := new(big.Int)
    80  	if x.Sign() != 0 || y.Sign() != 0 {
    81  		z.SetInt64(1)
    82  	}
    83  	return z
    84  }
    85  
    86  // affineFromJacobian reverses the Jacobian transform. See the comment at the
    87  // top of the file. If the point is ∞ it returns 0, 0.
    88  func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
    89  	if z.Sign() == 0 {
    90  		return new(big.Int), new(big.Int)
    91  	}
    92  
    93  	zinv := new(big.Int).ModInverse(z, curve.P)
    94  	zinvsq := new(big.Int).Mul(zinv, zinv)
    95  
    96  	xOut = new(big.Int).Mul(x, zinvsq)
    97  	xOut.Mod(xOut, curve.P)
    98  	zinvsq.Mul(zinvsq, zinv)
    99  	yOut = new(big.Int).Mul(y, zinvsq)
   100  	yOut.Mod(yOut, curve.P)
   101  	return
   102  }
   103  
   104  // Add implements [Curve.Add].
   105  //
   106  // Deprecated: the [CurveParams] methods are deprecated and are not guaranteed to
   107  // provide any security property. For ECDH, use the [crypto/ecdh] package.
   108  // For ECDSA, use the [crypto/ecdsa] package with a [Curve] value returned directly
   109  // from [P224], [P256], [P384], or [P521].
   110  func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
   111  	// If there is a dedicated constant-time implementation for this curve operation,
   112  	// use that instead of the generic one.
   113  	if specific, ok := matchesSpecificCurve(curve); ok {
   114  		return specific.Add(x1, y1, x2, y2)
   115  	}
   116  	panicIfNotOnCurve(curve, x1, y1)
   117  	panicIfNotOnCurve(curve, x2, y2)
   118  
   119  	z1 := zForAffine(x1, y1)
   120  	z2 := zForAffine(x2, y2)
   121  	return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
   122  }
   123  
   124  // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
   125  // (x2, y2, z2) and returns their sum, also in Jacobian form.
   126  func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
   127  	// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
   128  	x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
   129  	if z1.Sign() == 0 {
   130  		x3.Set(x2)
   131  		y3.Set(y2)
   132  		z3.Set(z2)
   133  		return x3, y3, z3
   134  	}
   135  	if z2.Sign() == 0 {
   136  		x3.Set(x1)
   137  		y3.Set(y1)
   138  		z3.Set(z1)
   139  		return x3, y3, z3
   140  	}
   141  
   142  	z1z1 := new(big.Int).Mul(z1, z1)
   143  	z1z1.Mod(z1z1, curve.P)
   144  	z2z2 := new(big.Int).Mul(z2, z2)
   145  	z2z2.Mod(z2z2, curve.P)
   146  
   147  	u1 := new(big.Int).Mul(x1, z2z2)
   148  	u1.Mod(u1, curve.P)
   149  	u2 := new(big.Int).Mul(x2, z1z1)
   150  	u2.Mod(u2, curve.P)
   151  	h := new(big.Int).Sub(u2, u1)
   152  	xEqual := h.Sign() == 0
   153  	if h.Sign() == -1 {
   154  		h.Add(h, curve.P)
   155  	}
   156  	i := new(big.Int).Lsh(h, 1)
   157  	i.Mul(i, i)
   158  	j := new(big.Int).Mul(h, i)
   159  
   160  	s1 := new(big.Int).Mul(y1, z2)
   161  	s1.Mul(s1, z2z2)
   162  	s1.Mod(s1, curve.P)
   163  	s2 := new(big.Int).Mul(y2, z1)
   164  	s2.Mul(s2, z1z1)
   165  	s2.Mod(s2, curve.P)
   166  	r := new(big.Int).Sub(s2, s1)
   167  	if r.Sign() == -1 {
   168  		r.Add(r, curve.P)
   169  	}
   170  	yEqual := r.Sign() == 0
   171  	if xEqual && yEqual {
   172  		return curve.doubleJacobian(x1, y1, z1)
   173  	}
   174  	r.Lsh(r, 1)
   175  	v := new(big.Int).Mul(u1, i)
   176  
   177  	x3.Set(r)
   178  	x3.Mul(x3, x3)
   179  	x3.Sub(x3, j)
   180  	x3.Sub(x3, v)
   181  	x3.Sub(x3, v)
   182  	x3.Mod(x3, curve.P)
   183  
   184  	y3.Set(r)
   185  	v.Sub(v, x3)
   186  	y3.Mul(y3, v)
   187  	s1.Mul(s1, j)
   188  	s1.Lsh(s1, 1)
   189  	y3.Sub(y3, s1)
   190  	y3.Mod(y3, curve.P)
   191  
   192  	z3.Add(z1, z2)
   193  	z3.Mul(z3, z3)
   194  	z3.Sub(z3, z1z1)
   195  	z3.Sub(z3, z2z2)
   196  	z3.Mul(z3, h)
   197  	z3.Mod(z3, curve.P)
   198  
   199  	return x3, y3, z3
   200  }
   201  
   202  // Double implements [Curve.Double].
   203  //
   204  // Deprecated: the [CurveParams] methods are deprecated and are not guaranteed to
   205  // provide any security property. For ECDH, use the [crypto/ecdh] package.
   206  // For ECDSA, use the [crypto/ecdsa] package with a [Curve] value returned directly
   207  // from [P224], [P256], [P384], or [P521].
   208  func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
   209  	// If there is a dedicated constant-time implementation for this curve operation,
   210  	// use that instead of the generic one.
   211  	if specific, ok := matchesSpecificCurve(curve); ok {
   212  		return specific.Double(x1, y1)
   213  	}
   214  	panicIfNotOnCurve(curve, x1, y1)
   215  
   216  	z1 := zForAffine(x1, y1)
   217  	return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
   218  }
   219  
   220  // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
   221  // returns its double, also in Jacobian form.
   222  func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
   223  	// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
   224  	delta := new(big.Int).Mul(z, z)
   225  	delta.Mod(delta, curve.P)
   226  	gamma := new(big.Int).Mul(y, y)
   227  	gamma.Mod(gamma, curve.P)
   228  	alpha := new(big.Int).Sub(x, delta)
   229  	if alpha.Sign() == -1 {
   230  		alpha.Add(alpha, curve.P)
   231  	}
   232  	alpha2 := new(big.Int).Add(x, delta)
   233  	alpha.Mul(alpha, alpha2)
   234  	alpha2.Set(alpha)
   235  	alpha.Lsh(alpha, 1)
   236  	alpha.Add(alpha, alpha2)
   237  
   238  	beta := alpha2.Mul(x, gamma)
   239  
   240  	x3 := new(big.Int).Mul(alpha, alpha)
   241  	beta8 := new(big.Int).Lsh(beta, 3)
   242  	beta8.Mod(beta8, curve.P)
   243  	x3.Sub(x3, beta8)
   244  	if x3.Sign() == -1 {
   245  		x3.Add(x3, curve.P)
   246  	}
   247  	x3.Mod(x3, curve.P)
   248  
   249  	z3 := new(big.Int).Add(y, z)
   250  	z3.Mul(z3, z3)
   251  	z3.Sub(z3, gamma)
   252  	if z3.Sign() == -1 {
   253  		z3.Add(z3, curve.P)
   254  	}
   255  	z3.Sub(z3, delta)
   256  	if z3.Sign() == -1 {
   257  		z3.Add(z3, curve.P)
   258  	}
   259  	z3.Mod(z3, curve.P)
   260  
   261  	beta.Lsh(beta, 2)
   262  	beta.Sub(beta, x3)
   263  	if beta.Sign() == -1 {
   264  		beta.Add(beta, curve.P)
   265  	}
   266  	y3 := alpha.Mul(alpha, beta)
   267  
   268  	gamma.Mul(gamma, gamma)
   269  	gamma.Lsh(gamma, 3)
   270  	gamma.Mod(gamma, curve.P)
   271  
   272  	y3.Sub(y3, gamma)
   273  	if y3.Sign() == -1 {
   274  		y3.Add(y3, curve.P)
   275  	}
   276  	y3.Mod(y3, curve.P)
   277  
   278  	return x3, y3, z3
   279  }
   280  
   281  // ScalarMult implements [Curve.ScalarMult].
   282  //
   283  // Deprecated: the [CurveParams] methods are deprecated and are not guaranteed to
   284  // provide any security property. For ECDH, use the [crypto/ecdh] package.
   285  // For ECDSA, use the [crypto/ecdsa] package with a [Curve] value returned directly
   286  // from [P224], [P256], [P384], or [P521].
   287  func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
   288  	// If there is a dedicated constant-time implementation for this curve operation,
   289  	// use that instead of the generic one.
   290  	if specific, ok := matchesSpecificCurve(curve); ok {
   291  		return specific.ScalarMult(Bx, By, k)
   292  	}
   293  	panicIfNotOnCurve(curve, Bx, By)
   294  
   295  	Bz := new(big.Int).SetInt64(1)
   296  	x, y, z := new(big.Int), new(big.Int), new(big.Int)
   297  
   298  	for _, byte := range k {
   299  		for bitNum := 0; bitNum < 8; bitNum++ {
   300  			x, y, z = curve.doubleJacobian(x, y, z)
   301  			if byte&0x80 == 0x80 {
   302  				x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
   303  			}
   304  			byte <<= 1
   305  		}
   306  	}
   307  
   308  	return curve.affineFromJacobian(x, y, z)
   309  }
   310  
   311  // ScalarBaseMult implements [Curve.ScalarBaseMult].
   312  //
   313  // Deprecated: the [CurveParams] methods are deprecated and are not guaranteed to
   314  // provide any security property. For ECDH, use the [crypto/ecdh] package.
   315  // For ECDSA, use the [crypto/ecdsa] package with a [Curve] value returned directly
   316  // from [P224], [P256], [P384], or [P521].
   317  func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
   318  	// If there is a dedicated constant-time implementation for this curve operation,
   319  	// use that instead of the generic one.
   320  	if specific, ok := matchesSpecificCurve(curve); ok {
   321  		return specific.ScalarBaseMult(k)
   322  	}
   323  
   324  	return curve.ScalarMult(curve.Gx, curve.Gy, k)
   325  }
   326  
   327  func matchesSpecificCurve(params *CurveParams) (Curve, bool) {
   328  	for _, c := range []Curve{p224, p256, p384, p521} {
   329  		if params == c.Params() {
   330  			return c, true
   331  		}
   332  	}
   333  	return nil, false
   334  }
   335  

View as plain text