Skip to content

Commit

Permalink
Move P256 ECDSA signature API back to libcrux
Browse files Browse the repository at this point in the history
  • Loading branch information
jschneider-bensch committed Jun 12, 2024
1 parent 20cb5b8 commit d0ad351
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 238 deletions.
9 changes: 0 additions & 9 deletions libcrux-ecdh/src/ecdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,6 @@ pub mod p256 {
pub use hacl::p256::validate_point;
pub use hacl::p256::validate_scalar_slice;
pub use hacl::p256::Error;
pub mod ecdsa {
use super::hacl;
pub use hacl::p256::ecdsa::sign_sha256;
pub use hacl::p256::ecdsa::sign_sha384;
pub use hacl::p256::ecdsa::sign_sha512;
pub use hacl::p256::ecdsa::verify_sha256;
pub use hacl::p256::ecdsa::verify_sha384;
pub use hacl::p256::ecdsa::verify_sha512;
}
}

pub use p256_internal::generate_secret as p256_generate_secret;
Expand Down
81 changes: 0 additions & 81 deletions libcrux-ecdh/src/hacl/p256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,84 +137,3 @@ pub fn secret_to_public(s: impl AsRef<[u8; 32]>) -> Result<[u8; 64], Error> {
Err(Error::InvalidScalar)
}
}

/// ECDSA on P256
pub mod ecdsa {
use super::*;
use libcrux_hacl::{
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) => {
/// Sign
///
/// * private key validation must be performed before calling this function
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)
}
}

/// Verification
///
/// * public key validation must be performed before calling this function
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
);
}
8 changes: 8 additions & 0 deletions src/hacl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub(crate) mod chacha20_poly1305;
#[cfg(not(target_arch = "wasm32"))]
pub(crate) mod drbg;
pub(crate) mod ed25519;
pub(crate) mod p256;

pub(crate) mod sha2;
pub(crate) mod sha3;
Expand All @@ -26,6 +27,7 @@ pub enum Error {
ChaCha20Poly1305(chacha20_poly1305::Error),
Curve25519(libcrux_ecdh::curve25519::Error),
P256(libcrux_ecdh::p256::Error),
P256ECDSA(p256::ecdsa::Error),
Ed25519(ed25519::Error),
Hkdf(libcrux_hkdf::Error),
}
Expand Down Expand Up @@ -59,3 +61,9 @@ impl From<ed25519::Error> for Error {
Error::Ed25519(val)
}
}

impl From<p256::ecdsa::Error> for Error {
fn from(val: p256::ecdsa::Error) -> Self {
Error::P256ECDSA(val)
}
}
147 changes: 6 additions & 141 deletions src/hacl/p256.rs
Original file line number Diff line number Diff line change
@@ -1,152 +1,17 @@
use libcrux_hacl::{
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,
};

use crate::ecdh::p256::PrivateKey;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
InvalidInput,
InvalidScalar,
InvalidPoint,
NoCompressedPoint,
NoUnCompressedPoint,
SigningError,
InvalidSignature,
}

/// Parse an uncompressed P256 point and return the 64 byte array with the
/// concatenation of X||Y
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)
}
}

/// Parse an compressed P256 point and return the 64 byte array with the
/// concatenation of `X` and `Y`.
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)
}
}

/// Validate a P256 point, where `point` is a 64 byte array with the
/// concatenation of `X` and `Y`.
///
/// Returns [`Error::InvalidPoint`] if the `point` is not valid.
pub fn validate_point(point: impl AsRef<[u8; 64]>) -> Result<(), Error> {
if unsafe { Hacl_P256_validate_public_key(point.as_ref().as_ptr() as _) } {
Ok(())
} else {
Err(Error::InvalidPoint)
}
}

/// Validate a P256 secret key (scalar).
///
/// Returns [`Error::InvalidScalar`] if the `scalar` is not valid.
pub fn validate_scalar(scalar: &impl AsRef<[u8; 32]>) -> Result<(), Error> {
validate_scalar_(scalar.as_ref())
}

/// Validate a P256 secret key (scalar).
///
/// Returns [`Error::InvalidScalar`] if the `scalar` is not valid.
pub fn validate_scalar_(scalar: &[u8; 32]) -> Result<(), Error> {
if scalar.as_ref().iter().all(|b| *b == 0) {
return Err(Error::InvalidScalar);
}

// Ensure that the key is in range [1, p-1]
if unsafe { Hacl_P256_validate_private_key(scalar.as_ref().as_ptr() as _) } {
Ok(())
} else {
Err(Error::InvalidScalar)
}
}

