github.com/onflow/flow-go/crypto@v0.24.8/sign.go (about)

     1  // Package crypto ...
     2  package crypto
     3  
     4  import (
     5  	"crypto/elliptic"
     6  	"fmt"
     7  
     8  	"github.com/btcsuite/btcd/btcec/v2"
     9  
    10  	"github.com/onflow/flow-go/crypto/hash"
    11  )
    12  
    13  // revive:disable:var-naming
    14  
    15  // revive:enable
    16  
    17  // SigningAlgorithm is an identifier for a signing algorithm
    18  // (and parameters if applicable)
    19  type SigningAlgorithm int
    20  
    21  const (
    22  	// Supported signing algorithms
    23  	UnknownSigningAlgorithm SigningAlgorithm = iota
    24  	// BLSBLS12381 is BLS on BLS 12-381 curve
    25  	BLSBLS12381
    26  	// ECDSAP256 is ECDSA on NIST P-256 curve
    27  	ECDSAP256
    28  	// ECDSASecp256k1 is ECDSA on secp256k1 curve
    29  	ECDSASecp256k1
    30  )
    31  
    32  // String returns the string representation of this signing algorithm.
    33  func (f SigningAlgorithm) String() string {
    34  	return [...]string{"UNKNOWN", "BLS_BLS12381", "ECDSA_P256", "ECDSA_secp256k1"}[f]
    35  }
    36  
    37  // Signature is a generic type, regardless of the signature scheme
    38  type Signature []byte
    39  
    40  // Signer interface
    41  type signer interface {
    42  	// generatePrivateKey generates a private key
    43  	generatePrivateKey([]byte) (PrivateKey, error)
    44  	// decodePrivateKey loads a private key from a byte array
    45  	decodePrivateKey([]byte) (PrivateKey, error)
    46  	// decodePublicKey loads a public key from a byte array
    47  	decodePublicKey([]byte) (PublicKey, error)
    48  	// decodePublicKeyCompressed loads a public key from a byte array representing a point in compressed form
    49  	decodePublicKeyCompressed([]byte) (PublicKey, error)
    50  }
    51  
    52  // newNonRelicSigner returns a signer that does not depend on Relic library.
    53  func newNonRelicSigner(algo SigningAlgorithm) (signer, error) {
    54  	switch algo {
    55  	case ECDSAP256:
    56  		return p256Instance, nil
    57  	case ECDSASecp256k1:
    58  		return secp256k1Instance, nil
    59  	default:
    60  		return nil, invalidInputsErrorf("the signature scheme %s is not supported", algo)
    61  	}
    62  }
    63  
    64  // Initialize the context of all algos not requiring Relic
    65  func initNonRelic() {
    66  	// P-256
    67  	p256Instance = &(ecdsaAlgo{
    68  		curve: elliptic.P256(),
    69  		algo:  ECDSAP256,
    70  	})
    71  
    72  	// secp256k1
    73  	secp256k1Instance = &(ecdsaAlgo{
    74  		curve: btcec.S256(),
    75  		algo:  ECDSASecp256k1,
    76  	})
    77  }
    78  
    79  // Signature format Check for non-relic algos (ECDSA)
    80  func signatureFormatCheckNonRelic(algo SigningAlgorithm, s Signature) (bool, error) {
    81  	switch algo {
    82  	case ECDSAP256:
    83  		return p256Instance.signatureFormatCheck(s), nil
    84  	case ECDSASecp256k1:
    85  		return secp256k1Instance.signatureFormatCheck(s), nil
    86  	default:
    87  		return false, invalidInputsErrorf(
    88  			"the signature scheme %s is not supported",
    89  			algo)
    90  	}
    91  }
    92  
    93  // SignatureFormatCheck verifies the format of a serialized signature,
    94  // regardless of messages or public keys.
    95  //
    96  // This function is only defined for ECDSA algos for now.
    97  //
    98  // If SignatureFormatCheck returns false then the input is not a valid
    99  // signature and will fail a verification against any message and public key.
   100  func SignatureFormatCheck(algo SigningAlgorithm, s Signature) (bool, error) {
   101  	// For now, signatureFormatCheckNonRelic is only defined for non-Relic algos.
   102  	return signatureFormatCheckNonRelic(algo, s)
   103  }
   104  
   105  // GeneratePrivateKey generates a private key of the algorithm using the entropy of the given seed.
   106  //
   107  // The seed minimum length is 32 bytes and it should have enough entropy.
   108  // It is recommended to use a secure crypto RNG to generate the seed.
   109  //
   110  // The function returns:
   111  //   - (false, invalidInputsErrors) if the signing algorithm is not supported or
   112  //     if the seed length is not valid (less than 32 bytes or larger than 256 bytes)
   113  //   - (false, error) if an unexpected error occurs
   114  //   - (sk, nil) if key generation was successful
   115  func GeneratePrivateKey(algo SigningAlgorithm, seed []byte) (PrivateKey, error) {
   116  	signer, err := newSigner(algo)
   117  	if err != nil {
   118  		return nil, fmt.Errorf("key generation failed: %w", err)
   119  	}
   120  	return signer.generatePrivateKey(seed)
   121  }
   122  
   123  // DecodePrivateKey decodes an array of bytes into a private key of the given algorithm
   124  //
   125  // The function returns:
   126  //   - (nil, invalidInputsErrors) if the signing algorithm is not supported
   127  //   - (nil, invalidInputsErrors) if the input does not serialize a valid private key:
   128  //   - ECDSA: bytes(x) where bytes() is the big-endian encoding padded to the curve order.
   129  //   - BLS: bytes(x) where bytes() is the big-endian encoding padded to the order of BLS12-381.
   130  //     for all algorithms supported, input is big-endian encoding
   131  //     of a the private scalar less than the curve order and left-padded to 32 bytes
   132  //   - (nil, error) if an unexpected error occurs
   133  //   - (sk, nil) otherwise
   134  func DecodePrivateKey(algo SigningAlgorithm, data []byte) (PrivateKey, error) {
   135  	signer, err := newSigner(algo)
   136  	if err != nil {
   137  		return nil, fmt.Errorf("decode private key failed: %w", err)
   138  	}
   139  	return signer.decodePrivateKey(data)
   140  }
   141  
   142  // DecodePublicKey decodes an array of bytes into a public key of the given algorithm
   143  //
   144  // The function returns:
   145  //   - (nil, invalidInputsErrors) if the signing algorithm is not supported
   146  //   - (nil, invalidInputsErrors) if the input does not serialize a valid public key:
   147  //   - ECDSA: bytes(x)||bytes(y) where bytes() is the big-endian encoding padded to the field size.
   148  //   - BLS: compressed serialization of a G2 point following https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-08.html#name-zcash-serialization-format-
   149  //   - (nil, error) if an unexpected error occurs
   150  //   - (sk, nil) otherwise
   151  func DecodePublicKey(algo SigningAlgorithm, data []byte) (PublicKey, error) {
   152  	signer, err := newSigner(algo)
   153  	if err != nil {
   154  		return nil, fmt.Errorf("decode public key failed: %w", err)
   155  	}
   156  	return signer.decodePublicKey(data)
   157  }
   158  
   159  // DecodePublicKeyCompressed decodes an array of bytes given in a compressed representation into a public key of the given algorithm
   160  // Only ECDSA is supported (BLS uses the compressed serialzation by default).
   161  //
   162  // The function returns:
   163  //   - (nil, invalidInputsErrors) if the signing algorithm is not supported (is not ECDSA)
   164  //   - (nil, invalidInputsErrors) if the input does not serialize a valid public key:
   165  //   - ECDSA: sign_byte||bytes(x) according to X9.62 section 4.3.6.
   166  //   - (nil, error) if an unexpected error occurs
   167  //   - (sk, nil) otherwise
   168  func DecodePublicKeyCompressed(algo SigningAlgorithm, data []byte) (PublicKey, error) {
   169  	signer, err := newSigner(algo)
   170  	if err != nil {
   171  		return nil, fmt.Errorf("decode public key failed: %w", err)
   172  	}
   173  	return signer.decodePublicKeyCompressed(data)
   174  }
   175  
   176  // Signature type tools
   177  
   178  // Bytes returns a byte array of the signature data
   179  func (s Signature) Bytes() []byte {
   180  	return s[:]
   181  }
   182  
   183  // String returns a String representation of the signature data
   184  func (s Signature) String() string {
   185  	return fmt.Sprintf("%#x", s.Bytes())
   186  }
   187  
   188  // Key Pair
   189  
   190  // PrivateKey is an unspecified signature scheme private key
   191  type PrivateKey interface {
   192  	// Algorithm returns the signing algorithm related to the private key.
   193  	Algorithm() SigningAlgorithm
   194  	// Size return the key size in bytes.
   195  	Size() int
   196  	// String return a hex representation of the key
   197  	String() string
   198  	// Sign generates a signature using the provided hasher.
   199  	Sign([]byte, hash.Hasher) (Signature, error)
   200  	// PublicKey returns the public key.
   201  	PublicKey() PublicKey
   202  	// Encode returns a bytes representation of the private key
   203  	Encode() []byte
   204  	// Equals returns true if the given PrivateKeys are equal. Keys are considered unequal if their algorithms are
   205  	// unequal or if their encoded representations are unequal. If the encoding of either key fails, they are considered
   206  	// unequal as well.
   207  	Equals(PrivateKey) bool
   208  }
   209  
   210  // PublicKey is an unspecified signature scheme public key.
   211  type PublicKey interface {
   212  	// Algorithm returns the signing algorithm related to the public key.
   213  	Algorithm() SigningAlgorithm
   214  	// Size() return the key size in bytes.
   215  	Size() int
   216  	// String return a hex representation of the key
   217  	String() string
   218  	// Verify verifies a signature of an input message using the provided hasher.
   219  	Verify(Signature, []byte, hash.Hasher) (bool, error)
   220  	// Encode returns a bytes representation of the public key.
   221  	Encode() []byte
   222  	// EncodeCompressed returns a compressed byte representation of the public key.
   223  	// The compressed serialization concept is generic to elliptic curves,
   224  	// but we refer to individual curve parameters for details of the compressed format
   225  	EncodeCompressed() []byte
   226  	// Equals returns true if the given PublicKeys are equal. Keys are considered unequal if their algorithms are
   227  	// unequal or if their encoded representations are unequal. If the encoding of either key fails, they are considered
   228  	// unequal as well.
   229  	Equals(PublicKey) bool
   230  }