#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unsafe_code)]
#![deny(unused_qualifications)]
#[cfg(not(feature = "std"))]
extern crate alloc;
pub use lib_q_core::{
Algorithm,
AlgorithmCategory,
Error,
Result,
SigKeypair,
SigPublicKey,
SigSecretKey,
Signature,
SignatureContext,
SignatureOperations,
};
pub mod provider;
#[cfg(feature = "ml-dsa")]
pub mod ml_dsa;
#[cfg(feature = "fn-dsa")]
pub mod fn_dsa;
#[cfg(feature = "slh-dsa")]
pub mod slh_dsa;
#[cfg(feature = "alloc")]
pub use provider::LibQSignatureProvider;
#[cfg(feature = "std")]
pub fn available_algorithms() -> Vec<&'static str> {
let mut algorithms = Vec::new();
#[cfg(feature = "ml-dsa")]
{
algorithms.extend(["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"]);
}
#[cfg(feature = "fn-dsa")]
{
algorithms.extend(["FN-DSA", "FN-DSA-512", "FN-DSA-1024"]);
}
#[cfg(feature = "slh-dsa")]
{
algorithms.extend([
"SLH-DSA-SHA256-128f-Robust",
"SLH-DSA-SHA256-192f-Robust",
"SLH-DSA-SHA256-256f-Robust",
"SLH-DSA-SHAKE256-128f-Robust",
"SLH-DSA-SHAKE256-192f-Robust",
"SLH-DSA-SHAKE256-256f-Robust",
]);
}
algorithms
}
#[cfg(not(feature = "std"))]
pub fn available_algorithms() -> &'static [&'static str] {
&[
#[cfg(feature = "ml-dsa")]
"ML-DSA-44",
#[cfg(feature = "ml-dsa")]
"ML-DSA-65",
#[cfg(feature = "ml-dsa")]
"ML-DSA-87",
#[cfg(feature = "fn-dsa")]
"FN-DSA",
#[cfg(feature = "fn-dsa")]
"FN-DSA-512",
#[cfg(feature = "fn-dsa")]
"FN-DSA-1024",
#[cfg(feature = "slh-dsa")]
"SLH-DSA-SHA256-128f-Robust",
#[cfg(feature = "slh-dsa")]
"SLH-DSA-SHA256-192f-Robust",
#[cfg(feature = "slh-dsa")]
"SLH-DSA-SHA256-256f-Robust",
#[cfg(feature = "slh-dsa")]
"SLH-DSA-SHAKE256-128f-Robust",
#[cfg(feature = "slh-dsa")]
"SLH-DSA-SHAKE256-192f-Robust",
#[cfg(feature = "slh-dsa")]
"SLH-DSA-SHAKE256-256f-Robust",
]
}
#[cfg(feature = "std")]
pub fn create_signature(algorithm: &str) -> Result<Box<dyn Signature>> {
match algorithm {
#[cfg(feature = "ml-dsa")]
"ml-dsa" | "mldsa65" | "ML-DSA-65" => Ok(Box::new(ml_dsa::MlDsa::ml_dsa_65())),
#[cfg(feature = "ml-dsa")]
"mldsa44" | "ML-DSA-44" => Ok(Box::new(ml_dsa::MlDsa::ml_dsa_44())),
#[cfg(feature = "ml-dsa")]
"mldsa87" | "ML-DSA-87" => Ok(Box::new(ml_dsa::MlDsa::ml_dsa_87())),
#[cfg(feature = "fn-dsa")]
"fn-dsa" | "FN-DSA" => Ok(Box::new(fn_dsa::FnDsa::level1())),
#[cfg(feature = "fn-dsa")]
"fn-dsa-512" | "FN-DSA-512" => Ok(Box::new(fn_dsa::FnDsa512::new())),
#[cfg(feature = "fn-dsa")]
"fn-dsa-1024" | "FN-DSA-1024" => Ok(Box::new(fn_dsa::FnDsa1024::new())),
#[cfg(feature = "slh-dsa")]
"slh-dsa" |
"SLH-DSA-SHA256-128f-Robust" |
"slh-dsa-sha256-128f-robust" |
"SLH-DSA-SHA256-192f-Robust" |
"slh-dsa-sha256-192f-robust" |
"SLH-DSA-SHA256-256f-Robust" |
"slh-dsa-sha256-256f-robust" |
"SLH-DSA-SHAKE256-128f-Robust" |
"slh-dsa-shake256-128f-robust" |
"SLH-DSA-SHAKE256-192f-Robust" |
"slh-dsa-shake256-192f-robust" |
"SLH-DSA-SHAKE256-256f-Robust" |
"slh-dsa-shake256-256f-robust" => Ok(Box::new(slh_dsa::SlhDsa::new())),
_ => Err(Error::InvalidAlgorithm {
algorithm: "Unknown algorithm",
}),
}
}
pub fn create_signature_context(algorithm: Algorithm) -> Result<SignatureContext> {
if !algorithm.supports_category(AlgorithmCategory::Signature) {
return Err(Error::InvalidAlgorithm {
algorithm: "Algorithm does not support signature operations",
});
}
Ok(SignatureContext::new())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_available_algorithms() {
let algorithms = available_algorithms();
#[cfg(any(feature = "ml-dsa", feature = "fn-dsa", feature = "slh-dsa"))]
assert!(
!algorithms.is_empty(),
"Should have at least one algorithm when features are enabled"
);
}
#[test]
fn test_create_signature_context() {
let result = create_signature_context(Algorithm::MlDsa65);
assert!(
result.is_ok(),
"Context creation should succeed for valid signature algorithm"
);
let mut ctx = result.unwrap();
let keypair_result = ctx.generate_keypair(Algorithm::MlDsa65, None);
assert!(
keypair_result.is_err(),
"Keypair generation should fail without provider"
);
if let Err(err) = keypair_result {
assert!(
matches!(
err,
Error::NotImplemented { .. } | Error::ProviderNotConfigured { .. }
),
"unexpected error without provider: {:?}",
err
);
}
}
#[test]
fn test_create_signature_context_invalid_algorithm() {
let result = create_signature_context(Algorithm::MlKem512);
assert!(result.is_err());
}
#[test]
fn test_provider_creation() {
let provider = LibQSignatureProvider::new();
assert!(provider.is_ok(), "Provider should be created successfully");
}
#[test]
fn test_provider_algorithm_support() {
let provider = LibQSignatureProvider::new().unwrap();
#[cfg(feature = "ml-dsa")]
{
let result = provider.generate_keypair(Algorithm::MlDsa65, None);
match result {
Ok(_) => {
}
Err(Error::NotImplemented { .. }) => {
}
Err(Error::RandomGenerationFailed { .. }) => {
}
Err(e) => {
panic!("Unexpected error type: {:?}", e);
}
}
}
let result = provider.generate_keypair(Algorithm::Sha3_256, None);
assert!(result.is_err());
if let Err(Error::InvalidAlgorithm { .. }) = result {
} else {
panic!("Expected InvalidAlgorithm error for non-signature algorithm");
}
}
#[test]
fn test_algorithm_naming_consistency() {
let algorithms = available_algorithms();
for algorithm in algorithms {
assert!(
algorithm.starts_with("ML-DSA-") ||
algorithm.starts_with("FN-DSA") ||
algorithm.starts_with("SLH-DSA-"),
"Algorithm name '{}' should follow NIST naming conventions",
algorithm
);
}
}
#[cfg(feature = "std")]
#[test]
fn test_legacy_compatibility() {
#[cfg(feature = "ml-dsa")]
{
let result = create_signature("ml-dsa");
assert!(result.is_ok(), "Legacy 'ml-dsa' name should work");
let result = create_signature("mldsa65");
assert!(result.is_ok(), "Legacy 'mldsa65' name should work");
let result = create_signature("ML-DSA-65");
assert!(result.is_ok(), "NIST 'ML-DSA-65' name should work");
}
}
#[cfg(feature = "std")]
#[test]
fn test_create_signature_unknown_algorithm() {
let result = create_signature("not-a-real-signature");
assert!(matches!(result, Err(Error::InvalidAlgorithm { .. })));
}
}