use crate::bootstrap::Bootstrap;
use crate::key::CloudKey;
use crate::trgsw::identity_key_switching;
use crate::trlwe::sample_extract_index;
use crate::utils::Ciphertext;
#[cfg(feature = "lut-bootstrap")]
use crate::trgsw::blind_rotate_with_testvec;
use super::super::lut::{Generator, LookupTable};
#[derive(Debug, Clone)]
pub struct LutBootstrap {
_private: (),
}
impl LutBootstrap {
pub fn new() -> Self {
Self { _private: () }
}
pub fn bootstrap_func<F>(
&self,
ct_in: &Ciphertext,
f: F,
message_modulus: usize,
cloud_key: &CloudKey,
) -> Ciphertext
where
F: Fn(usize) -> usize,
{
let generator = Generator::new(message_modulus);
let lookup_table = generator.generate_lookup_table(f);
self.bootstrap_lut(ct_in, &lookup_table, cloud_key)
}
pub fn bootstrap_lut(
&self,
ct_in: &Ciphertext,
lut: &LookupTable,
cloud_key: &CloudKey,
) -> Ciphertext {
let testvec = &lut.poly;
let rotated = blind_rotate_with_testvec(ct_in, testvec, cloud_key);
let extracted_lwe = sample_extract_index(&rotated, 0);
identity_key_switching(&extracted_lwe, &cloud_key.key_switching_key)
}
}
impl Default for LutBootstrap {
fn default() -> Self {
Self::new()
}
}
impl Bootstrap for LutBootstrap {
fn bootstrap(&self, ctxt: &Ciphertext, cloud_key: &CloudKey) -> Ciphertext {
self.bootstrap_func(ctxt, |x| x, 2, cloud_key)
}
fn bootstrap_without_key_switch(&self, ctxt: &Ciphertext, cloud_key: &CloudKey) -> Ciphertext {
let full_result = self.bootstrap(ctxt, cloud_key);
full_result
}
fn name(&self) -> &str {
"lut"
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::key;
use crate::params;
use rand::Rng;
#[test]
fn test_lut_bootstrap_creation() {
let bootstrap = LutBootstrap::new();
assert_eq!(bootstrap.name(), "lut");
}
#[test]
fn test_identity_function() {
let mut rng = rand::thread_rng();
let key = key::SecretKey::new();
let cloud_key = key::CloudKey::new(&key);
let bootstrap = LutBootstrap::new();
let identity = |x: usize| x;
for _ in 0..5 {
let plain = rng.gen::<bool>();
let message = if plain { 1 } else { 0 };
let encrypted = Ciphertext::encrypt_lwe_message(
message,
2,
params::SECURITY_128_BIT.tlwe_lv0.alpha,
&key.key_lv0,
);
let bootstrapped = bootstrap.bootstrap_func(&encrypted, identity, 2, &cloud_key);
let decrypted_message = bootstrapped.decrypt_lwe_message(2, &key.key_lv0);
let decrypted = decrypted_message != 0;
assert_eq!(plain, decrypted, "Identity function failed");
}
}
#[test]
fn test_not_function() {
let mut rng = rand::thread_rng();
let key = key::SecretKey::new();
let cloud_key = key::CloudKey::new(&key);
let bootstrap = LutBootstrap::new();
let not_func = |x: usize| 1 - x;
for _ in 0..5 {
let plain = rng.gen::<bool>();
let message = if plain { 1 } else { 0 };
let encrypted = Ciphertext::encrypt_lwe_message(
message,
2,
params::SECURITY_128_BIT.tlwe_lv0.alpha,
&key.key_lv0,
);
let bootstrapped = bootstrap.bootstrap_func(&encrypted, not_func, 2, &cloud_key);
let decrypted_message = bootstrapped.decrypt_lwe_message(2, &key.key_lv0);
let decrypted = decrypted_message != 0;
assert_eq!(!plain, decrypted, "NOT function failed");
}
}
#[test]
fn test_constant_function() {
let mut rng = rand::thread_rng();
let key = key::SecretKey::new();
let cloud_key = key::CloudKey::new(&key);
let bootstrap = LutBootstrap::new();
let constant_true = |_x: usize| 1;
for _ in 0..5 {
let plain = rng.gen::<bool>();
let message = if plain { 1 } else { 0 };
let encrypted = Ciphertext::encrypt_lwe_message(
message,
2,
params::SECURITY_128_BIT.tlwe_lv0.alpha,
&key.key_lv0,
);
let bootstrapped = bootstrap.bootstrap_func(&encrypted, constant_true, 2, &cloud_key);
let decrypted_message = bootstrapped.decrypt_lwe_message(2, &key.key_lv0);
let decrypted = decrypted_message != 0;
assert_eq!(true, decrypted, "Constant true function failed");
}
}
#[test]
fn test_lut_reuse() {
let mut rng = rand::thread_rng();
let key = key::SecretKey::new();
let cloud_key = key::CloudKey::new(&key);
let bootstrap = LutBootstrap::new();
let generator = Generator::new(2);
let not_func = |x: usize| 1 - x;
let lut = generator.generate_lookup_table(not_func);
for _ in 0..5 {
let plain = rng.gen::<bool>();
let message = if plain { 1 } else { 0 };
let encrypted = Ciphertext::encrypt_lwe_message(
message,
2,
params::SECURITY_128_BIT.tlwe_lv0.alpha,
&key.key_lv0,
);
let bootstrapped = bootstrap.bootstrap_lut(&encrypted, &lut, &cloud_key);
let decrypted_message = bootstrapped.decrypt_lwe_message(2, &key.key_lv0);
let decrypted = decrypted_message != 0;
assert_eq!(!plain, decrypted, "LUT reuse failed");
}
}
#[test]
fn test_bootstrap_trait() {
let bootstrap: Box<dyn Bootstrap> = Box::new(LutBootstrap::new());
assert_eq!(bootstrap.name(), "lut");
let mut rng = rand::thread_rng();
let key = key::SecretKey::new();
let cloud_key = key::CloudKey::new(&key);
let plain = rng.gen::<bool>();
let message = if plain { 1 } else { 0 };
let encrypted =
Ciphertext::encrypt_lwe_message(message, 2, params::tlwe_lv0::ALPHA, &key.key_lv0);
let bootstrapped = bootstrap.bootstrap(&encrypted, &cloud_key);
let decrypted_message = bootstrapped.decrypt_lwe_message(2, &key.key_lv0);
let decrypted = decrypted_message != 0;
assert_eq!(plain, decrypted);
}
}