module_lwe/
encrypt.rs

1use polynomial_ring::Polynomial;
2use ring_lwe::utils::{polyadd,polysub};
3use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, transpose, mul_vec_simple, gen_small_vector, compress, decompress, encode_message};
4
5/// Encrypt a message using the ring-LWE cryptosystem
6/// # Arguments
7/// * `a` - public key matrix
8/// * `t` - public key vector
9/// * `m_b` - binary message
10/// * `params` - Parameters for the ring-LWE cryptosystem
11/// * `seed` - random seed
12/// # Returns
13/// * `(u, v)` - ciphertext
14/// # Example
15/// ```
16/// let params = module_lwe::utils::Parameters::default();
17/// let (pk,sk) = module_lwe::keygen::keygen(&params, None);
18/// let m_b = vec![0,1,0,1,1,0,1,0];
19/// let (u, v) = module_lwe::encrypt::encrypt(&pk.0, &pk.1, &m_b, &params, None);
20/// ```
21pub fn encrypt(
22    a: &Vec<Vec<Polynomial<i64>>>,
23    t: &Vec<Polynomial<i64>>,
24    m_b: &Vec<i64>,
25    params: &Parameters,
26    seed: Option<u64>
27) -> (Vec<Polynomial<i64>>, Polynomial<i64>) {
28
29    //get parameters
30    let (n, q, k, f, omega) = (params.n, params.q, params.k, &params.f, params.omega);
31    
32    //generate random ephermal keys
33    let r = gen_small_vector(n, k, seed);
34    let e1 = gen_small_vector(n, k, seed);
35    let e2 = gen_small_vector(n, 1, seed)[0].clone(); // Single polynomial
36
37    // encode the message from binary to polynomial
38    let m = encode_message(&m_b, q);
39
40    // Compute u = a^T * r + e_1 mod q
41    let u = add_vec(&mul_mat_vec_simple(&transpose(a), &r, q, f, omega), &e1, q, f);
42
43    // Compute v = t * r + e_2 - m mod q
44    let v = polysub(&polyadd(&mul_vec_simple(t, &r, q, &f, omega), &e2, q, f), &m, q, f);
45
46    (u, v)
47}
48
49/// function to encrypt a message given a public_key string
50/// # Arguments
51/// * `pk_string` - public key string in base64 encoding
52/// * `message_string` - message string in base64 encoding
53/// * `params` - Parameters for the ring-LWE cryptosystem
54/// * `seed` - random seed
55/// # Returns
56/// * `ciphertext_str` - ciphertext string in base64 encoding
57/// # Example
58/// ```
59/// let params = module_lwe::utils::Parameters::default();
60/// let keypair = module_lwe::keygen::keygen_string(&params,None);
61/// let pk_string = keypair.get("public").unwrap();
62/// let sk_string = keypair.get("secret").unwrap();
63/// let message_string = "Hello, world!".to_string();
64/// let ciphertext_string = module_lwe::encrypt::encrypt_string(&pk_string, &message_string, &params, None);
65/// ```
66pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Parameters, seed: Option<u64>) -> String {
67    // Get parameters
68    let (n, k) = (params.n, params.k);
69
70    // Decode and deserialize the base64-encoded public key string
71    let pk_list: Vec<i64> = decompress(pk_string);
72
73    // Parse the public key
74    let a: Vec<Vec<Polynomial<i64>>> = pk_list[..k * k * n]
75        .chunks(k * n)
76        .map(|chunk| {
77            chunk.chunks(n).map(|coeffs| Polynomial::new(coeffs.to_vec())).collect()
78        })
79        .collect();
80
81    let t: Vec<Polynomial<i64>> = pk_list[k * k * n..]
82        .chunks(n)
83        .map(|coeffs| Polynomial::new(coeffs.to_vec()))
84        .collect();
85
86    // Parse message
87    let message_binary: Vec<i64> = message_string
88        .bytes()
89        .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1) as i64))
90        .collect();
91
92    // Break message into blocks
93    let message_blocks: Vec<Vec<i64>> = message_binary
94        .chunks(n) // Divide the binary message into chunks of size `n`
95        .map(|chunk| chunk.to_vec()) // Convert each chunk into a vector
96        .collect();
97
98    // Encrypt each block
99    let mut ciphertext_list = vec![];
100    for block in message_blocks {
101        let (u, v) = encrypt(&a, &t, &block, params, seed);
102        let u_flattened: Vec<i64> = u.iter()
103            .flat_map(|poly| {
104                let mut coeffs = poly.coeffs().to_vec();
105                coeffs.resize(n, 0); // Resize to include leading zeros up to size `n`
106                coeffs
107            })
108            .collect();
109        let mut v_flattened: Vec<i64> = v.coeffs().to_vec();
110        v_flattened.resize(n, 0);
111        ciphertext_list.extend(u_flattened);
112        ciphertext_list.extend(v_flattened);
113    }
114
115    // Serialize and Base64 encode the ciphertext coefficient list
116    compress(&ciphertext_list)
117}