use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
use prikk_error::{PrikkError, Result};
pub const ED25519_KEY_LEN: usize = 32;
pub const ED25519_SIGNATURE_LEN: usize = 64;
pub struct Ed25519KeyPair {
signing: SigningKey,
}
impl Ed25519KeyPair {
#[must_use]
pub fn from_seed(seed: &[u8; ED25519_KEY_LEN]) -> Self {
Self {
signing: SigningKey::from_bytes(seed),
}
}
pub fn generate() -> Result<Self> {
let mut seed = [0_u8; ED25519_KEY_LEN];
getrandom::fill(&mut seed)
.map_err(|e| PrikkError::Integrity(format!("OS CSPRNG unavailable: {e}")))?;
Ok(Self::from_seed(&seed))
}
#[must_use]
pub fn public_key_bytes(&self) -> [u8; ED25519_KEY_LEN] {
self.signing.verifying_key().to_bytes()
}
#[must_use]
pub fn sign(&self, message: &[u8]) -> [u8; ED25519_SIGNATURE_LEN] {
self.signing.sign(message).to_bytes()
}
}
pub fn verify_ed25519(
public_key: &[u8; ED25519_KEY_LEN],
message: &[u8],
signature: &[u8],
) -> Result<()> {
let verifying = VerifyingKey::from_bytes(public_key)
.map_err(|e| PrikkError::InvalidSignature(format!("malformed public key: {e}")))?;
let signature_array: [u8; ED25519_SIGNATURE_LEN] = signature.try_into().map_err(|_| {
PrikkError::InvalidSignature(format!(
"signature must be {ED25519_SIGNATURE_LEN} bytes, got {}",
signature.len()
))
})?;
let signature = Signature::from_bytes(&signature_array);
verifying
.verify_strict(message, &signature)
.map_err(|e| PrikkError::InvalidSignature(format!("signature verification failed: {e}")))
}
#[cfg(test)]
mod tests;