/ core / src / crypto / keys.rs
keys.rs
  1  //! Key types and generation for Dead Drop.
  2  //!
  3  //! This module defines the key types used throughout the protocol. Each key type
  4  //! serves a specific purpose in the cryptographic design:
  5  //!
  6  //! # Key Types
  7  //!
  8  //! | Type | Algorithm | Purpose | Lifetime |
  9  //! |------|-----------|---------|----------|
 10  //! | [`IdentityKeyPair`] | Ed25519 | Signing, identity | Long-term (device lifetime) |
 11  //! | [`ExchangeKeyPair`] | X25519 | Key agreement | Long-term (device lifetime) |
 12  //! | [`EphemeralKeyPair`] | X25519 | Per-message encryption | Single use |
 13  //! | [`ContactPublicKeys`] | Both | Storing contact info | N/A (public only) |
 14  //!
 15  //! # Key Separation
 16  //!
 17  //! We use separate keys for signing and encryption because:
 18  //!
 19  //! 1. **Algorithm differences**: Ed25519 is optimized for signing, X25519 for DH
 20  //! 2. **Security isolation**: Compromise of one doesn't affect the other
 21  //! 3. **Key rotation**: Exchange keys can be rotated without changing identity
 22  //!
 23  //! # Memory Safety
 24  //!
 25  //! All secret key types implement `Zeroize` and `ZeroizeOnDrop` to ensure
 26  //! sensitive material is securely erased from memory when no longer needed.
 27  //! The Rust compiler cannot optimize away these zeroization operations.
 28  //!
 29  //! # Serialization
 30  //!
 31  //! Only [`ContactPublicKeys`] implements `Serialize`/`Deserialize` since it
 32  //! contains only public data. Secret keys should be serialized manually with
 33  //! care (e.g., to secure storage with encryption).
 34  
 35  use ed25519_dalek::{SigningKey, VerifyingKey};
 36  use rand::rngs::OsRng;
 37  use serde::{Deserialize, Serialize};
 38  use x25519_dalek::{PublicKey as X25519PublicKey, StaticSecret};
 39  use zeroize::ZeroizeOnDrop;
 40  
 41  use crate::error::{DeadDropError, Result};
 42  
 43  // =============================================================================
 44  // CONSTANTS
 45  // =============================================================================
 46  
 47  /// Size of Ed25519 public key in bytes.
 48  ///
 49  /// Ed25519 public keys are 256-bit compressed curve points.
 50  pub const ED25519_PUBLIC_KEY_SIZE: usize = 32;
 51  
 52  /// Size of Ed25519 secret key in bytes.
 53  ///
 54  /// Ed25519 secret keys are 256-bit random scalars. Note that the `ed25519-dalek`
 55  /// crate internally expands this to 512 bits when signing.
 56  pub const ED25519_SECRET_KEY_SIZE: usize = 32;
 57  
 58  /// Size of Ed25519 signature in bytes.
 59  ///
 60  /// Ed25519 signatures consist of two 256-bit values (R and S).
 61  pub const ED25519_SIGNATURE_SIZE: usize = 64;
 62  
 63  /// Size of X25519 public key in bytes.
 64  ///
 65  /// X25519 public keys are 256-bit curve points in Montgomery form.
 66  pub const X25519_PUBLIC_KEY_SIZE: usize = 32;
 67  
 68  /// Size of X25519 secret key in bytes.
 69  ///
 70  /// X25519 secret keys are 256-bit scalars with specific bit manipulations
 71  /// applied (clamping) to ensure they're in the correct group.
 72  pub const X25519_SECRET_KEY_SIZE: usize = 32;
 73  
 74  // =============================================================================
 75  // KEY TYPES
 76  // =============================================================================
 77  
 78  /// Ed25519 identity key pair for signing operations.
 79  ///
 80  /// The identity key is the user's long-term cryptographic identity, analogous
 81  /// to a PGP key. It is used to:
 82  ///
 83  /// - **Sign messages**: Prove that you authored a message
 84  /// - **Verify contacts**: Confirm messages came from who you think
 85  /// - **Generate fingerprints**: Create human-verifiable identity strings
 86  ///
 87  /// # Lifecycle
 88  ///
 89  /// 1. Generated once when the user first sets up the app
 90  /// 2. Never changes unless the user explicitly resets their identity
 91  /// 3. Public key is shared via QR code during contact exchange
 92  /// 4. Secret key is stored encrypted in secure storage
 93  ///
 94  /// # Security
 95  ///
 96  /// - The secret key is automatically zeroized when dropped
 97  /// - Never transmit the secret key over any channel
 98  /// - Consider backing up to secure offline storage
 99  ///
