P-256#

ECDSA over the P-256 NIST curve.

Available Implementations#

#include "Hacl_P256.h"

API Reference#

// Note: HACL Packages will provide these in a later version.
#define HACL_SIGNATURE_ECDSA_P256_SECRETKEY_LEN 32

#define HACL_SIGNATURE_ECDSA_P256_PUBLICKEY_LEN 64
#define HACL_SIGNATURE_ECDSA_P256_PUBLICKEY_COMPRESSED_LEN 33
#define HACL_SIGNATURE_ECDSA_P256_PUBLICKEY_UNCOMPRESSED_LEN 65

#define HACL_SIGNATURE_ECDSA_P256_NONCE_LEN 32

#define HACL_SIGNATURE_ECDSA_P256_SIGNATURE_LEN 64
// We want to sign and verify a message.

// Message
const char* message = "Hello, World!";
uint32_t message_size = strlen(message);

// Keys
uint8_t sk[HACL_SIGNATURE_ECDSA_P256_SECRETKEY_LEN];
uint8_t pk[HACL_SIGNATURE_ECDSA_P256_PUBLICKEY_LEN];

// Note: This function is not in HACL*.
//       You need to bring your own keys.
generate_p256_keypair(sk, pk);

// Nonce
uint8_t nonce[HACL_SIGNATURE_ECDSA_P256_NONCE_LEN];

// Signature
uint8_t signature[HACL_SIGNATURE_ECDSA_P256_SIGNATURE_LEN];

// Sign
bool res_sign = Hacl_P256_ecdsa_sign_p256_sha2(
  signature, message_size, (uint8_t*)message, sk, nonce);

if (!res_sign) {
  // Error
}

// Verify
bool res_verify = Hacl_P256_ecdsa_verif_p256_sha2(
  message_size, (uint8_t*)message, pk, signature, signature + 32);

if (!res_verify) {
  // Error
}

Load and Store Keys#

bool Hacl_P256_uncompressed_to_raw(uint8_t *pk, uint8_t *pk_raw)#

Convert a public key from uncompressed to its raw form.

The function returns true for successful conversion of a public key and false otherwise.

The outparam pk_raw points to 64 bytes of valid memory, i.e., uint8_t[64]. The argument pk points to 65 bytes of valid memory, i.e., uint8_t[65].

The function DOESN’T check whether (x, y) is a valid point.

bool Hacl_P256_compressed_to_raw(uint8_t *pk, uint8_t *pk_raw)#

Convert a public key from compressed to its raw form.

The function returns true for successful conversion of a public key and false otherwise.

The outparam pk_raw points to 64 bytes of valid memory, i.e., uint8_t[64]. The argument pk points to 33 bytes of valid memory, i.e., uint8_t[33].

The function also checks whether (x, y) is a valid point.

void Hacl_P256_raw_to_uncompressed(uint8_t *pk_raw, uint8_t *pk)#

Convert a public key from raw to its uncompressed form.

The outparam pk points to 65 bytes of valid memory, i.e., uint8_t[65]. The argument pk_raw points to 64 bytes of valid memory, i.e., uint8_t[64].

The function DOESN’T check whether (x, y) is a valid point.

void Hacl_P256_raw_to_compressed(uint8_t *pk_raw, uint8_t *pk)#

Convert a public key from raw to its compressed form.

The outparam pk points to 33 bytes of valid memory, i.e., uint8_t[33]. The argument pk_raw points to 64 bytes of valid memory, i.e., uint8_t[64].

The function DOESN’T check whether (x, y) is a valid point.

Validate Keys#

bool Hacl_P256_validate_private_key(uint8_t *private_key)#

Private key validation.

The function returns true if a private key is valid and false otherwise.

The argument private_key points to 32 bytes of valid memory, i.e., uint8_t[32].

The private key is valid: • 0 < private_key < the order of the curve

bool Hacl_P256_validate_public_key(uint8_t *public_key)#

Public key validation.

The function returns true if a public key is valid and false otherwise.

The argument public_key points to 64 bytes of valid memory, i.e., uint8_t[64].

The public key (x || y) is valid (with respect to SP 800-56A): • the public key is not the “point at infinity”, represented as O. • the affine x and y coordinates of the point represented by the public key are in the range [0, p – 1] where p is the prime defining the finite field. • y^2 = x^3 + ax + b where a and b are the coefficients of the curve equation. The last extract is taken from: https://neilmadden.blog/2017/05/17/so-how-do-you-validate-nist-ecdh-public-keys/

Sign#

bool Hacl_P256_ecdsa_sign_p256_sha2(uint8_t *signature, uint32_t msg_len, uint8_t *msg, uint8_t *private_key, uint8_t *nonce)#

