Skip to main content

oxicrypto_sig/
lib.rs

1#![forbid(unsafe_code)]
2
3//! Pure Rust digital signature implementations for the OxiCrypto stack.
4//!
5//! # Algorithms
6//!
7//! | Algorithm | Module | Key sizes |
8//! |-----------|--------|-----------|
9//! | Ed25519 | (inline) | 32-byte scalar / 32-byte point |
10//! | Ed448 | [`ed448`] | 57-byte scalar / 57-byte point |
11//! | ECDSA P-256 | [`ecdsa_p256`] | 32-byte scalar / 33-byte SEC1 point |
12//! | ECDSA P-384 | [`ecdsa_p384`] | 48-byte scalar / 49-byte SEC1 point |
13//! | ECDSA P-521 | [`ecdsa_p521`] | 66-byte scalar / 67-byte SEC1 point |
14//! | RSA PKCS#1v15 | [`rsa_sig`] | DER PKCS#8 / DER SPKI |
15//! | RSA-PSS | [`rsa_sig`] | DER PKCS#8 / DER SPKI |
16//! | Schnorr BIP-340 | [`schnorr`] | 32-byte scalar / 32-byte x-only point / 64-byte sig |
17//! | FROST(Ed25519, SHA-512) | [`frost`] | `t`-of-`n` threshold Ed25519 (RFC 9591) |
18
19pub mod ecdsa_p256;
20pub mod ecdsa_p384;
21pub mod ecdsa_p521;
22pub mod ed448;
23pub mod ed448_ext;
24pub mod frost;
25pub mod rsa_sig;
26pub mod schnorr;
27
28pub use ecdsa_p256::{EcdsaP256Signer, EcdsaP256Verifier};
29pub use ecdsa_p384::{EcdsaP384Signer, EcdsaP384Verifier};
30pub use ecdsa_p521::{EcdsaP521Signer, EcdsaP521Verifier};
31pub use ed448::{Ed448SigningKey, Ed448VerifyingKey};
32pub use ed448_ext::{ed448ctx_sign, ed448ctx_verify, ed448ph_sign, ed448ph_verify};
33pub use rsa_sig::{
34    rsa_generate_keypair, rsa_oaep_sha256_decrypt, rsa_oaep_sha256_encrypt,
35    RsaPkcs1v15Sha256Signer, RsaPkcs1v15Sha256Verifier, RsaPkcs1v15Sha384Signer,
36    RsaPkcs1v15Sha384Verifier, RsaPkcs1v15Sha512Signer, RsaPkcs1v15Sha512Verifier,
37    RsaPssSha256Signer, RsaPssSha256Verifier, RsaPssSha384Signer, RsaPssSha384Verifier,
38    RsaPssSha512Signer, RsaPssSha512Verifier,
39};
40pub use schnorr::{schnorr_bip340_sign_with_aux, SchnorrBip340};
41
42// Trait-dispatched unit-struct wrappers (re-exports for convenience)
43// These are defined below after the Ed25519 impls.
44
45use ed25519_dalek::{Signature, SigningKey, VerifyingKey};
46use oxicrypto_core::{CryptoError, SecretKey, SecretVec, Signer, Verifier};
47use p256::elliptic_curve::Generate;
48
49// ── Key generation ────────────────────────────────────────────────────────────
50
51/// Generate an Ed25519 key pair.
52///
53/// Returns `(signing_key_bytes, verifying_key_bytes)`.
54/// `signing_key_bytes` is a 32-byte seed wrapped in [`SecretKey`].
55///
56/// This function uses the supplied RNG to fill a 32-byte seed and constructs
57/// the key pair from it, avoiding the `rand_core` 0.6/0.10 version boundary.
58#[must_use = "key pair result must be used"]
59pub fn ed25519_generate_keypair<R: rand_core::TryCryptoRng + ?Sized>(
60    rng: &mut R,
61) -> Result<(SecretKey<32>, [u8; 32]), CryptoError> {
62    let mut seed = [0u8; 32];
63    rng.try_fill_bytes(&mut seed)
64        .map_err(|_| CryptoError::Rng)?;
65    let signing_key = SigningKey::from_bytes(&seed);
66    let verifying_key = signing_key.verifying_key();
67    Ok((SecretKey::new(seed), *verifying_key.as_bytes()))
68}
69
70/// Generate an ECDSA P-256 key pair.
71///
72/// Returns `(secret_key_bytes, sec1_compressed_public_key_bytes)`.
73/// The secret key bytes are wrapped in [`SecretVec`] (zeroized on drop).
74#[must_use = "key pair result must be used"]
75pub fn ecdsa_p256_generate_keypair<R: rand_core::TryCryptoRng + ?Sized>(
76    rng: &mut R,
77) -> Result<(SecretVec, Vec<u8>), CryptoError> {
78    let secret_key = p256::SecretKey::try_generate_from_rng(rng).map_err(|_| CryptoError::Rng)?;
79    let public_key = secret_key.public_key();
80    let sk_bytes = SecretVec::from_slice(secret_key.to_bytes().as_slice());
81    let pk_bytes = public_key.to_sec1_bytes().to_vec();
82    Ok((sk_bytes, pk_bytes))
83}
84
85/// Generate an ECDSA P-384 key pair.
86///
87/// Returns `(secret_key_bytes, sec1_compressed_public_key_bytes)`.
88/// The secret key bytes are wrapped in [`SecretVec`] (zeroized on drop).
89#[must_use = "key pair result must be used"]
90pub fn ecdsa_p384_generate_keypair<R: rand_core::TryCryptoRng + ?Sized>(
91    rng: &mut R,
92) -> Result<(SecretVec, Vec<u8>), CryptoError> {
93    let secret_key = p384::SecretKey::try_generate_from_rng(rng).map_err(|_| CryptoError::Rng)?;
94    let public_key = secret_key.public_key();
95    let sk_bytes = SecretVec::from_slice(secret_key.to_bytes().as_slice());
96    let pk_bytes = public_key.to_sec1_bytes().to_vec();
97    Ok((sk_bytes, pk_bytes))
98}
99
100/// Generate an ECDSA P-521 key pair.
101///
102/// Returns `(secret_key_bytes, sec1_compressed_public_key_bytes)`.
103/// The secret key bytes are wrapped in [`SecretVec`] (zeroized on drop).
104#[must_use = "key pair result must be used"]
105pub fn ecdsa_p521_generate_keypair<R: rand_core::TryCryptoRng + ?Sized>(
106    rng: &mut R,
107) -> Result<(SecretVec, Vec<u8>), CryptoError> {
108    let secret_key = p521::SecretKey::try_generate_from_rng(rng).map_err(|_| CryptoError::Rng)?;
109    let public_key = secret_key.public_key();
110    let sk_bytes = SecretVec::from_slice(secret_key.to_bytes().as_slice());
111    let pk_bytes = public_key.to_sec1_bytes().to_vec();
112    Ok((sk_bytes, pk_bytes))
113}
114
115// ── Ed25519 batch verification ────────────────────────────────────────────────
116
117/// Verify a batch of Ed25519 signatures in a single call (sequential).
118///
119/// Returns `Ok(())` if every signature is valid.
120/// Returns `Err(CryptoError::BadInput)` if the slice lengths differ.
121/// Returns `Err(CryptoError::Sign)` if any signature is invalid.
122/// An empty batch returns `Ok(())`.
123#[must_use = "batch verification result must be checked"]
124pub fn ed25519_verify_batch(
125    messages: &[&[u8]],
126    signatures: &[Signature],
127    verifying_keys: &[VerifyingKey],
128) -> Result<(), CryptoError> {
129    use ed25519_dalek::Verifier as DalekVerifier;
130    if messages.len() != signatures.len() || messages.len() != verifying_keys.len() {
131        return Err(CryptoError::BadInput);
132    }
133    for ((msg, sig), vk) in messages
134        .iter()
135        .zip(signatures.iter())
136        .zip(verifying_keys.iter())
137    {
138        vk.verify(msg, sig).map_err(|_| CryptoError::Sign)?;
139    }
140    Ok(())
141}
142
143// ── Trait-dispatched unit-struct wrappers ─────────────────────────────────────
144//
145// Each ECDSA / Ed448 / RSA algorithm gets a zero-size unit struct implementing
146// `Signer` and `Verifier` from `oxicrypto-core`.  These parse raw key bytes on
147// each call, matching the trait surface expected by the facade factory functions.
148// The existing stateful structs (`EcdsaP256Signer`, `RsaPkcs1v15Sha256Signer`,
149// etc.) remain available for callers who prefer a pre-parsed key.
150
151// ── ECDSA P-256 trait wrappers ───────────────────────────────────────────────
152
153/// ECDSA P-256 signing primitive (trait-dispatched).
154///
155/// `sign(sk, msg, sig_out)`: `sk` is 32-byte raw scalar, returns DER signature.
156///
157/// Note: `signature_len()` returns 72, the DER **maximum** length.  Actual DER
158/// signatures are variable-length (typically 70--72 bytes).  Callers should
159/// use the return value of `sign()` for the true written length.
160#[derive(Debug, Default, Clone, Copy)]
161pub struct EcdsaP256;
162
163impl Signer for EcdsaP256 {
164    fn name(&self) -> &'static str {
165        "ECDSA-P256"
166    }
167    fn signature_len(&self) -> usize {
168        72
169    } // DER max length; actual is variable
170    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
171        let signer = EcdsaP256Signer::from_bytes(sk)?;
172        let sig_bytes = signer.sign(msg)?;
173        if sig_out.len() < sig_bytes.len() {
174            return Err(CryptoError::BufferTooSmall);
175        }
176        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
177        Ok(sig_bytes.len())
178    }
179}
180
181/// ECDSA P-256 verification primitive (trait-dispatched).
182///
183/// `verify(pk, msg, sig)`: `pk` is SEC1-encoded (compressed 33 or uncompressed 65 bytes).
184#[derive(Debug, Default, Clone, Copy)]
185pub struct EcdsaP256Verify;
186
187impl Verifier for EcdsaP256Verify {
188    fn name(&self) -> &'static str {
189        "ECDSA-P256"
190    }
191    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
192        let verifier = EcdsaP256Verifier::from_sec1_bytes(pk)?;
193        verifier.verify(msg, sig)
194    }
195}
196
197// ── ECDSA P-384 trait wrappers ───────────────────────────────────────────────
198
199/// ECDSA P-384 signing primitive (trait-dispatched).
200#[derive(Debug, Default, Clone, Copy)]
201pub struct EcdsaP384;
202
203impl Signer for EcdsaP384 {
204    fn name(&self) -> &'static str {
205        "ECDSA-P384"
206    }
207    fn signature_len(&self) -> usize {
208        104
209    } // DER max length
210    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
211        let signer = EcdsaP384Signer::from_bytes(sk)?;
212        let sig_bytes = signer.sign(msg)?;
213        if sig_out.len() < sig_bytes.len() {
214            return Err(CryptoError::BufferTooSmall);
215        }
216        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
217        Ok(sig_bytes.len())
218    }
219}
220
221/// ECDSA P-384 verification primitive (trait-dispatched).
222#[derive(Debug, Default, Clone, Copy)]
223pub struct EcdsaP384Verify;
224
225impl Verifier for EcdsaP384Verify {
226    fn name(&self) -> &'static str {
227        "ECDSA-P384"
228    }
229    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
230        let verifier = EcdsaP384Verifier::from_sec1_bytes(pk)?;
231        verifier.verify(msg, sig)
232    }
233}
234
235// ── ECDSA P-521 trait wrappers ───────────────────────────────────────────────
236
237/// ECDSA P-521 signing primitive (trait-dispatched).
238#[derive(Debug, Default, Clone, Copy)]
239pub struct EcdsaP521;
240
241impl Signer for EcdsaP521 {
242    fn name(&self) -> &'static str {
243        "ECDSA-P521"
244    }
245    fn signature_len(&self) -> usize {
246        139
247    } // DER max length
248    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
249        let signer = EcdsaP521Signer::from_bytes(sk)?;
250        let sig_bytes = signer.sign(msg)?;
251        if sig_out.len() < sig_bytes.len() {
252            return Err(CryptoError::BufferTooSmall);
253        }
254        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
255        Ok(sig_bytes.len())
256    }
257}
258
259/// ECDSA P-521 verification primitive (trait-dispatched).
260#[derive(Debug, Default, Clone, Copy)]
261pub struct EcdsaP521Verify;
262
263impl Verifier for EcdsaP521Verify {
264    fn name(&self) -> &'static str {
265        "ECDSA-P521"
266    }
267    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
268        let verifier = EcdsaP521Verifier::from_sec1_bytes(pk)?;
269        verifier.verify(msg, sig)
270    }
271}
272
273// ── Ed448 trait wrappers ─────────────────────────────────────────────────────
274
275/// Ed448 signing primitive (trait-dispatched).
276///
277/// `sign(sk, msg, sig_out)`: `sk` is 57-byte raw seed, returns 114-byte signature.
278#[derive(Debug, Default, Clone, Copy)]
279pub struct Ed448;
280
281impl Signer for Ed448 {
282    fn name(&self) -> &'static str {
283        "Ed448"
284    }
285    fn signature_len(&self) -> usize {
286        114
287    }
288    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
289        if sig_out.len() < 114 {
290            return Err(CryptoError::BufferTooSmall);
291        }
292        let signer = Ed448SigningKey::from_bytes(sk)?;
293        let sig_bytes = signer.sign(msg)?;
294        sig_out[..114].copy_from_slice(&sig_bytes);
295        Ok(114)
296    }
297}
298
299/// Ed448 verification primitive (trait-dispatched).
300#[derive(Debug, Default, Clone, Copy)]
301pub struct Ed448Verify;
302
303impl Verifier for Ed448Verify {
304    fn name(&self) -> &'static str {
305        "Ed448"
306    }
307    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
308        let verifier = Ed448VerifyingKey::from_bytes(pk)?;
309        verifier.verify(msg, sig)
310    }
311}
312
313// ── RSA PKCS#1v15 SHA-256 trait wrappers ─────────────────────────────────────
314
315/// RSA PKCS#1v15 SHA-256 signing primitive (trait-dispatched).
316///
317/// `sign(sk, msg, sig_out)`: `sk` is DER-encoded PKCS#8 private key.
318#[derive(Debug, Default, Clone, Copy)]
319pub struct RsaPkcs1v15Sha256;
320
321impl Signer for RsaPkcs1v15Sha256 {
322    fn name(&self) -> &'static str {
323        "RSA-PKCS1v15-SHA256"
324    }
325    fn signature_len(&self) -> usize {
326        512
327    } // up to 4096-bit key = 512 bytes
328    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
329        let signer = RsaPkcs1v15Sha256Signer::from_pkcs8_der(sk)?;
330        let sig_bytes = signer.sign(msg)?;
331        if sig_out.len() < sig_bytes.len() {
332            return Err(CryptoError::BufferTooSmall);
333        }
334        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
335        Ok(sig_bytes.len())
336    }
337}
338
339/// RSA PKCS#1v15 SHA-256 verification primitive (trait-dispatched).
340///
341/// `verify(pk, msg, sig)`: `pk` is DER-encoded SubjectPublicKeyInfo.
342#[derive(Debug, Default, Clone, Copy)]
343pub struct RsaPkcs1v15Sha256Verify;
344
345impl Verifier for RsaPkcs1v15Sha256Verify {
346    fn name(&self) -> &'static str {
347        "RSA-PKCS1v15-SHA256"
348    }
349    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
350        let verifier = RsaPkcs1v15Sha256Verifier::from_spki_der(pk)?;
351        verifier.verify(msg, sig)
352    }
353}
354
355// ── RSA PKCS#1v15 SHA-384 trait wrappers ─────────────────────────────────────
356
357/// RSA PKCS#1v15 SHA-384 signing primitive (trait-dispatched).
358#[derive(Debug, Default, Clone, Copy)]
359pub struct RsaPkcs1v15Sha384;
360
361impl Signer for RsaPkcs1v15Sha384 {
362    fn name(&self) -> &'static str {
363        "RSA-PKCS1v15-SHA384"
364    }
365    fn signature_len(&self) -> usize {
366        512
367    }
368    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
369        let signer = RsaPkcs1v15Sha384Signer::from_pkcs8_der(sk)?;
370        let sig_bytes = signer.sign(msg)?;
371        if sig_out.len() < sig_bytes.len() {
372            return Err(CryptoError::BufferTooSmall);
373        }
374        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
375        Ok(sig_bytes.len())
376    }
377}
378
379/// RSA PKCS#1v15 SHA-384 verification primitive (trait-dispatched).
380#[derive(Debug, Default, Clone, Copy)]
381pub struct RsaPkcs1v15Sha384Verify;
382
383impl Verifier for RsaPkcs1v15Sha384Verify {
384    fn name(&self) -> &'static str {
385        "RSA-PKCS1v15-SHA384"
386    }
387    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
388        let verifier = RsaPkcs1v15Sha384Verifier::from_spki_der(pk)?;
389        verifier.verify(msg, sig)
390    }
391}
392
393// ── RSA PKCS#1v15 SHA-512 trait wrappers ─────────────────────────────────────
394
395/// RSA PKCS#1v15 SHA-512 signing primitive (trait-dispatched).
396#[derive(Debug, Default, Clone, Copy)]
397pub struct RsaPkcs1v15Sha512;
398
399impl Signer for RsaPkcs1v15Sha512 {
400    fn name(&self) -> &'static str {
401        "RSA-PKCS1v15-SHA512"
402    }
403    fn signature_len(&self) -> usize {
404        512
405    }
406    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
407        let signer = RsaPkcs1v15Sha512Signer::from_pkcs8_der(sk)?;
408        let sig_bytes = signer.sign(msg)?;
409        if sig_out.len() < sig_bytes.len() {
410            return Err(CryptoError::BufferTooSmall);
411        }
412        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
413        Ok(sig_bytes.len())
414    }
415}
416
417/// RSA PKCS#1v15 SHA-512 verification primitive (trait-dispatched).
418#[derive(Debug, Default, Clone, Copy)]
419pub struct RsaPkcs1v15Sha512Verify;
420
421impl Verifier for RsaPkcs1v15Sha512Verify {
422    fn name(&self) -> &'static str {
423        "RSA-PKCS1v15-SHA512"
424    }
425    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
426        let verifier = RsaPkcs1v15Sha512Verifier::from_spki_der(pk)?;
427        verifier.verify(msg, sig)
428    }
429}
430
431// ── RSA-PSS SHA-256 trait wrappers ───────────────────────────────────────────
432
433/// RSA-PSS SHA-256 signing primitive (trait-dispatched).
434#[derive(Debug, Default, Clone, Copy)]
435pub struct RsaPssSha256;
436
437impl Signer for RsaPssSha256 {
438    fn name(&self) -> &'static str {
439        "RSA-PSS-SHA256"
440    }
441    fn signature_len(&self) -> usize {
442        512
443    }
444    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
445        let signer = RsaPssSha256Signer::from_pkcs8_der(sk)?;
446        let sig_bytes = signer.sign(msg)?;
447        if sig_out.len() < sig_bytes.len() {
448            return Err(CryptoError::BufferTooSmall);
449        }
450        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
451        Ok(sig_bytes.len())
452    }
453}
454
455/// RSA-PSS SHA-256 verification primitive (trait-dispatched).
456#[derive(Debug, Default, Clone, Copy)]
457pub struct RsaPssSha256Verify;
458
459impl Verifier for RsaPssSha256Verify {
460    fn name(&self) -> &'static str {
461        "RSA-PSS-SHA256"
462    }
463    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
464        let verifier = RsaPssSha256Verifier::from_spki_der(pk)?;
465        verifier.verify(msg, sig)
466    }
467}
468
469// ── RSA-PSS SHA-384 trait wrappers ───────────────────────────────────────────
470
471/// RSA-PSS SHA-384 signing primitive (trait-dispatched).
472#[derive(Debug, Default, Clone, Copy)]
473pub struct RsaPssSha384;
474
475impl Signer for RsaPssSha384 {
476    fn name(&self) -> &'static str {
477        "RSA-PSS-SHA384"
478    }
479    fn signature_len(&self) -> usize {
480        512
481    }
482    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
483        let signer = RsaPssSha384Signer::from_pkcs8_der(sk)?;
484        let sig_bytes = signer.sign(msg)?;
485        if sig_out.len() < sig_bytes.len() {
486            return Err(CryptoError::BufferTooSmall);
487        }
488        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
489        Ok(sig_bytes.len())
490    }
491}
492
493/// RSA-PSS SHA-384 verification primitive (trait-dispatched).
494#[derive(Debug, Default, Clone, Copy)]
495pub struct RsaPssSha384Verify;
496
497impl Verifier for RsaPssSha384Verify {
498    fn name(&self) -> &'static str {
499        "RSA-PSS-SHA384"
500    }
501    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
502        let verifier = RsaPssSha384Verifier::from_spki_der(pk)?;
503        verifier.verify(msg, sig)
504    }
505}
506
507// ── RSA-PSS SHA-512 trait wrappers ───────────────────────────────────────────
508
509/// RSA-PSS SHA-512 signing primitive (trait-dispatched).
510#[derive(Debug, Default, Clone, Copy)]
511pub struct RsaPssSha512;
512
513impl Signer for RsaPssSha512 {
514    fn name(&self) -> &'static str {
515        "RSA-PSS-SHA512"
516    }
517    fn signature_len(&self) -> usize {
518        512
519    }
520    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
521        let signer = RsaPssSha512Signer::from_pkcs8_der(sk)?;
522        let sig_bytes = signer.sign(msg)?;
523        if sig_out.len() < sig_bytes.len() {
524            return Err(CryptoError::BufferTooSmall);
525        }
526        sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
527        Ok(sig_bytes.len())
528    }
529}
530
531/// RSA-PSS SHA-512 verification primitive (trait-dispatched).
532#[derive(Debug, Default, Clone, Copy)]
533pub struct RsaPssSha512Verify;
534
535impl Verifier for RsaPssSha512Verify {
536    fn name(&self) -> &'static str {
537        "RSA-PSS-SHA512"
538    }
539    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
540        let verifier = RsaPssSha512Verifier::from_spki_der(pk)?;
541        verifier.verify(msg, sig)
542    }
543}
544
545/// Ed25519 signing primitive.
546///
547/// `sign(sk, msg, sig_out)` — `sk` must be 32 bytes (the raw seed / secret scalar).
548/// `sig_out` must be at least 64 bytes; returns 64.
549#[derive(Debug, Default, Clone, Copy)]
550pub struct Ed25519;
551
552impl Signer for Ed25519 {
553    fn name(&self) -> &'static str {
554        "Ed25519"
555    }
556    fn signature_len(&self) -> usize {
557        64
558    }
559    fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
560        if sig_out.len() < 64 {
561            return Err(CryptoError::BufferTooSmall);
562        }
563        let sk_bytes: &[u8; 32] = sk.try_into().map_err(|_| CryptoError::InvalidKey)?;
564        let signing_key = SigningKey::from_bytes(sk_bytes);
565
566        use ed25519_dalek::Signer as DalekSigner;
567        let signature: Signature = signing_key.sign(msg);
568        sig_out[..64].copy_from_slice(&signature.to_bytes());
569        Ok(64)
570    }
571}
572
573/// Ed25519 verification primitive.
574///
575/// `verify(pk, msg, sig)` — `pk` must be 32 bytes (compressed Edwards-y point).
576/// `sig` must be 64 bytes.
577#[derive(Debug, Default, Clone, Copy)]
578pub struct Ed25519Verifier;
579
580impl Verifier for Ed25519Verifier {
581    fn name(&self) -> &'static str {
582        "Ed25519"
583    }
584    fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
585        let pk_bytes: &[u8; 32] = pk.try_into().map_err(|_| CryptoError::InvalidKey)?;
586        let sig_bytes: &[u8; 64] = sig.try_into().map_err(|_| CryptoError::InvalidTag)?;
587
588        let verifying_key =
589            VerifyingKey::from_bytes(pk_bytes).map_err(|_| CryptoError::InvalidKey)?;
590        let signature = Signature::from_bytes(sig_bytes);
591
592        use ed25519_dalek::Verifier as DalekVerifier;
593        verifying_key
594            .verify(msg, &signature)
595            .map_err(|_| CryptoError::InvalidTag)
596    }
597}
598
599#[cfg(test)]
600mod tests {
601    use super::*;
602    use rand_chacha::ChaCha20Rng;
603    use rand_core::SeedableRng;
604
605    fn keypair_seed() -> ([u8; 32], [u8; 32]) {
606        // Deterministic seed for tests.
607        let seed = [0x5au8; 32];
608        let signing_key = SigningKey::from_bytes(&seed);
609        let pk = signing_key.verifying_key().to_bytes();
610        (seed, pk)
611    }
612
613    fn test_rng() -> ChaCha20Rng {
614        ChaCha20Rng::from_seed([42u8; 32])
615    }
616
617    #[test]
618    fn ed25519_sign_verify_round_trip() {
619        let signer = Ed25519;
620        let verifier = Ed25519Verifier;
621        let (sk, pk) = keypair_seed();
622        let msg = b"test message for oxicrypto";
623
624        let mut sig = [0u8; 64];
625        let len = signer.sign(&sk, msg, &mut sig).expect("sign failed");
626        assert_eq!(len, 64);
627        verifier
628            .verify(&pk, msg, &sig)
629            .expect("verify should succeed");
630    }
631
632    #[test]
633    fn ed25519_corrupted_sig_fails() {
634        let signer = Ed25519;
635        let verifier = Ed25519Verifier;
636        let (sk, pk) = keypair_seed();
637        let msg = b"another test message";
638
639        let mut sig = [0u8; 64];
640        signer.sign(&sk, msg, &mut sig).expect("sign failed");
641        // Corrupt the signature
642        sig[0] ^= 0xff;
643
644        let result = verifier.verify(&pk, msg, &sig);
645        assert_eq!(result, Err(CryptoError::InvalidTag));
646    }
647
648    #[test]
649    fn ed25519_wrong_key_fails() {
650        let signer = Ed25519;
651        let verifier = Ed25519Verifier;
652        let (sk, _pk) = keypair_seed();
653        // Different key pair for verification
654        let other_seed = [0xabu8; 32];
655        let other_sk = SigningKey::from_bytes(&other_seed);
656        let other_pk = other_sk.verifying_key().to_bytes();
657
658        let msg = b"message signed with sk";
659        let mut sig = [0u8; 64];
660        signer.sign(&sk, msg, &mut sig).expect("sign failed");
661
662        let result = verifier.verify(&other_pk, msg, &sig);
663        assert_eq!(result, Err(CryptoError::InvalidTag));
664    }
665
666    #[test]
667    fn ed25519_invalid_sk_length_errors() {
668        let signer = Ed25519;
669        let msg = b"msg";
670        let mut sig = [0u8; 64];
671        let result = signer.sign(&[0u8; 16], msg, &mut sig);
672        assert_eq!(result, Err(CryptoError::InvalidKey));
673    }
674
675    // ── Ed25519 key generation ────────────────────────────────────────────────
676
677    #[test]
678    fn ed25519_keygen_sign_verify() {
679        let mut rng = test_rng();
680        let (sk_secret, pk_bytes) =
681            ed25519_generate_keypair(&mut rng).expect("ed25519 keygen failed");
682
683        let msg = b"hello from ed25519 keygen test";
684        let signer = Ed25519;
685        let verifier = Ed25519Verifier;
686
687        let mut sig_buf = [0u8; 64];
688        let len = signer
689            .sign(sk_secret.as_bytes(), msg, &mut sig_buf)
690            .expect("sign failed");
691        assert_eq!(len, 64);
692        verifier
693            .verify(&pk_bytes, msg, &sig_buf)
694            .expect("verify failed");
695    }
696
697    // ── ECDSA key generation ──────────────────────────────────────────────────
698
699    #[test]
700    fn ecdsa_p256_keygen_sign_verify() {
701        let mut rng = test_rng();
702        let (sk_secret, pk_bytes) =
703            ecdsa_p256_generate_keypair(&mut rng).expect("p256 keygen failed");
704
705        let msg = b"hello from p256 keygen test";
706        let signer_struct =
707            EcdsaP256Signer::from_bytes(sk_secret.as_bytes()).expect("p256 signer from bytes");
708        let sig_bytes = signer_struct.sign(msg).expect("p256 sign failed");
709
710        let verifier_struct =
711            EcdsaP256Verifier::from_sec1_bytes(&pk_bytes).expect("p256 verifier from sec1");
712        verifier_struct
713            .verify(msg, &sig_bytes)
714            .expect("p256 verify failed");
715    }
716
717    #[test]
718    fn ecdsa_p384_keygen_sign_verify() {
719        let mut rng = test_rng();
720        let (sk_secret, pk_bytes) =
721            ecdsa_p384_generate_keypair(&mut rng).expect("p384 keygen failed");
722
723        let msg = b"hello from p384 keygen test";
724        let signer_struct =
725            EcdsaP384Signer::from_bytes(sk_secret.as_bytes()).expect("p384 signer from bytes");
726        let sig_bytes = signer_struct.sign(msg).expect("p384 sign failed");
727
728        let verifier_struct =
729            EcdsaP384Verifier::from_sec1_bytes(&pk_bytes).expect("p384 verifier from sec1");
730        verifier_struct
731            .verify(msg, &sig_bytes)
732            .expect("p384 verify failed");
733    }
734
735    #[test]
736    fn ecdsa_p521_keygen_sign_verify() {
737        let mut rng = test_rng();
738        let (sk_secret, pk_bytes) =
739            ecdsa_p521_generate_keypair(&mut rng).expect("p521 keygen failed");
740
741        let msg = b"hello from p521 keygen test";
742        let signer_struct =
743            EcdsaP521Signer::from_bytes(sk_secret.as_bytes()).expect("p521 signer from bytes");
744        let sig_bytes = signer_struct.sign(msg).expect("p521 sign failed");
745
746        let verifier_struct =
747            EcdsaP521Verifier::from_sec1_bytes(&pk_bytes).expect("p521 verifier from sec1");
748        verifier_struct
749            .verify(msg, &sig_bytes)
750            .expect("p521 verify failed");
751    }
752
753    // ── Ed25519 batch verification ────────────────────────────────────────────
754
755    #[test]
756    fn ed25519_batch_verify_all_valid() {
757        use ed25519_dalek::Signer as DalekSigner;
758        let seeds: [[u8; 32]; 5] = [[0x01; 32], [0x02; 32], [0x03; 32], [0x04; 32], [0x05; 32]];
759        let signing_keys: Vec<SigningKey> = seeds.iter().map(SigningKey::from_bytes).collect();
760        let verifying_keys: Vec<VerifyingKey> =
761            signing_keys.iter().map(|sk| sk.verifying_key()).collect();
762
763        let messages: [&[u8]; 5] = [b"msg1", b"msg2", b"msg3", b"msg4", b"msg5"];
764        let signatures: Vec<Signature> = signing_keys
765            .iter()
766            .zip(messages.iter())
767            .map(|(sk, msg)| sk.sign(msg))
768            .collect();
769
770        let msg_refs: Vec<&[u8]> = messages.to_vec();
771        ed25519_verify_batch(&msg_refs, &signatures, &verifying_keys)
772            .expect("batch verify of 5 valid sigs should succeed");
773    }
774
775    #[test]
776    fn ed25519_batch_verify_one_tampered() {
777        use ed25519_dalek::Signer as DalekSigner;
778        let seeds: [[u8; 32]; 3] = [[0x11; 32], [0x22; 32], [0x33; 32]];
779        let signing_keys: Vec<SigningKey> = seeds.iter().map(SigningKey::from_bytes).collect();
780        let verifying_keys: Vec<VerifyingKey> =
781            signing_keys.iter().map(|sk| sk.verifying_key()).collect();
782
783        let messages: [&[u8]; 3] = [b"alpha", b"beta", b"gamma"];
784        let mut signatures: Vec<Signature> = signing_keys
785            .iter()
786            .zip(messages.iter())
787            .map(|(sk, msg)| sk.sign(msg))
788            .collect();
789
790        // Tamper the second signature
791        let mut tampered_bytes = signatures[1].to_bytes();
792        tampered_bytes[0] ^= 0xff;
793        signatures[1] = Signature::from_bytes(&tampered_bytes);
794
795        let msg_refs: Vec<&[u8]> = messages.to_vec();
796        let result = ed25519_verify_batch(&msg_refs, &signatures, &verifying_keys);
797        assert!(
798            result.is_err(),
799            "batch verify with tampered sig should fail"
800        );
801    }
802
803    #[test]
804    fn ed25519_batch_verify_empty() {
805        let result = ed25519_verify_batch(&[], &[], &[]);
806        assert!(result.is_ok(), "empty batch should succeed");
807    }
808
809    #[test]
810    fn ed25519_batch_verify_mismatched_lengths() {
811        let seed = [0x99u8; 32];
812        let sk = SigningKey::from_bytes(&seed);
813        use ed25519_dalek::Signer as DalekSigner;
814        let sig = sk.sign(b"test");
815        let vk = sk.verifying_key();
816
817        // messages.len() != signatures.len()
818        let result = ed25519_verify_batch(&[b"test", b"extra"], &[sig], &[vk]);
819        assert_eq!(result, Err(CryptoError::BadInput));
820    }
821}