diff --git a/Cargo.toml b/Cargo.toml index 2f682da..d2f7acb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ rand = "0.8.5" rand_distr = "0.4.3" ntt = "0.1.9" ring-lwe = "0.1.6" +base64 = "0.21" +bincode = "1.3" [dev-dependencies] criterion = "0.5.1" diff --git a/src/decrypt.rs b/src/decrypt.rs index 9bcd99f..dee8069 100644 --- a/src/decrypt.rs +++ b/src/decrypt.rs @@ -1,6 +1,6 @@ use polynomial_ring::Polynomial; use ring_lwe::utils::{polysub,nearest_int}; -use crate::utils::{Parameters,mul_vec_simple}; +use crate::utils::{Parameters,mul_vec_simple,decompress}; /// Decrypt a ciphertext /// # Arguments @@ -41,60 +41,58 @@ pub fn decrypt( /// decrypt a ciphertext string given a secret key /// # Arguments -/// * `sk_string` - secret key string -/// * `ciphertext_string` - ciphertext string +/// * `sk_string` - secret key string in base64 encoding +/// * `ciphertext_string` - ciphertext string in base64 encoding /// * `params` - Parameters for the ring-LWE cryptosystem /// # Returns -/// * `message_string` - decrypted message string -pub fn decrypt_string(sk_string: &String, ciphertext_string: &String, params: &Parameters) -> String { - - //get parameters +/// * `message_string` - decrypted message string as plaintext +pub fn decrypt_string(sk_string: &String, ciphertext_base64: &String, params: &Parameters) -> String { + // Get parameters let (n, k) = (params.n, params.k); - - // Convert the secret key string into a Vec> - let sk_array: Vec = sk_string.split(',') - .filter_map(|s| s.parse().ok()) - .collect(); + + // Base64 decode the secret key string + let sk_array: Vec = decompress(sk_string); + + // Convert the secret key into a Vec> let sk: Vec> = sk_array.chunks(n) .map(|chunk| Polynomial::new(chunk.to_vec())) .collect(); - - // Parse ciphertext into u and v - let ciphertext_list: Vec = ciphertext_string.split(',') - .filter_map(|s| s.parse().ok()) - .collect(); + + // Base64 decode and deserialize the ciphertext string + let ciphertext_list: Vec = decompress(ciphertext_base64); + let block_size = (k + 1) * n; let num_blocks = ciphertext_list.len() / block_size; let mut message_binary = vec![]; - + for i in 0..num_blocks { // Get u and v for this block let u_array = &ciphertext_list[i * block_size..i * block_size + k * n]; let v_array = &ciphertext_list[i * block_size + k * n..(i + 1) * block_size]; - + let u: Vec> = u_array.chunks(n) .map(|chunk| Polynomial::new(chunk.to_vec())) .collect(); let v = Polynomial::new(v_array.to_vec()); - + // Decrypt the ciphertext let mut m_b = decrypt(&sk, &u, &v, ¶ms); - m_b.resize(n,0); - + m_b.resize(n, 0); + message_binary.extend(m_b); } - + // Group the bits back into bytes (8 bits each) let byte_chunks: Vec = message_binary.chunks(8) .map(|chunk| chunk.iter().map(|bit| bit.to_string()).collect()) .collect(); - + // Convert each binary string back into a character let message_string: String = byte_chunks.iter() .map(|byte| char::from_u32(i64::from_str_radix(byte, 2).unwrap() as u32).unwrap()) .collect(); - - //trim the null characters \0 = '00000000' from the end + + // Trim the null characters \0 = '00000000' from the end message_string.trim_end_matches('\0').to_string() -} \ No newline at end of file +} diff --git a/src/encrypt.rs b/src/encrypt.rs index fea74dd..7b7e04b 100644 --- a/src/encrypt.rs +++ b/src/encrypt.rs @@ -1,6 +1,6 @@ use polynomial_ring::Polynomial; use ring_lwe::utils::{polyadd,polysub,nearest_int}; -use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, transpose, mul_vec_simple, gen_small_vector}; +use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, transpose, mul_vec_simple, gen_small_vector, compress, decompress}; /// Encrypt a message using the ring-LWE cryptosystem /// # Arguments @@ -51,12 +51,12 @@ pub fn encrypt( /// function to encrypt a message given a public_key string /// # Arguments -/// * `pk_string` - public key string -/// * `message_string` - message string +/// * `pk_string` - public key string in base64 encoding +/// * `message_string` - message string in base64 encoding /// * `params` - Parameters for the ring-LWE cryptosystem /// * `seed` - random seed /// # Returns -/// * `ciphertext_str` - ciphertext string +/// * `ciphertext_str` - ciphertext string in base64 encoding /// # Example /// ``` /// let params = module_lwe::utils::Parameters::default(); @@ -67,14 +67,13 @@ pub fn encrypt( /// let ciphertext_string = module_lwe::encrypt::encrypt_string(&pk_string, &message_string, ¶ms, None); /// ``` pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Parameters, seed: Option) -> String { - - //get parameters + // Get parameters let (n, k) = (params.n, params.k); - // Parse public key - - let pk_list: Vec = pk_string.split(',').map(|x| x.parse::().unwrap()).collect(); + // Decode and deserialize the base64-encoded public key string + let pk_list: Vec = decompress(pk_string); + // Parse the public key let a: Vec>> = pk_list[..k * k * n] .chunks(k * n) .map(|chunk| { @@ -93,7 +92,7 @@ pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Para .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1) as i64)) .collect(); - // Break message into blocks, including the last partial block if necessary + // Break message into blocks let message_blocks: Vec> = message_binary .chunks(n) // Divide the binary message into chunks of size `n` .map(|chunk| chunk.to_vec()) // Convert each chunk into a vector @@ -111,12 +110,11 @@ pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Para }) .collect(); let mut v_flattened: Vec = v.coeffs().to_vec(); - v_flattened.resize(n,0); + v_flattened.resize(n, 0); ciphertext_list.extend(u_flattened); ciphertext_list.extend(v_flattened); } - let ciphertext_str = ciphertext_list.iter().map(|x| x.to_string()).collect::>().join(","); - - ciphertext_str + // Serialize and Base64 encode the ciphertext coefficient list + compress(&ciphertext_list) } \ No newline at end of file diff --git a/src/keygen.rs b/src/keygen.rs index 5f82df6..053562e 100644 --- a/src/keygen.rs +++ b/src/keygen.rs @@ -1,6 +1,6 @@ use polynomial_ring::Polynomial; use std::collections::HashMap; -use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, gen_small_vector, gen_uniform_matrix}; +use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, gen_small_vector, gen_uniform_matrix,compress}; /// Generate public and secret keys for the ring-LWE cryptosystem /// # Arguments @@ -29,22 +29,22 @@ pub fn keygen( } /// Generate public and secret keys for the ring-LWE cryptosystem and return them as a HashMap +/// They are serialized and base64 encoded /// # Arguments /// * `params` - Parameters for the ring-LWE cryptosystem /// * `seed` - random seed /// # Returns -/// * `keys` - HashMap containing the public and secret keys +/// * `keys` - HashMap containing the public and secret keys as base64 encoded strings /// # Example /// ``` /// let params = module_lwe::utils::Parameters::default(); /// let keys = module_lwe::keygen::keygen_string(¶ms, None); /// ``` pub fn keygen_string(params: &Parameters, seed: Option) -> HashMap { + // Generate public and secret keys + let (pk, sk) = keygen(params, seed); - //generate public, secret keys - let (pk,sk) = keygen(params,seed); - - // Convert public key to a flattened list of coefficients + // Convert the public key to a flattened list of coefficients let mut pk_coeffs: Vec = pk.0 .iter() .flat_map(|row| { @@ -55,6 +55,7 @@ pub fn keygen_string(params: &Parameters, seed: Option) -> HashMap) -> HashMap = sk .iter() .flat_map(|poly| { @@ -74,20 +75,10 @@ pub fn keygen_string(params: &Parameters, seed: Option) -> HashMap>() - .join(","); - let sk_coeffs_str = sk_coeffs.iter() - .map(|coef| coef.to_string()) - .collect::>() - .join(","); - - //store the secret/public key in a HashMap + // Store the Base64 encoded keys in a HashMap let mut keys: HashMap = HashMap::new(); - keys.insert(String::from("secret"), sk_coeffs_str); - keys.insert(String::from("public"), pk_coeffs_str); - + keys.insert(String::from("secret"), compress(&sk_coeffs)); + keys.insert(String::from("public"), compress(&pk_coeffs)); + keys } \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index 8c2559d..b2f3b40 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,6 +4,8 @@ use rand::SeedableRng; use rand::rngs::StdRng; use ring_lwe::utils::{polyadd, polymul_fast, gen_uniform_poly}; use ntt::omega; +use base64::{engine::general_purpose, Engine as _}; +use bincode; #[derive(Debug)] /// default parameters for module-LWE @@ -143,4 +145,24 @@ pub fn gen_uniform_matrix(size : usize, rank: usize, modulus: i64, seed: Option< } } m +} + +/// seralize and encode a vector of i64 to a base64 encoded string +/// # Arguments +/// * `data` - vector of i64 +/// # Returns +/// * `encoded` - base64 encoded string +pub fn compress(data: &Vec) -> String { + let serialized_data = bincode::serialize(data).expect("Failed to serialize data"); + general_purpose::STANDARD.encode(&serialized_data) +} + +/// decode and deserialize a base64 encoded string to a vector of i64 +/// # Arguments +/// * `base64_str` - base64 encoded string +/// # Returns +/// * `decoded_data` - vector of i64 +pub fn decompress(base64_str: &str) -> Vec { + let decoded_bytes = general_purpose::STANDARD.decode(base64_str).expect("Failed to decode base64 string"); + bincode::deserialize(&decoded_bytes).expect("Failed to deserialize data") } \ No newline at end of file