Skip to content

Commit fab5d0e

Browse files
Merge pull request #32 from lattice-based-cryptography/use_base64_encoding
use base64 encoding for sk, pk, ct
2 parents 0c082c6 + dadb5b0 commit fab5d0e

File tree

5 files changed

+73
-62
lines changed

5 files changed

+73
-62
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ rand = "0.8.5"
1515
rand_distr = "0.4.3"
1616
ntt = "0.1.9"
1717
ring-lwe = "0.1.6"
18+
base64 = "0.21"
19+
bincode = "1.3"
1820

1921
[dev-dependencies]
2022
criterion = "0.5.1"

src/decrypt.rs

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use polynomial_ring::Polynomial;
22
use ring_lwe::utils::{polysub,nearest_int};
3-
use crate::utils::{Parameters,mul_vec_simple};
3+
use crate::utils::{Parameters,mul_vec_simple,decompress};
44

55
/// Decrypt a ciphertext
66
/// # Arguments
@@ -41,60 +41,58 @@ pub fn decrypt(
4141

4242
/// decrypt a ciphertext string given a secret key
4343
/// # Arguments
44-
/// * `sk_string` - secret key string
45-
/// * `ciphertext_string` - ciphertext string
44+
/// * `sk_string` - secret key string in base64 encoding
45+
/// * `ciphertext_string` - ciphertext string in base64 encoding
4646
/// * `params` - Parameters for the ring-LWE cryptosystem
4747
/// # Returns
48-
/// * `message_string` - decrypted message string
49-
pub fn decrypt_string(sk_string: &String, ciphertext_string: &String, params: &Parameters) -> String {
50-
51-
//get parameters
48+
/// * `message_string` - decrypted message string as plaintext
49+
pub fn decrypt_string(sk_string: &String, ciphertext_base64: &String, params: &Parameters) -> String {
50+
// Get parameters
5251
let (n, k) = (params.n, params.k);
53-
54-
// Convert the secret key string into a Vec<Polynomial<i64>>
55-
let sk_array: Vec<i64> = sk_string.split(',')
56-
.filter_map(|s| s.parse().ok())
57-
.collect();
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>>
5857
let sk: Vec<Polynomial<i64>> = sk_array.chunks(n)
5958
.map(|chunk| Polynomial::new(chunk.to_vec()))
6059
.collect();
61-
62-
// Parse ciphertext into u and v
63-
let ciphertext_list: Vec<i64> = ciphertext_string.split(',')
64-
.filter_map(|s| s.parse().ok())
65-
.collect();
60+
61+
// Base64 decode and deserialize the ciphertext string
62+
let ciphertext_list: Vec<i64> = decompress(ciphertext_base64);
63+
6664
let block_size = (k + 1) * n;
6765
let num_blocks = ciphertext_list.len() / block_size;
6866

6967
let mut message_binary = vec![];
70-
68+
7169
for i in 0..num_blocks {
7270
// Get u and v for this block
7371
let u_array = &ciphertext_list[i * block_size..i * block_size + k * n];
7472
let v_array = &ciphertext_list[i * block_size + k * n..(i + 1) * block_size];
75-
73+
7674
let u: Vec<Polynomial<i64>> = u_array.chunks(n)
7775
.map(|chunk| Polynomial::new(chunk.to_vec()))
7876
.collect();
7977
let v = Polynomial::new(v_array.to_vec());
80-
78+
8179
// Decrypt the ciphertext
8280
let mut m_b = decrypt(&sk, &u, &v, &params);
83-
m_b.resize(n,0);
84-
81+
m_b.resize(n, 0);
82+
8583
message_binary.extend(m_b);
8684
}
87-
85+
8886
// Group the bits back into bytes (8 bits each)
8987
let byte_chunks: Vec<String> = message_binary.chunks(8)
9088
.map(|chunk| chunk.iter().map(|bit| bit.to_string()).collect())
9189
.collect();
92-
90+
9391
// Convert each binary string back into a character
9492
let message_string: String = byte_chunks.iter()
9593
.map(|byte| char::from_u32(i64::from_str_radix(byte, 2).unwrap() as u32).unwrap())
9694
.collect();
97-
98-
//trim the null characters \0 = '00000000' from the end
95+
96+
// Trim the null characters \0 = '00000000' from the end
9997
message_string.trim_end_matches('\0').to_string()
100-
}
98+
}

src/encrypt.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use polynomial_ring::Polynomial;
22
use ring_lwe::utils::{polyadd,polysub,nearest_int};
3-
use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, transpose, mul_vec_simple, gen_small_vector};
3+
use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, transpose, mul_vec_simple, gen_small_vector, compress, decompress};
44

