_hope_core/genome.rs
1//! # Hope Genome v1.4.0 - Sealed Genome (Ethical Ruleset)
2//!
3//! **Hardened Security Edition - KeyStore Integration**
4//!
5//! ## Major Changes in v1.4.0
6//!
7//! ### 1. KeyStore Trait Support
8//! - **Backward Compatible**: Still supports deprecated `KeyPair`
9//! - **New API**: Accepts any `KeyStore` implementation
10//! - **Future-Proof**: Easy to use HSM, TPM, etc.
11//!
12//! ### 2. Ed25519 Signatures
13//! - All proofs now signed with Ed25519 (via KeyStore)
14//! - Faster, smaller, more secure than RSA
15//!
16//! ---
17//!
18//! **Date**: 2025-12-30
19//! **Version**: 1.4.0 (Hardened Security Edition)
20//! **Author**: Máté Róbert <stratosoiteam@gmail.com>
21
22#[allow(deprecated)]
23use crate::crypto::{create_key_store, hash_bytes, KeyPair, KeyStore, KeyStoreConfig};
24use crate::proof::{Action, IntegrityProof};
25use thiserror::Error;
26
27#[derive(Debug, Error)]
28pub enum GenomeError {
29 #[error("Genome not sealed yet")]
30 NotSealed,
31
32 #[error("Genome already sealed")]
33 AlreadySealed,
34
35 #[error("Action violates genome rules: {0}")]
36 RuleViolation(String),
37
38 #[error("HSM configuration error: environment variable {0} not set")]
39 HsmConfigError(String),
40
41 #[error("Crypto error: {0}")]
42 CryptoError(#[from] crate::crypto::CryptoError),
43}
44
45pub type Result<T> = std::result::Result<T, GenomeError>;
46
47/// The sealed genome - immutable ethical ruleset
48///
49/// This is the core of the Hope Genome framework. It:
50/// - Contains immutable ethical rules
51/// - Signs action approvals with Ed25519 (v1.4.0+)
52/// - Provides cryptographic proofs for all decisions
53///
54/// ## Example (v1.4.0 New API)
55///
56/// ```rust
57/// use _hope_core::genome::SealedGenome;
58/// use _hope_core::crypto::SoftwareKeyStore;
59/// use _hope_core::proof::Action;
60///
61/// // Create genome with new KeyStore API
62/// let key_store = SoftwareKeyStore::generate().unwrap();
63/// let rules = vec!["Do no harm".to_string()];
64///
65/// let mut genome = SealedGenome::with_key_store(
66/// rules,
67/// Box::new(key_store),
68/// ).unwrap();
69///
70/// genome.seal().unwrap();
71///
72/// // Verify action and get proof
73/// let action = Action::delete("test.txt");
74/// let proof = genome.verify_action(&action).unwrap();
75/// ```
76pub struct SealedGenome {
77 /// Ethical rules (immutable after sealing)
78 rules: Vec<String>,
79
80 /// Whether the genome is sealed
81 sealed: bool,
82
83 /// Cryptographic key store for signing (v1.4.0: trait-based)
84 key_store: Box<dyn KeyStore>,
85
86 /// Hash of the sealed genome (for proof binding)
87 capsule_hash: Option<String>,
88
89 /// Default TTL for proofs (seconds)
90 default_ttl: u64,
91}
92
93impl SealedGenome {
94 /// Create a new genome with rules.
95 ///
96 /// **HARDENED SECURITY**: This function automatically detects if an HSM is configured
97 /// via environment variables. If `PKCS11_MODULE_PATH` is set, it will create an
98 /// `HsmKeyStore`, ensuring the private key never enters system RAM. Otherwise, it
99 /// falls back to a software-based key store for development and testing.
100 ///
101 /// # HSM Configuration (Environment Variables)
102 /// - `PKCS11_MODULE_PATH`: Path to the PKCS#11 library (`.so` or `.dll`).
103 /// - `PKCS11_TOKEN_LABEL`: Label of the HSM token.
104 /// - `PKCS11_KEY_LABEL`: Label of the key within the HSM.
105 /// - `PKCS11_PIN`: The user PIN for the HSM. **WARNING**: Use secrets management in production.
106 ///
107 /// # Example
108 /// ```rust
109 /// use _hope_core::genome::SealedGenome;
110 ///
111 /// // This will use SoftwareKeyStore unless HSM env vars are set.
112 /// let rules = vec!["Do no harm".to_string()];
113 /// let genome = SealedGenome::new(rules).unwrap();
114 /// ```
115 pub fn new(rules: Vec<String>) -> Result<Self> {
116 #[cfg(not(feature = "hsm-support"))]
117 let config = KeyStoreConfig::Software;
118
119 #[cfg(feature = "hsm-support")]
120 let config = {
121 // Use std::env explicitly to avoid ambiguity
122 use std::env;
123 if let Ok(pkcs11_path) = env::var("PKCS11_MODULE_PATH") {
124 // If HSM path is set, construct HsmConfig from environment variables.
125 let hsm_config = crate::crypto::HsmConfig {
126 pkcs11_lib_path: pkcs11_path,
127 token_label: env::var("PKCS11_TOKEN_LABEL").map_err(|_| {
128 GenomeError::HsmConfigError("PKCS11_TOKEN_LABEL".to_string())
129 })?,
130 key_label: env::var("PKCS11_KEY_LABEL")
131 .map_err(|_| GenomeError::HsmConfigError("PKCS11_KEY_LABEL".to_string()))?,
132 pin: env::var("PKCS11_PIN")
133 .map_err(|_| GenomeError::HsmConfigError("PKCS11_PIN".to_string()))?,
134 };
135 KeyStoreConfig::Hsm(hsm_config)
136 } else {
137 KeyStoreConfig::Software
138 }
139 };
140
141 let key_store = create_key_store(config)?;
142 Self::with_key_store(rules, key_store)
143 }
144
145 /// Create a new genome with an existing KeyPair (deprecated)
146 ///
147 /// **DEPRECATED in v1.4.0**: Use `with_key_store()` instead.
148 ///
149 /// # Example (Legacy)
150 /// ```rust
151 /// use _hope_core::genome::SealedGenome;
152 /// use _hope_core::crypto::KeyPair;
153 ///
154 /// # #[allow(deprecated)]
155 /// let keypair = KeyPair::generate().unwrap();
156 /// # #[allow(deprecated)]
157 /// let genome = SealedGenome::with_keypair(
158 /// vec!["Rule 1".to_string()],
159 /// keypair,
160 /// ).unwrap();
161 /// ```
162 #[allow(deprecated)]
163 #[deprecated(since = "1.4.0", note = "Use with_key_store() for new code")]
164 pub fn with_keypair(rules: Vec<String>, keypair: KeyPair) -> Result<Self> {
165 Ok(SealedGenome {
166 rules,
167 sealed: false,
168 key_store: Box::new(keypair),
169 capsule_hash: None,
170 default_ttl: 60, // 1 minute default
171 })
172 }
173
174 /// Create a new genome with a custom KeyStore (v1.4.0)
175 ///
176 /// This is the recommended way to create a genome in v1.4.0+.
177 /// Supports any KeyStore implementation (Software, HSM, etc.).
178 ///
179 /// # Example
180 /// ```rust
181 /// use _hope_core::genome::SealedGenome;
182 /// use _hope_core::crypto::SoftwareKeyStore;
183 ///
184 /// let key_store = SoftwareKeyStore::generate().unwrap();
185 /// let rules = vec!["Protect privacy".to_string()];
186 ///
187 /// let genome = SealedGenome::with_key_store(
188 /// rules,
189 /// Box::new(key_store),
190 /// ).unwrap();
191 /// ```
192 pub fn with_key_store(rules: Vec<String>, key_store: Box<dyn KeyStore>) -> Result<Self> {
193 Ok(SealedGenome {
194 rules,
195 sealed: false,
196 key_store,
197 capsule_hash: None,
198 default_ttl: 60, // 1 minute default
199 })
200 }
201
202 /// Seal the genome (make it immutable)
203 ///
204 /// After sealing:
205 /// - Rules cannot be modified
206 /// - Capsule hash is computed
207 /// - Actions can be verified and signed
208 ///
209 /// # Example
210 /// ```rust
211 /// use _hope_core::genome::SealedGenome;
212 ///
213 /// let mut genome = SealedGenome::new(vec!["Rule 1".to_string()]).unwrap();
214 /// genome.seal().unwrap();
215 ///
216 /// assert!(genome.is_sealed());
217 /// ```
218 pub fn seal(&mut self) -> Result<()> {
219 if self.sealed {
220 return Err(GenomeError::AlreadySealed);
221 }
222
223 // Compute capsule hash (hash of all rules)
224 let rules_json = serde_json::to_string(&self.rules).unwrap();
225 let hash = hash_bytes(rules_json.as_bytes());
226 self.capsule_hash = Some(hex::encode(hash));
227
228 self.sealed = true;
229
230 Ok(())
231 }
232
233 /// Check if genome is sealed
234 pub fn is_sealed(&self) -> bool {
235 self.sealed
236 }
237
238 /// Get the rules
239 pub fn rules(&self) -> &[String] {
240 &self.rules
241 }
242
243 /// Set default TTL for proofs (in seconds)
244 ///
245 /// # Example
246 /// ```rust
247 /// use _hope_core::genome::SealedGenome;
248 ///
249 /// let mut genome = SealedGenome::new(vec!["Rule 1".to_string()]).unwrap();
250 /// genome.set_default_ttl(3600); // 1 hour
251 /// ```
252 pub fn set_default_ttl(&mut self, ttl: u64) {
253 self.default_ttl = ttl;
254 }
255
256 /// Verify an action against the genome rules
257 ///
258 /// This is where ethical decision-making happens.
259 /// Returns a cryptographically signed proof if approved.
260 ///
261 /// # Security (v1.4.0)
262 /// - Proof signed with Ed25519 (fast, secure)
263 /// - Includes nonce for replay attack prevention
264 /// - Bound to capsule hash (prevents proof reuse across genomes)
265 ///
266 /// # Example
267 /// ```rust
268 /// use _hope_core::genome::SealedGenome;
269 /// use _hope_core::proof::Action;
270 ///
271 /// let mut genome = SealedGenome::new(vec!["Do no harm".to_string()]).unwrap();
272 /// genome.seal().unwrap();
273 ///
274 /// let action = Action::delete("test.txt");
275 /// let proof = genome.verify_action(&action).unwrap();
276 ///
277 /// assert!(!proof.signature.is_empty());
278 /// assert_eq!(proof.signature.len(), 64); // Ed25519 signature
279 /// ```
280 pub fn verify_action(&self, action: &Action) -> Result<IntegrityProof> {
281 if !self.sealed {
282 return Err(GenomeError::NotSealed);
283 }
284
285 // Basic rule checking (simple implementation)
286 // In production, this would use sophisticated reasoning
287 let action_str = format!("{:?}", action);
288
289 // Check rules (simplified)
290 for rule in &self.rules {
291 if rule.contains("no harm") && action_str.contains("delete") {
292 // More sophisticated checking would happen here
293 }
294 }
295
296 // Create proof
297 let capsule_hash = self.capsule_hash.as_ref().unwrap().clone();
298 let mut proof = IntegrityProof::new(action, capsule_hash, self.default_ttl);
299
300 // Sign the proof (v1.4.0: uses KeyStore trait)
301 let signing_data = proof.signing_data();
302 proof.signature = self.key_store.sign(&signing_data)?;
303
304 Ok(proof)
305 }
306
307 /// Get the capsule hash
308 ///
309 /// Returns `None` if genome is not yet sealed.
310 pub fn capsule_hash(&self) -> Option<&str> {
311 self.capsule_hash.as_deref()
312 }
313
314 /// Get the public key bytes (for verification by external parties)
315 ///
316 /// # Example
317 /// ```rust
318 /// use _hope_core::genome::SealedGenome;
319 ///
320 /// let genome = SealedGenome::new(vec!["Rule 1".to_string()]).unwrap();
321 /// let public_key = genome.public_key_bytes();
322 ///
323 /// assert_eq!(public_key.len(), 32); // Ed25519 public key
324 /// ```
325 pub fn public_key_bytes(&self) -> Vec<u8> {
326 self.key_store.public_key_bytes()
327 }
328
329 /// Get key store information (for debugging/logging)
330 pub fn key_store_info(&self) -> String {
331 self.key_store.identifier()
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338 use crate::crypto::SoftwareKeyStore;
339
340 #[test]
341 fn test_genome_creation() {
342 let rules = vec!["Do no harm".to_string(), "Respect privacy".to_string()];
343 let genome = SealedGenome::new(rules).unwrap();
344
345 assert!(!genome.is_sealed());
346 assert_eq!(genome.rules().len(), 2);
347 }
348
349 #[test]
350 fn test_genome_creation_with_key_store() {
351 let key_store = SoftwareKeyStore::generate().unwrap();
352 let rules = vec!["Rule 1".to_string()];
353
354 let genome = SealedGenome::with_key_store(rules, Box::new(key_store)).unwrap();
355
356 assert!(!genome.is_sealed());
357 assert_eq!(genome.rules().len(), 1);
358 }
359
360 #[test]
361 fn test_genome_sealing() {
362 let rules = vec!["Rule 1".to_string()];
363 let mut genome = SealedGenome::new(rules).unwrap();
364
365 assert!(genome.seal().is_ok());
366 assert!(genome.is_sealed());
367 assert!(genome.capsule_hash().is_some());
368 }
369
370 #[test]
371 fn test_cannot_seal_twice() {
372 let rules = vec!["Rule 1".to_string()];
373 let mut genome = SealedGenome::new(rules).unwrap();
374
375 genome.seal().unwrap();
376
377 let result = genome.seal();
378 assert!(matches!(result, Err(GenomeError::AlreadySealed)));
379 }
380
381 #[test]
382 fn test_cannot_verify_unsealed() {
383 let rules = vec!["Rule 1".to_string()];
384 let genome = SealedGenome::new(rules).unwrap();
385
386 let action = Action::delete("test.txt");
387 let result = genome.verify_action(&action);
388
389 assert!(matches!(result, Err(GenomeError::NotSealed)));
390 }
391
392 #[test]
393 fn test_verify_action_creates_valid_proof() {
394 let rules = vec!["Do no harm".to_string()];
395 let mut genome = SealedGenome::new(rules).unwrap();
396 genome.seal().unwrap();
397
398 let action = Action::delete("test.txt");
399 let proof = genome.verify_action(&action).unwrap();
400
401 // Verify proof properties
402 assert_eq!(proof.action_hash, action.hash());
403 assert!(!proof.signature.is_empty());
404 assert_eq!(proof.signature.len(), 64); // Ed25519 signature is 64 bytes
405 assert_eq!(proof.ttl, 60); // Default TTL
406 }
407
408 #[test]
409 fn test_capsule_hash_deterministic() {
410 let rules = vec!["Rule 1".to_string(), "Rule 2".to_string()];
411 let mut genome1 = SealedGenome::new(rules.clone()).unwrap();
412 let mut genome2 = SealedGenome::new(rules.clone()).unwrap();
413
414 genome1.seal().unwrap();
415 genome2.seal().unwrap();
416
417 assert_eq!(genome1.capsule_hash(), genome2.capsule_hash());
418 }
419
420 #[test]
421 fn test_different_rules_different_hashes() {
422 let rules1 = vec!["Rule 1".to_string()];
423 let rules2 = vec!["Rule 2".to_string()];
424
425 let mut genome1 = SealedGenome::new(rules1).unwrap();
426 let mut genome2 = SealedGenome::new(rules2).unwrap();
427
428 genome1.seal().unwrap();
429 genome2.seal().unwrap();
430
431 assert_ne!(genome1.capsule_hash(), genome2.capsule_hash());
432 }
433
434 #[test]
435 fn test_custom_ttl() {
436 let rules = vec!["Rule 1".to_string()];
437 let mut genome = SealedGenome::new(rules).unwrap();
438 genome.set_default_ttl(3600);
439 genome.seal().unwrap();
440
441 let action = Action::delete("test.txt");
442 let proof = genome.verify_action(&action).unwrap();
443
444 assert_eq!(proof.ttl, 3600);
445 }
446
447 #[test]
448 fn test_public_key_export() {
449 let genome = SealedGenome::new(vec!["Rule 1".to_string()]).unwrap();
450 let public_key = genome.public_key_bytes();
451
452 assert_eq!(public_key.len(), 32); // Ed25519 public key is 32 bytes
453 }
454
455 #[test]
456 fn test_proof_signature_can_be_verified() {
457 let key_store = SoftwareKeyStore::generate().unwrap();
458 let key_store_clone = key_store.clone();
459
460 let mut genome =
461 SealedGenome::with_key_store(vec!["Rule 1".to_string()], Box::new(key_store)).unwrap();
462
463 genome.seal().unwrap();
464
465 let action = Action::delete("test.txt");
466 let proof = genome.verify_action(&action).unwrap();
467
468 // Verify signature with the same key store
469 let signing_data = proof.signing_data();
470 assert!(key_store_clone
471 .verify(&signing_data, &proof.signature)
472 .is_ok());
473 }
474
475 #[test]
476 #[allow(deprecated)]
477 fn test_backward_compatibility_with_keypair() {
478 let keypair = KeyPair::generate().unwrap();
479 let mut genome = SealedGenome::with_keypair(vec!["Rule 1".to_string()], keypair).unwrap();
480
481 genome.seal().unwrap();
482
483 let action = Action::delete("test.txt");
484 let proof = genome.verify_action(&action).unwrap();
485
486 assert!(!proof.signature.is_empty());
487 }
488
489 #[test]
490 fn test_key_store_info() {
491 let genome = SealedGenome::new(vec!["Rule 1".to_string()]).unwrap();
492 let info = genome.key_store_info();
493
494 assert!(info.contains("KeyPair") || info.contains("SoftwareKeyStore"));
495 }
496}