Skip to content

use base64 encoding for sk, pk, ct #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
52 changes: 25 additions & 27 deletions src/decrypt.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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<Polynomial<i64>>
let sk_array: Vec<i64> = sk_string.split(',')
.filter_map(|s| s.parse().ok())
.collect();

// Base64 decode the secret key string
let sk_array: Vec<i64> = decompress(sk_string);

// Convert the secret key into a Vec<Polynomial<i64>>
let sk: Vec<Polynomial<i64>> = sk_array.chunks(n)
.map(|chunk| Polynomial::new(chunk.to_vec()))
.collect();

// Parse ciphertext into u and v
let ciphertext_list: Vec<i64> = ciphertext_string.split(',')
.filter_map(|s| s.parse().ok())
.collect();

// Base64 decode and deserialize the ciphertext string
let ciphertext_list: Vec<i64> = 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<Polynomial<i64>> = 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, &params);
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<String> = 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()
}
}
26 changes: 12 additions & 14 deletions src/encrypt.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -67,14 +67,13 @@ pub fn encrypt(
/// let ciphertext_string = module_lwe::encrypt::encrypt_string(&pk_string, &message_string, &params, None);
/// ```
pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Parameters, seed: Option<u64>) -> String {

//get parameters
// Get parameters
let (n, k) = (params.n, params.k);

// Parse public key

let pk_list: Vec<i64> = pk_string.split(',').map(|x| x.parse::<i64>().unwrap()).collect();
// Decode and deserialize the base64-encoded public key string
let pk_list: Vec<i64> = decompress(pk_string);

// Parse the public key
let a: Vec<Vec<Polynomial<i64>>> = pk_list[..k * k * n]
.chunks(k * n)
.map(|chunk| {
Expand All @@ -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<Vec<i64>> = message_binary
.chunks(n) // Divide the binary message into chunks of size `n`
.map(|chunk| chunk.to_vec()) // Convert each chunk into a vector
Expand All @@ -111,12 +110,11 @@ pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Para
})
.collect();
let mut v_flattened: Vec<i64> = 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::<Vec<String>>().join(",");

ciphertext_str
// Serialize and Base64 encode the ciphertext coefficient list
compress(&ciphertext_list)
}
33 changes: 12 additions & 21 deletions src/keygen.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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(&params, None);
/// ```
pub fn keygen_string(params: &Parameters, seed: Option<u64>) -> HashMap<String, String> {
// 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<i64> = pk.0
.iter()
.flat_map(|row| {
Expand All @@ -55,6 +55,7 @@ pub fn keygen_string(params: &Parameters, seed: Option<u64>) -> HashMap<String,
})
})
.collect();

pk_coeffs.extend(
pk.1.iter()
.flat_map(|poly| {
Expand All @@ -64,7 +65,7 @@ pub fn keygen_string(params: &Parameters, seed: Option<u64>) -> HashMap<String,
})
);

// Convert secret key to a flattened list of coefficients
// Convert the secret key to a flattened list of coefficients
let sk_coeffs: Vec<i64> = sk
.iter()
.flat_map(|poly| {
Expand All @@ -74,20 +75,10 @@ pub fn keygen_string(params: &Parameters, seed: Option<u64>) -> HashMap<String,
})
.collect();

// Convert the public/secret key coefficients to a comma-separated string
let pk_coeffs_str = pk_coeffs.iter()
.map(|coef| coef.to_string())
.collect::<Vec<String>>()
.join(",");
let sk_coeffs_str = sk_coeffs.iter()
.map(|coef| coef.to_string())
.collect::<Vec<String>>()
.join(",");

//store the secret/public key in a HashMap
// Store the Base64 encoded keys in a HashMap
let mut keys: HashMap<String, String> = 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
}
22 changes: 22 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<i64>) -> 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<i64> {
let decoded_bytes = general_purpose::STANDARD.decode(base64_str).expect("Failed to decode base64 string");
bincode::deserialize(&decoded_bytes).expect("Failed to deserialize data")
}