1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
//! Wasif Vernam Cipher Implementation
//!
//! This module implements the Wasif Vernam cipher, a quantum-resistant encryption scheme
//! that combines multiple layers of security:
//!
//! 1. Base Layer: ChaCha20-Poly1305 for authenticated encryption
//! 2. XOR Layer: HKDF-derived keystream or TRUE Vernam random data
//! 3. Optional: Ciphertext scrambling for traffic analysis resistance
//! 4. Optional: Recursive key chain for forward secrecy
use chacha20poly1305::{
aead::{Aead, Error as AeadError},
ChaCha20Poly1305, KeyInit, Nonce,
};
use hkdf::Hkdf;
use sha2::{Digest, Sha256};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use tokio::sync::Mutex;
use zeroize::{Zeroize, Zeroizing};
use crate::anti_replay::AntiReplayContainer;
use crate::recursive_chain::RecursiveChain;
use crate::scramble::CiphertextScrambler;
use crate::true_vernam::{TrueVernamBuffer, SynchronizedVernamBuffer};
use std::time::Duration;
use tokio::time::interval;
use tracing::{debug, error, info, warn};
/// The main Wasif Vernam cipher implementation
///
/// ✅ TRUE INFORMATION-THEORETIC SECURITY: When using SynchronizedVernamBuffer with shared
/// random seeds, this provides TRUE unbreakable encryption by the laws of physics.
///
/// Security Modes:
/// - Mode 0x01: TRUE OTP via SynchronizedVernamBuffer (information-theoretic, unbreakable)
/// - Mode 0x02: HKDF-based XOR (computational, 256-bit security)
///
/// For TRUE OTP: Both parties must derive the same shared seed during handshake (e.g., from
/// ML-KEM shared secret + drand entropy + peer contributions). The keystream is generated
/// deterministically from seed + position - NO key transmission required!
pub struct WasifVernam {
cipher: ChaCha20Poly1305,
nonce_counter: AtomicU64,
anti_replay: Arc<AntiReplayContainer>,
swarm_seed: Zeroizing<[u8; 32]>,
key_offset: AtomicU64,
has_swarm_entropy: bool,
true_vernam_buffer: Option<Arc<Mutex<TrueVernamBuffer>>>,
/// TRUE OTP: Synchronized keystream generator (no key transmission!)
synchronized_buffer: Option<Arc<SynchronizedVernamBuffer>>,
scrambler: Option<CiphertextScrambler>,
key_chain: Option<RecursiveChain>,
}
impl WasifVernam {
/// Create a new Wasif Vernam cipher with the given key
pub fn new(key: [u8; 32]) -> Result<Self, AeadError> {
let cipher = ChaCha20Poly1305::new_from_slice(&key)
.map_err(|_| chacha20poly1305::aead::Error)?;
Ok(Self {
cipher,
nonce_counter: AtomicU64::new(0),
anti_replay: Arc::new(AntiReplayContainer::new()),
swarm_seed: Zeroizing::new([0u8; 32]),
key_offset: AtomicU64::new(0),
has_swarm_entropy: false,
true_vernam_buffer: None,
synchronized_buffer: None,
scrambler: None,
key_chain: None,
})
}
/// Enable TRUE Vernam mode with a buffer for random data
pub fn enable_true_vernam(&mut self, _buffer_size: usize) {
let buffer = TrueVernamBuffer::new();
self.true_vernam_buffer = Some(Arc::new(Mutex::new(buffer)));
}
/// Enable TRUE Vernam mode with synchronized keystream generation
///
/// This provides information-theoretic security by using a shared seed
/// derived from multiple entropy sources (ML-KEM + drand + peer contributions).
/// Both parties generate identical keystreams from the same shared seed.
///
/// # Arguments
/// * `shared_seed` - 32-byte shared seed from create_shared_seed()
pub fn enable_synchronized_vernam(&mut self, shared_seed: [u8; 32]) {
let sync_buffer = SynchronizedVernamBuffer::new(shared_seed);
self.synchronized_buffer = Some(Arc::new(sync_buffer));
info!("✅ Enabled TRUE synchronized Vernam mode (information-theoretic security)");
}
/// Create a shared seed from multiple entropy sources for TRUE OTP
///
/// This combines multiple entropy sources using XOR for information-theoretic security:
/// - ML-KEM shared secret from handshake
/// - drand entropy (both parties fetch same round)
/// - Peer contributions XOR'd during handshake
///
/// The result is information-theoretically secure if at least one source is random.
///
/// # Arguments
/// * `mlkem_secret` - 32-byte shared secret from ML-KEM handshake
/// * `drand_entropy` - 32-byte drand entropy (same round for both parties)
/// * `peer_contributions` - XOR of all peer contributions from handshake
///
/// # Returns
/// 32-byte shared seed for synchronized Vernam buffer
pub fn create_shared_seed(
mlkem_secret: [u8; 32],
drand_entropy: [u8; 32],
peer_contributions: [u8; 32],
) -> [u8; 32] {
let mut shared_seed = [0u8; 32];
// Information-theoretic XOR combination: secure if any source is random
for i in 0..32 {
shared_seed[i] = mlkem_secret[i] ^ drand_entropy[i] ^ peer_contributions[i];
}
debug!("🔑 Created shared seed from ML-KEM + drand + peer contributions (information-theoretic)");
shared_seed
}
/// Enable ciphertext scrambling with a specific permutation size
pub fn enable_scrambling(&mut self, size: usize) {
// Use the swarm seed as entropy for scrambling
self.scrambler = Some(CiphertextScrambler::from_entropy(&self.swarm_seed, size));
}
/// Enable recursive key chain for forward secrecy
pub fn enable_key_chain(&mut self, initial_seed: [u8; 32], is_alice: bool) {
self.key_chain = Some(RecursiveChain::new(&initial_seed, is_alice));
}
/// Generate a keystream using HKDF with the swarm seed
///
/// ⚠️ SECURITY NOTE: This uses a static swarm seed. For forward secrecy,
/// call refresh_entropy() periodically or use the recursive key chain feature.
fn generate_keystream(&self, offset: u64, length: usize) -> Vec<u8> {
// Use stack allocation for small sizes to avoid heap allocation in hot path
const SMALL_BUFFER_SIZE: usize = 1024;
let hk = Hkdf::<Sha256>::new(Some(b"zks-vernam-keystream"), &*self.swarm_seed);
let info = format!("offset-{}", offset);
if length <= SMALL_BUFFER_SIZE {
let mut small_buffer = [0u8; SMALL_BUFFER_SIZE];
if hk.expand(info.as_bytes(), &mut small_buffer[..length]).is_err() {
return Vec::new(); // Return empty vector on HKDF failure
}
small_buffer[..length].to_vec()
} else {
let mut keystream = vec![0u8; length];
if hk.expand(info.as_bytes(), &mut keystream).is_err() {
return Vec::new(); // Return empty vector on HKDF failure
}
keystream
}
}
/// Update the cipher key (used during key rotation)
fn update_cipher_key(&mut self, new_key: [u8; 32]) -> Result<(), AeadError> {
self.cipher = ChaCha20Poly1305::new_from_slice(&new_key)
.map_err(|_| chacha20poly1305::aead::Error)?;
info!("🔑 Cipher key rotated successfully");
Ok(())
}
/// Encrypt data using the Wasif Vernam cipher
pub fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, AeadError> {
// Generate unique nonce and get counter
let mut nonce_bytes = [0u8; 12];
let counter = self.nonce_counter.fetch_add(1, Ordering::SeqCst);
// Check for nonce wraparound - this would cause nonce reuse
// Note: counter is the value BEFORE the increment, so 0 is valid for the first call
if counter == u64::MAX {
// Counter wrapped around - this is a security risk
error!("🚨 CRITICAL: Nonce counter wrapped around - nonce reuse imminent!");
return Err(AeadError);
}
// Use counter as part of nonce for uniqueness
nonce_bytes[4..12].copy_from_slice(&counter.to_be_bytes());
// Key rotation logic
if let Some(ref mut chain) = self.key_chain {
if counter % 1000 == 0 && counter > 0 {
let mut entropy = [0u8; 32];
if getrandom::getrandom(&mut entropy).is_err() {
warn!("RNG unavailable during key rotation");
return Err(AeadError);
}
let new_key = chain.advance(&entropy);
if let Err(_) = self.update_cipher_key(new_key) {
warn!("Failed to update cipher key during rotation");
return Err(AeadError);
}
// Reset nonce counter after key rotation to prevent correlation
self.nonce_counter.store(0, Ordering::SeqCst);
info!("🔑 Cipher key rotated successfully - nonce counter reset");
entropy.zeroize();
}
}
// True Vernam XOR layer (if swarm entropy available)
let mut mixed_data = Zeroizing::new(data.to_vec());
let key_offset = if self.has_swarm_entropy {
// Use synchronized buffer if available (information-theoretic security)
if let Some(ref sync_buffer) = self.synchronized_buffer {
let keystream = sync_buffer.consume_sync(data.len());
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
}
self.key_offset.fetch_add(data.len() as u64, Ordering::SeqCst)
} else {
// Fallback to static swarm seed (computational security)
let offset = self.key_offset.fetch_add(data.len() as u64, Ordering::SeqCst);
let keystream = self.generate_keystream(offset, data.len());
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
}
offset
}
} else {
0
};
// ChaCha20-Poly1305 encryption
let nonce = Nonce::from_slice(&nonce_bytes);
let mut ciphertext = self.cipher.encrypt(nonce, mixed_data.as_ref())?;
// Scrambling (if enabled)
if let Some(ref scrambler) = self.scrambler {
if ciphertext.len() == scrambler.size() {
scrambler.scramble(&mut ciphertext);
}
}
// Build result envelope
let mut result = Vec::with_capacity(12 + 8 + ciphertext.len());
result.extend_from_slice(&nonce_bytes);
result.extend_from_slice(&key_offset.to_be_bytes());
result.append(&mut ciphertext);
Ok(result)
}
/// Decrypt data encrypted with the Wasif Vernam cipher
pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, AeadError> {
if data.len() < 12 + 8 {
return Err(AeadError);
}
// Extract nonce and key offset
let nonce = Nonce::from_slice(&data[0..12]);
let key_offset = match data[12..20].try_into() {
Ok(bytes) => u64::from_be_bytes(bytes),
Err(_) => return Err(AeadError),
};
let ciphertext = &data[20..];
// Check for replay attacks using counter from nonce bytes 4-12
let counter_bytes = &data[4..12];
let pid = match counter_bytes.try_into() {
Ok(bytes) => u64::from_be_bytes(bytes),
Err(_) => return Err(AeadError),
};
if !self.anti_replay.validate_pid(pid) {
warn!("Replay attack detected!");
return Err(AeadError);
}
// Descramble (if enabled)
let mut ciphertext = ciphertext.to_vec();
if let Some(ref scrambler) = self.scrambler {
if ciphertext.len() == scrambler.size() {
scrambler.unscramble(&mut ciphertext);
}
}
// ChaCha20-Poly1305 decryption
let mut plaintext = Zeroizing::new(self.cipher.decrypt(nonce, ciphertext.as_slice())?);
// Reverse XOR layer (if swarm entropy was used)
if self.has_swarm_entropy && key_offset > 0 {
// Use synchronized buffer if available (information-theoretic security)
if let Some(ref sync_buffer) = self.synchronized_buffer {
let keystream = sync_buffer.consume_sync(plaintext.len());
for (i, byte) in plaintext.iter_mut().enumerate() {
*byte ^= keystream[i];
}
} else {
// Fallback to static swarm seed (computational security)
let keystream = self.generate_keystream(key_offset, plaintext.len());
if keystream.len() != plaintext.len() {
warn!("⚠️ HKDF keystream generation failed for decryption: expected {}, got {}", plaintext.len(), keystream.len());
return Err(AeadError);
}
for (i, byte) in plaintext.iter_mut().enumerate() {
*byte ^= keystream[i];
}
}
}
Ok((*plaintext).clone())
}
/// Encrypt data using TRUE Vernam mode with embedded XOR key
///
/// INFORMATION-THEORETIC SECURITY:
/// - ZK:// (Direct): Messages ≤64 bytes get TRUE unbreakable encryption
/// - ZKS:// (Swarm): Messages ≤32 bytes get TRUE unbreakable encryption
/// - Larger messages: Use HKDF expansion (256-bit computational security)
pub fn encrypt_true_vernam(&mut self, data: &[u8]) -> Result<Vec<u8>, AeadError> {
let mut nonce_bytes = [0u8; 12];
let counter = self.nonce_counter.fetch_add(1, Ordering::SeqCst);
// Check for nonce wraparound - this would cause nonce reuse
// Note: counter is the value BEFORE the increment, so 0 is valid for the first call
if counter == u64::MAX {
// Counter wrapped around - this is a security risk
error!("🚨 CRITICAL: Nonce counter wrapped around - nonce reuse imminent!");
return Err(AeadError);
}
nonce_bytes[4..12].copy_from_slice(&counter.to_be_bytes());
let mut mixed_data = Zeroizing::new(data.to_vec());
let mut xor_key = Zeroizing::new(vec![0u8; data.len()]);
let mut mode_byte = 0x00u8;
// ⚠️ SECURITY LIMITATION: This is "synthetic" OTP, not true OTP.
// TRUE OTP requires pre-synchronized entropy between parties.
// This implementation provides computational security + XOR obfuscation.
let info_theoretic_threshold = 32; // XOR of 32-byte sources = 32 bytes output
if data.len() <= info_theoretic_threshold {
// TRUE UNBREAKABLE: Use synchronized Vernam buffer (no key transmission!)
if let Some(ref sync_buffer) = self.synchronized_buffer {
// Generate identical keystream on both parties from shared seed
let keystream = sync_buffer.consume_sync(data.len());
// XOR with synchronized keystream (information-theoretically secure)
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
xor_key[i] = keystream[i]; // Store for potential debugging
}
mode_byte = 0x01; // 0x01 = TRUE Vernam mode (information-theoretic)
debug!("🔐 TRUE OTP: Generated {} synchronized bytes (unbreakable by physics)", data.len());
} else if let Some(ref buffer_arc) = self.true_vernam_buffer {
// Fallback to old TrueVernamBuffer if synchronized not available
match buffer_arc.try_lock() {
Ok(mut buffer) => {
match buffer.consume(data.len()) {
Ok(keystream) => {
// XOR with TRUE random data (information-theoretically secure)
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
xor_key[i] = keystream[i];
}
mode_byte = 0x01; // 0x01 = True Vernam mode (information-theoretic)
debug!("🔐 INFORMATION-THEORETIC: Used {} TRUE random bytes for encryption (unbreakable by physics)", data.len());
},
Err(_) => {
// Buffer empty/error - fallback to HKDF mode
warn!("⚠️ True Vernam buffer unavailable! Falling back to HKDF mode");
if self.has_swarm_entropy {
let offset = self.key_offset.fetch_add(data.len() as u64, Ordering::SeqCst);
let keystream = self.generate_keystream(offset, data.len());
if keystream.len() != data.len() {
warn!("⚠️ HKDF keystream generation failed for {} bytes", data.len());
return Err(AeadError);
}
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
xor_key[i] = keystream[i];
}
mode_byte = 0x02; // 0x02 = HKDF fallback mode (computational)
}
}
}
}
Err(_) => {
// Failed to acquire lock - log and fallback to HKDF mode
warn!("⚠️ Failed to acquire TrueVernamBuffer lock! Falling back to HKDF mode");
if self.has_swarm_entropy {
let offset = self.key_offset.fetch_add(data.len() as u64, Ordering::SeqCst);
let keystream = self.generate_keystream(offset, data.len());
if keystream.len() != data.len() {
warn!("⚠️ HKDF keystream generation failed for {} bytes", data.len());
return Err(AeadError);
}
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
xor_key[i] = keystream[i];
}
mode_byte = 0x02; // 0x02 = HKDF fallback mode (computational)
}
}
}
} else if self.has_swarm_entropy {
// No synchronized buffer, use HKDF mode
let offset = self.key_offset.fetch_add(data.len() as u64, Ordering::SeqCst);
let keystream = self.generate_keystream(offset, data.len());
if keystream.len() != data.len() {
warn!("⚠️ HKDF keystream generation failed for {} bytes", data.len());
return Err(AeadError);
}
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
xor_key[i] = keystream[i];
}
mode_byte = 0x02; // 0x02 = HKDF fallback mode (computational)
}
} else {
// LARGER MESSAGES: Use HKDF expansion (computational security, 256-bit)
if self.has_swarm_entropy {
let offset = self.key_offset.fetch_add(data.len() as u64, Ordering::SeqCst);
let keystream = self.generate_keystream(offset, data.len());
if keystream.len() != data.len() {
warn!("⚠️ HKDF keystream generation failed for {} bytes", data.len());
return Err(AeadError);
}
for (i, byte) in mixed_data.iter_mut().enumerate() {
*byte ^= keystream[i];
xor_key[i] = keystream[i];
}
mode_byte = 0x02; // 0x02 = HKDF mode (computational)
debug!("🔐 COMPUTATIONAL: Used HKDF for {} bytes (256-bit security)", data.len());
}
}
// Base Layer: Encrypt with ChaCha20-Poly1305
let nonce = Nonce::from_slice(&nonce_bytes);
let ciphertext = self.cipher.encrypt(nonce, mixed_data.as_ref())?;
// Build result: [Nonce (12) | Mode (1) | Ciphertext]
// CRITICAL: Never embed XOR key for true OTP - both parties must have synchronized entropy!
let mut result = Vec::with_capacity(12 + 1 + ciphertext.len());
result.extend_from_slice(&nonce_bytes);
result.push(mode_byte);
result.extend_from_slice(&ciphertext);
Ok(result)
}
/// Decrypt data encrypted with TRUE Vernam mode
pub fn decrypt_true_vernam(&self, data: &[u8]) -> Result<Vec<u8>, AeadError> {
if data.len() < 12 + 1 + 16 {
return Err(AeadError);
}
let nonce = Nonce::from_slice(&data[0..12]);
let mode = data[12];
// CRITICAL: For true OTP, never extract XOR key from ciphertext - use synchronized entropy!
let ciphertext = &data[13..];
// Base Layer: Decrypt with ChaCha20-Poly1305
let payload = Zeroizing::new(self.cipher.decrypt(nonce, ciphertext)?);
// Extract and reverse XOR based on mode
let plaintext: Vec<u8> = match mode {
0x01 => {
// TRUE OTP: Generate identical keystream from synchronized buffer (no key transmission!)
if let Some(ref sync_buffer) = self.synchronized_buffer {
// Generate identical keystream on both parties from shared seed
let keystream = sync_buffer.consume_sync(payload.len());
// XOR with synchronized keystream (information-theoretically secure)
let mut result = payload.clone();
for (i, byte) in result.iter_mut().enumerate() {
*byte ^= keystream[i];
}
debug!("🔐 TRUE OTP: Generated {} synchronized bytes for decryption (unbreakable by physics)", payload.len());
result.to_vec()
} else if let Some(ref buffer_arc) = self.true_vernam_buffer {
// Fallback to old TrueVernamBuffer if synchronized not available
if let Ok(mut buffer) = buffer_arc.try_lock() {
match buffer.consume(payload.len()) {
Ok(xor_key) => {
let mut result = payload.clone();
for (i, byte) in result.iter_mut().enumerate() {
*byte ^= xor_key[i];
}
debug!("🔐 Decrypted with TRUE Vernam mode using synchronized entropy");
result.to_vec()
}
Err(_) => {
warn!("⚠️ True Vernam buffer empty during decryption!");
return Err(AeadError);
}
}
} else {
warn!("⚠️ Could not lock True Vernam buffer for decryption!");
return Err(AeadError);
}
} else {
warn!("⚠️ No synchronized buffer available for decryption!");
return Err(AeadError);
}
}
0x02 => {
// HKDF fallback mode
warn!("⚠️ HKDF fallback mode detected");
payload.to_vec()
}
_ => {
// No XOR layer
payload.to_vec()
}
};
Ok(plaintext)
}
/// Fetch swarm entropy seed from zks-vernam worker
pub async fn fetch_remote_key(
&mut self,
vernam_url: &str,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let url = format!("{}/entropy?size=32&n=10", vernam_url.trim_end_matches('/'));
let response = reqwest::get(&url).await?;
if !response.status().is_success() {
return Err(format!("Failed to fetch entropy: {}", response.status()).into());
}
let body = response.text().await?;
let json: serde_json::Value = serde_json::from_str(&body)?;
let entropy_hex = json["entropy"].as_str().ok_or("Missing entropy field")?;
let entropy = hex::decode(entropy_hex)?;
// Hash to get seed
let mut hasher = Sha256::new();
hasher.update(&entropy);
self.swarm_seed = Zeroizing::new(hasher.finalize().into());
self.has_swarm_entropy = true;
self.key_offset.store(0, Ordering::SeqCst);
info!("Fetched Swarm Entropy seed from worker - Infinite Vernam active!");
Ok(())
}
/// Set the swarm entropy seed directly (used when receiving from peer)
pub fn set_remote_key(&mut self, key: Vec<u8>) {
if !key.is_empty() {
let mut hasher = Sha256::new();
hasher.update(&key);
self.swarm_seed = Zeroizing::new(hasher.finalize().into());
self.has_swarm_entropy = true;
self.key_offset.store(0, Ordering::SeqCst);
info!(
"Applied {} bytes of Swarm Entropy - Infinite Vernam active!",
key.len()
);
}
}
/// Get the swarm seed (for sharing with peer)
pub fn get_remote_key(&self) -> &[u8] {
if self.has_swarm_entropy {
&*self.swarm_seed
} else {
&[]
}
}
/// Check if swarm entropy is available
pub fn has_swarm_entropy(&self) -> bool {
self.has_swarm_entropy
}
/// Get the swarm seed as a fixed-size array (for True Vernam fetcher)
pub fn get_swarm_seed(&self) -> [u8; 32] {
*self.swarm_seed
}
/// Refresh the swarm seed by mixing in new entropy (FORWARD SECRECY)
pub fn refresh_entropy(&mut self, fresh_entropy: &[u8]) {
if fresh_entropy.is_empty() {
return;
}
// Combine old seed with fresh entropy
let mut input = Vec::with_capacity(32 + fresh_entropy.len() + 8);
input.extend_from_slice(&*self.swarm_seed);
input.extend_from_slice(fresh_entropy);
// Add current offset as "generation" to prevent replay
let generation = self.key_offset.load(Ordering::SeqCst);
input.extend_from_slice(&generation.to_be_bytes());
// Derive new seed using HKDF
let hk = Hkdf::<Sha256>::new(Some(b"zks-entropy-refresh-v1"), &input);
let mut new_seed = [0u8; 32];
if hk.expand(b"refreshed-swarm-seed", &mut new_seed).is_err() {
warn!("HKDF expansion failed during entropy refresh");
return;
}
// Update seed (old seed is now unreachable - forward secrecy!)
self.swarm_seed = Zeroizing::new(new_seed);
self.has_swarm_entropy = true;
info!(
"🔄 Refreshed swarm entropy - Forward secrecy checkpoint! (generation: {})",
generation
);
}
/// Get current key offset (for monitoring/debugging)
pub fn get_key_offset(&self) -> u64 {
self.key_offset.load(Ordering::SeqCst)
}
/// Check if entropy refresh is recommended (e.g., after 1MB of traffic)
pub fn needs_refresh(&self) -> bool {
const REFRESH_THRESHOLD: u64 = 1024 * 1024; // 1MB
self.key_offset.load(Ordering::SeqCst) % REFRESH_THRESHOLD < 1024
}
}
impl Drop for WasifVernam {
fn drop(&mut self) {
// Zeroize the cipher state (this is handled by ChaCha20Poly1305's Drop)
// Zeroize the nonce counter to prevent timing analysis
self.nonce_counter.store(0, Ordering::SeqCst);
self.key_offset.store(0, Ordering::SeqCst);
// Key chain state is already zeroized via Zeroizing wrapper on its internal fields
// Note: swarm_seed is already Zeroizing<[u8; 32]>, so it will auto-zeroize
// Note: true_vernam_buffer contains TrueVernamBuffer which has its own Drop impl
// Note: scrambler contains only permutation maps (not sensitive cryptographic material)
info!("🔒 WasifVernam cipher zeroized - all sensitive data cleared");
}
}
/// Continuous Entropy Refresher: Periodically fetches fresh entropy and refreshes the cipher
///
/// This is what makes ZKS a TRUE continuous entropy system:
/// - Every 30 seconds (or after 1MB traffic), fetch fresh entropy from swarm/worker
/// - Mix into existing seed using refresh_entropy()
/// - Provides forward secrecy: past traffic is unrecoverable even if current seed leaks
pub struct ContinuousEntropyRefresher {
cipher: Arc<Mutex<WasifVernam>>,
}
impl ContinuousEntropyRefresher {
/// Create a new continuous entropy refresher
pub fn new(cipher: Arc<Mutex<WasifVernam>>) -> Self {
Self { cipher }
}
/// Start the background entropy refresh task
pub fn start_background_task(self) {
tokio::spawn(async move {
let mut interval = interval(Duration::from_secs(30)); // Refresh every 30 seconds
loop {
interval.tick().await;
if let Err(e) = self.fetch_and_refresh().await {
warn!("Failed to refresh entropy: {}", e);
}
}
});
}
/// Fetch fresh entropy using LOCAL CSPRNG (no worker call to avoid duplicates)
/// The TrueVernamFetcher already mixes local+worker+swarm every 10 seconds,
/// so this refresher only needs to add LOCAL entropy for forward secrecy.
async fn fetch_and_refresh(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// Use local CSPRNG instead of fetching from worker
// (TrueVernamFetcher already handles worker+swarm mixing)
let mut fresh_entropy = [0u8; 32];
getrandom::getrandom(&mut fresh_entropy).map_err(|e| format!("getrandom failed: {}", e))?;
// Refresh the cipher's seed with LOCAL fresh entropy
{
let mut cipher = self.cipher.lock().await;
cipher.refresh_entropy(&fresh_entropy);
}
info!("🔄 Continuous entropy refresh complete (local CSPRNG) - forward secrecy active!");
Ok(())
}
}
/// Keep the old name as an alias for backward compatibility
pub type EntropyTaxPayer = ContinuousEntropyRefresher;