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.
9 // CurveParams contains the parameters of an elliptic curve and also provides
10 // a generic, non-constant time implementation of Curve.
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
24 func (curve *CurveParams) Params() *CurveParams {
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.
35 // polynomial returns x³ - 3x + b.
36 func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
37 x3 := new(big.Int).Mul(x, x)
40 threeX := new(big.Int).Lsh(x, 1)
50 // IsOnCurve implements Curve.IsOnCurve.
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)
63 if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
64 y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
69 y2 := new(big.Int).Mul(y, y)
72 return curve.polynomial(x).Cmp(y2) == 0
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 {
80 if x.Sign() != 0 || y.Sign() != 0 {
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) {
90 return new(big.Int), new(big.Int)
93 zinv := new(big.Int).ModInverse(z, curve.P)
94 zinvsq := new(big.Int).Mul(zinv, zinv)
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)
104 // Add implements Curve.Add.
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)
116 panicIfNotOnCurve(curve, x1, y1)
117 panicIfNotOnCurve(curve, x2, y2)
119 z1 := zForAffine(x1, y1)
120 z2 := zForAffine(x2, y2)
121 return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
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)
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)
147 u1 := new(big.Int).Mul(x1, z2z2)
149 u2 := new(big.Int).Mul(x2, z1z1)
151 h := new(big.Int).Sub(u2, u1)
152 xEqual := h.Sign() == 0
156 i := new(big.Int).Lsh(h, 1)
158 j := new(big.Int).Mul(h, i)
160 s1 := new(big.Int).Mul(y1, z2)
163 s2 := new(big.Int).Mul(y2, z1)
166 r := new(big.Int).Sub(s2, s1)
170 yEqual := r.Sign() == 0
171 if xEqual && yEqual {
172 return curve.doubleJacobian(x1, y1, z1)
175 v := new(big.Int).Mul(u1, i)
202 // Double implements Curve.Double.
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)
214 panicIfNotOnCurve(curve, x1, y1)
216 z1 := zForAffine(x1, y1)
217 return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
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)
232 alpha2 := new(big.Int).Add(x, delta)
233 alpha.Mul(alpha, alpha2)
236 alpha.Add(alpha, alpha2)
238 beta := alpha2.Mul(x, gamma)
240 x3 := new(big.Int).Mul(alpha, alpha)
241 beta8 := new(big.Int).Lsh(beta, 3)
242 beta8.Mod(beta8, curve.P)
249 z3 := new(big.Int).Add(y, z)
263 if beta.Sign() == -1 {
264 beta.Add(beta, curve.P)
266 y3 := alpha.Mul(alpha, beta)
268 gamma.Mul(gamma, gamma)
270 gamma.Mod(gamma, curve.P)
281 // ScalarMult implements Curve.ScalarMult.
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)
293 panicIfNotOnCurve(curve, Bx, By)
295 Bz := new(big.Int).SetInt64(1)
296 x, y, z := new(big.Int), new(big.Int), new(big.Int)
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)
308 return curve.affineFromJacobian(x, y, z)
311 // ScalarBaseMult implements Curve.ScalarBaseMult.
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)
324 return curve.ScalarMult(curve.Gx, curve.Gy, k)
327 func matchesSpecificCurve(params *CurveParams) (Curve, bool) {
328 for _, c := range []Curve{p224, p256, p384, p521} {
329 if params == c.Params() {