/ abzu-core / src / identity.rs
identity.rs
  1  //! Identity Types
  2  //!
  3  //! Strict newtype wrappers for Machine and User identities.
  4  //! The compiler enforces separation - you cannot accidentally use
  5  //! a MachineIdentity where a UserIdentity is expected.
  6  //!
  7  //! # Architecture
  8  //!
  9  //! - **MachineIdentity**: Infrastructure operations (routing, DHT, mesh address)
 10  //! - **UserIdentity**: Application operations (messaging, content signing, mailbox)
 11  
 12  use ed25519_dalek::{SigningKey, VerifyingKey, Signature, Signer};
 13  
 14  /// Machine identity for infrastructure operations.
 15  ///
 16  /// Used for:
 17  /// - Mesh address derivation
 18  /// - Routing table operations
 19  /// - DHT participation (FindNode, Ping)
 20  /// - Transport layer authentication
 21  ///
 22  /// This identity is tied to the node/device, not the user.
 23  #[derive(Debug)]
 24  pub struct MachineIdentity(SigningKey);
 25  
 26  impl MachineIdentity {
 27      /// Create a new machine identity from a signing key
 28      pub fn new(key: SigningKey) -> Self {
 29          Self(key)
 30      }
 31  
 32      /// Generate a new random machine identity
 33      pub fn generate() -> Self {
 34          Self(SigningKey::generate(&mut rand::rngs::OsRng))
 35      }
 36  
 37      /// Get the verifying (public) key
 38      pub fn verifying_key(&self) -> VerifyingKey {
 39          self.0.verifying_key()
 40      }
 41  
 42      /// Get the public key bytes (32 bytes)
 43      pub fn public_bytes(&self) -> [u8; 32] {
 44          *self.0.verifying_key().as_bytes()
 45      }
 46  
 47      /// Sign data for infrastructure operations
 48      pub fn sign(&self, data: &[u8]) -> Signature {
 49          self.0.sign(data)
 50      }
 51  
 52      /// Expose the raw signing key.
 53      ///
 54      /// # Security
 55      /// This method exposes private key material. Only use for:
 56      /// - Serialization to secure storage
 57      /// - Key derivation in trusted contexts
 58      ///
 59      /// Never log, transmit, or store the result in plaintext.
 60      pub fn expose_signing_key(&self) -> &SigningKey {
 61          &self.0
 62      }
 63  
 64      /// Create from raw bytes (for deserialization)
 65      pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, ed25519_dalek::SignatureError> {
 66          Ok(Self(SigningKey::from_bytes(bytes)))
 67      }
 68  }
 69  
 70  /// User identity for application operations.
 71  ///
 72  /// Used for:
 73  /// - Message signing and encryption
 74  /// - Content ownership signatures
 75  /// - Mailbox address derivation
 76  /// - Contact relationships
 77  ///
 78  /// This identity represents a user/account and is portable between nodes.
 79  #[derive(Debug)]
 80  pub struct UserIdentity(SigningKey);
 81  
 82  impl UserIdentity {
 83      /// Create a new user identity from a signing key
 84      pub fn new(key: SigningKey) -> Self {
 85          Self(key)
 86      }
 87  
 88      /// Generate a new random user identity
 89      pub fn generate() -> Self {
 90          Self(SigningKey::generate(&mut rand::rngs::OsRng))
 91      }
 92  
 93      /// Get the verifying (public) key
 94      pub fn verifying_key(&self) -> VerifyingKey {
 95          self.0.verifying_key()
 96      }
 97  
 98      /// Get the public key bytes (32 bytes)
 99      pub fn public_bytes(&self) -> [u8; 32] {
100          *self.0.verifying_key().as_bytes()
101      }
102  
103      /// Sign data for user operations (messages, content)
104      pub fn sign(&self, data: &[u8]) -> Signature {
105          self.0.sign(data)
106      }
107  
108      /// Expose the raw signing key.
109      ///
110      /// # Security
111      /// This method exposes private key material. Only use for:
112      /// - Serialization to secure storage
113      /// - Key derivation in trusted contexts
114      ///
115      /// Never log, transmit, or store the result in plaintext.
116      pub fn expose_signing_key(&self) -> &SigningKey {
117          &self.0
118      }
119  
120      /// Create from raw bytes (for deserialization)
121      pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, ed25519_dalek::SignatureError> {
122          Ok(Self(SigningKey::from_bytes(bytes)))
123      }
124  }
125  
126  #[cfg(test)]
127  mod tests {
128      use super::*;
129  
130      #[test]
131      fn machine_identity_roundtrip() {
132          let machine = MachineIdentity::generate();
133          let pubkey = machine.public_bytes();
134          
135          // Sign and verify
136          let data = b"routing data";
137          let sig = machine.sign(data);
138          assert!(machine.verifying_key().verify_strict(data, &sig).is_ok());
139          
140          // Roundtrip through bytes
141          let bytes = machine.expose_signing_key().to_bytes();
142          let restored = MachineIdentity::from_bytes(&bytes).unwrap();
143          assert_eq!(restored.public_bytes(), pubkey);
144      }
145  
146      #[test]
147      fn user_identity_roundtrip() {
148          let user = UserIdentity::generate();
149          let pubkey = user.public_bytes();
150          
151          // Sign and verify
152          let data = b"message content";
153          let sig = user.sign(data);
154          assert!(user.verifying_key().verify_strict(data, &sig).is_ok());
155          
156          // Roundtrip through bytes
157          let bytes = user.expose_signing_key().to_bytes();
158          let restored = UserIdentity::from_bytes(&bytes).unwrap();
159          assert_eq!(restored.public_bytes(), pubkey);
160      }
161  
162      #[test]
163      fn identities_are_distinct_types() {
164          // This test ensures the compiler enforces type separation.
165          // If you uncomment the line below, it will fail to compile:
166          // let machine: MachineIdentity = UserIdentity::generate(); // ERROR!
167          
168          let machine = MachineIdentity::generate();
169          let user = UserIdentity::generate();
170          
171          // Different types, different keys
172          assert_ne!(machine.public_bytes(), user.public_bytes());
173      }
174  }