keys.rs
1 //! Key generation and management. 2 3 use acdc_core::{config::NodeInstance, Error, Result}; 4 use acdc_tui::output; 5 use std::fs; 6 use std::path::Path; 7 use std::process::Command; 8 use tracing::debug; 9 10 /// Key file names. 11 pub const PRIVATE_KEY_FILE: &str = "private.key"; 12 pub const PUBLIC_KEY_FILE: &str = "public.key"; 13 pub const ADDRESS_FILE: &str = "address"; 14 pub const VALIDATOR_KEY_FILE: &str = "validator.key"; 15 16 /// Generate keys for a node instance. 17 pub fn generate_keys(instance: &NodeInstance) -> Result<bool> { 18 let keys_path = Path::new(&instance.keys.path); 19 20 // Create keys directory 21 fs::create_dir_all(keys_path).map_err(|e| Error::Io(e))?; 22 23 output::status("Generating cryptographic keys..."); 24 25 // Check if keys already exist 26 let private_key_path = keys_path.join(PRIVATE_KEY_FILE); 27 if private_key_path.exists() { 28 output::warning("Keys already exist, skipping generation"); 29 return Ok(false); 30 } 31 32 // Generate account key pair 33 // In production, this would call the ADNet binary or use the crypto library 34 // For now, generate placeholder keys for testing 35 generate_account_keys(keys_path)?; 36 37 // For validators, also generate validator-specific keys 38 if matches!(instance.role, acdc_core::NodeRole::Validator) { 39 generate_validator_keys(keys_path)?; 40 } 41 42 output::success("Keys generated successfully"); 43 output::warning("IMPORTANT: Back up your keys! They cannot be recovered if lost."); 44 45 Ok(true) 46 } 47 48 /// Generate account keys (private key, public key, address). 49 fn generate_account_keys(keys_path: &Path) -> Result<()> { 50 debug!("Generating account keys in {:?}", keys_path); 51 52 // Check if adnet binary is available for proper key generation 53 if check_adnet_binary() { 54 // Use ADNet for key generation 55 let output = Command::new("adnet") 56 .args(["account", "new", "--output", keys_path.to_str().unwrap()]) 57 .output() 58 .map_err(|e| Error::Io(e))?; 59 60 if !output.status.success() { 61 let stderr = String::from_utf8_lossy(&output.stderr); 62 return Err(Error::KeyManagement(format!( 63 "Key generation failed: {}", 64 stderr 65 ))); 66 } 67 } else { 68 // Generate placeholder keys for development 69 // In production, this would be replaced with proper crypto 70 generate_placeholder_keys(keys_path)?; 71 } 72 73 Ok(()) 74 } 75 76 /// Generate validator-specific keys. 77 fn generate_validator_keys(keys_path: &Path) -> Result<()> { 78 debug!("Generating validator keys in {:?}", keys_path); 79 80 let validator_key_path = keys_path.join(VALIDATOR_KEY_FILE); 81 82 if check_adnet_binary() { 83 let output = Command::new("adnet") 84 .args([ 85 "validator", 86 "keygen", 87 "--output", 88 validator_key_path.to_str().unwrap(), 89 ]) 90 .output() 91 .map_err(|e| Error::Io(e))?; 92 93 if !output.status.success() { 94 let stderr = String::from_utf8_lossy(&output.stderr); 95 return Err(Error::KeyManagement(format!( 96 "Validator key generation failed: {}", 97 stderr 98 ))); 99 } 100 } else { 101 // Placeholder for development 102 fs::write(&validator_key_path, "PLACEHOLDER_VALIDATOR_KEY\n").map_err(|e| Error::Io(e))?; 103 output::info("Note", "Placeholder validator key generated (dev mode)"); 104 } 105 106 Ok(()) 107 } 108 109 /// Check if the ADNet binary is available. 110 fn check_adnet_binary() -> bool { 111 Command::new("adnet") 112 .arg("--version") 113 .output() 114 .map(|o| o.status.success()) 115 .unwrap_or(false) 116 } 117 118 /// Generate placeholder keys for development. 119 fn generate_placeholder_keys(keys_path: &Path) -> Result<()> { 120 output::info("Note", "Generating placeholder keys (ADNet not installed)"); 121 122 // Generate random-ish placeholder data 123 let timestamp = std::time::SystemTime::now() 124 .duration_since(std::time::UNIX_EPOCH) 125 .unwrap() 126 .as_nanos(); 127 128 let private_key = format!("APrivateKey1placeholder{:032x}", timestamp); 129 let public_key = format!("aleo1placeholder{:048x}", timestamp); 130 let address = format!("ax1placeholder{:048x}", timestamp); 131 132 fs::write( 133 keys_path.join(PRIVATE_KEY_FILE), 134 format!("{}\n", private_key), 135 ) 136 .map_err(|e| Error::Io(e))?; 137 fs::write(keys_path.join(PUBLIC_KEY_FILE), format!("{}\n", public_key)) 138 .map_err(|e| Error::Io(e))?; 139 fs::write(keys_path.join(ADDRESS_FILE), format!("{}\n", address)).map_err(|e| Error::Io(e))?; 140 141 // Set secure permissions 142 #[cfg(unix)] 143 { 144 use std::os::unix::fs::PermissionsExt; 145 let private_key_path = keys_path.join(PRIVATE_KEY_FILE); 146 let mut perms = fs::metadata(&private_key_path)?.permissions(); 147 perms.set_mode(0o600); 148 fs::set_permissions(&private_key_path, perms)?; 149 } 150 151 Ok(()) 152 } 153 154 /// Import keys from a file. 155 pub fn import_keys(source_path: &Path, dest_path: &Path) -> Result<()> { 156 output::status("Importing keys..."); 157 158 if !source_path.exists() { 159 return Err(Error::KeyManagement(format!( 160 "Source path does not exist: {:?}", 161 source_path 162 ))); 163 } 164 165 fs::create_dir_all(dest_path).map_err(|e| Error::Io(e))?; 166 167 // Copy key files 168 let files = [ 169 PRIVATE_KEY_FILE, 170 PUBLIC_KEY_FILE, 171 ADDRESS_FILE, 172 VALIDATOR_KEY_FILE, 173 ]; 174 let mut copied = 0; 175 176 for file in &files { 177 let src = source_path.join(file); 178 if src.exists() { 179 let dst = dest_path.join(file); 180 fs::copy(&src, &dst).map_err(|e| Error::Io(e))?; 181 copied += 1; 182 debug!("Copied {:?} to {:?}", src, dst); 183 } 184 } 185 186 if copied == 0 { 187 return Err(Error::KeyManagement( 188 "No valid key files found in source directory".to_string(), 189 )); 190 } 191 192 output::success(&format!("Imported {} key file(s)", copied)); 193 Ok(()) 194 } 195 196 /// Export keys to a file (for backup). 197 pub fn export_keys(keys_path: &Path, export_path: &Path) -> Result<()> { 198 output::status("Exporting keys..."); 199 200 if !keys_path.exists() { 201 return Err(Error::KeyManagement(format!( 202 "Keys path does not exist: {:?}", 203 keys_path 204 ))); 205 } 206 207 fs::create_dir_all(export_path).map_err(|e| Error::Io(e))?; 208 209 // Copy key files 210 let files = [ 211 PRIVATE_KEY_FILE, 212 PUBLIC_KEY_FILE, 213 ADDRESS_FILE, 214 VALIDATOR_KEY_FILE, 215 ]; 216 let mut exported = 0; 217 218 for file in &files { 219 let src = keys_path.join(file); 220 if src.exists() { 221 let dst = export_path.join(file); 222 fs::copy(&src, &dst).map_err(|e| Error::Io(e))?; 223 exported += 1; 224 } 225 } 226 227 output::success(&format!( 228 "Exported {} key file(s) to {:?}", 229 exported, export_path 230 )); 231 Ok(()) 232 } 233 234 /// Verify key files exist and are valid. 235 pub fn verify_keys(keys_path: &Path) -> Result<KeyVerification> { 236 let mut verification = KeyVerification::default(); 237 238 let private_key_path = keys_path.join(PRIVATE_KEY_FILE); 239 verification.private_key = private_key_path.exists(); 240 241 let public_key_path = keys_path.join(PUBLIC_KEY_FILE); 242 verification.public_key = public_key_path.exists(); 243 244 let address_path = keys_path.join(ADDRESS_FILE); 245 verification.address = address_path.exists(); 246 247 let validator_key_path = keys_path.join(VALIDATOR_KEY_FILE); 248 verification.validator_key = validator_key_path.exists(); 249 250 // Read address for display 251 if verification.address { 252 verification.address_value = fs::read_to_string(&address_path).ok(); 253 } 254 255 Ok(verification) 256 } 257 258 /// Key verification result. 259 #[derive(Debug, Default)] 260 pub struct KeyVerification { 261 /// Private key exists 262 pub private_key: bool, 263 /// Public key exists 264 pub public_key: bool, 265 /// Address file exists 266 pub address: bool, 267 /// Validator key exists (for validators) 268 pub validator_key: bool, 269 /// Address value (if available) 270 pub address_value: Option<String>, 271 } 272 273 impl KeyVerification { 274 /// Check if minimum required keys are present. 275 pub fn is_valid(&self) -> bool { 276 self.private_key && self.address 277 } 278 279 /// Check if validator keys are present. 280 pub fn has_validator_keys(&self) -> bool { 281 self.validator_key 282 } 283 } 284 285 /// Print key verification status. 286 pub fn print_verification(verification: &KeyVerification) { 287 if verification.private_key { 288 output::success("Private key: Present"); 289 } else { 290 output::error("Private key: Missing"); 291 } 292 293 if verification.public_key { 294 output::success("Public key: Present"); 295 } else { 296 output::warning("Public key: Missing"); 297 } 298 299 if verification.address { 300 if let Some(ref addr) = verification.address_value { 301 output::success(&format!("Address: {}", addr.trim())); 302 } else { 303 output::success("Address: Present"); 304 } 305 } else { 306 output::error("Address: Missing"); 307 } 308 309 if verification.validator_key { 310 output::success("Validator key: Present"); 311 } 312 }