chie_crypto/
signing.rs

1//! Digital signatures using Ed25519.
2
3use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
4use thiserror::Error;
5use zeroize::ZeroizeOnDrop;
6
7/// Secret key for signing (32 bytes).
8pub type SecretKey = [u8; 32];
9
10/// Public key for verification (32 bytes).
11pub type PublicKey = [u8; 32];
12
13/// Signature (64 bytes).
14pub type SignatureBytes = [u8; 64];
15
16#[derive(Debug, Error)]
17pub enum SigningError {
18    #[error("Invalid secret key")]
19    InvalidSecretKey,
20
21    #[error("Invalid public key")]
22    InvalidPublicKey,
23
24    #[error("Invalid signature")]
25    InvalidSignature,
26
27    #[error("Signature verification failed")]
28    VerificationFailed,
29}
30
31/// Key pair for signing and verification.
32///
33/// The secret key material is automatically zeroized when dropped.
34#[derive(ZeroizeOnDrop)]
35pub struct KeyPair {
36    signing_key: SigningKey,
37}
38
39impl Clone for KeyPair {
40    fn clone(&self) -> Self {
41        // Clone by reconstructing from secret key bytes
42        let secret = self.signing_key.to_bytes();
43        Self {
44            signing_key: SigningKey::from_bytes(&secret),
45        }
46    }
47}
48
49impl KeyPair {
50    /// Generate a new random key pair.
51    pub fn generate() -> Self {
52        let mut secret = [0u8; 32];
53        getrandom::fill(&mut secret).expect("Failed to generate random bytes");
54        let signing_key = SigningKey::from_bytes(&secret);
55        Self { signing_key }
56    }
57
58    /// Create a key pair from a secret key.
59    pub fn from_secret_key(secret: &SecretKey) -> Result<Self, SigningError> {
60        let signing_key = SigningKey::from_bytes(secret);
61        Ok(Self { signing_key })
62    }
63
64    /// Get the secret key bytes.
65    pub fn secret_key(&self) -> SecretKey {
66        self.signing_key.to_bytes()
67    }
68
69    /// Get the public key bytes.
70    pub fn public_key(&self) -> PublicKey {
71        self.signing_key.verifying_key().to_bytes()
72    }
73
74    /// Sign a message.
75    pub fn sign(&self, message: &[u8]) -> SignatureBytes {
76        let signature = self.signing_key.sign(message);
77        signature.to_bytes()
78    }
79
80    /// Verify a signature using this keypair's public key.
81    pub fn verify(&self, message: &[u8], signature: &[u8]) -> bool {
82        if signature.len() != 64 {
83            return false;
84        }
85        let mut sig_bytes = [0u8; 64];
86        sig_bytes.copy_from_slice(signature);
87        verify(&self.public_key(), message, &sig_bytes).is_ok()
88    }
89}
90
91/// Verify a signature.
92pub fn verify(
93    public_key: &PublicKey,
94    message: &[u8],
95    signature: &SignatureBytes,
96) -> Result<(), SigningError> {
97    let verifying_key =
98        VerifyingKey::from_bytes(public_key).map_err(|_| SigningError::InvalidPublicKey)?;
99
100    let signature = Signature::from_bytes(signature);
101
102    verifying_key
103        .verify(message, &signature)
104        .map_err(|_| SigningError::VerificationFailed)
105}
106
107/// Item for batch verification.
108#[derive(Debug, Clone)]
109pub struct BatchVerifyItem {
110    /// Public key for verification.
111    pub public_key: PublicKey,
112    /// Message that was signed.
113    pub message: Vec<u8>,
114    /// Signature to verify.
115    pub signature: SignatureBytes,
116}
117
118impl BatchVerifyItem {
119    /// Create a new batch verification item.
120    pub fn new(public_key: PublicKey, message: Vec<u8>, signature: SignatureBytes) -> Self {
121        Self {
122            public_key,
123            message,
124            signature,
125        }
126    }
127}
128
129/// Result of batch verification.
130#[derive(Debug, Clone)]
131pub struct BatchVerifyResult {
132    /// Total items verified.
133    pub total: usize,
134    /// Number of valid signatures.
135    pub valid_count: usize,
136    /// Number of invalid signatures.
137    pub invalid_count: usize,
138    /// Indices of invalid signatures (if tracking enabled).
139    pub invalid_indices: Vec<usize>,
140    /// Whether all signatures are valid.
141    pub all_valid: bool,
142}
143
144/// Verify multiple signatures in batch.
145///
146/// This is more efficient than verifying signatures individually as it can
147/// use batch verification optimizations. However, if any signature is invalid,
148/// it falls back to individual verification to identify which ones failed.
149pub fn verify_batch(items: &[BatchVerifyItem]) -> Result<BatchVerifyResult, SigningError> {
150    if items.is_empty() {
151        return Ok(BatchVerifyResult {
152            total: 0,
153            valid_count: 0,
154            invalid_count: 0,
155            invalid_indices: vec![],
156            all_valid: true,
157        });
158    }
159
160    // Prepare vectors for batch verification
161    let mut verifying_keys = Vec::with_capacity(items.len());
162    let mut signatures = Vec::with_capacity(items.len());
163    let messages: Vec<&[u8]> = items.iter().map(|item| item.message.as_slice()).collect();
164
165    for item in items {
166        let vk = VerifyingKey::from_bytes(&item.public_key)
167            .map_err(|_| SigningError::InvalidPublicKey)?;
168        let sig = Signature::from_bytes(&item.signature);
169        verifying_keys.push(vk);
170        signatures.push(sig);
171    }
172
173    // Try batch verification first
174    let batch_result = ed25519_dalek::verify_batch(&messages, &signatures, &verifying_keys);
175
176    if batch_result.is_ok() {
177        // All signatures valid
178        return Ok(BatchVerifyResult {
179            total: items.len(),
180            valid_count: items.len(),
181            invalid_count: 0,
182            invalid_indices: vec![],
183            all_valid: true,
184        });
185    }
186
187    // Batch failed - verify individually to find which ones failed
188    let mut invalid_indices = Vec::new();
189    let mut valid_count = 0;
190
191    for (i, item) in items.iter().enumerate() {
192        match verify(&item.public_key, &item.message, &item.signature) {
193            Ok(()) => valid_count += 1,
194            Err(_) => invalid_indices.push(i),
195        }
196    }
197
198    Ok(BatchVerifyResult {
199        total: items.len(),
200        valid_count,
201        invalid_count: invalid_indices.len(),
202        invalid_indices,
203        all_valid: false,
204    })
205}
206
207/// Verify multiple signatures, returning only success/failure.
208///
209/// This is a faster version that doesn't track which signatures failed.
210pub fn verify_batch_fast(items: &[BatchVerifyItem]) -> bool {
211    if items.is_empty() {
212        return true;
213    }
214
215    // Prepare vectors for batch verification
216    let mut verifying_keys = Vec::with_capacity(items.len());
217    let mut signatures = Vec::with_capacity(items.len());
218    let messages: Vec<&[u8]> = items.iter().map(|item| item.message.as_slice()).collect();
219
220    for item in items {
221        match VerifyingKey::from_bytes(&item.public_key) {
222            Ok(vk) => verifying_keys.push(vk),
223            Err(_) => return false,
224        }
225        signatures.push(Signature::from_bytes(&item.signature));
226    }
227
228    ed25519_dalek::verify_batch(&messages, &signatures, &verifying_keys).is_ok()
229}
230
231/// Verify dual signatures (provider + requester) common in CHIE Protocol.
232pub fn verify_dual_signatures(
233    provider_pubkey: &PublicKey,
234    requester_pubkey: &PublicKey,
235    provider_message: &[u8],
236    requester_message: &[u8],
237    provider_signature: &SignatureBytes,
238    requester_signature: &SignatureBytes,
239) -> Result<(), SigningError> {
240    let items = vec![
241        BatchVerifyItem::new(
242            *provider_pubkey,
243            provider_message.to_vec(),
244            *provider_signature,
245        ),
246        BatchVerifyItem::new(
247            *requester_pubkey,
248            requester_message.to_vec(),
249            *requester_signature,
250        ),
251    ];
252
253    let result = verify_batch(&items)?;
254    if result.all_valid {
255        Ok(())
256    } else {
257        Err(SigningError::VerificationFailed)
258    }
259}
260
261#[cfg(test)]
262mod tests {
263    use super::*;
264
265    #[test]
266    fn test_sign_verify() {
267        let keypair = KeyPair::generate();
268        let message = b"Hello, CHIE Protocol!";
269
270        let signature = keypair.sign(message);
271        let public_key = keypair.public_key();
272
273        assert!(verify(&public_key, message, &signature).is_ok());
274        assert!(verify(&public_key, b"Wrong message", &signature).is_err());
275    }
276
277    #[test]
278    fn test_keypair_from_secret() {
279        let keypair1 = KeyPair::generate();
280        let secret = keypair1.secret_key();
281        let keypair2 = KeyPair::from_secret_key(&secret).unwrap();
282
283        assert_eq!(keypair1.public_key(), keypair2.public_key());
284    }
285
286    #[test]
287    fn test_verify_with_wrong_public_key() {
288        let keypair1 = KeyPair::generate();
289        let keypair2 = KeyPair::generate();
290        let message = b"Test message";
291
292        let signature = keypair1.sign(message);
293        let wrong_pubkey = keypair2.public_key();
294
295        let result = verify(&wrong_pubkey, message, &signature);
296        assert!(result.is_err());
297        assert!(matches!(result, Err(SigningError::VerificationFailed)));
298    }
299
300    #[test]
301    fn test_invalid_signature_format() {
302        let keypair = KeyPair::generate();
303        let message = b"Test message";
304
305        let mut signature = keypair.sign(message);
306        // Corrupt the signature
307        signature[0] ^= 0xFF;
308
309        let result = verify(&keypair.public_key(), message, &signature);
310        assert!(result.is_err());
311        assert!(matches!(result, Err(SigningError::VerificationFailed)));
312    }
313
314    #[test]
315    fn test_keypair_verify_method() {
316        let keypair = KeyPair::generate();
317        let message = b"Test message";
318
319        let signature = keypair.sign(message);
320        assert!(keypair.verify(message, &signature));
321        assert!(!keypair.verify(b"Wrong message", &signature));
322    }
323
324    #[test]
325    fn test_keypair_verify_invalid_signature_length() {
326        let keypair = KeyPair::generate();
327        let message = b"Test message";
328
329        // Too short signature
330        let short_sig = [0u8; 32];
331        assert!(!keypair.verify(message, &short_sig));
332
333        // Too long signature
334        let long_sig = [0u8; 96];
335        assert!(!keypair.verify(message, &long_sig));
336    }
337
338    #[test]
339    fn test_batch_verify_all_valid() {
340        let mut items = Vec::new();
341        for _ in 0..10 {
342            let keypair = KeyPair::generate();
343            let message = b"Test message";
344            let signature = keypair.sign(message);
345            items.push(BatchVerifyItem::new(
346                keypair.public_key(),
347                message.to_vec(),
348                signature,
349            ));
350        }
351
352        let result = verify_batch(&items).unwrap();
353        assert_eq!(result.total, 10);
354        assert_eq!(result.valid_count, 10);
355        assert_eq!(result.invalid_count, 0);
356        assert!(result.all_valid);
357        assert!(result.invalid_indices.is_empty());
358    }
359
360    #[test]
361    fn test_batch_verify_some_invalid() {
362        let mut items = Vec::new();
363
364        // Add 5 valid signatures
365        for _ in 0..5 {
366            let keypair = KeyPair::generate();
367            let message = b"Valid message";
368            let signature = keypair.sign(message);
369            items.push(BatchVerifyItem::new(
370                keypair.public_key(),
371                message.to_vec(),
372                signature,
373            ));
374        }
375
376        // Add 3 invalid signatures
377        for _ in 0..3 {
378            let keypair = KeyPair::generate();
379            let message = b"Original message";
380            let signature = keypair.sign(message);
381            items.push(BatchVerifyItem::new(
382                keypair.public_key(),
383                b"Different message".to_vec(), // Wrong message!
384                signature,
385            ));
386        }
387
388        let result = verify_batch(&items).unwrap();
389        assert_eq!(result.total, 8);
390        assert_eq!(result.valid_count, 5);
391        assert_eq!(result.invalid_count, 3);
392        assert!(!result.all_valid);
393        assert_eq!(result.invalid_indices, vec![5, 6, 7]);
394    }
395
396    #[test]
397    fn test_batch_verify_empty() {
398        let items = vec![];
399        let result = verify_batch(&items).unwrap();
400        assert_eq!(result.total, 0);
401        assert_eq!(result.valid_count, 0);
402        assert_eq!(result.invalid_count, 0);
403        assert!(result.all_valid);
404    }
405
406    #[test]
407    fn test_batch_verify_fast_all_valid() {
408        let mut items = Vec::new();
409        for _ in 0..10 {
410            let keypair = KeyPair::generate();
411            let message = b"Test message";
412            let signature = keypair.sign(message);
413            items.push(BatchVerifyItem::new(
414                keypair.public_key(),
415                message.to_vec(),
416                signature,
417            ));
418        }
419
420        assert!(verify_batch_fast(&items));
421    }
422
423    #[test]
424    fn test_batch_verify_fast_one_invalid() {
425        let mut items = Vec::new();
426
427        // Add valid signatures
428        for _ in 0..5 {
429            let keypair = KeyPair::generate();
430            let message = b"Valid message";
431            let signature = keypair.sign(message);
432            items.push(BatchVerifyItem::new(
433                keypair.public_key(),
434                message.to_vec(),
435                signature,
436            ));
437        }
438
439        // Add one invalid signature
440        let keypair = KeyPair::generate();
441        let signature = keypair.sign(b"Original");
442        items.push(BatchVerifyItem::new(
443            keypair.public_key(),
444            b"Modified".to_vec(),
445            signature,
446        ));
447
448        assert!(!verify_batch_fast(&items));
449    }
450
451    #[test]
452    fn test_batch_verify_fast_empty() {
453        let items = vec![];
454        assert!(verify_batch_fast(&items));
455    }
456
457    #[test]
458    fn test_dual_signatures_valid() {
459        let provider = KeyPair::generate();
460        let requester = KeyPair::generate();
461
462        let provider_msg = b"Provider proof";
463        let requester_msg = b"Requester proof";
464
465        let provider_sig = provider.sign(provider_msg);
466        let requester_sig = requester.sign(requester_msg);
467
468        let result = verify_dual_signatures(
469            &provider.public_key(),
470            &requester.public_key(),
471            provider_msg,
472            requester_msg,
473            &provider_sig,
474            &requester_sig,
475        );
476
477        assert!(result.is_ok());
478    }
479
480    #[test]
481    fn test_dual_signatures_invalid_provider() {
482        let provider = KeyPair::generate();
483        let requester = KeyPair::generate();
484
485        let provider_msg = b"Provider proof";
486        let requester_msg = b"Requester proof";
487
488        let provider_sig = provider.sign(b"Wrong message");
489        let requester_sig = requester.sign(requester_msg);
490
491        let result = verify_dual_signatures(
492            &provider.public_key(),
493            &requester.public_key(),
494            provider_msg,
495            requester_msg,
496            &provider_sig,
497            &requester_sig,
498        );
499
500        assert!(result.is_err());
501        assert!(matches!(result, Err(SigningError::VerificationFailed)));
502    }
503
504    #[test]
505    fn test_dual_signatures_invalid_requester() {
506        let provider = KeyPair::generate();
507        let requester = KeyPair::generate();
508
509        let provider_msg = b"Provider proof";
510        let requester_msg = b"Requester proof";
511
512        let provider_sig = provider.sign(provider_msg);
513        let requester_sig = requester.sign(b"Wrong message");
514
515        let result = verify_dual_signatures(
516            &provider.public_key(),
517            &requester.public_key(),
518            provider_msg,
519            requester_msg,
520            &provider_sig,
521            &requester_sig,
522        );
523
524        assert!(result.is_err());
525        assert!(matches!(result, Err(SigningError::VerificationFailed)));
526    }
527
528    #[test]
529    fn test_keypair_clone() {
530        let keypair1 = KeyPair::generate();
531        let keypair2 = keypair1.clone();
532
533        let message = b"Test message";
534        let sig1 = keypair1.sign(message);
535        let sig2 = keypair2.sign(message);
536
537        // Both signatures should be valid with either public key
538        assert!(verify(&keypair1.public_key(), message, &sig1).is_ok());
539        assert!(verify(&keypair2.public_key(), message, &sig2).is_ok());
540        assert!(verify(&keypair1.public_key(), message, &sig2).is_ok());
541        assert!(verify(&keypair2.public_key(), message, &sig1).is_ok());
542
543        // Public keys should be identical
544        assert_eq!(keypair1.public_key(), keypair2.public_key());
545    }
546
547    #[test]
548    fn test_signature_determinism() {
549        let keypair = KeyPair::generate();
550        let message = b"Deterministic test";
551
552        let sig1 = keypair.sign(message);
553        let sig2 = keypair.sign(message);
554
555        // Ed25519 signatures are deterministic
556        assert_eq!(sig1, sig2);
557    }
558
559    #[test]
560    fn test_different_messages_different_signatures() {
561        let keypair = KeyPair::generate();
562        let message1 = b"First message";
563        let message2 = b"Second message";
564
565        let sig1 = keypair.sign(message1);
566        let sig2 = keypair.sign(message2);
567
568        assert_ne!(sig1, sig2);
569    }
570
571    #[test]
572    fn test_keypair_generation_randomness() {
573        let keypair1 = KeyPair::generate();
574        let keypair2 = KeyPair::generate();
575        let keypair3 = KeyPair::generate();
576
577        // All keypairs should have different public keys
578        assert_ne!(keypair1.public_key(), keypair2.public_key());
579        assert_ne!(keypair2.public_key(), keypair3.public_key());
580        assert_ne!(keypair1.public_key(), keypair3.public_key());
581    }
582}