zipher 0.3.0

Cryptography utilities and implementations including Argon2, bcrypt, post-quantum algorithms and JWT support
Documentation
use hex;
use kenzu::Builder;
use pqcrypto_mldsa::mldsa87::*;
use pqcrypto_traits::sign::PublicKey;
use pqcrypto_traits::sign::SecretKey;
use pqcrypto_traits::sign::{DetachedSignature, SignedMessage};
use std::{error::Error as StdError, fmt};

pub type MlDsaPublicKeyType = Vec<u8>;
pub type MlDsaSecretKeyType = Vec<u8>;

#[derive(Debug, PartialEq, Default)]
pub enum MlDsaError {
    #[default]
    KeyGenerationFailed,
    SigningFailed,
    VerificationFailed,
    HexEncodingFailed,
    HexDecodingFailed,
    Other(String),
}

impl fmt::Display for MlDsaError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            MlDsaError::KeyGenerationFailed => write!(f, "key generation failed"),
            MlDsaError::SigningFailed => write!(f, "signing failed"),
            MlDsaError::VerificationFailed => write!(f, "verification failed"),
            MlDsaError::HexEncodingFailed => write!(f, "hex encoding failed"),
            MlDsaError::HexDecodingFailed => write!(f, "hex decoding failed"),
            MlDsaError::Other(s) => write!(f, "other: {}", s),
        }
    }
}

impl StdError for MlDsaError {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        None
    }
}

impl From<hex::FromHexError> for MlDsaError {
    fn from(_: hex::FromHexError) -> Self {
        MlDsaError::HexDecodingFailed
    }
}
impl From<String> for MlDsaError {
    fn from(s: String) -> Self {
        MlDsaError::Other(s)
    }
}
impl From<&str> for MlDsaError {
    fn from(s: &str) -> Self {
        MlDsaError::Other(s.to_string())
    }
}

fn keys() -> (MlDsaPublicKeyType, MlDsaSecretKeyType) {
    let (pk, sk) = keypair();
    let pk = pk.as_bytes().to_vec();
    let sk = sk.as_bytes().to_vec();
    (pk, sk)
}

#[derive(Builder)]
pub struct MlDsa {
    #[opt(default = keys())]
    pub pk_and_sk: (MlDsaPublicKeyType, MlDsaSecretKeyType),
}

impl MlDsa {
    pub fn sign(&self, message: &[u8]) -> Result<String, MlDsaError> {
        let (_, sk) = &self.pk_and_sk;
        let sk = SecretKey::from_bytes(sk).map_err(|_| MlDsaError::KeyGenerationFailed)?;
        let signed_message = sign(message, &sk);
        Ok(hex::encode(signed_message.as_bytes()))
    }

    pub fn verify(&self, signed_message_hex: &str) -> Result<Vec<u8>, MlDsaError> {
        let (pk, _) = &self.pk_and_sk;
        let pk = &PublicKey::from_bytes(pk).map_err(|_| MlDsaError::KeyGenerationFailed)?;
        let signed_message_bytes = hex::decode(signed_message_hex)?;
        let signed_message = SignedMessage::from_bytes(&signed_message_bytes)
            .map_err(|_| MlDsaError::VerificationFailed)?;
        let message = open(&signed_message, pk).map_err(|_| MlDsaError::VerificationFailed)?;
        Ok(message)
    }

    pub fn sign_detached(&self, message: &[u8]) -> Result<String, MlDsaError> {
        let (_, sk) = &self.pk_and_sk;
        let sk = SecretKey::from_bytes(sk).map_err(|_| MlDsaError::KeyGenerationFailed)?;
        let signature = detached_sign(message, &sk);
        Ok(hex::encode(signature.as_bytes()))
    }

    pub fn verify_detached(&self, message: &[u8], signature_hex: &str) -> Result<(), MlDsaError> {
        let (pk, _) = &self.pk_and_sk;
        let pk = &PublicKey::from_bytes(pk).map_err(|_| MlDsaError::KeyGenerationFailed)?;
        let signature_bytes = hex::decode(signature_hex)?;
        let signature = DetachedSignature::from_bytes(&signature_bytes)
            .map_err(|_| MlDsaError::VerificationFailed)?;
        verify_detached_signature(&signature, message, pk)
            .map_err(|_| MlDsaError::VerificationFailed)
    }
}