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 }