Path: blob/main/frontier/08-lattices-post-quantum/rust/src/lib.rs
483 views
unlisted
//! # Module 08: Lattices and Post-Quantum Cryptography — Exercises1//!2//! ## Progression3//! 1. `gram_schmidt_2d` — signature + doc4//! 2. `lll_reduce_2d` — signature + doc5//! 3. `lwe_keygen` — signature + doc6//! 4. `lwe_encrypt` — signature + doc7//! 5. `lwe_decrypt` — signature only89/// Compute the Gram-Schmidt orthogonalization of two 2D basis vectors.10///11/// Given basis vectors b1 and b2, compute the orthogonal basis b1*, b2*12/// where b2* = b2 - proj(b2, b1*).13///14/// Returns the orthogonalized basis as f64 vectors.15pub fn gram_schmidt_2d(b1: [i64; 2], b2: [i64; 2]) -> ([f64; 2], [f64; 2]) {16todo!("2D Gram-Schmidt orthogonalization")17}1819/// Apply the LLL algorithm to a 2D lattice basis.20///21/// The LLL algorithm produces a "reduced" basis where the vectors are22/// nearly orthogonal and short. For 2D, this is equivalent to the23/// Gaussian lattice reduction algorithm.24///25/// Returns the reduced basis vectors.26pub fn lll_reduce_2d(b1: [i64; 2], b2: [i64; 2]) -> ([i64; 2], [i64; 2]) {27todo!("2D LLL (Gaussian) lattice reduction")28}2930/// Generate an LWE key pair.31///32/// - Choose a random secret vector `s` of dimension `n` (mod `q`)33/// - Generate a random matrix `A` of size `m × n` (mod `q`)34/// - Compute `b = A*s + e` where `e` is a small noise vector35///36/// Returns `(A, b, s)` — public key is `(A, b)`, secret key is `s`.37pub fn lwe_keygen(n: usize, m: usize, q: i64) -> (Vec<Vec<i64>>, Vec<i64>, Vec<i64>) {38todo!("LWE key generation: A, b = As + e, s")39}4041/// Encrypt a single bit using LWE.42///43/// To encrypt bit `msg` ∈ {0, 1}:44/// - Choose a random subset S of the rows of A45/// - Compute `u = Σ A[i] for i in S` (mod q)46/// - Compute `v = Σ b[i] for i in S + msg * ⌊q/2⌋` (mod q)47///48/// Returns ciphertext `(u, v)`.49pub fn lwe_encrypt(a: &[Vec<i64>], b: &[i64], msg: u8, q: i64) -> (Vec<i64>, i64) {50todo!("LWE encryption of a single bit")51}5253/// Decrypt an LWE ciphertext.54///55/// Compute `v - <u, s>` mod q. If the result is closer to 0, the bit is 0.56/// If closer to q/2, the bit is 1.57pub fn lwe_decrypt(s: &[i64], u: &[i64], v: i64, q: i64) -> u8 {58todo!("LWE decryption: recover bit from noisy inner product")59}6061#[cfg(test)]62mod tests {63use super::*;6465#[test]66#[ignore]67fn test_gram_schmidt_2d() {68let (b1s, b2s) = gram_schmidt_2d([3, 1], [2, 2]);69// b1* should be unchanged70assert!((b1s[0] - 3.0).abs() < 1e-10);71assert!((b1s[1] - 1.0).abs() < 1e-10);72// b2* should be orthogonal to b1*73let dot = b1s[0] * b2s[0] + b1s[1] * b2s[1];74assert!(dot.abs() < 1e-10, "Should be orthogonal");75}7677#[test]78#[ignore]79fn test_lll_reduce_2d() {80// A bad basis for the same lattice81let (r1, r2) = lll_reduce_2d([1, 0], [100, 1]);82// Reduced basis should have shorter vectors83let norm_sq = |v: [i64; 2]| (v[0] * v[0] + v[1] * v[1]) as f64;84assert!(norm_sq(r1) <= norm_sq([100, 1]) as f64);85assert!(norm_sq(r2) <= norm_sq([100, 1]) as f64);86}8788#[test]89#[ignore]90fn test_lwe_roundtrip() {91let q = 97;92let (a, b, s) = lwe_keygen(4, 8, q);93for msg in [0u8, 1u8] {94let (u, v) = lwe_encrypt(&a, &b, msg, q);95let decrypted = lwe_decrypt(&s, &u, v, q);96assert_eq!(decrypted, msg, "LWE decrypt should recover the bit");97}98}99}100101102