extern crate alloc;
use alloc::format;
use slh_dsa::{SigningKey, VerifyingKey, Shake256f};
use slh_dsa::signature::{Keypair, Signer, Verifier};
use rand_core::{CryptoRng, RngCore};
use crate::ctx::check_ctx;
use crate::error::{SigError, SigResult};
use crate::prehash::{check_prehash, frame_prehash, PreHash};
use crate::types::{SigAlgorithm, SigPublicKey, SigSecretKey, Signature};
pub struct SlhDsaShake256fKeypair {
signing_key: SigningKey<Shake256f>,
}
impl SlhDsaShake256fKeypair {
pub const SECURITY_STRENGTH_BITS: u32 = 256;
pub fn generate<R: CryptoRng + RngCore>(rng: &mut R) -> SigResult<Self> {
let mut sk_seed = [0u8; 32];
let mut sk_prf = [0u8; 32];
let mut pk_seed = [0u8; 32];
rng.fill_bytes(&mut sk_seed);
rng.fill_bytes(&mut sk_prf);
rng.fill_bytes(&mut pk_seed);
Ok(Self { signing_key: SigningKey::<Shake256f>::slh_keygen_internal(&sk_seed, &sk_prf, &pk_seed) })
}
pub fn public_key(&self) -> SigPublicKey {
SigPublicKey::new(SigAlgorithm::SlhDsaShake256f, self.signing_key.verifying_key().to_bytes().to_vec())
}
pub fn secret_key(&self) -> SigSecretKey {
SigSecretKey::new(SigAlgorithm::SlhDsaShake256f, self.signing_key.to_bytes().to_vec())
}
pub fn sign<R: CryptoRng + RngCore>(&self, rng: &mut R, message: &[u8]) -> SigResult<Signature> {
let mut opt_rand = [0u8; 32];
rng.fill_bytes(&mut opt_rand);
let sig = self.signing_key.try_sign_with_context(message, &[], Some(&opt_rand))
.map_err(|e| SigError::Signing(format!("{:?}", e)))?;
Ok(Signature::new(SigAlgorithm::SlhDsaShake256f, sig.to_bytes().to_vec()))
}
pub fn sign_deterministic(&self, message: &[u8]) -> SigResult<Signature> {
let sig = self.signing_key.try_sign(message)
.map_err(|e| SigError::Signing(format!("{:?}", e)))?;
Ok(Signature::new(SigAlgorithm::SlhDsaShake256f, sig.to_bytes().to_vec()))
}
pub fn verify(public_key: &SigPublicKey, message: &[u8], signature: &Signature) -> SigResult<()> {
if public_key.algorithm != SigAlgorithm::SlhDsaShake256f {
return Err(SigError::InvalidPublicKey(format!("expected SLH-DSA-SHAKE-256f key, got {:?}", public_key.algorithm)));
}
if signature.algorithm != SigAlgorithm::SlhDsaShake256f {
return Err(SigError::InvalidSignature(format!("expected SLH-DSA-SHAKE-256f signature, got {:?}", signature.algorithm)));
}
let vk = VerifyingKey::<Shake256f>::try_from(public_key.bytes.as_slice())
.map_err(|e| SigError::InvalidPublicKey(format!("{:?}", e)))?;
let sig = slh_dsa::Signature::<Shake256f>::try_from(signature.bytes.as_slice())
.map_err(|e| SigError::InvalidSignature(format!("{:?}", e)))?;
vk.verify(message, &sig).map_err(|_| SigError::VerificationFailed)
}
pub fn sign_ctx<R: CryptoRng + RngCore>(&self, rng: &mut R, ctx: &[u8], message: &[u8]) -> SigResult<Signature> {
check_ctx(ctx)?;
let mut opt_rand = [0u8; 32];
rng.fill_bytes(&mut opt_rand);
let sig = self.signing_key.try_sign_with_context(message, ctx, Some(&opt_rand))
.map_err(|e| SigError::Signing(format!("{:?}", e)))?;
Ok(Signature::new(SigAlgorithm::SlhDsaShake256f, sig.to_bytes().to_vec()))
}
pub fn sign_ctx_deterministic(&self, ctx: &[u8], message: &[u8]) -> SigResult<Signature> {
check_ctx(ctx)?;
let sig = self.signing_key.try_sign_with_context(message, ctx, None)
.map_err(|e| SigError::Signing(format!("{:?}", e)))?;
Ok(Signature::new(SigAlgorithm::SlhDsaShake256f, sig.to_bytes().to_vec()))
}
pub fn verify_ctx(public_key: &SigPublicKey, ctx: &[u8], message: &[u8], signature: &Signature) -> SigResult<()> {
check_ctx(ctx)?;
if public_key.algorithm != SigAlgorithm::SlhDsaShake256f {
return Err(SigError::InvalidPublicKey(format!("expected SLH-DSA-SHAKE-256f key, got {:?}", public_key.algorithm)));
}
if signature.algorithm != SigAlgorithm::SlhDsaShake256f {
return Err(SigError::InvalidSignature(format!("expected SLH-DSA-SHAKE-256f signature, got {:?}", signature.algorithm)));
}
let vk = VerifyingKey::<Shake256f>::try_from(public_key.bytes.as_slice())
.map_err(|e| SigError::InvalidPublicKey(format!("{:?}", e)))?;
let sig = slh_dsa::Signature::<Shake256f>::try_from(signature.bytes.as_slice())
.map_err(|e| SigError::InvalidSignature(format!("{:?}", e)))?;
vk.try_verify_with_context(message, ctx, &sig).map_err(|_| SigError::VerificationFailed)
}
pub fn sign_prehash<R: CryptoRng + RngCore>(
&self,
rng: &mut R,
ctx: &[u8],
hash: PreHash,
digest: &[u8],
) -> SigResult<Signature> {
check_ctx(ctx)?;
check_prehash(hash, digest, Self::SECURITY_STRENGTH_BITS, "SLH-DSA-SHAKE-256f")?;
let m_prime = frame_prehash(ctx, hash, digest);
let mut opt_rand = [0u8; 32];
rng.fill_bytes(&mut opt_rand);
let sig = self.signing_key.slh_sign_internal(&[m_prime.as_slice()], Some(&opt_rand));
Ok(Signature::new(SigAlgorithm::SlhDsaShake256f, sig.to_bytes().to_vec()))
}
pub fn sign_prehash_deterministic(
&self,
ctx: &[u8],
hash: PreHash,
digest: &[u8],
) -> SigResult<Signature> {
check_ctx(ctx)?;
check_prehash(hash, digest, Self::SECURITY_STRENGTH_BITS, "SLH-DSA-SHAKE-256f")?;
let m_prime = frame_prehash(ctx, hash, digest);
let sig = self.signing_key.slh_sign_internal(&[m_prime.as_slice()], None);
Ok(Signature::new(SigAlgorithm::SlhDsaShake256f, sig.to_bytes().to_vec()))
}
pub fn verify_prehash(
public_key: &SigPublicKey,
ctx: &[u8],
hash: PreHash,
digest: &[u8],
signature: &Signature,
) -> SigResult<()> {
check_ctx(ctx)?;
check_prehash(hash, digest, Self::SECURITY_STRENGTH_BITS, "SLH-DSA-SHAKE-256f")?;
if public_key.algorithm != SigAlgorithm::SlhDsaShake256f {
return Err(SigError::InvalidPublicKey(format!("expected SLH-DSA-SHAKE-256f key, got {:?}", public_key.algorithm)));
}
if signature.algorithm != SigAlgorithm::SlhDsaShake256f {
return Err(SigError::InvalidSignature(format!("expected SLH-DSA-SHAKE-256f signature, got {:?}", signature.algorithm)));
}
let vk = VerifyingKey::<Shake256f>::try_from(public_key.bytes.as_slice())
.map_err(|e| SigError::InvalidPublicKey(format!("{:?}", e)))?;
let sig = slh_dsa::Signature::<Shake256f>::try_from(signature.bytes.as_slice())
.map_err(|e| SigError::InvalidSignature(format!("{:?}", e)))?;
let m_prime = frame_prehash(ctx, hash, digest);
vk.slh_verify_internal(&[m_prime.as_slice()], &sig).map_err(|_| SigError::VerificationFailed)
}
pub fn from_secret_key_bytes(bytes: &[u8]) -> SigResult<Self> {
let signing_key = SigningKey::<Shake256f>::try_from(bytes)
.map_err(|e| SigError::InvalidSecretKey(format!("{:?}", e)))?;
Ok(Self { signing_key })
}
}