use crate::{Result, QsshError};
use sha3::{Sha3_256, Digest};
use rand::{RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;
#[derive(Clone, Debug)]
pub struct LamportKeyPair {
private_key: Vec<[u8; 32]>,
public_key: Vec<[u8; 32]>,
index: u64,
}
impl LamportKeyPair {
pub fn from_qkd_entropy(qkd_key: &[u8], index: u64) -> Self {
let mut rng = ChaCha20Rng::from_seed({
let mut seed = [0u8; 32];
let mut hasher = Sha3_256::new();
hasher.update(qkd_key);
hasher.update(b"lamport_keygen");
hasher.update(&index.to_le_bytes());
seed.copy_from_slice(&hasher.finalize());
seed
});
let mut private_key = Vec::with_capacity(512);
let mut public_key = Vec::with_capacity(512);
for _ in 0..512 {
let mut priv_block = [0u8; 32];
rng.fill_bytes(&mut priv_block);
private_key.push(priv_block);
let pub_block = Sha3_256::digest(&priv_block).into();
public_key.push(pub_block);
}
Self { private_key, public_key, index }
}
pub fn sign(&self, message: &[u8]) -> LamportSignature {
let hash = Sha3_256::digest(message);
let mut signature_blocks = Vec::with_capacity(256);
for (i, &byte) in hash.iter().enumerate() {
for bit in 0..8 {
let bit_value = (byte >> bit) & 1;
let key_index = i * 8 + bit + (bit_value as usize * 256);
signature_blocks.push(self.private_key[key_index]);
}
}
LamportSignature {
blocks: signature_blocks,
key_index: self.index,
}
}
}
pub struct LamportSignature {
blocks: Vec<[u8; 32]>,
key_index: u64,
}
pub struct DoubleRatchetState {
dh_sending_key: Option<[u8; 32]>,
dh_receiving_key: Option<[u8; 32]>,
root_chain_key: [u8; 32],
sending_chain_key: [u8; 32],
receiving_chain_key: [u8; 32],
sending_message_number: u32,
receiving_message_number: u32,
previous_sending_chain_length: u32,
qkd_session_id: Option<String>,
}
impl DoubleRatchetState {
pub fn from_qkd_session(session_key: &[u8], session_id: String) -> Self {
let mut root_key = [0u8; 32];
let mut send_key = [0u8; 32];
let mut recv_key = [0u8; 32];
let mut hasher = Sha3_256::new();
hasher.update(session_key);
hasher.update(b"root_chain");
root_key.copy_from_slice(&hasher.finalize_reset());
hasher.update(session_key);
hasher.update(b"send_chain");
send_key.copy_from_slice(&hasher.finalize_reset());
hasher.update(session_key);
hasher.update(b"recv_chain");
recv_key.copy_from_slice(&hasher.finalize());
Self {
dh_sending_key: None,
dh_receiving_key: None,
root_chain_key: root_key,
sending_chain_key: send_key,
receiving_chain_key: recv_key,
sending_message_number: 0,
receiving_message_number: 0,
previous_sending_chain_length: 0,
qkd_session_id: Some(session_id),
}
}
pub fn ratchet_with_qkd(&mut self, new_qkd_key: &[u8]) {
let mut hasher = Sha3_256::new();
hasher.update(&self.root_chain_key);
hasher.update(new_qkd_key);
hasher.update(b"ratchet");
self.root_chain_key.copy_from_slice(&hasher.finalize_reset());
hasher.update(&self.root_chain_key);
hasher.update(b"send");
self.sending_chain_key.copy_from_slice(&hasher.finalize_reset());
hasher.update(&self.root_chain_key);
hasher.update(b"recv");
self.receiving_chain_key.copy_from_slice(&hasher.finalize());
self.previous_sending_chain_length = self.sending_message_number;
self.sending_message_number = 0;
}
pub fn encrypt(&mut self, plaintext: &[u8]) -> RatchetMessage {
let mut hasher = Sha3_256::new();
hasher.update(&self.sending_chain_key);
hasher.update(b"chain");
self.sending_chain_key.copy_from_slice(&hasher.finalize_reset());
hasher.update(&self.sending_chain_key);
hasher.update(b"msgkey");
let message_key: [u8; 32] = hasher.finalize().into();
let mut ciphertext = plaintext.to_vec();
for (i, byte) in ciphertext.iter_mut().enumerate() {
*byte ^= message_key[i % 32];
}
let msg = RatchetMessage {
ratchet_key: self.dh_sending_key,
previous_chain_length: self.previous_sending_chain_length,
message_number: self.sending_message_number,
ciphertext,
};
self.sending_message_number += 1;
msg
}
}
pub struct RatchetMessage {
ratchet_key: Option<[u8; 32]>,
previous_chain_length: u32,
message_number: u32,
ciphertext: Vec<u8>,
}
pub struct QkdManager {
sessions: std::collections::HashMap<String, QkdSession>,
qkd_endpoint: Option<String>,
}
pub struct QkdSession {
pub session_id: String,
pub peer_id: String,
pub shared_key: Vec<u8>,
pub key_rate: f64, pub qber: f64, pub timestamp: std::time::Instant,
}
impl QkdManager {
pub fn new(endpoint: Option<String>) -> Self {
Self {
sessions: std::collections::HashMap::new(),
qkd_endpoint: endpoint,
}
}
pub async fn get_qkd_key(&mut self, peer_id: &str) -> Result<Vec<u8>> {
if let Some(session) = self.sessions.get(peer_id) {
if session.timestamp.elapsed().as_secs() < 300 { return Ok(session.shared_key.clone());
}
}
let session = self.establish_qkd_session(peer_id).await?;
let key = session.shared_key.clone();
self.sessions.insert(peer_id.to_string(), session);
Ok(key)
}
async fn establish_qkd_session(&self, peer_id: &str) -> Result<QkdSession> {
log::info!("Establishing QKD session with {}", peer_id);
let mut key = vec![0u8; 256]; rand::thread_rng().fill_bytes(&mut key);
Ok(QkdSession {
session_id: format!("qkd-{}-{}", peer_id, uuid::Uuid::new_v4()),
peer_id: peer_id.to_string(),
shared_key: key,
key_rate: 10_000.0, qber: 0.02, timestamp: std::time::Instant::now(),
})
}
}
pub struct QuantumSession {
pub qkd: QkdManager,
pub lamport_key: LamportKeyPair,
pub ratchet: DoubleRatchetState,
lamport_index: u64,
}
impl QuantumSession {
pub async fn new(peer_id: &str, qkd_endpoint: Option<String>) -> Result<Self> {
let mut qkd = QkdManager::new(qkd_endpoint);
let qkd_key = qkd.get_qkd_key(peer_id).await?;
let lamport_key = LamportKeyPair::from_qkd_entropy(&qkd_key, 0);
let ratchet = DoubleRatchetState::from_qkd_session(
&qkd_key,
format!("session-{}", peer_id)
);
Ok(Self {
qkd,
lamport_key,
ratchet,
lamport_index: 0,
})
}
pub async fn secure_send(&mut self, message: &[u8]) -> Result<(LamportSignature, RatchetMessage)> {
let signature = self.lamport_key.sign(message);
let encrypted = self.ratchet.encrypt(message);
self.lamport_index += 1;
if self.lamport_index % 100 == 0 {
self.refresh_lamport_keys().await?;
}
Ok((signature, encrypted))
}
async fn refresh_lamport_keys(&mut self) -> Result<()> {
let peer_id = self.ratchet.qkd_session_id.as_ref()
.ok_or_else(|| QsshError::Protocol("No QKD session".into()))?;
let new_qkd_key = self.qkd.get_qkd_key(peer_id).await?;
self.lamport_key = LamportKeyPair::from_qkd_entropy(&new_qkd_key, self.lamport_index);
self.ratchet.ratchet_with_qkd(&new_qkd_key);
log::info!("Refreshed quantum keys with QKD entropy");
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_quantum_session() {
let mut session = QuantumSession::new("test-peer", None).await.unwrap();
let message = b"Hello Quantum World!";
let (signature, encrypted) = session.secure_send(message).await.unwrap();
assert_eq!(signature.key_index, 0);
assert!(!encrypted.ciphertext.is_empty());
}
#[test]
fn test_lamport_signature() {
let qkd_key = vec![0x42; 32];
let keypair = LamportKeyPair::from_qkd_entropy(&qkd_key, 0);
let message = b"Test message";
let signature = keypair.sign(message);
assert_eq!(signature.blocks.len(), 256);
}
}