ring_lwe/encrypt.rs
1use crate::utils::{Parameters, mod_coeffs, polymul_fast, polyadd, gen_ternary_poly,compress,decompress};
2use polynomial_ring::Polynomial;
3
4/// Encrypt a polynomial using the public key
5/// # Arguments:
6/// * `pk` - public key as an array of two Polynomials
7/// * `m` - plaintext polynomial
8/// * `params` - ring-LWE parameters
9/// * `seed` - random seed
10/// # Returns:
11/// (ciphertext component 0, ciphertext component 1)
12/// # Example:
13/// ```
14/// let params = ring_lwe::utils::Parameters::default();
15/// let (pk, sk) = ring_lwe::keygen::keygen(¶ms, None);
16/// let m = polynomial_ring::Polynomial::new(vec![1, 0, 1]);
17/// let ct = ring_lwe::encrypt::encrypt(&pk, &m, ¶ms, None);
18/// ```
19pub fn encrypt(
20 pk: &[Polynomial<i64>; 2], // Public key (b, a)
21 m: &Polynomial<i64>, // Plaintext polynomial
22 params: &Parameters, //parameters (n,q,t,f)
23 seed: Option<u64> // Seed for random number generator
24) -> [Polynomial<i64>; 2] {
25 let (n,q,t,f,omega) = (params.n, params.q, params.t, ¶ms.f, params.omega);
26 // Scale the plaintext polynomial. use floor(m*q/t) rather than floor (q/t)*m
27 let scaled_m = mod_coeffs(m * q / t, q);
28
29 // Generate random polynomials
30 let e1 = gen_ternary_poly(n, seed);
31 let e2 = gen_ternary_poly(n, seed);
32 let u = gen_ternary_poly(n, seed);
33
34 // Compute ciphertext components
35 let ct0 = polyadd(&polyadd(&polymul_fast(&pk[0], &u, q, f, omega), &e1, q, f),&scaled_m,q,f);
36 let ct1 = polyadd(&polymul_fast(&pk[1], &u, q, f, omega), &e2, q, f);
37
38 [ct0, ct1]
39}
40
41/// Encrypt a string using the public key
42/// # Arguments:
43/// * `pk_string` - public key as a base64 encoded string
44/// * `message` - message to encrypt
45/// * `params` - ring-LWE parameters
46/// * `seed` - random seed
47/// # Returns:
48/// encrypted message as a base64 encoded string
49/// # Example:
50/// ```
51/// let params = ring_lwe::utils::Parameters::default();
52/// let keys = ring_lwe::keygen::keygen_string(¶ms, None);
53/// let pk_string = keys.get("public").unwrap();
54/// let message = String::from("hello");
55/// let ciphertext_string = ring_lwe::encrypt::encrypt_string(pk_string, &message, ¶ms, None);
56/// ```
57pub fn encrypt_string(pk_base64: &String, message: &String, params: &Parameters, seed: Option<u64>) -> String {
58 // Decode the Base64 public key string
59 let pk_arr: Vec<i64> = decompress(pk_base64);
60
61 // Split the public key into two polynomials
62 let pk_b = Polynomial::new(pk_arr[..params.n].to_vec());
63 let pk_a = Polynomial::new(pk_arr[params.n..].to_vec());
64 let pk = [pk_b, pk_a];
65
66 // Convert each byte into its 8-bit representation (MSB first)
67 let message_bits: Vec<i64> = message
68 .bytes()
69 .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1) as i64))
70 .collect();
71
72 // Convert bits into a vector of Polynomials
73 let message_blocks: Vec<Polynomial<i64>> = message_bits
74 .chunks(params.n) // Pack bits into polynomials of size `n`
75 .map(|chunk| Polynomial::new(chunk.to_vec()))
76 .collect();
77
78 // Encrypt each integer message block
79 let mut ciphertext_list: Vec<i64> = Vec::new();
80 for message_block in message_blocks {
81 let ciphertext = encrypt(&pk, &message_block, ¶ms, seed);
82 ciphertext_list.extend(ciphertext[0].coeffs());
83 ciphertext_list.extend(ciphertext[1].coeffs());
84 }
85
86 // Serialize the ciphertext list to binary and encode as Base64
87 compress(&ciphertext_list)
88}