module_lwe/
decrypt.rs

1use polynomial_ring::Polynomial;
2use ring_lwe::utils::{polysub,nearest_int};
3use crate::utils::{Parameters,mul_vec_simple,decompress};
4
5/// Decrypt a ciphertext
6/// # Arguments
7/// * `sk` - secret key
8/// * `q` - ciphertext modulus
9/// * `f` - polynomial modulus
10/// * `u` - ciphertext vector
11/// * `v` - ciphertext polynomial
12/// # Returns
13/// * `decrypted_coeffs` - plaintext vector
14/// # Example
15/// ```
16/// let params = module_lwe::utils::Parameters::default();
17/// let (pk,sk) = module_lwe::keygen::keygen(&params, None);
18/// let mut m_b = vec![0,1,0,1,0,0,1,1,1,0,1];
19/// m_b.resize(params.n, 0);
20/// let (u, v) = module_lwe::encrypt::encrypt(&pk.0, &pk.1, &m_b, &params, None);
21/// let decrypted_coeffs = module_lwe::decrypt::decrypt(&sk, &u, &v, &params);
22/// assert_eq!(m_b, decrypted_coeffs);
23/// ```
24pub fn decrypt(
25    sk: &Vec<Polynomial<i64>>,    //secret key
26    u: &Vec<Polynomial<i64>>, //ciphertext vector
27	v: &Polynomial<i64> ,		//ciphertext polynomial
28    params: &Parameters
29) -> Vec<i64> {
30	let (q, f, omega) = (params.q, &params.f, params.omega); //get parameters
31	let scaled_pt = polysub(&v, &mul_vec_simple(&sk, &u, q, &f, omega), q, f); //Compute v-sk*u mod q
32	let half_q = nearest_int(q,2); // compute nearest integer to q/2
33	let mut decrypted_coeffs = vec![];
34	let mut s;
35	for c in scaled_pt.coeffs().iter() {
36		s = nearest_int(*c,half_q).rem_euclid(2);
37		decrypted_coeffs.push(s);
38	}
39    decrypted_coeffs
40}
41
42/// decrypt a ciphertext string given a secret key
43/// # Arguments
44/// * `sk_string` - secret key string in base64 encoding
45/// * `ciphertext_string` - ciphertext string in base64 encoding
46/// * `params` - Parameters for the ring-LWE cryptosystem
47/// # Returns
48/// * `message_string` - decrypted message string as plaintext
49pub fn decrypt_string(sk_string: &String, ciphertext_base64: &String, params: &Parameters) -> String {
50    // Get parameters
51    let (n, k) = (params.n, params.k);
52
53    // Base64 decode the secret key string
54    let sk_array: Vec<i64> = decompress(sk_string);
55
56    // Convert the secret key into a Vec<Polynomial<i64>>
57    let sk: Vec<Polynomial<i64>> = sk_array.chunks(n)
58        .map(|chunk| Polynomial::new(chunk.to_vec()))
59        .collect();
60
61    // Base64 decode and deserialize the ciphertext string
62    let ciphertext_list: Vec<i64> = decompress(ciphertext_base64);
63
64    let block_size = (k + 1) * n;
65    let num_blocks = ciphertext_list.len() / block_size;
66
67    let mut message_binary = vec![];
68
69    for i in 0..num_blocks {
70        // Get u and v for this block
71        let u_array = &ciphertext_list[i * block_size..i * block_size + k * n];
72        let v_array = &ciphertext_list[i * block_size + k * n..(i + 1) * block_size];
73
74        let u: Vec<Polynomial<i64>> = u_array.chunks(n)
75            .map(|chunk| Polynomial::new(chunk.to_vec()))
76            .collect();
77        let v = Polynomial::new(v_array.to_vec());
78
79        // Abstracted block decryption
80        let m_b = decode_block(&sk, &u, &v, params);
81
82        message_binary.extend(m_b);
83    }
84
85    // Group the bits back into bytes (8 bits each)
86    let byte_chunks: Vec<String> = message_binary.chunks(8)
87        .map(|chunk| chunk.iter().map(|bit| bit.to_string()).collect())
88        .collect();
89
90    // Convert each binary string back into a character
91    let message_string: String = byte_chunks.iter()
92        .map(|byte| char::from_u32(i64::from_str_radix(byte, 2).unwrap() as u32).unwrap())
93        .collect();
94
95    // Trim the null characters \0 = '00000000' from the end
96    message_string.trim_end_matches('\0').to_string()
97}
98
99fn decode_block(sk: &Vec<Polynomial<i64>>, u: &Vec<Polynomial<i64>>, v: &Polynomial<i64>, params: &Parameters) -> Vec<i64> {
100    let mut m_b = decrypt(sk, u, v, params);
101    m_b.resize(params.n, 0);
102    m_b
103}