55
/// Encrypt a message using the ring-LWE cryptosystem
66
/// # Arguments
@@ -51,12 +51,12 @@ pub fn encrypt(
5151

5252
/// function to encrypt a message given a public_key string
5353
/// # Arguments
54-
/// * `pk_string` - public key string
55-
/// * `message_string` - message string
54+
/// * `pk_string` - public key string in base64 encoding
55+
/// * `message_string` - message string in base64 encoding
5656
/// * `params` - Parameters for the ring-LWE cryptosystem
5757
/// * `seed` - random seed
5858
/// # Returns
59-
/// * `ciphertext_str` - ciphertext string
59+
/// * `ciphertext_str` - ciphertext string in base64 encoding
6060
/// # Example
6161
/// ```
6262
/// let params = module_lwe::utils::Parameters::default();
@@ -67,14 +67,13 @@ pub fn encrypt(
6767
/// let ciphertext_string = module_lwe::encrypt::encrypt_string(&pk_string, &message_string, &params, None);
6868
/// ```
6969
pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Parameters, seed: Option<u64>) -> String {
70-
71-
//get parameters
70+
// Get parameters
7271
let (n, k) = (params.n, params.k);
7372

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

76+
// Parse the public key
7877
let a: Vec<Vec<Polynomial<i64>>> = pk_list[..k * k * n]
7978
.chunks(k * n)
8079
.map(|chunk| {
@@ -93,7 +92,7 @@ pub fn encrypt_string(pk_string: &String, message_string: &String, params: &Para
9392
.flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1) as i64))
9493
.collect();
9594

96-
// Break message into blocks, including the last partial block if necessary
95+
// Break message into blocks
9796
let message_blocks: Vec<Vec<i64>> = message_binary
9897
.chunks(n) // Divide the binary message into chunks of size `n`
9998
.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
111110
})
112111
.collect();
113112
let mut v_flattened: Vec<i64> = v.coeffs().to_vec();
114-
v_flattened.resize(n,0);
113+
v_flattened.resize(n, 0);
115114
ciphertext_list.extend(u_flattened);
116115
ciphertext_list.extend(v_flattened);
117116
}
118117

119-
let ciphertext_str = ciphertext_list.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(",");
120-
121-
ciphertext_str
118+
// Serialize and Base64 encode the ciphertext coefficient list
119+
compress(&ciphertext_list)
122120
}

src/keygen.rs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use polynomial_ring::Polynomial;
22
use std::collections::HashMap;
3-
use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, gen_small_vector, gen_uniform_matrix};
3+
use crate::utils::{Parameters, add_vec, mul_mat_vec_simple, gen_small_vector, gen_uniform_matrix,compress};
44

55
/// Generate public and secret keys for the ring-LWE cryptosystem
66
/// # Arguments
@@ -29,22 +29,22 @@ pub fn keygen(
2929
}
3030

