github.com/onflow/flow-go/crypto@v0.24.8/ecdsa.go (about) 1 package crypto 2 3 // Elliptic Curve Digital Signature Algorithm is implemented as 4 // defined in FIPS 186-4 (although the hash functions implemented in this package are SHA2 and SHA3). 5 6 // Most of the implementation is Go based and is not optimized for performance. 7 8 // This implementation does not include any security against side-channel attacks. 9 10 import ( 11 "crypto/ecdsa" 12 "crypto/elliptic" 13 "crypto/rand" 14 "crypto/sha256" 15 "fmt" 16 "math/big" 17 18 "github.com/btcsuite/btcd/btcec/v2" 19 "golang.org/x/crypto/hkdf" 20 21 "github.com/onflow/flow-go/crypto/hash" 22 ) 23 24 const ( 25 // NIST P256 26 SignatureLenECDSAP256 = 64 27 PrKeyLenECDSAP256 = 32 28 // PubKeyLenECDSAP256 is the size of uncompressed points on P256 29 PubKeyLenECDSAP256 = 64 30 31 // SECG secp256k1 32 SignatureLenECDSASecp256k1 = 64 33 PrKeyLenECDSASecp256k1 = 32 34 // PubKeyLenECDSASecp256k1 is the size of uncompressed points on secp256k1 35 PubKeyLenECDSASecp256k1 = 64 36 ) 37 38 // ecdsaAlgo embeds SignAlgo 39 type ecdsaAlgo struct { 40 // elliptic curve 41 curve elliptic.Curve 42 // the signing algo and parameters 43 algo SigningAlgorithm 44 } 45 46 // ECDSA contexts for each supported curve 47 // 48 // NIST P-256 curve 49 var p256Instance *ecdsaAlgo 50 51 // SECG secp256k1 curve https://www.secg.org/sec2-v2.pdf 52 var secp256k1Instance *ecdsaAlgo 53 54 func bitsToBytes(bits int) int { 55 return (bits + 7) >> 3 56 } 57 58 // signHash returns the signature of the hash using the private key 59 // the signature is the concatenation bytes(r)||bytes(s) 60 // where r and s are padded to the curve order size 61 func (sk *prKeyECDSA) signHash(h hash.Hash) (Signature, error) { 62 r, s, err := ecdsa.Sign(rand.Reader, sk.goPrKey, h) 63 if err != nil { 64 return nil, fmt.Errorf("ECDSA Sign failed: %w", err) 65 } 66 rBytes := r.Bytes() 67 sBytes := s.Bytes() 68 Nlen := bitsToBytes((sk.alg.curve.Params().N).BitLen()) 69 signature := make([]byte, 2*Nlen) 70 // pad the signature with zeroes 71 copy(signature[Nlen-len(rBytes):], rBytes) 72 copy(signature[2*Nlen-len(sBytes):], sBytes) 73 return signature, nil 74 } 75 76 // Sign signs an array of bytes 77 // 78 // The resulting signature is the concatenation bytes(r)||bytes(s), 79 // where r and s are padded to the curve order size. 80 // The private key is read only while sha2 and sha3 hashers are 81 // modified temporarily. 82 // 83 // The function returns: 84 // - (false, nilHasherError) if a hasher is nil 85 // - (false, invalidHasherSizeError) when the hasher's output size is less than the curve order (currently 32 bytes). 86 // - (nil, error) if an unexpected error occurs 87 // - (signature, nil) otherwise 88 func (sk *prKeyECDSA) Sign(data []byte, alg hash.Hasher) (Signature, error) { 89 if alg == nil { 90 return nil, nilHasherError 91 } 92 // check hasher's size is at least the curve order in bytes 93 Nlen := bitsToBytes((sk.alg.curve.Params().N).BitLen()) 94 if alg.Size() < Nlen { 95 return nil, invalidHasherSizeErrorf( 96 "hasher's size should be at least %d, got %d", Nlen, alg.Size()) 97 } 98 99 h := alg.ComputeHash(data) 100 return sk.signHash(h) 101 } 102 103 // verifyHash implements ECDSA signature verification 104 func (pk *pubKeyECDSA) verifyHash(sig Signature, h hash.Hash) (bool, error) { 105 Nlen := bitsToBytes((pk.alg.curve.Params().N).BitLen()) 106 107 if len(sig) != 2*Nlen { 108 return false, nil 109 } 110 111 var r big.Int 112 var s big.Int 113 r.SetBytes(sig[:Nlen]) 114 s.SetBytes(sig[Nlen:]) 115 return ecdsa.Verify(pk.goPubKey, h, &r, &s), nil 116 } 117 118 // Verify verifies a signature of an input data under the public key. 119 // 120 // If the input signature slice has an invalid length or fails to deserialize into valid 121 // scalars, the function returns false without an error. 122 // 123 // Public keys are read only, sha2 and sha3 hashers are 124 // modified temporarily. 125 // 126 // The function returns: 127 // - (false, nilHasherError) if a hasher is nil 128 // - (false, invalidHasherSizeError) when the hasher's output size is less than the curve order (currently 32 bytes). 129 // - (false, error) if an unexpected error occurs 130 // - (validity, nil) otherwise 131 func (pk *pubKeyECDSA) Verify(sig Signature, data []byte, alg hash.Hasher) (bool, error) { 132 if alg == nil { 133 return false, nilHasherError 134 } 135 136 // check hasher's size is at least the curve order in bytes 137 Nlen := bitsToBytes((pk.alg.curve.Params().N).BitLen()) 138 if alg.Size() < Nlen { 139 return false, invalidHasherSizeErrorf( 140 "hasher's size should be at least %d, got %d", Nlen, alg.Size()) 141 } 142 143 h := alg.ComputeHash(data) 144 return pk.verifyHash(sig, h) 145 } 146 147 // signatureFormatCheck verifies the format of a serialized signature, 148 // regardless of messages or public keys. 149 // If FormatCheck returns false then the input is not a valid ECDSA 150 // signature and will fail a verification against any message and public key. 151 func (a *ecdsaAlgo) signatureFormatCheck(sig Signature) bool { 152 N := a.curve.Params().N 153 Nlen := bitsToBytes(N.BitLen()) 154 155 if len(sig) != 2*Nlen { 156 return false 157 } 158 159 var r big.Int 160 var s big.Int 161 r.SetBytes(sig[:Nlen]) 162 s.SetBytes(sig[Nlen:]) 163 164 if r.Sign() == 0 || s.Sign() == 0 { 165 return false 166 } 167 168 if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 { 169 return false 170 } 171 172 // We could also check whether r and r+N are quadratic residues modulo (p) 173 // using Euler's criterion. 174 return true 175 } 176 177 var one = new(big.Int).SetInt64(1) 178 179 // goecdsaGenerateKey generates a public and private key pair 180 // for the crypto/ecdsa library using the input seed 181 func goecdsaGenerateKey(c elliptic.Curve, seed []byte) *ecdsa.PrivateKey { 182 k := new(big.Int).SetBytes(seed) 183 n := new(big.Int).Sub(c.Params().N, one) 184 k.Mod(k, n) 185 k.Add(k, one) 186 187 priv := new(ecdsa.PrivateKey) 188 priv.PublicKey.Curve = c 189 priv.D = k 190 // public key is not computed 191 return priv 192 } 193 194 // generatePrivateKey generates a private key for ECDSA 195 // deterministically using the input seed. 196 // 197 // It is recommended to use a secure crypto RNG to generate the seed. 198 // The seed must have enough entropy. 199 func (a *ecdsaAlgo) generatePrivateKey(seed []byte) (PrivateKey, error) { 200 if len(seed) < KeyGenSeedMinLen || len(seed) > KeyGenSeedMaxLen { 201 return nil, invalidInputsErrorf("seed byte length should be between %d and %d", 202 KeyGenSeedMinLen, KeyGenSeedMaxLen) 203 } 204 205 // use HKDF to extract the seed entropy and expand it into key bytes 206 207 // use SHA2-256 as the building block H in HKDF 208 hashFunction := sha256.New 209 salt := []byte("") // HKDF salt 210 info := []byte("") // HKDF info 211 // use extra 128 bits to reduce the modular reduction bias 212 Nlen := bitsToBytes((a.curve.Params().N).BitLen()) 213 okmLength := Nlen + (securityBits / 8) 214 215 // instantiate HKDF and extract okm 216 reader := hkdf.New(hashFunction, seed, salt, info) 217 okm := make([]byte, okmLength) 218 n, err := reader.Read(okm) 219 if err != nil || n != okmLength { 220 return nil, fmt.Errorf("key generation failed because of the HKDF reader, %d bytes were read: %w", 221 n, err) 222 } 223 defer overwrite(okm) // overwrite okm 224 225 sk := goecdsaGenerateKey(a.curve, okm) 226 return &prKeyECDSA{ 227 alg: a, 228 goPrKey: sk, 229 pubKey: nil, // public key is not computed 230 }, nil 231 } 232 233 func (a *ecdsaAlgo) rawDecodePrivateKey(der []byte) (PrivateKey, error) { 234 n := a.curve.Params().N 235 nlen := bitsToBytes(n.BitLen()) 236 if len(der) != nlen { 237 return nil, invalidInputsErrorf("input has incorrect %s key size", a.algo) 238 } 239 var d big.Int 240 d.SetBytes(der) 241 242 if d.Cmp(n) >= 0 { 243 return nil, invalidInputsErrorf("input is not a valid %s key", a.algo) 244 } 245 246 priv := ecdsa.PrivateKey{ 247 D: &d, 248 } 249 priv.PublicKey.Curve = a.curve 250 251 return &prKeyECDSA{ 252 alg: a, 253 goPrKey: &priv, 254 pubKey: nil, // public key is not computed 255 }, nil 256 } 257 258 func (a *ecdsaAlgo) decodePrivateKey(der []byte) (PrivateKey, error) { 259 return a.rawDecodePrivateKey(der) 260 } 261 262 func (a *ecdsaAlgo) rawDecodePublicKey(der []byte) (PublicKey, error) { 263 p := (a.curve.Params().P) 264 plen := bitsToBytes(p.BitLen()) 265 if len(der) != 2*plen { 266 return nil, invalidInputsErrorf("input has incorrect %s key size, got %d, expects %d", 267 a.algo, len(der), 2*plen) 268 } 269 var x, y big.Int 270 x.SetBytes(der[:plen]) 271 y.SetBytes(der[plen:]) 272 273 // all the curves supported for now have a cofactor equal to 1, 274 // so that IsOnCurve guarantees the point is on the right subgroup. 275 if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 || !a.curve.IsOnCurve(&x, &y) { 276 return nil, invalidInputsErrorf("input %x is not a valid %s key", der, a.algo) 277 } 278 279 pk := ecdsa.PublicKey{ 280 Curve: a.curve, 281 X: &x, 282 Y: &y, 283 } 284 285 return &pubKeyECDSA{a, &pk}, nil 286 } 287 288 func (a *ecdsaAlgo) decodePublicKey(der []byte) (PublicKey, error) { 289 return a.rawDecodePublicKey(der) 290 } 291 292 // decodePublicKeyCompressed returns a public key given the bytes of a compressed public key according to X9.62 section 4.3.6. 293 // this compressed representation uses an extra byte to disambiguate sign 294 func (a *ecdsaAlgo) decodePublicKeyCompressed(pkBytes []byte) (PublicKey, error) { 295 expectedLen := bitsToBytes(a.curve.Params().BitSize) + 1 296 if len(pkBytes) != expectedLen { 297 return nil, invalidInputsErrorf(fmt.Sprintf("input length incompatible, expected %d, got %d", expectedLen, len(pkBytes))) 298 } 299 var goPubKey *ecdsa.PublicKey 300 301 if a.curve == elliptic.P256() { 302 x, y := elliptic.UnmarshalCompressed(a.curve, pkBytes) 303 if x == nil { 304 return nil, invalidInputsErrorf("Key %x can't be interpreted as %v", pkBytes, a.algo.String()) 305 } 306 goPubKey = new(ecdsa.PublicKey) 307 goPubKey.Curve = a.curve 308 goPubKey.X = x 309 goPubKey.Y = y 310 311 } else if a.curve == btcec.S256() { 312 pk, err := btcec.ParsePubKey(pkBytes) 313 if err != nil { 314 return nil, invalidInputsErrorf("Key %x can't be interpreted as %v", pkBytes, a.algo.String()) 315 } 316 // convert to a crypto/ecdsa key 317 goPubKey = pk.ToECDSA() 318 } else { 319 return nil, invalidInputsErrorf("the input curve is not supported") 320 } 321 return &pubKeyECDSA{a, goPubKey}, nil 322 } 323 324 // prKeyECDSA is the private key of ECDSA, it implements the generic PrivateKey 325 type prKeyECDSA struct { 326 // the signature algo 327 alg *ecdsaAlgo 328 // ecdsa private key 329 goPrKey *ecdsa.PrivateKey 330 // public key 331 pubKey *pubKeyECDSA 332 } 333 334 // Algorithm returns the algo related to the private key 335 func (sk *prKeyECDSA) Algorithm() SigningAlgorithm { 336 return sk.alg.algo 337 } 338 339 // Size returns the length of the private key in bytes 340 func (sk *prKeyECDSA) Size() int { 341 return bitsToBytes((sk.alg.curve.Params().N).BitLen()) 342 } 343 344 // PublicKey returns the public key associated to the private key 345 func (sk *prKeyECDSA) PublicKey() PublicKey { 346 // compute the public key once 347 if sk.pubKey == nil { 348 priv := sk.goPrKey 349 priv.PublicKey.X, priv.PublicKey.Y = priv.Curve.ScalarBaseMult(priv.D.Bytes()) 350 } 351 sk.pubKey = &pubKeyECDSA{ 352 alg: sk.alg, 353 goPubKey: &sk.goPrKey.PublicKey, 354 } 355 return sk.pubKey 356 } 357 358 // given a private key (d), returns a raw encoding bytes(d) in big endian 359 // padded to the private key length 360 func (sk *prKeyECDSA) rawEncode() []byte { 361 skBytes := sk.goPrKey.D.Bytes() 362 Nlen := bitsToBytes((sk.alg.curve.Params().N).BitLen()) 363 skEncoded := make([]byte, Nlen) 364 // pad sk with zeroes 365 copy(skEncoded[Nlen-len(skBytes):], skBytes) 366 return skEncoded 367 } 368 369 // Encode returns a byte representation of a private key. 370 // a simple raw byte encoding in big endian is used for all curves 371 func (sk *prKeyECDSA) Encode() []byte { 372 return sk.rawEncode() 373 } 374 375 // Equals test the equality of two private keys 376 func (sk *prKeyECDSA) Equals(other PrivateKey) bool { 377 // check the key type 378 otherECDSA, ok := other.(*prKeyECDSA) 379 if !ok { 380 return false 381 } 382 // check the curve 383 if sk.alg.curve != otherECDSA.alg.curve { 384 return false 385 } 386 return sk.goPrKey.D.Cmp(otherECDSA.goPrKey.D) == 0 387 } 388 389 // String returns the hex string representation of the key. 390 func (sk *prKeyECDSA) String() string { 391 return fmt.Sprintf("%#x", sk.Encode()) 392 } 393 394 // pubKeyECDSA is the public key of ECDSA, it implements PublicKey 395 type pubKeyECDSA struct { 396 // the signature algo 397 alg *ecdsaAlgo 398 // public key data 399 goPubKey *ecdsa.PublicKey 400 } 401 402 // Algorithm returns the the algo related to the private key 403 func (pk *pubKeyECDSA) Algorithm() SigningAlgorithm { 404 return pk.alg.algo 405 } 406 407 // Size returns the length of the public key in bytes 408 func (pk *pubKeyECDSA) Size() int { 409 return 2 * bitsToBytes((pk.goPubKey.Params().P).BitLen()) 410 } 411 412 // EncodeCompressed returns a compressed encoding according to X9.62 section 4.3.6. 413 // This compressed representation uses an extra byte to disambiguate parity. 414 // The expected input is a public key (x,y). 415 func (pk *pubKeyECDSA) EncodeCompressed() []byte { 416 return elliptic.MarshalCompressed(pk.goPubKey.Curve, pk.goPubKey.X, pk.goPubKey.Y) 417 } 418 419 // given a public key (x,y), returns a raw uncompressed encoding bytes(x)||bytes(y) 420 // x and y are padded to the field size 421 func (pk *pubKeyECDSA) rawEncode() []byte { 422 xBytes := pk.goPubKey.X.Bytes() 423 yBytes := pk.goPubKey.Y.Bytes() 424 Plen := bitsToBytes((pk.alg.curve.Params().P).BitLen()) 425 pkEncoded := make([]byte, 2*Plen) 426 // pad the public key coordinates with zeroes 427 copy(pkEncoded[Plen-len(xBytes):], xBytes) 428 copy(pkEncoded[2*Plen-len(yBytes):], yBytes) 429 return pkEncoded 430 } 431 432 // Encode returns a byte representation of a public key. 433 // a simple uncompressed raw encoding X||Y is used for all curves 434 // X and Y are the big endian byte encoding of the x and y coordinates of the public key 435 func (pk *pubKeyECDSA) Encode() []byte { 436 return pk.rawEncode() 437 } 438 439 // Equals test the equality of two private keys 440 func (pk *pubKeyECDSA) Equals(other PublicKey) bool { 441 // check the key type 442 otherECDSA, ok := other.(*pubKeyECDSA) 443 if !ok { 444 return false 445 } 446 // check the curve 447 if pk.alg.curve != otherECDSA.alg.curve { 448 return false 449 } 450 return (pk.goPubKey.X.Cmp(otherECDSA.goPubKey.X) == 0) && 451 (pk.goPubKey.Y.Cmp(otherECDSA.goPubKey.Y) == 0) 452 } 453 454 // String returns the hex string representation of the key. 455 func (pk *pubKeyECDSA) String() string { 456 return fmt.Sprintf("%#x", pk.Encode()) 457 }