use getrandom::getrandom;
use sha3::{Digest, Sha3_256, Shake256};
use sha3::digest::{Update, ExtendableOutput};
use std::io::Read;
use std::thread;
use std::time::{Instant, Duration};
const LATTICE_DIM: usize = 256; const CODE_LENGTH: usize = 512;
pub struct PublicKey {
_lattice_matrix: Vec<Vec<u8>>, _code_generator: Vec<u8>, }
pub struct SecretKey {
_lattice_secret: Vec<u8>, _code_secret: Vec<u8>, }
pub struct Ciphertext {
lattice_cipher: Vec<u8>, code_cipher: Vec<u8>, }
pub struct SharedSecret(Vec<u8>);
impl SharedSecret {
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
}
pub struct TrueRandom {
entropy_pool: Vec<u8>, }
impl TrueRandom {
pub fn new() -> Self {
let mut initial_entropy = vec![0u8; 64];
getrandom(&mut initial_entropy).expect("Failed to get system entropy");
TrueRandom {
entropy_pool: initial_entropy,
}
}
fn collect_jitter(&mut self) {
let mut jitter = Vec::new();
for _ in 0..10 {
let start = Instant::now();
thread::sleep(Duration::from_nanos(1));
let elapsed = start.elapsed().as_nanos() as u8;
jitter.push(elapsed);
}
self.entropy_pool.extend(jitter);
}
fn quantum_sim_entropy(&mut self) -> Vec<u8> {
let mut sim_entropy = Vec::new();
let now = Instant::now().elapsed().as_nanos();
let mut state = now as u64;
for _ in 0..16 {
state ^= state.wrapping_add(self.entropy_pool[state as usize % self.entropy_pool.len()] as u64);
sim_entropy.push((state & 0xFF) as u8);
}
sim_entropy
}
pub fn generate(&mut self, len: usize) -> Vec<u8> {
self.collect_jitter();
let sim_entropy = self.quantum_sim_entropy();
self.entropy_pool.extend(sim_entropy);
let mut hasher = Sha3_256::new();
Update::update(&mut hasher, &self.entropy_pool);
let mixed = hasher.finalize();
if len > mixed.len() {
let mut xof = Shake256::default();
xof.update(&mixed);
let mut reader = xof.finalize_xof();
let mut output = vec![0u8; len];
reader.read_exact(&mut output).unwrap();
output
} else {
mixed[..len].to_vec()
}
}
}
impl Default for TrueRandom {
fn default() -> Self {
Self::new()
}
}
pub fn keypair() -> (PublicKey, SecretKey) {
let mut trng = TrueRandom::new();
let lattice_secret = trng.generate(LATTICE_DIM);
let lattice_matrix = vec![trng.generate(LATTICE_DIM); LATTICE_DIM];
let code_secret = trng.generate(CODE_LENGTH / 8);
let code_generator = trng.generate(CODE_LENGTH);
(
PublicKey {
_lattice_matrix: lattice_matrix,
_code_generator: code_generator,
},
SecretKey {
_lattice_secret: lattice_secret,
_code_secret: code_secret,
},
)
}
pub fn encapsulate(_pk: &PublicKey) -> (Ciphertext, SharedSecret) {
let mut trng = TrueRandom::new();
let lattice_cipher = trng.generate(LATTICE_DIM);
let code_cipher = trng.generate(CODE_LENGTH);
let mut hasher = Sha3_256::new();
Update::update(&mut hasher, &lattice_cipher);
Update::update(&mut hasher, &code_cipher);
let shared_secret = SharedSecret(hasher.finalize().to_vec());
(
Ciphertext {
lattice_cipher,
code_cipher,
},
shared_secret,
)
}
pub fn decapsulate(ct: &Ciphertext, _sk: &SecretKey) -> SharedSecret {
let mut hasher = Sha3_256::new();
Update::update(&mut hasher, &ct.lattice_cipher);
Update::update(&mut hasher, &ct.code_cipher);
SharedSecret(hasher.finalize().to_vec())
}
pub fn derive_keys(shared_secret: &SharedSecret, num_keys: usize) -> Vec<Vec<u8>> {
let mut keys = Vec::new();
let mut xof = Shake256::default();
xof.update(&shared_secret.0);
let mut reader = xof.finalize_xof();
for _ in 0..num_keys {
let mut key = vec![0u8; 32];
reader.read_exact(&mut key).unwrap();
keys.push(key);
}
keys
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_true_random() {
let mut trng = TrueRandom::new();
let rand1 = trng.generate(32);
let rand2 = trng.generate(32);
assert_eq!(rand1.len(), 32);
assert_eq!(rand2.len(), 32);
assert_ne!(rand1, rand2);
}
#[test]
fn test_encryption() {
let (pk, sk) = keypair();
let (ct, ss1) = encapsulate(&pk);
let ss2 = decapsulate(&ct, &sk);
assert_eq!(ss1.as_bytes(), ss2.as_bytes());
let keys = derive_keys(&ss1, 3);
assert_eq!(keys.len(), 3);
assert_eq!(keys[0].len(), 32);
}
}