#![allow(clippy::len_without_is_empty)]
#[cfg(feature = "hazmat")]
pub mod address;
#[cfg(not(feature = "hazmat"))]
pub(crate) mod address;
pub(crate) mod fors;
#[cfg(feature = "hazmat")]
pub mod hash;
#[cfg(not(feature = "hazmat"))]
pub(crate) mod hash;
#[cfg(feature = "hazmat")]
pub mod hash_sha2;
#[cfg(not(feature = "hazmat"))]
pub(crate) mod hash_sha2;
pub(crate) mod hypertree;
pub mod params;
pub mod rng;
pub(crate) mod sha3;
#[cfg(feature = "hazmat")]
pub mod slh;
#[cfg(not(feature = "hazmat"))]
pub(crate) mod slh;
pub(crate) mod wots;
pub(crate) mod xmss;
#[cfg(test)]
mod acvp_internal;
pub use crate::prehash::PreHash;
pub use params::{
Params, Sha2_128f, Sha2_128s, Sha2_192f, Sha2_192s, Sha2_256f, Sha2_256s, Shake128f, Shake128s, Shake192f,
Shake192s, Shake256f, Shake256s,
};
pub use rng::CryptoRng;
#[cfg(feature = "std")]
pub use rng::OsRng;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SlhDsaError {
RngFailure,
InvalidKey,
InvalidSignature,
VerificationFailed,
ContextTooLong,
FaultDetected,
}
impl core::fmt::Display for SlhDsaError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SlhDsaError::RngFailure => write!(f, "RNG failure"),
SlhDsaError::InvalidKey => write!(f, "Invalid key"),
SlhDsaError::InvalidSignature => write!(f, "Invalid signature"),
SlhDsaError::VerificationFailed => write!(f, "Verification failed"),
SlhDsaError::ContextTooLong => write!(f, "Context string exceeds 255 bytes"),
SlhDsaError::FaultDetected => write!(f, "Signing-side fault detected by FORS redundancy"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for SlhDsaError {}
use crate::secret::SecretBytes;
use alloc::vec::Vec;
use core::marker::PhantomData;
pub struct VerifyingKey<P: Params> {
bytes: Vec<u8>,
_marker: PhantomData<P>,
}
impl<P: Params> VerifyingKey<P> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, SlhDsaError> {
if bytes.len() != P::PK_LEN {
return Err(SlhDsaError::InvalidKey);
}
Ok(Self {
bytes: bytes.to_vec(),
_marker: PhantomData,
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
}
impl<P: Params> AsRef<[u8]> for VerifyingKey<P> {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl<P: Params> core::ops::Deref for VerifyingKey<P> {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes
}
}
impl<P: Params> Clone for VerifyingKey<P> {
fn clone(&self) -> Self {
Self {
bytes: self.bytes.clone(),
_marker: PhantomData,
}
}
}
pub struct SigningKey<P: Params> {
bytes: SecretBytes,
_marker: PhantomData<P>,
}
impl<P: Params> SigningKey<P> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, SlhDsaError> {
if bytes.len() != P::SK_LEN {
return Err(SlhDsaError::InvalidKey);
}
Ok(Self {
bytes: SecretBytes::from_slice(bytes),
_marker: PhantomData,
})
}
pub fn as_bytes(&self) -> &[u8] {
self.bytes.as_bytes()
}
pub fn len(&self) -> usize {
self.bytes.len()
}
}
impl<P: Params> AsRef<[u8]> for SigningKey<P> {
fn as_ref(&self) -> &[u8] {
self.bytes.as_bytes()
}
}
impl<P: Params> core::ops::Deref for SigningKey<P> {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.bytes.as_bytes()
}
}
pub struct Signature<P: Params> {
bytes: Vec<u8>,
_marker: PhantomData<P>,
}
impl<P: Params> Signature<P> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, SlhDsaError> {
if bytes.len() != params::sig_len::<P>() {
return Err(SlhDsaError::InvalidSignature);
}
Ok(Self {
bytes: bytes.to_vec(),
_marker: PhantomData,
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
}
impl<P: Params> AsRef<[u8]> for Signature<P> {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl<P: Params> core::ops::Deref for Signature<P> {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes
}
}
impl<P: Params> Clone for Signature<P> {
fn clone(&self) -> Self {
Self {
bytes: self.bytes.clone(),
_marker: PhantomData,
}
}
}
pub struct SlhDsa<P: Params> {
_marker: core::marker::PhantomData<P>,
}
impl<P: Params> SlhDsa<P> {
pub fn keygen(rng: &mut dyn CryptoRng) -> Result<(SigningKey<P>, VerifyingKey<P>), SlhDsaError> {
let (sk_v, pk_v) = slh::slh_keygen::<P>(rng)?;
Ok((
SigningKey {
bytes: SecretBytes::from_vec(sk_v),
_marker: PhantomData,
},
VerifyingKey {
bytes: pk_v,
_marker: PhantomData,
},
))
}
pub fn sign(
message: &[u8],
ctx: &[u8],
secret_key: &SigningKey<P>,
rng: &mut dyn CryptoRng,
) -> Result<Signature<P>, SlhDsaError> {
let sig_v = slh::slh_sign::<P>(message, ctx, secret_key.as_bytes(), rng)?;
Ok(Signature {
bytes: sig_v,
_marker: PhantomData,
})
}
pub fn sign_prehash(
message: &[u8],
ctx: &[u8],
ph: PreHash,
secret_key: &SigningKey<P>,
rng: &mut dyn CryptoRng,
) -> Result<Signature<P>, SlhDsaError> {
let sig_v = slh::slh_sign_prehash::<P>(message, ctx, ph, secret_key.as_bytes(), rng)?;
Ok(Signature {
bytes: sig_v,
_marker: PhantomData,
})
}
pub fn verify(
message: &[u8],
ctx: &[u8],
signature: &Signature<P>,
public_key: &VerifyingKey<P>,
) -> Result<bool, SlhDsaError> {
slh::slh_verify::<P>(message, signature.as_bytes(), ctx, public_key.as_bytes())
}
pub fn verify_prehash(
message: &[u8],
ctx: &[u8],
ph: PreHash,
signature: &Signature<P>,
public_key: &VerifyingKey<P>,
) -> Result<bool, SlhDsaError> {
slh::slh_verify_prehash::<P>(message, signature.as_bytes(), ctx, ph, public_key.as_bytes())
}
pub fn signature_size() -> usize {
params::sig_len::<P>()
}
pub fn public_key_size() -> usize {
P::PK_LEN
}
pub fn secret_key_size() -> usize {
P::SK_LEN
}
}