/ crates / bot / src / identity.rs
identity.rs
  1  /// Multi-chain identity generation for Alpha and Delta chains
  2  ///
  3  /// Generates cryptographic identities (keypairs and addresses) for both
  4  /// Alpha (ax1 bech32 addresses) and Delta (dx1 bech32 addresses) chains.
  5  
  6  use crate::{BotError, Result};
  7  use ed25519_dalek::{SigningKey, VerifyingKey, Signature, Signer};
  8  use blake2::{Blake2s256, Digest};
  9  use rand::rngs::OsRng;
 10  use serde::{Deserialize, Serialize};
 11  
 12  /// A multi-chain identity for Alpha and Delta protocols
 13  #[derive(Debug, Clone, Serialize, Deserialize)]
 14  pub struct Identity {
 15      /// Unique identifier
 16      pub id: String,
 17  
 18      /// Alpha chain address (ax1...)
 19      pub alpha_address: String,
 20  
 21      /// Delta chain address (dx1...)
 22      pub delta_address: String,
 23  
 24      /// Private key (stored as bytes, careful with serialization)
 25      #[serde(skip)]
 26      signing_key: Option<SigningKey>,
 27  }
 28  
 29  impl Identity {
 30      /// Create a new identity from a signing key
 31      pub fn from_signing_key(id: String, signing_key: SigningKey) -> Result<Self> {
 32          let verifying_key = signing_key.verifying_key();
 33  
 34          // Generate addresses for both chains
 35          let alpha_address = Self::generate_address(&verifying_key, "ax")?;
 36          let delta_address = Self::generate_address(&verifying_key, "dx")?;
 37  
 38          Ok(Self {
 39              id,
 40              alpha_address,
 41              delta_address,
 42              signing_key: Some(signing_key),
 43          })
 44      }
 45  
 46      /// Generate a bech32 address from a verifying key
 47      fn generate_address(verifying_key: &VerifyingKey, prefix: &str) -> Result<String> {
 48          // Hash the public key
 49          let mut hasher = Blake2s256::new();
 50          hasher.update(verifying_key.as_bytes());
 51          let hash = hasher.finalize();
 52  
 53          // Take first 32 bytes (full hash for Blake2s256)
 54          let address_bytes = &hash[..];
 55  
 56          // Convert to bech32
 57          // Note: For production, use proper bech32 encoding
 58          // This is a simplified version for the testbot framework
 59          let encoded = bech32::encode(
 60              prefix,
 61              address_bytes.to_vec(),
 62              bech32::Variant::Bech32,
 63          ).map_err(|e| BotError::IdentityError(format!("Bech32 encoding failed: {}", e)))?;
 64  
 65          Ok(encoded)
 66      }
 67  
 68      /// Sign a message with this identity
 69      pub fn sign(&self, message: &[u8]) -> Result<Signature> {
 70          let signing_key = self.signing_key.as_ref()
 71              .ok_or_else(|| BotError::IdentityError("No signing key available".to_string()))?;
 72  
 73          Ok(signing_key.sign(message))
 74      }
 75  
 76      /// Get the verifying key
 77      pub fn verifying_key(&self) -> Result<VerifyingKey> {
 78          let signing_key = self.signing_key.as_ref()
 79              .ok_or_else(|| BotError::IdentityError("No signing key available".to_string()))?;
 80  
 81          Ok(signing_key.verifying_key())
 82      }
 83  
 84      /// Create a view-only identity (no signing capability)
 85      pub fn view_only(id: String, alpha_address: String, delta_address: String) -> Self {
 86          Self {
 87              id,
 88              alpha_address,
 89              delta_address,
 90              signing_key: None,
 91          }
 92      }
 93  
 94      /// Check if this identity can sign
 95      pub fn can_sign(&self) -> bool {
 96          self.signing_key.is_some()
 97      }
 98  }
 99  
100  /// Generator for creating new identities
101  pub struct IdentityGenerator {
102      /// Deterministic seed for reproducible bot generation
103      seed: Option<u64>,
104  }
105  
106  impl IdentityGenerator {
107      /// Create a new identity generator
108      pub fn new() -> Self {
109          Self { seed: None }
110      }
111  
112      /// Create a generator with a deterministic seed
113      pub fn with_seed(seed: u64) -> Self {
114          Self { seed: Some(seed) }
115      }
116  
117      /// Generate a new identity
118      pub fn generate(&self, bot_id: String) -> Result<Identity> {
119          // For now, use OS random source
120          // TODO: Add deterministic generation from seed for reproducibility
121          let signing_key = SigningKey::generate(&mut OsRng);
122  
123          Identity::from_signing_key(bot_id, signing_key)
124      }
125  
126      /// Generate multiple identities
127      pub fn generate_batch(&self, prefix: &str, count: usize) -> Result<Vec<Identity>> {
128          let mut identities = Vec::with_capacity(count);
129  
130          for i in 0..count {
131              let bot_id = format!("{}-{}", prefix, i);
132              identities.push(self.generate(bot_id)?);
133          }
134  
135          Ok(identities)
136      }
137  }
138  
139  impl Default for IdentityGenerator {
140      fn default() -> Self {
141          Self::new()
142      }
143  }
144  
145  #[cfg(test)]
146  mod tests {
147      use super::*;
148  
149      #[test]
150      fn test_identity_generation() {
151          let generator = IdentityGenerator::new();
152          let identity = generator.generate("test-bot-1".to_string())
153              .expect("Failed to generate identity");
154  
155          assert!(identity.alpha_address.starts_with("ax"));
156          assert!(identity.delta_address.starts_with("dx"));
157          assert!(identity.can_sign());
158      }
159  
160      #[test]
161      fn test_batch_generation() {
162          let generator = IdentityGenerator::new();
163          let identities = generator.generate_batch("bot", 10)
164              .expect("Failed to generate batch");
165  
166          assert_eq!(identities.len(), 10);
167  
168          for (i, identity) in identities.iter().enumerate() {
169              assert_eq!(identity.id, format!("bot-{}", i));
170              assert!(identity.can_sign());
171          }
172      }
173  
174      #[test]
175      fn test_view_only_identity() {
176          let identity = Identity::view_only(
177              "view-bot".to_string(),
178              "ax1test123".to_string(),
179              "dx1test456".to_string(),
180          );
181  
182          assert!(!identity.can_sign());
183          assert!(identity.sign(&[1, 2, 3]).is_err());
184      }
185  
186      #[test]
187      fn test_signing() {
188          let generator = IdentityGenerator::new();
189          let identity = generator.generate("signer-bot".to_string())
190              .expect("Failed to generate identity");
191  
192          let message = b"test message";
193          let signature = identity.sign(message)
194              .expect("Failed to sign message");
195  
196          // Verify the signature
197          let verifying_key = identity.verifying_key()
198              .expect("Failed to get verifying key");
199  
200          assert!(verifying_key.verify(message, &signature).is_ok());
201      }
202  }