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  }