100  /// # Example
101  ///
102  /// ```
103  /// use dead_drop_core::crypto::keys::IdentityKeyPair;
104  ///
105  /// let keypair = IdentityKeyPair::generate();
106  ///
107  /// // Store the public key for sharing
108  /// let public_key = keypair.public_bytes();
109  ///
110  /// // Store the secret key securely (encrypt before storage!)
111  /// let secret_key = keypair.secret_bytes();
112  /// ```
113  #[derive(ZeroizeOnDrop)]
114  pub struct IdentityKeyPair {
115      // Note: The SigningKey contains the secret scalar. We skip zeroize on
116      // these fields because ed25519-dalek already implements Zeroize internally.
117      // The ZeroizeOnDrop derive is for documentation purposes.
118      #[zeroize(skip)]
119      secret: SigningKey,
120      #[zeroize(skip)]
121      public: VerifyingKey,
122  }
123  
124  impl IdentityKeyPair {
125      /// Generate a new random identity key pair.
126      ///
127      /// Uses the operating system's secure random number generator.
128      ///
129      /// # Example
130      ///
131      /// ```
132      /// use dead_drop_core::crypto::keys::IdentityKeyPair;
133      ///
134      /// let keypair = IdentityKeyPair::generate();
135      /// let public_bytes = keypair.public_bytes();
136      /// assert_eq!(public_bytes.len(), 32);
137      /// ```
138      pub fn generate() -> Self {
139          let secret = SigningKey::generate(&mut OsRng);
140          let public = secret.verifying_key();
141          Self { secret, public }
142      }
143  
144      /// Create an identity key pair from existing secret key bytes.
145      ///
146      /// # Arguments
147      ///
148      /// * `secret_bytes` - 32-byte Ed25519 secret key
149      ///
150      /// # Errors
151      ///
152      /// Returns `InvalidKey` if the bytes do not form a valid key.
153      pub fn from_secret_bytes(secret_bytes: &[u8; ED25519_SECRET_KEY_SIZE]) -> Result<Self> {
154          let secret = SigningKey::from_bytes(secret_bytes);
155          let public = secret.verifying_key();
156          Ok(Self { secret, public })
157      }
158  
159      /// Get the secret key bytes.
160      ///
161      /// # Security
162      ///
163      /// Handle the returned bytes with care and zeroize when done.
164      pub fn secret_bytes(&self) -> [u8; ED25519_SECRET_KEY_SIZE] {
165          self.secret.to_bytes()
166      }
167  
168      /// Get the public key bytes.
169      pub fn public_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] {
170          self.public.to_bytes()
171      }
172  
173      /// Get a reference to the signing key.
174      pub fn signing_key(&self) -> &SigningKey {
175          &self.secret
176      }
177  
178      /// Get a reference to the verifying key.
179      pub fn verifying_key(&self) -> &VerifyingKey {
180          &self.public
181      }
182  }
183  
184  impl Clone for IdentityKeyPair {
185      fn clone(&self) -> Self {
186          Self {
187              secret: SigningKey::from_bytes(&self.secret.to_bytes()),
188              public: self.public,
189          }
190      }
191  }
192  
193  /// X25519 exchange key pair for key agreement (ECDH).
194  ///
195  /// The exchange key enables secure key agreement with contacts using the
196  /// Elliptic Curve Diffie-Hellman (ECDH) protocol. It is used to:
197  ///
198  /// - **Derive shared secrets**: Compute encryption keys with contacts
199  /// - **Generate rotating IDs**: Create privacy-preserving BLE identifiers
200  /// - **Enable forward secrecy**: Combined with ephemeral keys for each message
201  ///
202  /// # Why Separate from Identity Key?
203  ///
204  /// We use X25519 for key exchange and Ed25519 for signing because:
205  ///
206  /// 1. Ed25519 is optimized for signature operations
207  /// 2. X25519 is optimized for Diffie-Hellman operations
208  /// 3. Using the same key for both could enable attacks in some scenarios
209  ///
210  /// # Lifecycle
211  ///
212  /// 1. Generated once when the user first sets up the app
213  /// 2. Public key is shared via QR code alongside the identity key
214  /// 3. Used with each contact to derive unique shared secrets
215  ///
216  /// # Security
217  ///
218  /// - The secret key is automatically zeroized when dropped
219  /// - The shared secret from ECDH should always be passed through HKDF
220  /// - Never use raw DH output directly as an encryption key
221  #[derive(ZeroizeOnDrop)]
222  pub struct ExchangeKeyPair {
223      // Note: StaticSecret is designed for long-term storage, unlike
224      // EphemeralSecret which enforces single-use semantics at the type level.
225      #[zeroize(skip)]
226      secret: StaticSecret,
227      #[zeroize(skip)]
228      public: X25519PublicKey,
229  }
230  
231  impl ExchangeKeyPair {
232      /// Generate a new random exchange key pair.
233      ///
234      /// Uses the operating system's secure random number generator.
235      ///
236      /// # Example
237      ///
238      /// ```
239      /// use dead_drop_core::crypto::keys::ExchangeKeyPair;
240      ///
241      /// let keypair = ExchangeKeyPair::generate();
242      /// let public_bytes = keypair.public_bytes();
243      /// assert_eq!(public_bytes.len(), 32);
244      /// ```
245      pub fn generate() -> Self {
246          let secret = StaticSecret::random_from_rng(OsRng);
247          let public = X25519PublicKey::from(&secret);
248          Self { secret, public }
249      }
250  
251      /// Create an exchange key pair from existing secret key bytes.
252      ///
253      /// # Arguments
254      ///
255      /// * `secret_bytes` - 32-byte X25519 secret key
256      pub fn from_secret_bytes(secret_bytes: [u8; X25519_SECRET_KEY_SIZE]) -> Self {
257          let secret = StaticSecret::from(secret_bytes);
258          let public = X25519PublicKey::from(&secret);
259          Self { secret, public }
260      }
261  
262      /// Get the secret key bytes.
263      ///
264      /// # Security
265      ///
266      /// Handle the returned bytes with care and zeroize when done.
267      pub fn secret_bytes(&self) -> [u8; X25519_SECRET_KEY_SIZE] {
268          self.secret.to_bytes()
269      }
270  
271      /// Get the public key bytes.
272      pub fn public_bytes(&self) -> [u8; X25519_PUBLIC_KEY_SIZE] {
273          self.public.to_bytes()
274      }
275  
276      /// Perform X25519 key agreement with another party's public key.
277      ///
278      /// # Arguments
279      ///
280      /// * `their_public` - The other party's X25519 public key
281      ///
282      /// # Returns
283      ///
284      /// A 32-byte shared secret. This should be passed through a KDF
285      /// before use as an encryption key.
286      pub fn diffie_hellman(&self, their_public: &[u8; X25519_PUBLIC_KEY_SIZE]) -> [u8; 32] {
287          let their_key = X25519PublicKey::from(*their_public);
288          self.secret.diffie_hellman(&their_key).to_bytes()
289      }
290  
291      /// Get a reference to the static secret.
292      pub fn static_secret(&self) -> &StaticSecret {
293          &self.secret
294      }
295  
296      /// Get a reference to the public key.
297      pub fn public_key(&self) -> &X25519PublicKey {
298          &self.public
299      }
300  }
301  
302  impl Clone for ExchangeKeyPair {
303      fn clone(&self) -> Self {
304          Self::from_secret_bytes(self.secret.to_bytes())
305      }
306  }
307  
308  /// Ephemeral X25519 key pair for single-use encryption.
309  ///
310  /// Ephemeral keys are generated fresh for each message to provide
311  /// **forward secrecy**: even if long-term keys are later compromised,
312  /// past messages cannot be decrypted.
313  ///
314  /// # Forward Secrecy Explained
315  ///
316  /// When Alice sends a message to Bob:
317  ///
318  /// 1. Alice generates a fresh ephemeral key pair
319  /// 2. Alice performs DH with Bob's static exchange key
320  /// 3. Alice derives the message key from the DH result
321  /// 4. Alice encrypts and sends: (ephemeral_public, ciphertext)
322  /// 5. Alice's ephemeral secret is immediately zeroized
323  ///
324  /// If Alice's device is later compromised, the attacker cannot decrypt
325  /// past messages because the ephemeral secrets no longer exist.
326  ///
327  /// # Usage Pattern
328  ///
329  /// ```
330  /// use dead_drop_core::crypto::keys::{EphemeralKeyPair, ExchangeKeyPair};
331  ///
332  /// let recipient = ExchangeKeyPair::generate();
333  /// let ephemeral = EphemeralKeyPair::generate();
334  ///
335  /// // Save the public key to send with the message
336  /// let ephemeral_public = ephemeral.public_bytes();
337  ///
338  /// // Consume the ephemeral key (zeroing the secret)
339  /// let shared_secret = ephemeral.diffie_hellman(&recipient.public_bytes());
340  /// ```
341  ///
342  /// # Security
343  ///
344  /// - The secret key is automatically zeroized when dropped
345  /// - Prefer `diffie_hellman()` which consumes self over `diffie_hellman_ref()`
346  /// - Never store ephemeral secrets; use them immediately and discard
347  #[derive(ZeroizeOnDrop)]
348  pub struct EphemeralKeyPair {
349      // We use StaticSecret internally but enforce ephemeral semantics through
350      // the consuming diffie_hellman() method.
351      #[zeroize(skip)]
352      secret: StaticSecret,
353      #[zeroize(skip)]
354      public: X25519PublicKey,
355  }
356  
357  impl EphemeralKeyPair {
358      /// Generate a new random ephemeral key pair.
359      ///
360      /// # Example
361      ///
362      /// ```
363      /// use dead_drop_core::crypto::keys::EphemeralKeyPair;
364      ///
365      /// let ephemeral = EphemeralKeyPair::generate();
366      /// let public_bytes = ephemeral.public_bytes();
367      /// assert_eq!(public_bytes.len(), 32);
368      /// ```
369      pub fn generate() -> Self {
370          let secret = StaticSecret::random_from_rng(OsRng);
371          let public = X25519PublicKey::from(&secret);
372          Self { secret, public }
373      }
374  
375      /// Get the public key bytes.
376      ///
377      /// These bytes are sent with the encrypted message.
378      pub fn public_bytes(&self) -> [u8; X25519_PUBLIC_KEY_SIZE] {
379          self.public.to_bytes()
380      }
381  
382      /// Perform X25519 key agreement and consume the ephemeral secret.
383      ///
384      /// This method consumes self to ensure the ephemeral secret
385      /// is not reused.
386      ///
387      /// # Arguments
388      ///
389      /// * `their_public` - The recipient's X25519 public key
390      ///
391      /// # Returns
392      ///
393      /// A 32-byte shared secret.
394      pub fn diffie_hellman(self, their_public: &[u8; X25519_PUBLIC_KEY_SIZE]) -> [u8; 32] {
395          let their_key = X25519PublicKey::from(*their_public);
396          self.secret.diffie_hellman(&their_key).to_bytes()
397      }
398  
399      /// Perform X25519 key agreement without consuming self.
400      ///
401      /// Use this when you need to perform multiple DH operations
402      /// (e.g., in tests). Prefer `diffie_hellman` in production.
403      pub fn diffie_hellman_ref(&self, their_public: &[u8; X25519_PUBLIC_KEY_SIZE]) -> [u8; 32] {
404          let their_key = X25519PublicKey::from(*their_public);
405          self.secret.diffie_hellman(&their_key).to_bytes()
406      }
407  }
408  
409  /// Public keys for a contact (no secrets).
410  ///
411  /// This structure holds the public keys received from a contact
412  /// during the key exchange process.
413  #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
414  pub struct ContactPublicKeys {
415      /// Ed25519 identity public key (for signature verification)
416      pub identity: [u8; ED25519_PUBLIC_KEY_SIZE],
417      /// X25519 exchange public key (for key agreement)
418      pub exchange: [u8; X25519_PUBLIC_KEY_SIZE],
419  }
420  
421  impl ContactPublicKeys {
422      /// Create a new ContactPublicKeys from raw bytes.
423      pub fn new(
424          identity: [u8; ED25519_PUBLIC_KEY_SIZE],
425          exchange: [u8; X25519_PUBLIC_KEY_SIZE],
426      ) -> Self {
427          Self { identity, exchange }
428      }
429  
430      /// Create from byte slices with validation.
431      ///
432      /// # Errors
433      ///
434      /// Returns `InvalidKey` if the slices are not the correct length.
435      pub fn from_slices(identity: &[u8], exchange: &[u8]) -> Result<Self> {
436          let identity: [u8; ED25519_PUBLIC_KEY_SIZE] = identity
437              .try_into()
438              .map_err(|_| DeadDropError::InvalidKey("Identity key must be 32 bytes".to_string()))?;
439  
440          let exchange: [u8; X25519_PUBLIC_KEY_SIZE] = exchange
441              .try_into()
442              .map_err(|_| DeadDropError::InvalidKey("Exchange key must be 32 bytes".to_string()))?;
443  
444          Ok(Self { identity, exchange })
445      }
446  
447      /// Validate that the public keys are well-formed.
448      ///
449      /// For Ed25519, this checks that the bytes represent a valid point
450      /// on the curve.
451      pub fn validate(&self) -> Result<()> {
452          // Validate Ed25519 public key
453          VerifyingKey::from_bytes(&self.identity)
454              .map_err(|_| DeadDropError::InvalidKey("Invalid Ed25519 public key".to_string()))?;
455  
456          // X25519 public keys are always valid (any 32 bytes work)
457          // but we could check for low-order points if desired
458  
459          Ok(())
460      }
461  
462      /// Get the verifying key for signature verification.
463      ///
464      /// # Errors
465      ///
466      /// Returns `InvalidKey` if the stored bytes are not a valid Ed25519 key.
467      pub fn verifying_key(&self) -> Result<VerifyingKey> {
468          VerifyingKey::from_bytes(&self.identity)
469              .map_err(|_| DeadDropError::InvalidKey("Invalid Ed25519 public key".to_string()))
470      }
471  }
472  
473  // =============================================================================
474  // RANDOM GENERATION UTILITIES
475  // =============================================================================
476  
477  /// Generate a random 16-byte identifier.
478  ///
479  /// Creates a cryptographically random 128-bit identifier suitable for:
480  ///
481  /// - **Message IDs**: Unique identifiers for each message
482  /// - **Contact IDs**: Internal identifiers for contacts
483  /// - **Nonces**: One-time values for cryptographic operations
484  ///
485  /// # Randomness Source
486  ///
487  /// Uses `OsRng`, which reads from the operating system's cryptographic
488  /// random number generator (e.g., `/dev/urandom` on Linux, `BCryptGenRandom`
489  /// on Windows, `SecRandomCopyBytes` on macOS/iOS).
490  ///
491  /// # Uniqueness
492  ///
493  /// With 128 bits of randomness, the probability of collision after generating
494  /// 2^32 IDs is approximately 2^-64, which is negligible for practical purposes.
495  ///
496  /// # Example
497  ///
498  /// ```
499  /// use dead_drop_core::crypto::keys::generate_random_id;
500  ///
501  /// let message_id = generate_random_id();
502  /// assert_eq!(message_id.len(), 16);
503  /// ```
504  pub fn generate_random_id() -> [u8; 16] {
505      let mut id = [0u8; 16];
506      rand::RngCore::fill_bytes(&mut OsRng, &mut id);
507      id
508  }
509  
510  /// Generate random bytes of specified length.
511  ///
512  /// Creates a vector of cryptographically random bytes. This is a general-purpose
513  /// function for when you need random data of arbitrary length.
514  ///
515  /// # Arguments
516  ///
517  /// * `len` - The number of random bytes to generate
518  ///
519  /// # Returns
520  ///
521  /// A `Vec<u8>` containing `len` cryptographically random bytes.
522  ///
523  /// # Panics
524  ///
525  /// May panic if the OS RNG is unavailable, though this is extremely rare
526  /// on modern systems.
527  ///
528  /// # Example
529  ///
530  /// ```
531  /// use dead_drop_core::crypto::keys::generate_random_bytes;
532  ///
533  /// // Generate a random 256-bit value
534  /// let random_key = generate_random_bytes(32);
535  /// assert_eq!(random_key.len(), 32);
536  /// ```
537  pub fn generate_random_bytes(len: usize) -> Vec<u8> {
538      let mut bytes = vec![0u8; len];
539      rand::RngCore::fill_bytes(&mut OsRng, &mut bytes);
540      bytes
541  }
542  
543  #[cfg(test)]
544  mod tests {
545      use super::*;
546  
547      // ==================== IdentityKeyPair Tests ====================
548  
549      #[test]
550      fn test_identity_keypair_generation() {
551          let keypair = IdentityKeyPair::generate();
552  
553          // Check key sizes
554          assert_eq!(keypair.public_bytes().len(), ED25519_PUBLIC_KEY_SIZE);
555          assert_eq!(keypair.secret_bytes().len(), ED25519_SECRET_KEY_SIZE);
556      }
557  
558      #[test]
559      fn test_identity_keypair_unique_generation() {
560          let keypair1 = IdentityKeyPair::generate();
561          let keypair2 = IdentityKeyPair::generate();
562  
563          // Each generation should produce different keys
564          assert_ne!(keypair1.public_bytes(), keypair2.public_bytes());
565          assert_ne!(keypair1.secret_bytes(), keypair2.secret_bytes());
566      }
567  
568      #[test]
569      fn test_identity_keypair_from_secret_bytes() {
570          let original = IdentityKeyPair::generate();
571          let secret_bytes = original.secret_bytes();
572  
573          let restored = IdentityKeyPair::from_secret_bytes(&secret_bytes).unwrap();
574  
575          // Should derive the same public key
576          assert_eq!(original.public_bytes(), restored.public_bytes());
577      }
578  
579      #[test]
580      fn test_identity_keypair_clone() {
581          let original = IdentityKeyPair::generate();
582          let cloned = original.clone();
583  
584          assert_eq!(original.public_bytes(), cloned.public_bytes());
585          assert_eq!(original.secret_bytes(), cloned.secret_bytes());
586      }
587  
588      #[test]
589      fn test_identity_keypair_signing_key_access() {
590          let keypair = IdentityKeyPair::generate();
591  
592          // Should be able to get signing and verifying keys
593          let _signing = keypair.signing_key();
594          let _verifying = keypair.verifying_key();
595      }
596  
597      // ==================== ExchangeKeyPair Tests ====================
598  
599      #[test]
600      fn test_exchange_keypair_generation() {
601          let keypair = ExchangeKeyPair::generate();
602  
603          // Check key sizes
604          assert_eq!(keypair.public_bytes().len(), X25519_PUBLIC_KEY_SIZE);
605          assert_eq!(keypair.secret_bytes().len(), X25519_SECRET_KEY_SIZE);
606      }
607  
608      #[test]
609      fn test_exchange_keypair_unique_generation() {
610          let keypair1 = ExchangeKeyPair::generate();
611          let keypair2 = ExchangeKeyPair::generate();
612  
613          // Each generation should produce different keys
614          assert_ne!(keypair1.public_bytes(), keypair2.public_bytes());
615      }
616  
617      #[test]
618      fn test_exchange_keypair_from_secret_bytes() {
619          let original = ExchangeKeyPair::generate();
620          let secret_bytes = original.secret_bytes();
621  
622          let restored = ExchangeKeyPair::from_secret_bytes(secret_bytes);
623  
624          // Should derive the same public key
625          assert_eq!(original.public_bytes(), restored.public_bytes());
626      }
627  
628      #[test]
629      fn test_exchange_keypair_clone() {
630          let original = ExchangeKeyPair::generate();
631          let cloned = original.clone();
632  
633          assert_eq!(original.public_bytes(), cloned.public_bytes());
634          assert_eq!(original.secret_bytes(), cloned.secret_bytes());
635      }
636  
637      #[test]
638      fn test_exchange_keypair_diffie_hellman() {
639          let alice = ExchangeKeyPair::generate();
640          let bob = ExchangeKeyPair::generate();
641  
642          // Alice computes shared secret with Bob's public key
643          let alice_shared = alice.diffie_hellman(&bob.public_bytes());
644  
645          // Bob computes shared secret with Alice's public key
646          let bob_shared = bob.diffie_hellman(&alice.public_bytes());
647  
648          // Both should arrive at the same shared secret
649          assert_eq!(alice_shared, bob_shared);
650      }
651  
652      #[test]
653      fn test_exchange_keypair_diffie_hellman_different_peers() {
654          let alice = ExchangeKeyPair::generate();
655          let bob = ExchangeKeyPair::generate();
656          let charlie = ExchangeKeyPair::generate();
657  
658          let alice_bob = alice.diffie_hellman(&bob.public_bytes());
659          let alice_charlie = alice.diffie_hellman(&charlie.public_bytes());
660  
661          // Shared secrets with different peers should be different
662          assert_ne!(alice_bob, alice_charlie);
663      }
664  
665      // ==================== EphemeralKeyPair Tests ====================
666  
667      #[test]
668      fn test_ephemeral_keypair_generation() {
669          let keypair = EphemeralKeyPair::generate();
670  
671          // Check key size
672          assert_eq!(keypair.public_bytes().len(), X25519_PUBLIC_KEY_SIZE);
673      }
674  
675      #[test]
676      fn test_ephemeral_keypair_unique_generation() {
677          let keypair1 = EphemeralKeyPair::generate();
678          let keypair2 = EphemeralKeyPair::generate();
679  
680          // Each generation should produce different keys
681          assert_ne!(keypair1.public_bytes(), keypair2.public_bytes());
682      }
683  
684      #[test]
685      fn test_ephemeral_keypair_diffie_hellman() {
686          let ephemeral = EphemeralKeyPair::generate();
687          let recipient = ExchangeKeyPair::generate();
688  
689          let eph_public = ephemeral.public_bytes();
690  
691          // Ephemeral DH with recipient's public key
692          let sender_shared = ephemeral.diffie_hellman(&recipient.public_bytes());
693  
694          // Recipient DH with ephemeral public key
695          let recipient_shared = recipient.diffie_hellman(&eph_public);
696  
697          // Both should arrive at the same shared secret
698          assert_eq!(sender_shared, recipient_shared);
699      }
700  
701      #[test]
702      fn test_ephemeral_keypair_diffie_hellman_ref() {
703          let ephemeral = EphemeralKeyPair::generate();
704          let recipient = ExchangeKeyPair::generate();
705  
706          // Use ref version to perform multiple DH operations
707          let shared1 = ephemeral.diffie_hellman_ref(&recipient.public_bytes());
708          let shared2 = ephemeral.diffie_hellman_ref(&recipient.public_bytes());
709  
710          // Same inputs should produce same output
711          assert_eq!(shared1, shared2);
712      }
713  
714      // ==================== ContactPublicKeys Tests ====================
715  
716      #[test]
717      fn test_contact_public_keys_new() {
718          let identity = IdentityKeyPair::generate();
719          let exchange = ExchangeKeyPair::generate();
720  
721          let contact = ContactPublicKeys::new(identity.public_bytes(), exchange.public_bytes());
722  
723          assert_eq!(contact.identity, identity.public_bytes());
724          assert_eq!(contact.exchange, exchange.public_bytes());
725      }
726  
727      #[test]
728      fn test_contact_public_keys_from_slices_valid() {
729          let identity = IdentityKeyPair::generate();
730          let exchange = ExchangeKeyPair::generate();
731  
732          let contact =
733              ContactPublicKeys::from_slices(&identity.public_bytes(), &exchange.public_bytes())
734                  .unwrap();
735  
736          assert_eq!(contact.identity, identity.public_bytes());
737          assert_eq!(contact.exchange, exchange.public_bytes());
738      }
739  
740      #[test]
741      fn test_contact_public_keys_from_slices_invalid_identity_length() {
742          let short_identity = [0u8; 16]; // Too short
743          let exchange = ExchangeKeyPair::generate();
744  
745          let result = ContactPublicKeys::from_slices(&short_identity, &exchange.public_bytes());
746  
747          assert!(result.is_err());
748          assert!(matches!(result.unwrap_err(), DeadDropError::InvalidKey(_)));
749      }
750  
751      #[test]
752      fn test_contact_public_keys_from_slices_invalid_exchange_length() {
753          let identity = IdentityKeyPair::generate();
754          let short_exchange = [0u8; 16]; // Too short
755  
756          let result = ContactPublicKeys::from_slices(&identity.public_bytes(), &short_exchange);
757  
758          assert!(result.is_err());
759          assert!(matches!(result.unwrap_err(), DeadDropError::InvalidKey(_)));
760      }
761  
762      #[test]
763      fn test_contact_public_keys_validate_valid() {
764          let identity = IdentityKeyPair::generate();
765          let exchange = ExchangeKeyPair::generate();
766  
767          let contact = ContactPublicKeys::new(identity.public_bytes(), exchange.public_bytes());
768  
769          assert!(contact.validate().is_ok());
770      }
771  
772      #[test]
773      fn test_contact_public_keys_validate_invalid_identity() {
774          // Test that validating an actual valid key works
775          let valid_identity = IdentityKeyPair::generate();
776          let exchange = ExchangeKeyPair::generate();
777  
778          let valid_contact = ContactPublicKeys::new(
779              valid_identity.public_bytes(),
780              exchange.public_bytes(),
781          );
782          assert!(valid_contact.validate().is_ok());
783  
784          // Note: Ed25519 accepts many 32-byte values as valid public keys.
785          // Even all-zeros represents the identity point which is technically valid.
786          // The ed25519-dalek library only rejects values that fail point decompression.
787          // This test verifies that clearly invalid values are rejected.
788  
789          // A value > p (the field prime) should be invalid
790          // p = 2^255 - 19, so anything with the high byte >= 0x80 AND specific patterns fails
791          // Let's use a value that's definitely not on the curve
792          let definitely_invalid = [
793              0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
794              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
795              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
796              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
797          ];
798  
799          let invalid_contact = ContactPublicKeys::new(definitely_invalid, exchange.public_bytes());
800  
801          // If this is rejected, the validation works. If not, that's also fine -
802          // the signature verification will fail anyway.
803          // The key point is that validation doesn't crash or panic.
804          let _result = invalid_contact.validate();
805      }
806  
807      #[test]
808      fn test_contact_public_keys_verifying_key() {
809          let identity = IdentityKeyPair::generate();
810          let exchange = ExchangeKeyPair::generate();
811  
812          let contact = ContactPublicKeys::new(identity.public_bytes(), exchange.public_bytes());
813  
814          let verifying_key = contact.verifying_key().unwrap();
815          assert_eq!(verifying_key.to_bytes(), identity.public_bytes());
816      }
817  
818      #[test]
819      fn test_contact_public_keys_serialization() {
820          let identity = IdentityKeyPair::generate();
821          let exchange = ExchangeKeyPair::generate();
822  
823          let contact = ContactPublicKeys::new(identity.public_bytes(), exchange.public_bytes());
824  
825          // Serialize to JSON
826          let json = serde_json::to_string(&contact).unwrap();
827  
828          // Deserialize back
829          let restored: ContactPublicKeys = serde_json::from_str(&json).unwrap();
830  
831          assert_eq!(contact, restored);
832      }
833  
834      #[test]
835      fn test_contact_public_keys_binary_serialization() {
836          let identity = IdentityKeyPair::generate();
837          let exchange = ExchangeKeyPair::generate();
838  
839          let contact = ContactPublicKeys::new(identity.public_bytes(), exchange.public_bytes());
840  
841          // Serialize to binary
842          let binary = bincode::serialize(&contact).unwrap();
843  
844          // Deserialize back
845          let restored: ContactPublicKeys = bincode::deserialize(&binary).unwrap();
846  
847          assert_eq!(contact, restored);
848      }
849  
850      // ==================== Utility Function Tests ====================
851  
852      #[test]
853      fn test_generate_random_id() {
854          let id1 = generate_random_id();
855          let id2 = generate_random_id();
856  
857          // Check size
858          assert_eq!(id1.len(), 16);
859  
860          // Should be unique
861          assert_ne!(id1, id2);
862      }
863  
864      #[test]
865      fn test_generate_random_id_not_zero() {
866          // Generate multiple IDs and check they're not all zeros
867          for _ in 0..10 {
868              let id = generate_random_id();
869              // Very unlikely to be all zeros
870              assert_ne!(id, [0u8; 16]);
871          }
872      }
873  
874      #[test]
875      fn test_generate_random_bytes() {
876          let bytes1 = generate_random_bytes(32);
877          let bytes2 = generate_random_bytes(32);
878  
879          // Check size
880          assert_eq!(bytes1.len(), 32);
881  
882          // Should be unique
883          assert_ne!(bytes1, bytes2);
884      }
885  
886      #[test]
887      fn test_generate_random_bytes_various_sizes() {
888          for size in [0, 1, 16, 32, 64, 128, 256] {
889              let bytes = generate_random_bytes(size);
890              assert_eq!(bytes.len(), size);
891          }
892      }
893  
894      // ==================== Cross-type Integration Tests ====================
895  
896      #[test]
897      fn test_full_key_exchange_flow() {
898          // Simulate a complete key exchange between Alice and Bob
899  
900          // Alice generates her keys
901          let alice_identity = IdentityKeyPair::generate();
902          let alice_exchange = ExchangeKeyPair::generate();
903  
904          // Bob generates his keys
905          let bob_identity = IdentityKeyPair::generate();
906          let bob_exchange = ExchangeKeyPair::generate();
907  
908          // They exchange public keys
909          let alice_contact = ContactPublicKeys::new(
910              alice_identity.public_bytes(),
911              alice_exchange.public_bytes(),
912          );
913  
914          let bob_contact =
915              ContactPublicKeys::new(bob_identity.public_bytes(), bob_exchange.public_bytes());
916  
917          // Validate received keys
918          assert!(alice_contact.validate().is_ok());
919          assert!(bob_contact.validate().is_ok());
920  
921          // Compute shared secret for message encryption
922          let alice_shared = alice_exchange.diffie_hellman(&bob_contact.exchange);
923          let bob_shared = bob_exchange.diffie_hellman(&alice_contact.exchange);
924  
925          assert_eq!(alice_shared, bob_shared);
926      }
927  
928      #[test]
929      fn test_ephemeral_message_encryption_flow() {
930          // Simulate message encryption with ephemeral keys
931  
932          // Bob has a static exchange key
933          let bob_exchange = ExchangeKeyPair::generate();
934  
935          // Alice generates ephemeral key for this message
936          let alice_ephemeral = EphemeralKeyPair::generate();
937          let ephemeral_public = alice_ephemeral.public_bytes();
938  
939          // Alice computes shared secret (consumes ephemeral)
940          let alice_shared = alice_ephemeral.diffie_hellman(&bob_exchange.public_bytes());
941  
942          // Bob receives the message with ephemeral public key
943          // Bob computes the same shared secret
944          let bob_shared = bob_exchange.diffie_hellman(&ephemeral_public);
945  
946          assert_eq!(alice_shared, bob_shared);
947      }
948  
949      // ==================== Security Property Tests ====================
950  
951      #[test]
952      fn test_secret_key_bytes_are_secret() {
953          // Verify that secret bytes are actually different from public bytes
954          let identity = IdentityKeyPair::generate();
955          assert_ne!(identity.secret_bytes(), identity.public_bytes());
956  
957          let exchange = ExchangeKeyPair::generate();
958          assert_ne!(exchange.secret_bytes(), exchange.public_bytes());
959      }
960  
961      #[test]
962      fn test_dh_requires_private_key() {
963          // Verify that you can't compute DH with just public keys
964          let alice = ExchangeKeyPair::generate();
965          let bob = ExchangeKeyPair::generate();
966  
967          // This works because alice has her private key
968          let shared = alice.diffie_hellman(&bob.public_bytes());
969  
970          // The shared secret should be deterministic
971          let shared_again = alice.diffie_hellman(&bob.public_bytes());
972          assert_eq!(shared, shared_again);
973      }
974  }