use hacl_sys::{
Hacl_P256_compressed_to_raw, Hacl_P256_dh_initiator, Hacl_P256_dh_responder,
Hacl_P256_uncompressed_to_raw, Hacl_P256_validate_private_key, Hacl_P256_validate_public_key,
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
InvalidInput,
InvalidScalar,
InvalidPoint,
NoCompressedPoint,
NoUnCompressedPoint,
SigningError,
InvalidSignature,
}
#[must_use]
pub fn uncompressed_to_coordinates(point: &[u8]) -> Result<[u8; 64], Error> {
let mut concat_point = [0u8; 64];
if point.len() >= 65 {
let ok = unsafe {
Hacl_P256_uncompressed_to_raw(point.as_ptr() as _, concat_point.as_mut_ptr())
};
if ok {
Ok(concat_point)
} else {
Err(Error::InvalidInput)
}
} else {
Err(Error::NoCompressedPoint)
}
}
#[must_use]
pub fn compressed_to_coordinates(point: &[u8]) -> Result<[u8; 64], Error> {
let mut concat_point = [0u8; 64];
if point.len() >= 33 {
let ok =
unsafe { Hacl_P256_compressed_to_raw(point.as_ptr() as _, concat_point.as_mut_ptr()) };
if ok {
Ok(concat_point)
} else {
Err(Error::InvalidInput)
}
} else {
Err(Error::NoUnCompressedPoint)
}
}
#[must_use]
pub fn validate_point(point: &[u8; 64]) -> Result<(), Error> {
if unsafe { Hacl_P256_validate_public_key(point.as_ptr() as _) } {
Ok(())
} else {
Err(Error::InvalidPoint)
}
}
pub fn validate_scalar(scalar: &[u8; 32]) -> Result<(), Error> {
if scalar.iter().all(|b| *b == 0) {
return Err(Error::InvalidScalar);
}
if unsafe { Hacl_P256_validate_private_key(scalar.as_ptr() as _) } {
Ok(())
} else {
Err(Error::InvalidScalar)
}
}
pub fn validate_scalar_slice(scalar: &[u8]) -> Result<[u8; 32], Error> {
if scalar.is_empty() {
return Err(Error::InvalidScalar);
}
let mut private = [0u8; 32];
let sk_len = if scalar.len() >= 32 { 32 } else { scalar.len() };
for i in 0..sk_len {
private[31 - i] = scalar[scalar.len() - 1 - i];
}
validate_scalar(&private).map(|_| private)
}
#[must_use]
pub fn ecdh(private_key: &[u8; 32], public_key: &[u8; 64]) -> Result<[u8; 64], Error> {
let mut shared = [0u8; 64];
let ok = unsafe {
Hacl_P256_dh_responder(
shared.as_mut_ptr(),
public_key.as_ptr() as _,
private_key.as_ptr() as _,
)
};
if !ok {
Err(Error::InvalidInput)
} else {
Ok(shared)
}
}
#[must_use]
pub fn secret_to_public(s: &[u8; 32]) -> Result<[u8; 64], Error> {
validate_scalar(s)?;
let mut out = [0u8; 64];
if unsafe { Hacl_P256_dh_initiator(out.as_mut_ptr(), s.as_ptr() as _) } {
Ok(out)
} else {
Err(Error::InvalidScalar)
}
}
pub mod ecdsa {
use super::*;
use hacl_sys::{
Hacl_P256_ecdsa_sign_p256_sha2, Hacl_P256_ecdsa_sign_p256_sha384,
Hacl_P256_ecdsa_sign_p256_sha512, Hacl_P256_ecdsa_verif_p256_sha2,
Hacl_P256_ecdsa_verif_p256_sha384, Hacl_P256_ecdsa_verif_p256_sha512,
};
macro_rules! implement {
($sign:ident, $fun_sign:expr, $verify:ident, $fun_verify:expr) => {
#[must_use]
pub fn $sign(
payload: &[u8],
private_key: &[u8; 32],
nonce: &[u8; 32],
) -> Result<[u8; 64], Error> {
let mut result = [0u8; 64];
if unsafe {
$fun_sign(
result.as_mut_ptr(),
payload.len().try_into().map_err(|_| Error::InvalidInput)?,
payload.as_ptr() as _,
private_key.as_ptr() as _,
nonce.as_ptr() as _,
)
} {
Ok(result)
} else {
Err(Error::SigningError)
}
}
#[must_use]
pub fn $verify(
payload: &[u8],
public_key: &[u8; 64],
signature_r: &[u8; 32],
signature_s: &[u8; 32],
) -> Result<(), Error> {
if unsafe {
$fun_verify(
payload.len().try_into().map_err(|_| Error::InvalidInput)?,
payload.as_ptr() as _,
public_key.as_ptr() as _,
signature_r.as_ptr() as _,
signature_s.as_ptr() as _,
)
} {
Ok(())
} else {
Err(Error::SigningError)
}
}
};
}
implement!(
sign_sha256,
Hacl_P256_ecdsa_sign_p256_sha2,
verify_sha256,
Hacl_P256_ecdsa_verif_p256_sha2
);
implement!(
sign_sha384,
Hacl_P256_ecdsa_sign_p256_sha384,
verify_sha384,
Hacl_P256_ecdsa_verif_p256_sha384
);
implement!(
sign_sha512,
Hacl_P256_ecdsa_sign_p256_sha512,
verify_sha512,
Hacl_P256_ecdsa_verif_p256_sha512
);
}