#![allow(non_snake_case)]
use std::sync::Arc;
use crate::core::{RiResult, RiError};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct DilithiumPublicKey(pub Vec<u8>);
#[derive(Debug, Clone)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct DilithiumSecretKey(pub Vec<u8>);
#[derive(Debug, Clone)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct DilithiumSignature(pub Vec<u8>);
#[derive(Debug, Clone)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct DilithiumSigner {
algorithm: Arc<std::sync::RwLock<DilithiumAlgorithm>>,
}
#[derive(Debug, Clone, Copy)]
enum DilithiumAlgorithm {
Dilithium2,
Dilithium3,
Dilithium5,
}
impl DilithiumSigner {
pub fn new() -> Self {
Self {
algorithm: Arc::new(std::sync::RwLock::new(DilithiumAlgorithm::Dilithium2)),
}
}
pub fn with_algorithm(algorithm: super::RiPostQuantumAlgorithm) -> Self {
let algo = match algorithm {
super::RiPostQuantumAlgorithm::Dilithium2 => DilithiumAlgorithm::Dilithium2,
super::RiPostQuantumAlgorithm::Dilithium3 => DilithiumAlgorithm::Dilithium3,
super::RiPostQuantumAlgorithm::Dilithium5 => DilithiumAlgorithm::Dilithium5,
_ => DilithiumAlgorithm::Dilithium2,
};
Self {
algorithm: Arc::new(std::sync::RwLock::new(algo)),
}
}
#[cfg(feature = "protocol")]
pub fn keygen(&self) -> RiResult<(Vec<u8>, Vec<u8>)> {
use oqs::sig::Sig;
let algo = *self.algorithm.read().map_err(|e|
RiError::InvalidState(format!("Lock error: {}", e))
)?;
let sig = match algo {
DilithiumAlgorithm::Dilithium2 => Sig::new(oqs::sig::Algorithm::Dilithium2),
DilithiumAlgorithm::Dilithium3 => Sig::new(oqs::sig::Algorithm::Dilithium3),
DilithiumAlgorithm::Dilithium5 => Sig::new(oqs::sig::Algorithm::Dilithium5),
}.map_err(|e| RiError::Other(format!("Failed to initialize Dilithium: {:?}", e)))?;
let (pk, sk) = sig.keypair()
.map_err(|e| RiError::Other(format!("Dilithium keygen failed: {:?}", e)))?;
Ok((pk.into_vec(), sk.into_vec()))
}
#[cfg(not(feature = "protocol"))]
pub fn keygen(&self) -> RiResult<(Vec<u8>, Vec<u8>)> {
Err(RiError::Other(
"Post-quantum cryptography requires the 'protocol' feature. \
Enable with: cargo build --features protocol".to_string()
))
}
#[cfg(feature = "protocol")]
pub fn sign(&self, secret_key: &[u8], message: &[u8]) -> RiResult<Vec<u8>> {
use oqs::sig::Sig;
let algo = *self.algorithm.read().map_err(|e|
RiError::InvalidState(format!("Lock error: {}", e))
)?;
let sig = match algo {
DilithiumAlgorithm::Dilithium2 => Sig::new(oqs::sig::Algorithm::Dilithium2),
DilithiumAlgorithm::Dilithium3 => Sig::new(oqs::sig::Algorithm::Dilithium3),
DilithiumAlgorithm::Dilithium5 => Sig::new(oqs::sig::Algorithm::Dilithium5),
}.map_err(|e| RiError::Other(format!("Failed to initialize Dilithium: {:?}", e)))?;
let sk = sig.secret_key_from_bytes(secret_key)
.ok_or_else(|| RiError::Other("Invalid secret key".to_string()))?;
let signature = sig.sign(message, &sk)
.map_err(|e| RiError::Other(format!("Dilithium sign failed: {:?}", e)))?;
Ok(signature.into_vec())
}
#[cfg(not(feature = "protocol"))]
pub fn sign(&self, _secret_key: &[u8], _message: &[u8]) -> RiResult<Vec<u8>> {
Err(RiError::Other(
"Post-quantum cryptography requires the 'protocol' feature. \
Enable with: cargo build --features protocol".to_string()
))
}
#[cfg(feature = "protocol")]
pub fn verify(&self, public_key: &[u8], message: &[u8], signature: &[u8]) -> RiResult<bool> {
use oqs::sig::Sig;
let algo = *self.algorithm.read().map_err(|e|
RiError::InvalidState(format!("Lock error: {}", e))
)?;
let sig = match algo {
DilithiumAlgorithm::Dilithium2 => Sig::new(oqs::sig::Algorithm::Dilithium2),
DilithiumAlgorithm::Dilithium3 => Sig::new(oqs::sig::Algorithm::Dilithium3),
DilithiumAlgorithm::Dilithium5 => Sig::new(oqs::sig::Algorithm::Dilithium5),
}.map_err(|e| RiError::Other(format!("Failed to initialize Dilithium: {:?}", e)))?;
let pk = sig.public_key_from_bytes(public_key)
.ok_or_else(|| RiError::Other("Invalid public key".to_string()))?;
let sig_bytes = sig.signature_from_bytes(signature)
.ok_or_else(|| RiError::Other("Invalid signature".to_string()))?;
let result = sig.verify(message, &sig_bytes, &pk);
Ok(result.is_ok())
}
#[cfg(not(feature = "protocol"))]
pub fn verify(&self, _public_key: &[u8], _message: &[u8], _signature: &[u8]) -> RiResult<bool> {
Err(RiError::Other(
"Post-quantum cryptography requires the 'protocol' feature. \
Enable with: cargo build --features protocol".to_string()
))
}
}
impl Default for DilithiumSigner {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "pyo3")]
#[pyo3::prelude::pymethods]
impl DilithiumSigner {
#[new]
pub fn new_py() -> Self {
Self::new()
}
pub fn keygen_py(&self) -> Option<(Vec<u8>, Vec<u8>)> {
self.keygen().ok()
}
pub fn sign_py(&self, secret_key: &[u8], message: &[u8]) -> Option<Vec<u8>> {
self.sign(secret_key, message).ok()
}
pub fn verify_py(&self, public_key: &[u8], message: &[u8], signature: &[u8]) -> bool {
self.verify(public_key, message, signature).unwrap_or(false)
}
}