Skip to main content

oxicrypto_sig/
ed448.rs

1#![forbid(unsafe_code)]
2
3//! Ed448 signature wrappers for the OxiCrypto stack.
4//!
5//! Backed by `ed448-goldilocks` (Pure Rust, no unsafe, no FFI).
6//! Secret keys are 57-byte raw seeds; public keys are 57-byte compressed Edwards points.
7//! Signatures are 114 bytes.
8
9use ed448_goldilocks::{
10    signature::{Signer as Ed448Signer, Verifier as Ed448Verifier},
11    EdwardsScalarBytes, Signature, SigningKey, VerifyingKey,
12};
13use oxicrypto_core::{CryptoError, Vec};
14
15/// Ed448 signing key.
16///
17/// The secret key is a 57-byte raw seed (RFC 8032 ยง5.2.5 encoding).
18pub struct Ed448SigningKey {
19    signing_key: SigningKey,
20}
21
22impl Ed448SigningKey {
23    /// Construct from a 57-byte raw seed.
24    pub fn from_bytes(seed: &[u8]) -> Result<Self, CryptoError> {
25        let sk_bytes: [u8; 57] = seed.try_into().map_err(|_| CryptoError::InvalidKey)?;
26        let scalar = EdwardsScalarBytes::from(sk_bytes);
27        Ok(Self {
28            signing_key: SigningKey::from(scalar),
29        })
30    }
31
32    /// Sign `message` and return the 114-byte raw signature.
33    #[must_use = "signature result must be checked"]
34    pub fn sign(&self, message: &[u8]) -> Result<Vec<u8>, CryptoError> {
35        let sig: Signature = Ed448Signer::sign(&self.signing_key, message);
36        Ok(sig.to_bytes().to_vec())
37    }
38
39    /// Return the corresponding 57-byte verifying key (compressed Edwards-y).
40    #[must_use]
41    pub fn verifying_key_bytes(&self) -> [u8; 57] {
42        let vk: VerifyingKey = self.signing_key.verifying_key();
43        *vk.as_bytes()
44    }
45}
46
47/// Ed448 verifying key.
48pub struct Ed448VerifyingKey {
49    verifying_key: VerifyingKey,
50}
51
52impl Ed448VerifyingKey {
53    /// Construct from 57-byte compressed public key bytes.
54    pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
55        let pk_bytes: &[u8; 57] = bytes.try_into().map_err(|_| CryptoError::InvalidKey)?;
56        let verifying_key =
57            VerifyingKey::from_bytes(pk_bytes).map_err(|_| CryptoError::InvalidKey)?;
58        Ok(Self { verifying_key })
59    }
60
61    /// Verify 114-byte `signature` over `message`.
62    #[must_use = "verification result must be checked"]
63    pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), CryptoError> {
64        let sig_bytes: [u8; 114] = signature.try_into().map_err(|_| CryptoError::InvalidTag)?;
65        let sig = Signature::from_bytes(&sig_bytes);
66        Ed448Verifier::verify(&self.verifying_key, message, &sig)
67            .map_err(|_| CryptoError::InvalidTag)
68    }
69}