github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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 the standard NIST P-224, P-256, P-384, and P-521
     6  // elliptic curves over prime fields.
     7  //
     8  // Direct use of this package is deprecated, beyond the P224(), P256(), P384(),
     9  // and P521() values necessary to use the crypto/ecdsa package. Most other uses
    10  // should migrate to the more efficient and safer crypto/ecdh package.
    11  package elliptic
    12  
    13  import (
    14  	"io"
    15  	"math/big"
    16  	"sync"
    17  )
    18  
    19  // A Curve represents a short-form Weierstrass curve with a=-3.
    20  //
    21  // The behavior of Add, Double, and ScalarMult when the input is not a point on
    22  // the curve is undefined.
    23  //
    24  // Note that the conventional point at infinity (0, 0) is not considered on the
    25  // curve, although it can be returned by Add, Double, ScalarMult, or
    26  // ScalarBaseMult (but not the Unmarshal or UnmarshalCompressed functions).
    27  //
    28  // Using Curve implementations besides those returned by P224(), P256(), P384(),
    29  // and P521() is deprecated.
    30  type Curve interface {
    31  	// Params returns the parameters for the curve.
    32  	Params() *CurveParams
    33  
    34  	// IsOnCurve reports whether the given (x,y) lies on the curve.
    35  	//
    36  	// Deprecated: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
    37  	// package. The NewPublicKey methods of NIST curves in crypto/ecdh accept
    38  	// the same encoding as the Unmarshal function, and perform on-curve checks.
    39  	IsOnCurve(x, y *big.Int) bool
    40  
    41  	// Add returns the sum of (x1,y1) and (x2,y2).
    42  	//
    43  	// Deprecated: this is a low-level unsafe API.
    44  	Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
    45  
    46  	// Double returns 2*(x,y).
    47  	//
    48  	// Deprecated: this is a low-level unsafe API.
    49  	Double(x1, y1 *big.Int) (x, y *big.Int)
    50  
    51  	// ScalarMult returns k*(x,y) where k is an integer in big-endian form.
    52  	//
    53  	// Deprecated: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
    54  	// package. Most uses of ScalarMult can be replaced by a call to the ECDH
    55  	// methods of NIST curves in crypto/ecdh.
    56  	ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int)
    57  
    58  	// ScalarBaseMult returns k*G, where G is the base point of the group
    59  	// and k is an integer in big-endian form.
    60  	//
    61  	// Deprecated: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
    62  	// package. Most uses of ScalarBaseMult can be replaced by a call to the
    63  	// PrivateKey.PublicKey method in crypto/ecdh.
    64  	ScalarBaseMult(k []byte) (x, y *big.Int)
    65  }
    66  
    67  var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
    68  
    69  // GenerateKey returns a public/private key pair. The private key is
    70  // generated using the given reader, which must return random data.
    71  //
    72  // Deprecated: for ECDH, use the GenerateKey methods of the crypto/ecdh package;
    73  // for ECDSA, use the GenerateKey function of the crypto/ecdsa package.
    74  func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) {
    75  	N := curve.Params().N
    76  	bitSize := N.BitLen()
    77  	byteLen := (bitSize + 7) / 8
    78  	priv = make([]byte, byteLen)
    79  
    80  	for x == nil {
    81  		_, err = io.ReadFull(rand, priv)
    82  		if err != nil {
    83  			return
    84  		}
    85  		// We have to mask off any excess bits in the case that the size of the
    86  		// underlying field is not a whole number of bytes.
    87  		priv[0] &= mask[bitSize%8]
    88  		// This is because, in tests, rand will return all zeros and we don't
    89  		// want to get the point at infinity and loop forever.
    90  		priv[1] ^= 0x42
    91  
    92  		// If the scalar is out of range, sample another random number.
    93  		if new(big.Int).SetBytes(priv).Cmp(N) >= 0 {
    94  			continue
    95  		}
    96  
    97  		x, y = curve.ScalarBaseMult(priv)
    98  	}
    99  	return
   100  }
   101  
   102  // Marshal converts a point on the curve into the uncompressed form specified in
   103  // SEC 1, Version 2.0, Section 2.3.3. If the point is not on the curve (or is
   104  // the conventional point at infinity), the behavior is undefined.
   105  //
   106  // Deprecated: for ECDH, use the crypto/ecdh package. This function returns an
   107  // encoding equivalent to that of PublicKey.Bytes in crypto/ecdh.
   108  func Marshal(curve Curve, x, y *big.Int) []byte {
   109  	panicIfNotOnCurve(curve, x, y)
   110  
   111  	byteLen := (curve.Params().BitSize + 7) / 8
   112  
   113  	ret := make([]byte, 1+2*byteLen)
   114  	ret[0] = 4 // uncompressed point
   115  
   116  	x.FillBytes(ret[1 : 1+byteLen])
   117  	y.FillBytes(ret[1+byteLen : 1+2*byteLen])
   118  
   119  	return ret
   120  }
   121  
   122  // MarshalCompressed converts a point on the curve into the compressed form
   123  // specified in SEC 1, Version 2.0, Section 2.3.3. If the point is not on the
   124  // curve (or is the conventional point at infinity), the behavior is undefined.
   125  func MarshalCompressed(curve Curve, x, y *big.Int) []byte {
   126  	panicIfNotOnCurve(curve, x, y)
   127  	byteLen := (curve.Params().BitSize + 7) / 8
   128  	compressed := make([]byte, 1+byteLen)
   129  	compressed[0] = byte(y.Bit(0)) | 2
   130  	x.FillBytes(compressed[1:])
   131  	return compressed
   132  }
   133  
   134  // unmarshaler is implemented by curves with their own constant-time Unmarshal.
   135  //
   136  // There isn't an equivalent interface for Marshal/MarshalCompressed because
   137  // that doesn't involve any mathematical operations, only FillBytes and Bit.
   138  type unmarshaler interface {
   139  	Unmarshal([]byte) (x, y *big.Int)
   140  	UnmarshalCompressed([]byte) (x, y *big.Int)
   141  }
   142  
   143  // Assert that the known curves implement unmarshaler.
   144  var _ = []unmarshaler{p224, p256, p384, p521}
   145  
   146  // Unmarshal converts a point, serialized by Marshal, into an x, y pair. It is
   147  // an error if the point is not in uncompressed form, is not on the curve, or is
   148  // the point at infinity. On error, x = nil.
   149  //
   150  // Deprecated: for ECDH, use the crypto/ecdh package. This function accepts an
   151  // encoding equivalent to that of the NewPublicKey methods in crypto/ecdh.
   152  func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
   153  	if c, ok := curve.(unmarshaler); ok {
   154  		return c.Unmarshal(data)
   155  	}
   156  
   157  	byteLen := (curve.Params().BitSize + 7) / 8
   158  	if len(data) != 1+2*byteLen {
   159  		return nil, nil
   160  	}
   161  	if data[0] != 4 { // uncompressed form
   162  		return nil, nil
   163  	}
   164  	p := curve.Params().P
   165  	x = new(big.Int).SetBytes(data[1 : 1+byteLen])
   166  	y = new(big.Int).SetBytes(data[1+byteLen:])
   167  	if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 {
   168  		return nil, nil
   169  	}
   170  	if !curve.IsOnCurve(x, y) {
   171  		return nil, nil
   172  	}
   173  	return
   174  }
   175  
   176  // UnmarshalCompressed converts a point, serialized by MarshalCompressed, into
   177  // an x, y pair. It is an error if the point is not in compressed form, is not
   178  // on the curve, or is the point at infinity. On error, x = nil.
   179  func UnmarshalCompressed(curve Curve, data []byte) (x, y *big.Int) {
   180  	if c, ok := curve.(unmarshaler); ok {
   181  		return c.UnmarshalCompressed(data)
   182  	}
   183  
   184  	byteLen := (curve.Params().BitSize + 7) / 8
   185  	if len(data) != 1+byteLen {
   186  		return nil, nil
   187  	}
   188  	if data[0] != 2 && data[0] != 3 { // compressed form
   189  		return nil, nil
   190  	}
   191  	p := curve.Params().P
   192  	x = new(big.Int).SetBytes(data[1:])
   193  	if x.Cmp(p) >= 0 {
   194  		return nil, nil
   195  	}
   196  	// y² = x³ - 3x + b
   197  	y = curve.Params().polynomial(x)
   198  	y = y.ModSqrt(y, p)
   199  	if y == nil {
   200  		return nil, nil
   201  	}
   202  	if byte(y.Bit(0)) != data[0]&1 {
   203  		y.Neg(y).Mod(y, p)
   204  	}
   205  	if !curve.IsOnCurve(x, y) {
   206  		return nil, nil
   207  	}
   208  	return
   209  }
   210  
   211  func panicIfNotOnCurve(curve Curve, x, y *big.Int) {
   212  	// (0, 0) is the point at infinity by convention. It's ok to operate on it,
   213  	// although IsOnCurve is documented to return false for it. See Issue 37294.
   214  	if x.Sign() == 0 && y.Sign() == 0 {
   215  		return
   216  	}
   217  
   218  	if !curve.IsOnCurve(x, y) {
   219  		panic("crypto/elliptic: attempted operation on invalid point")
   220  	}
   221  }
   222  
   223  var initonce sync.Once
   224  
   225  func initAll() {
   226  	initP224()
   227  	initP256()
   228  	initP384()
   229  	initP521()
   230  }
   231  
   232  // P224 returns a Curve which implements NIST P-224 (FIPS 186-3, section D.2.2),
   233  // also known as secp224r1. The CurveParams.Name of this Curve is "P-224".
   234  //
   235  // Multiple invocations of this function will return the same value, so it can
   236  // be used for equality checks and switch statements.
   237  //
   238  // The cryptographic operations are implemented using constant-time algorithms.
   239  func P224() Curve {
   240  	initonce.Do(initAll)
   241  	return p224
   242  }
   243  
   244  // P256 returns a Curve which implements NIST P-256 (FIPS 186-3, section D.2.3),
   245  // also known as secp256r1 or prime256v1. The CurveParams.Name of this Curve is
   246  // "P-256".
   247  //
   248  // Multiple invocations of this function will return the same value, so it can
   249  // be used for equality checks and switch statements.
   250  //
   251  // The cryptographic operations are implemented using constant-time algorithms.
   252  func P256() Curve {
   253  	initonce.Do(initAll)
   254  	return p256
   255  }
   256  
   257  // P384 returns a Curve which implements NIST P-384 (FIPS 186-3, section D.2.4),
   258  // also known as secp384r1. The CurveParams.Name of this Curve is "P-384".
   259  //
   260  // Multiple invocations of this function will return the same value, so it can
   261  // be used for equality checks and switch statements.
   262  //
   263  // The cryptographic operations are implemented using constant-time algorithms.
   264  func P384() Curve {
   265  	initonce.Do(initAll)
   266  	return p384
   267  }
   268  
   269  // P521 returns a Curve which implements NIST P-521 (FIPS 186-3, section D.2.5),
   270  // also known as secp521r1. The CurveParams.Name of this Curve is "P-521".
   271  //
   272  // Multiple invocations of this function will return the same value, so it can
   273  // be used for equality checks and switch statements.
   274  //
   275  // The cryptographic operations are implemented using constant-time algorithms.
   276  func P521() Curve {
   277  	initonce.Do(initAll)
   278  	return p521
   279  }