3131
/// Generate public and secret keys for the ring-LWE cryptosystem and return them as a HashMap
32+
/// They are serialized and base64 encoded
3233
/// # Arguments
3334
/// * `params` - Parameters for the ring-LWE cryptosystem
3435
/// * `seed` - random seed
3536
/// # Returns
36-
/// * `keys` - HashMap containing the public and secret keys
37+
/// * `keys` - HashMap containing the public and secret keys as base64 encoded strings
3738
/// # Example
3839
/// ```
3940
/// let params = module_lwe::utils::Parameters::default();
4041
/// let keys = module_lwe::keygen::keygen_string(&params, None);
4142
/// ```
4243
pub fn keygen_string(params: &Parameters, seed: Option<u64>) -> HashMap<String, String> {
44+
// Generate public and secret keys
45+
let (pk, sk) = keygen(params, seed);
4346

44-
//generate public, secret keys
45-
let (pk,sk) = keygen(params,seed);
46-
47-
// Convert public key to a flattened list of coefficients
47+
// Convert the public key to a flattened list of coefficients
4848
let mut pk_coeffs: Vec<i64> = pk.0
4949
.iter()
5050
.flat_map(|row| {
@@ -55,6 +55,7 @@ pub fn keygen_string(params: &Parameters, seed: Option<u64>) -> HashMap<String,
5555
})
5656
})
5757
.collect();
58+
5859
pk_coeffs.extend(
5960
pk.1.iter()
6061
.flat_map(|poly| {
@@ -64,7 +65,7 @@ pub fn keygen_string(params: &Parameters, seed: Option<u64>) -> HashMap<String,
6465
})
6566
);
6667

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

77-
// Convert the public/secret key coefficients to a comma-separated string
78-
let pk_coeffs_str = pk_coeffs.iter()
79-
.map(|coef| coef.to_string())
80-
.collect::<Vec<String>>()
81-
.join(",");
82-
let sk_coeffs_str = sk_coeffs.iter()
83-
.map(|coef| coef.to_string())
84-
.collect::<Vec<String>>()
85-
.join(",");
86-
87-
//store the secret/public key in a HashMap
78+
// Store the Base64 encoded keys in a HashMap
8879
let mut keys: HashMap<String, String> = HashMap::new();
89-
keys.insert(String::from("secret"), sk_coeffs_str);
90-
keys.insert(String::from("public"), pk_coeffs_str);
91-
80+
keys.insert(String::from("secret"), compress(&sk_coeffs));
81+
keys.insert(String::from("public"), compress(&pk_coeffs));
82+
9283
keys
9384
}

src/utils.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use rand::SeedableRng;
44
use rand::rngs::StdRng;
55
use ring_lwe::utils::{polyadd, polymul_fast, gen_uniform_poly};
66
use ntt::omega;
7+
use base64::{engine::general_purpose, Engine as _};
8+
use bincode;
79

810
#[derive(Debug)]
911
/// default parameters for module-LWE
@@ -143,4 +145,24 @@ pub fn gen_uniform_matrix(size : usize, rank: usize, modulus: i64, seed: Option<
143145
}
144146
}
145147
m
148+
}
149+
150+
/// seralize and encode a vector of i64 to a base64 encoded string
151+
/// # Arguments
152+
/// * `data` - vector of i64
153+
/// # Returns
154+
/// * `encoded` - base64 encoded string
155+
pub fn compress(data: &Vec<i64>) -> String {
156+
let serialized_data = bincode::serialize(data).expect("Failed to serialize data");
157+
general_purpose::STANDARD.encode(&serialized_data)
158+
}
159+
160+
/// decode and deserialize a base64 encoded string to a vector of i64
161+
/// # Arguments
162+
/// * `base64_str` - base64 encoded string
163+
/// # Returns
164+
/// * `decoded_data` - vector of i64
165+
pub fn decompress(base64_str: &str) -> Vec<i64> {
166+
let decoded_bytes = general_purpose::STANDARD.decode(base64_str).expect("Failed to decode base64 string");
167+
bincode::deserialize(&decoded_bytes).expect("Failed to deserialize data")
146168
}

0 commit comments

Comments
 (0)