Create an ECDSA signature using SHA2-256.

The function returns true for successful creation of an ECDSA signature and false otherwise.

The outparam signature (R || S) points to 64 bytes of valid memory, i.e., uint8_t[64]. The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The arguments private_key and nonce point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether private_key and nonce are valid: • 0 < private_key < the order of the curve • 0 < nonce < the order of the curve

bool Hacl_P256_ecdsa_sign_p256_sha384(uint8_t *signature, uint32_t msg_len, uint8_t *msg, uint8_t *private_key, uint8_t *nonce)#

Create an ECDSA signature using SHA2-384.

The function returns true for successful creation of an ECDSA signature and false otherwise.

The outparam signature (R || S) points to 64 bytes of valid memory, i.e., uint8_t[64]. The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The arguments private_key and nonce point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether private_key and nonce are valid: • 0 < private_key < the order of the curve • 0 < nonce < the order of the curve

bool Hacl_P256_ecdsa_sign_p256_sha512(uint8_t *signature, uint32_t msg_len, uint8_t *msg, uint8_t *private_key, uint8_t *nonce)#

Create an ECDSA signature using SHA2-512.

The function returns true for successful creation of an ECDSA signature and false otherwise.

The outparam signature (R || S) points to 64 bytes of valid memory, i.e., uint8_t[64]. The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The arguments private_key and nonce point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether private_key and nonce are valid: • 0 < private_key < the order of the curve • 0 < nonce < the order of the curve

bool Hacl_P256_ecdsa_sign_p256_without_hash(uint8_t *signature, uint32_t msg_len, uint8_t *msg, uint8_t *private_key, uint8_t *nonce)#

Create an ECDSA signature WITHOUT hashing first.

This function is intended to receive a hash of the input. For convenience, we recommend using one of the hash-and-sign combined functions above.

The argument msg MUST be at least 32 bytes (i.e. msg_len >= 32).

NOTE: The equivalent functions in OpenSSL and Fiat-Crypto both accept inputs smaller than 32 bytes. These libraries left-pad the input with enough zeroes to reach the minimum 32 byte size. Clients who need behavior identical to OpenSSL need to perform the left-padding themselves.

The function returns true for successful creation of an ECDSA signature and false otherwise.

The outparam signature (R || S) points to 64 bytes of valid memory, i.e., uint8_t[64]. The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The arguments private_key and nonce point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether private_key and nonce are valid values: • 0 < private_key < the order of the curve • 0 < nonce < the order of the curve

Verify#

bool Hacl_P256_ecdsa_verif_p256_sha2(uint32_t msg_len, uint8_t *msg, uint8_t *public_key, uint8_t *signature_r, uint8_t *signature_s)#

Verify an ECDSA signature using SHA2-256.

The function returns true if the signature is valid and false otherwise.

The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The argument public_key (x || y) points to 64 bytes of valid memory, i.e., uint8_t[64]. The arguments signature_r and signature_s point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether public_key is valid

bool Hacl_P256_ecdsa_verif_p256_sha384(uint32_t msg_len, uint8_t *msg, uint8_t *public_key, uint8_t *signature_r, uint8_t *signature_s)#

Verify an ECDSA signature using SHA2-384.

The function returns true if the signature is valid and false otherwise.

The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The argument public_key (x || y) points to 64 bytes of valid memory, i.e., uint8_t[64]. The arguments signature_r and signature_s point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether public_key is valid

bool Hacl_P256_ecdsa_verif_p256_sha512(uint32_t msg_len, uint8_t *msg, uint8_t *public_key, uint8_t *signature_r, uint8_t *signature_s)#

Verify an ECDSA signature using SHA2-512.

The function returns true if the signature is valid and false otherwise.

The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The argument public_key (x || y) points to 64 bytes of valid memory, i.e., uint8_t[64]. The arguments signature_r and signature_s point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether public_key is valid

bool Hacl_P256_ecdsa_verif_without_hash(uint32_t msg_len, uint8_t *msg, uint8_t *public_key, uint8_t *signature_r, uint8_t *signature_s)#

Verify an ECDSA signature WITHOUT hashing first.

This function is intended to receive a hash of the input. For convenience, we recommend using one of the hash-and-verify combined functions above.

The argument msg MUST be at least 32 bytes (i.e. msg_len >= 32).

The function returns true if the signature is valid and false otherwise.

The argument msg points to msg_len bytes of valid memory, i.e., uint8_t[msg_len]. The argument public_key (x || y) points to 64 bytes of valid memory, i.e., uint8_t[64]. The arguments signature_r and signature_s point to 32 bytes of valid memory, i.e., uint8_t[32].

The function also checks whether public_key is valid