1use crate::error::IdentityError;
27use crate::{P2PError, Result};
28use serde::{Deserialize, Serialize};
29use sha2::{Digest, Sha256};
30use std::fmt;
31
32use crate::quantum_crypto::ant_quic_integration::{MlDsaPublicKey, MlDsaSecretKey, MlDsaSignature};
34
35#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
39pub struct NodeId(pub [u8; 32]);
40
41impl NodeId {
42 pub fn from_public_key(public_key: &MlDsaPublicKey) -> Self {
44 let mut hasher = Sha256::new();
45 hasher.update(public_key.as_bytes());
46 let hash = hasher.finalize();
47 let mut id = [0u8; 32];
48 id.copy_from_slice(&hash);
49 Self(id)
50 }
51
52 pub fn to_bytes(&self) -> &[u8; 32] {
54 &self.0
55 }
56
57 pub fn xor_distance(&self, other: &NodeId) -> [u8; 32] {
59 let mut distance = [0u8; 32];
60 for (i, out) in distance.iter_mut().enumerate() {
61 *out = self.0[i] ^ other.0[i];
62 }
63 distance
64 }
65
66 pub fn from_public_key_bytes(bytes: &[u8]) -> Result<Self> {
68 if bytes.len() != 1952 {
70 return Err(P2PError::Identity(IdentityError::InvalidFormat(
71 "Invalid ML-DSA public key length".to_string().into(),
72 )));
73 }
74
75 let public_key = MlDsaPublicKey::from_bytes(bytes).map_err(|e| {
77 IdentityError::InvalidFormat(format!("Invalid ML-DSA public key: {:?}", e).into())
78 })?;
79
80 Ok(NodeId::from_public_key(&public_key))
81 }
82
83 pub fn from_bytes(bytes: [u8; 32]) -> Self {
85 Self(bytes)
86 }
87}
88
89impl fmt::Display for NodeId {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(f, "{}", hex::encode(&self.0[..8])) }
93}
94
95#[derive(Clone)]
97pub struct PublicNodeIdentity {
98 public_key: MlDsaPublicKey,
100 node_id: NodeId,
102}
103
104impl PublicNodeIdentity {
105 pub fn node_id(&self) -> &NodeId {
107 &self.node_id
108 }
109
110 pub fn public_key(&self) -> &MlDsaPublicKey {
112 &self.public_key
113 }
114
115 }
117
118pub struct NodeIdentity {
120 secret_key: MlDsaSecretKey,
122 public_key: MlDsaPublicKey,
124 node_id: NodeId,
126}
127
128impl NodeIdentity {
129 pub fn generate() -> Result<Self> {
131 let (public_key, secret_key) =
133 crate::quantum_crypto::generate_ml_dsa_keypair().map_err(|e| {
134 P2PError::Identity(IdentityError::InvalidFormat(
135 format!("Failed to generate ML-DSA key pair: {}", e).into(),
136 ))
137 })?;
138
139 let node_id = NodeId::from_public_key(&public_key);
140
141 Ok(Self {
142 secret_key,
143 public_key,
144 node_id,
145 })
146 }
147
148 pub fn to_user_id(&self) -> crate::peer_record::UserId {
150 crate::peer_record::UserId::from_bytes(self.node_id.0)
151 }
152
153 pub fn from_seed(seed: &[u8; 32]) -> Result<Self> {
155 use saorsa_pqc::{HkdfSha3_256, api::traits::Kdf};
157
158 const ML_DSA_PUB_LEN: usize = 1952;
160 const ML_DSA_SEC_LEN: usize = 4032;
161
162 let mut derived = vec![0u8; ML_DSA_PUB_LEN + ML_DSA_SEC_LEN];
163 HkdfSha3_256::derive(seed, None, b"saorsa-node-identity-seed", &mut derived).map_err(
164 |_| P2PError::Identity(IdentityError::InvalidFormat("HKDF expand failed".into())),
165 )?;
166
167 let pub_bytes = &derived[..ML_DSA_PUB_LEN];
168 let sec_bytes = &derived[ML_DSA_PUB_LEN..];
169
170 let public_key =
172 crate::quantum_crypto::ant_quic_integration::MlDsaPublicKey::from_bytes(pub_bytes)
173 .map_err(|e| {
174 P2PError::Identity(IdentityError::InvalidFormat(
175 format!("Invalid ML-DSA public key bytes: {e}").into(),
176 ))
177 })?;
178 let secret_key =
179 crate::quantum_crypto::ant_quic_integration::MlDsaSecretKey::from_bytes(sec_bytes)
180 .map_err(|e| {
181 P2PError::Identity(IdentityError::InvalidFormat(
182 format!("Invalid ML-DSA secret key bytes: {e}").into(),
183 ))
184 })?;
185
186 let node_id = NodeId::from_public_key(&public_key);
187
188 Ok(Self {
189 secret_key,
190 public_key,
191 node_id,
192 })
193 }
194
195 pub fn node_id(&self) -> &NodeId {
197 &self.node_id
198 }
199
200 pub fn public_key(&self) -> &MlDsaPublicKey {
202 &self.public_key
203 }
204
205 pub fn secret_key_bytes(&self) -> &[u8] {
209 self.secret_key.as_bytes()
210 }
211
212 pub fn sign(&self, message: &[u8]) -> Result<MlDsaSignature> {
214 crate::quantum_crypto::ml_dsa_sign(&self.secret_key, message).map_err(|e| {
215 P2PError::Identity(IdentityError::InvalidFormat(
216 format!("ML-DSA signing failed: {:?}", e).into(),
217 ))
218 })
219 }
220
221 pub fn verify(&self, message: &[u8], signature: &MlDsaSignature) -> Result<bool> {
223 crate::quantum_crypto::ml_dsa_verify(&self.public_key, message, signature).map_err(|e| {
224 P2PError::Identity(IdentityError::InvalidFormat(
225 format!("ML-DSA verification failed: {:?}", e).into(),
226 ))
227 })
228 }
229
230 pub fn to_public(&self) -> PublicNodeIdentity {
232 PublicNodeIdentity {
233 public_key: self.public_key.clone(),
234 node_id: self.node_id.clone(),
235 }
236 }
237}
238
239impl NodeIdentity {
240 pub fn from_secret_key(_secret_key: MlDsaSecretKey) -> Result<Self> {
244 Err(P2PError::Identity(IdentityError::InvalidFormat(
245 "Creating identity from secret key alone is not supported"
246 .to_string()
247 .into(),
248 )))
249 }
250}
251
252impl NodeIdentity {
253 pub async fn save_to_file(&self, path: &std::path::Path) -> Result<()> {
255 use tokio::fs;
256 let data = self.export();
257 let json = serde_json::to_string_pretty(&data).map_err(|e| {
258 P2PError::Identity(crate::error::IdentityError::InvalidFormat(
259 format!("Failed to serialize identity: {}", e).into(),
260 ))
261 })?;
262
263 if let Some(parent) = path.parent() {
264 fs::create_dir_all(parent).await.map_err(|e| {
265 P2PError::Identity(crate::error::IdentityError::InvalidFormat(
266 format!("Failed to create directory: {}", e).into(),
267 ))
268 })?;
269 }
270
271 tokio::fs::write(path, json).await.map_err(|e| {
272 P2PError::Identity(crate::error::IdentityError::InvalidFormat(
273 format!("Failed to write identity file: {}", e).into(),
274 ))
275 })?;
276 Ok(())
277 }
278
279 pub async fn load_from_file(path: &std::path::Path) -> Result<Self> {
281 let json = tokio::fs::read_to_string(path).await.map_err(|e| {
282 P2PError::Identity(crate::error::IdentityError::InvalidFormat(
283 format!("Failed to read identity file: {}", e).into(),
284 ))
285 })?;
286 let data: IdentityData = serde_json::from_str(&json).map_err(|e| {
287 P2PError::Identity(crate::error::IdentityError::InvalidFormat(
288 format!("Failed to deserialize identity: {}", e).into(),
289 ))
290 })?;
291 Self::import(&data)
292 }
293}
294
295#[derive(Serialize, Deserialize)]
297pub struct IdentityData {
298 pub secret_key: Vec<u8>,
300 pub public_key: Vec<u8>,
302}
303
304impl NodeIdentity {
305 pub fn export(&self) -> IdentityData {
307 IdentityData {
308 secret_key: self.secret_key.as_bytes().to_vec(),
309 public_key: self.public_key.as_bytes().to_vec(),
310 }
311 }
312
313 pub fn import(data: &IdentityData) -> Result<Self> {
315 let secret_key = crate::quantum_crypto::ant_quic_integration::MlDsaSecretKey::from_bytes(
317 &data.secret_key,
318 )
319 .map_err(|e| {
320 P2PError::Identity(IdentityError::InvalidFormat(
321 format!("Invalid ML-DSA secret key: {e}").into(),
322 ))
323 })?;
324 let public_key = crate::quantum_crypto::ant_quic_integration::MlDsaPublicKey::from_bytes(
325 &data.public_key,
326 )
327 .map_err(|e| {
328 P2PError::Identity(IdentityError::InvalidFormat(
329 format!("Invalid ML-DSA public key: {e}").into(),
330 ))
331 })?;
332
333 let node_id = NodeId::from_public_key(&public_key);
334 Ok(Self {
335 secret_key,
336 public_key,
337 node_id,
338 })
339 }
340}
341
342#[cfg(test)]
343mod tests {
344 use super::*;
345
346 #[test]
347 fn test_node_id_generation() {
348 let (public_key, _secret_key) = crate::quantum_crypto::generate_ml_dsa_keypair()
349 .expect("ML-DSA key generation should succeed");
350 let node_id = NodeId::from_public_key(&public_key);
351
352 assert_eq!(node_id.to_bytes().len(), 32);
354
355 let node_id2 = NodeId::from_public_key(&public_key);
357 assert_eq!(node_id, node_id2);
358 }
359
360 #[test]
361 fn test_xor_distance() {
362 let id1 = NodeId([0u8; 32]);
363 let mut id2_bytes = [0u8; 32];
364 id2_bytes[0] = 0xFF;
365 let id2 = NodeId(id2_bytes);
366
367 let distance = id1.xor_distance(&id2);
368 assert_eq!(distance[0], 0xFF);
369 for byte in &distance[1..] {
370 assert_eq!(*byte, 0);
371 }
372 }
373
374 #[test]
375 fn test_proof_of_work() {
376 }
378
379 #[test]
380 fn test_identity_generation() {
381 let identity = NodeIdentity::generate().expect("Identity generation should succeed");
382
383 let message = b"Hello, P2P!";
385 let signature = identity.sign(message).unwrap();
386 assert!(identity.verify(message, &signature).unwrap());
387
388 assert!(!identity.verify(b"Wrong message", &signature).unwrap());
390 }
391
392 #[test]
393 fn test_deterministic_generation() {
394 let seed = [0x42; 32];
395 let identity1 = NodeIdentity::from_seed(&seed).expect("Identity from seed should succeed");
396 let identity2 = NodeIdentity::from_seed(&seed).expect("Identity from seed should succeed");
397
398 assert_eq!(identity1.node_id, identity2.node_id);
400 assert_eq!(
401 identity1.public_key().as_bytes(),
402 identity2.public_key().as_bytes()
403 );
404 }
405
406 #[test]
407 fn test_identity_persistence() {
408 let identity = NodeIdentity::generate().expect("Identity generation should succeed");
409
410 let data = identity.export();
412
413 let imported = NodeIdentity::import(&data).expect("Import should succeed with valid data");
415
416 assert_eq!(identity.node_id, imported.node_id);
418 assert_eq!(
419 identity.public_key().as_bytes(),
420 imported.public_key().as_bytes()
421 );
422
423 let message = b"Test message";
425 let signature = imported.sign(message);
426 assert!(identity.verify(message, &signature.unwrap()).unwrap());
427 }
428}