tibet_cortex_core/
crypto.rs1use ed25519_dalek::{SigningKey, VerifyingKey, Signer, Verifier, Signature};
2use sha2::{Sha256, Digest};
3use serde::{Serialize, Deserialize};
4use zeroize::{Zeroize, ZeroizeOnDrop};
5
6use crate::error::{CortexError, CortexResult};
7
8pub struct KeyPair {
10 signing: SigningKey,
11 verifying: VerifyingKey,
12}
13
14impl KeyPair {
15 pub fn generate() -> Self {
16 let mut rng = rand::rngs::OsRng;
17 let signing = SigningKey::generate(&mut rng);
18 let verifying = signing.verifying_key();
19 Self { signing, verifying }
20 }
21
22 pub fn sign(&self, data: &[u8]) -> Vec<u8> {
23 self.signing.sign(data).to_bytes().to_vec()
24 }
25
26 pub fn verify(&self, data: &[u8], signature: &[u8]) -> CortexResult<()> {
27 let sig = Signature::from_slice(signature)
28 .map_err(|e| CortexError::Crypto(e.to_string()))?;
29 self.verifying
30 .verify(data, &sig)
31 .map_err(|_| CortexError::SignatureInvalid)
32 }
33
34 pub fn verifying_key_bytes(&self) -> [u8; 32] {
35 self.verifying.to_bytes()
36 }
37
38 pub fn from_signing_key_bytes(bytes: &[u8; 32]) -> Self {
39 let signing = SigningKey::from_bytes(bytes);
40 let verifying = signing.verifying_key();
41 Self { signing, verifying }
42 }
43}
44
45impl Drop for KeyPair {
46 fn drop(&mut self) {
47 }
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
53pub struct ContentHash(pub String);
54
55impl ContentHash {
56 pub fn compute(data: &[u8]) -> Self {
57 let mut hasher = Sha256::new();
58 hasher.update(data);
59 let result = hasher.finalize();
60 Self(format!("sha256:{}", hex::encode(result)))
61 }
62
63 pub fn verify(&self, data: &[u8]) -> bool {
64 let computed = Self::compute(data);
65 computed == *self
66 }
67
68 pub fn as_str(&self) -> &str {
69 &self.0
70 }
71}
72
73impl std::fmt::Display for ContentHash {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(f, "{}", self.0)
76 }
77}
78
79#[derive(Zeroize, ZeroizeOnDrop)]
81pub struct SecureBuffer {
82 data: Vec<u8>,
83}
84
85impl SecureBuffer {
86 pub fn new(data: Vec<u8>) -> Self {
87 Self { data }
88 }
89
90 pub fn as_bytes(&self) -> &[u8] {
91 &self.data
92 }
93
94 pub fn len(&self) -> usize {
95 self.data.len()
96 }
97
98 pub fn is_empty(&self) -> bool {
99 self.data.is_empty()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_keypair_sign_verify() {
109 let kp = KeyPair::generate();
110 let data = b"TIBET Cortex test data";
111 let sig = kp.sign(data);
112 assert!(kp.verify(data, &sig).is_ok());
113 }
114
115 #[test]
116 fn test_tampered_data_fails() {
117 let kp = KeyPair::generate();
118 let data = b"original data";
119 let sig = kp.sign(data);
120 assert!(kp.verify(b"tampered data", &sig).is_err());
121 }
122
123 #[test]
124 fn test_content_hash() {
125 let data = b"hello cortex";
126 let hash = ContentHash::compute(data);
127 assert!(hash.verify(data));
128 assert!(!hash.verify(b"tampered"));
129 assert!(hash.as_str().starts_with("sha256:"));
130 }
131
132 #[test]
133 fn test_secure_buffer_basics() {
134 let buf = SecureBuffer::new(vec![1, 2, 3, 4]);
135 assert_eq!(buf.len(), 4);
136 assert_eq!(buf.as_bytes(), &[1, 2, 3, 4]);
137 assert!(!buf.is_empty());
138 }
140}