extern crate alloc;
use alloc::{format, vec, vec::Vec};
use fn_dsa::{
sign_key_size, vrfy_key_size, signature_size, FN_DSA_LOGN_512,
KeyPairGenerator, KeyPairGenerator512,
SigningKey, SigningKey512,
VerifyingKey, VerifyingKey512,
DomainContext, DOMAIN_NONE, HASH_ID_RAW,
HASH_ID_SHA256, HASH_ID_SHA384, HASH_ID_SHA512,
HASH_ID_SHA3_256, HASH_ID_SHA3_384, HASH_ID_SHA3_512,
HASH_ID_SHAKE128, HASH_ID_SHAKE256,
};
use rand_core::{CryptoRng, RngCore};
use crate::ctx::check_ctx;
use crate::error::{SigError, SigResult};
use crate::prehash::{check_prehash, PreHash};
use crate::types::{SigAlgorithm, SigPublicKey, SigSecretKey, Signature};
pub struct FnDsa512Keypair {
sign_key: Vec<u8>,
vrfy_key: Vec<u8>,
}
impl FnDsa512Keypair {
pub const SECURITY_STRENGTH_BITS: u32 = 128;
pub fn generate<R: CryptoRng + RngCore>(rng: &mut R) -> SigResult<Self> {
let mut sign_key = vec![0u8; sign_key_size(FN_DSA_LOGN_512)];
let mut vrfy_key = vec![0u8; vrfy_key_size(FN_DSA_LOGN_512)];
let mut kg = KeyPairGenerator512::default();
kg.keygen(FN_DSA_LOGN_512, rng, &mut sign_key, &mut vrfy_key);
Ok(Self { sign_key, vrfy_key })
}
pub fn public_key(&self) -> SigPublicKey {
SigPublicKey::new(SigAlgorithm::FnDsa512, self.vrfy_key.clone())
}
pub fn secret_key(&self) -> SigSecretKey {
SigSecretKey::new(SigAlgorithm::FnDsa512, self.sign_key.clone())
}
pub fn sign<R: CryptoRng + RngCore>(&self, rng: &mut R, message: &[u8]) -> SigResult<Signature> {
let mut sk = SigningKey512::decode(&self.sign_key)
.ok_or_else(|| SigError::InvalidSecretKey("malformed FN-DSA-512 signing key".into()))?;
let mut sig = vec![0u8; signature_size(FN_DSA_LOGN_512)];
sk.sign(rng, &DOMAIN_NONE, &HASH_ID_RAW, message, &mut sig)
.ok_or_else(|| SigError::Signing("fn-dsa signing failed".into()))?;
Ok(Signature::new(SigAlgorithm::FnDsa512, sig))
}
pub fn verify(public_key: &SigPublicKey, message: &[u8], signature: &Signature) -> SigResult<()> {
if public_key.algorithm != SigAlgorithm::FnDsa512 {
return Err(SigError::InvalidPublicKey(
format!("expected FN-DSA-512 key, got {:?}", public_key.algorithm)
));
}
if signature.algorithm != SigAlgorithm::FnDsa512 {
return Err(SigError::InvalidSignature(
format!("expected FN-DSA-512 signature, got {:?}", signature.algorithm)
));
}
let vk = VerifyingKey512::decode(&public_key.bytes)
.ok_or_else(|| SigError::InvalidPublicKey("malformed FN-DSA-512 public key".into()))?;
if vk.verify(&signature.bytes, &DOMAIN_NONE, &HASH_ID_RAW, message) {
Ok(())
} else {
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 sk = SigningKey512::decode(&self.sign_key)
.ok_or_else(|| SigError::InvalidSecretKey("malformed FN-DSA-512 signing key".into()))?;
let mut sig = vec![0u8; signature_size(FN_DSA_LOGN_512)];
sk.sign(rng, &DomainContext(ctx), &HASH_ID_RAW, message, &mut sig)
.ok_or_else(|| SigError::Signing("fn-dsa signing failed".into()))?;
Ok(Signature::new(SigAlgorithm::FnDsa512, sig))
}
pub fn verify_ctx(public_key: &SigPublicKey, ctx: &[u8], message: &[u8], signature: &Signature) -> SigResult<()> {
check_ctx(ctx)?;
if public_key.algorithm != SigAlgorithm::FnDsa512 {
return Err(SigError::InvalidPublicKey(
format!("expected FN-DSA-512 key, got {:?}", public_key.algorithm)
));
}
if signature.algorithm != SigAlgorithm::FnDsa512 {
return Err(SigError::InvalidSignature(
format!("expected FN-DSA-512 signature, got {:?}", signature.algorithm)
));
}
let vk = VerifyingKey512::decode(&public_key.bytes)
.ok_or_else(|| SigError::InvalidPublicKey("malformed FN-DSA-512 public key".into()))?;
if vk.verify(&signature.bytes, &DomainContext(ctx), &HASH_ID_RAW, message) {
Ok(())
} else {
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, "FN-DSA-512")?;
let hash_id = fn_dsa_hash_id(hash);
let mut sk = SigningKey512::decode(&self.sign_key)
.ok_or_else(|| SigError::InvalidSecretKey("malformed FN-DSA-512 signing key".into()))?;
let mut sig = vec![0u8; signature_size(FN_DSA_LOGN_512)];
sk.sign(rng, &DomainContext(ctx), hash_id, digest, &mut sig)
.ok_or_else(|| SigError::Signing("fn-dsa signing failed".into()))?;
Ok(Signature::new(SigAlgorithm::FnDsa512, sig))
}
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, "FN-DSA-512")?;
if public_key.algorithm != SigAlgorithm::FnDsa512 {
return Err(SigError::InvalidPublicKey(
format!("expected FN-DSA-512 key, got {:?}", public_key.algorithm)
));
}
if signature.algorithm != SigAlgorithm::FnDsa512 {
return Err(SigError::InvalidSignature(
format!("expected FN-DSA-512 signature, got {:?}", signature.algorithm)
));
}
let vk = VerifyingKey512::decode(&public_key.bytes)
.ok_or_else(|| SigError::InvalidPublicKey("malformed FN-DSA-512 public key".into()))?;
let hash_id = fn_dsa_hash_id(hash);
if vk.verify(&signature.bytes, &DomainContext(ctx), hash_id, digest) {
Ok(())
} else {
Err(SigError::VerificationFailed)
}
}
pub fn from_key_bytes(pk_bytes: &[u8], sk_bytes: &[u8]) -> SigResult<Self> {
VerifyingKey512::decode(pk_bytes)
.ok_or_else(|| SigError::InvalidPublicKey("malformed FN-DSA-512 public key".into()))?;
SigningKey512::decode(sk_bytes)
.ok_or_else(|| SigError::InvalidSecretKey("malformed FN-DSA-512 signing key".into()))?;
Ok(Self { sign_key: sk_bytes.to_vec(), vrfy_key: pk_bytes.to_vec() })
}
}
fn fn_dsa_hash_id(hash: PreHash) -> &'static fn_dsa::HashIdentifier<'static> {
match hash {
PreHash::Sha256 => &HASH_ID_SHA256,
PreHash::Sha384 => &HASH_ID_SHA384,
PreHash::Sha512 => &HASH_ID_SHA512,
PreHash::Sha3_256 => &HASH_ID_SHA3_256,
PreHash::Sha3_384 => &HASH_ID_SHA3_384,
PreHash::Sha3_512 => &HASH_ID_SHA3_512,
PreHash::Shake128 => &HASH_ID_SHAKE128,
PreHash::Shake256 => &HASH_ID_SHAKE256,
}
}