/// Validate a P256 secret key (scalar).
pub fn validate_scalar_slice(scalar: &[u8]) -> Result<PrivateKey, Error> {
if scalar.is_empty() {
return Err(Error::InvalidScalar);
}

let mut private = [0u8; 32];
// Force the length of `sk` to 32 bytes.
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(|_| PrivateKey(private))
}

/// Compute the ECDH with the `private_key` and `public_key`.
///
/// Returns the 64 bytes shared key.
pub fn ecdh(
private_key: impl AsRef<[u8; 32]>,
public_key: impl AsRef<[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_ref().as_ptr() as _,
private_key.as_ref().as_ptr() as _,
)
};
if !ok {
Err(Error::InvalidInput)
} else {
Ok(shared)
}
}

/// Compute the public key for the provided `private_key`.
///
/// Returns the 64 bytes public key.
pub fn secret_to_public(s: impl AsRef<[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_ref().as_ptr() as _) } {
Ok(out)
} else {
Err(Error::InvalidScalar)
}
}

/// ECDSA on P256
pub mod ecdsa {
use super::*;

use libcrux_hacl::{
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,
};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
InvalidInput,
SigningError,
}
macro_rules! implement {
($sign:ident, $fun_sign:expr, $verify:ident, $fun_verify:expr) => {
/// Sign
Expand Down
14 changes: 7 additions & 7 deletions src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,23 +373,23 @@ pub fn sign(
Algorithm::EcDsaP256(DigestAlgorithm::Sha256) => {
let (private_key, nonce) = ecdsa_p256_sign_prep(private_key, rng)?;
ecdsa_p256_sign_post(
libcrux_ecdh::p256::ecdsa::sign_sha256(payload, private_key.as_ref(), &nonce)
crate::hacl::p256::ecdsa::sign_sha256(payload, private_key.as_ref(), &nonce)
.map_err(into_signing_error)?,
alg,
)?
}
Algorithm::EcDsaP256(DigestAlgorithm::Sha384) => {
let (private_key, nonce) = ecdsa_p256_sign_prep(private_key, rng)?;
ecdsa_p256_sign_post(
libcrux_ecdh::p256::ecdsa::sign_sha384(payload, private_key.as_ref(), &nonce)
crate::hacl::p256::ecdsa::sign_sha384(payload, private_key.as_ref(), &nonce)
.map_err(into_signing_error)?,
alg,
)?
}
Algorithm::EcDsaP256(DigestAlgorithm::Sha512) => {
let (private_key, nonce) = ecdsa_p256_sign_prep(private_key, rng)?;
ecdsa_p256_sign_post(
libcrux_ecdh::p256::ecdsa::sign_sha512(payload, private_key.as_ref(), &nonce)
crate::hacl::p256::ecdsa::sign_sha512(payload, private_key.as_ref(), &nonce)
.map_err(into_signing_error)?,
alg,
)?
Expand Down Expand Up @@ -446,17 +446,17 @@ pub fn verify(payload: &[u8], signature: &Signature, public_key: &[u8]) -> Resul
Signature::EcDsaP256(signature) => match signature.alg {
Algorithm::EcDsaP256(DigestAlgorithm::Sha256) => {
let pk = ecdsa_p256_verify_prep(public_key)?;
libcrux_ecdh::p256::ecdsa::verify_sha256(payload, &pk, &signature.r, &signature.s)
crate::hacl::p256::ecdsa::verify_sha256(payload, &pk, &signature.r, &signature.s)
}
Algorithm::EcDsaP256(DigestAlgorithm::Sha384) => {
let pk = ecdsa_p256_verify_prep(public_key)?;
libcrux_ecdh::p256::ecdsa::verify_sha384(payload, &pk, &signature.r, &signature.s)
crate::hacl::p256::ecdsa::verify_sha384(payload, &pk, &signature.r, &signature.s)
}
Algorithm::EcDsaP256(DigestAlgorithm::Sha512) => {
let pk = ecdsa_p256_verify_prep(public_key)?;
libcrux_ecdh::p256::ecdsa::verify_sha512(payload, &pk, &signature.r, &signature.s)
crate::hacl::p256::ecdsa::verify_sha512(payload, &pk, &signature.r, &signature.s)
}
_ => Err(libcrux_ecdh::p256::Error::InvalidInput),
_ => Err(crate::hacl::p256::ecdsa::Error::InvalidInput),
}
.map_err(into_verify_error),
Signature::Ed25519(signature) => {
Expand Down

0 comments on commit d0ad351

Please sign in to comment.