use crate::key::SecretKeyLv0;
use crate::params;
use crate::params::Torus;
use crate::tlwe::TLWELv0;
use rand::Rng;
#[derive(Debug, Clone)]
pub struct PublicKeyLv0 {
pub encryptions: Vec<TLWELv0>,
}
impl PublicKeyLv0 {
pub fn new(secret_key: &SecretKeyLv0) -> Self {
Self::new_with_params(
secret_key,
params::tlwe_lv0::N * 2, params::tlwe_lv0::ALPHA,
)
}
pub fn new_with_params(secret_key: &SecretKeyLv0, size: usize, alpha: f64) -> Self {
let mut encryptions = Vec::with_capacity(size);
for _ in 0..size {
encryptions.push(TLWELv0::encrypt_f64(0.0, alpha, secret_key));
}
PublicKeyLv0 { encryptions }
}
pub fn encrypt_f64(&self, plaintext: f64, alpha: f64) -> TLWELv0 {
let mut rng = rand::thread_rng();
let mut result = TLWELv0::new();
let plaintext_torus = crate::utils::f64_to_torus(plaintext);
result.p[params::tlwe_lv0::N] = plaintext_torus;
for enc in &self.encryptions {
if rng.gen_bool(0.5) {
if rng.gen_bool(0.5) {
for i in 0..=params::tlwe_lv0::N {
result.p[i] = result.p[i].wrapping_add(enc.p[i]);
}
} else {
for i in 0..=params::tlwe_lv0::N {
result.p[i] = result.p[i].wrapping_sub(enc.p[i]);
}
}
}
}
let normal_distr = rand_distr::Normal::new(0.0, alpha).unwrap();
let mut rng = rand::thread_rng();
let noise = crate::utils::gaussian_f64(0.0, &normal_distr, &mut rng);
result.p[params::tlwe_lv0::N] = result.p[params::tlwe_lv0::N].wrapping_add(noise);
result
}
pub fn encrypt_bool(&self, plaintext: bool, alpha: f64) -> TLWELv0 {
let p = if plaintext { 0.125 } else { -0.125 };
self.encrypt_f64(p, alpha)
}
}
#[derive(Debug, Clone)]
pub struct ProxyReencryptionKey {
pub key_encryptions: Vec<TLWELv0>,
pub base: usize,
pub t: usize,
}
impl ProxyReencryptionKey {
pub fn new_asymmetric(key_from: &SecretKeyLv0, public_key_to: &PublicKeyLv0) -> Self {
Self::new_asymmetric_with_params(
key_from,
public_key_to,
params::KSK_ALPHA,
params::trgsw_lv1::BASEBIT,
params::trgsw_lv1::IKS_T,
)
}
pub fn new_asymmetric_with_params(
key_from: &SecretKeyLv0,
public_key_to: &PublicKeyLv0,
alpha: f64,
basebit: usize,
t: usize,
) -> Self {
let base = 1 << basebit;
let n = params::tlwe_lv0::N;
let mut key_encryptions = vec![TLWELv0::new(); base * t * n];
for i in 0..n {
for j in 0..t {
for k in 0..base {
if k == 0 {
continue; }
let p = ((k as u32 * key_from[i]) as f64) / ((1 << ((j + 1) * basebit)) as f64);
let idx = (base * t * i) + (base * j) + k;
key_encryptions[idx] = public_key_to.encrypt_f64(p, alpha);
}
}
}
ProxyReencryptionKey {
key_encryptions,
base,
t,
}
}
pub fn new_symmetric(key_from: &SecretKeyLv0, key_to: &SecretKeyLv0) -> Self {
Self::new_symmetric_with_params(
key_from,
key_to,
params::KSK_ALPHA,
params::trgsw_lv1::BASEBIT,
params::trgsw_lv1::IKS_T,
)
}
pub fn new_symmetric_with_params(
key_from: &SecretKeyLv0,
key_to: &SecretKeyLv0,
alpha: f64,
basebit: usize,
t: usize,
) -> Self {
let base = 1 << basebit;
let n = params::tlwe_lv0::N;
let mut key_encryptions = vec![TLWELv0::new(); base * t * n];
for i in 0..n {
for j in 0..t {
for k in 0..base {
if k == 0 {
continue; }
let p = ((k as u32 * key_from[i]) as f64) / ((1 << ((j + 1) * basebit)) as f64);
let idx = (base * t * i) + (base * j) + k;
key_encryptions[idx] = TLWELv0::encrypt_f64(p, alpha, key_to);
}
}
}
ProxyReencryptionKey {
key_encryptions,
base,
t,
}
}
}
pub fn reencrypt_tlwe_lv0(ct_from: &TLWELv0, reenc_key: &ProxyReencryptionKey) -> TLWELv0 {
let n = params::tlwe_lv0::N;
let basebit = if reenc_key.base.count_ones() == 1 {
reenc_key.base.trailing_zeros() as usize
} else {
3 };
let base = reenc_key.base;
let t = reenc_key.t;
let mut result = TLWELv0::new();
result.p[n] = ct_from.b();
let prec_offset: Torus = 1 << (32 - (1 + basebit * t));
for i in 0..n {
let a_bar = ct_from.p[i].wrapping_add(prec_offset);
for j in 0..t {
let k = (a_bar >> (32 - (j + 1) * basebit)) & ((1 << basebit) - 1);
if k != 0 {
let idx = (base * t * i) + (base * j) + k as usize;
for x in 0..=n {
result.p[x] = result.p[x].wrapping_sub(reenc_key.key_encryptions[idx].p[x]);
}
}
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
use crate::key::SecretKey;
use rand::Rng;
#[test]
fn test_public_key_encryption() {
let secret_key = SecretKey::new();
let public_key = PublicKeyLv0::new(&secret_key.key_lv0);
for &message in &[true, false] {
let ct = public_key.encrypt_bool(message, params::tlwe_lv0::ALPHA);
let decrypted = ct.decrypt_bool(&secret_key.key_lv0);
assert_eq!(decrypted, message);
}
}
#[test]
fn test_public_key_multiple() {
let secret_key = SecretKey::new();
let public_key = PublicKeyLv0::new(&secret_key.key_lv0);
let mut rng = rand::thread_rng();
let mut correct = 0;
let iterations = 100;
for _ in 0..iterations {
let message = rng.gen_bool(0.5);
let ct = public_key.encrypt_bool(message, params::tlwe_lv0::ALPHA);
if ct.decrypt_bool(&secret_key.key_lv0) == message {
correct += 1;
}
}
let accuracy = correct as f64 / iterations as f64;
assert!(
accuracy > 0.95,
"Public key encryption accuracy {} is too low",
accuracy
);
}
#[test]
fn test_proxy_reencryption_asymmetric() {
let alice_key = SecretKey::new();
let bob_key = SecretKey::new();
let bob_public_key = PublicKeyLv0::new(&bob_key.key_lv0);
let reenc_key = ProxyReencryptionKey::new_asymmetric(&alice_key.key_lv0, &bob_public_key);
for message in &[true, false] {
let alice_ct = TLWELv0::encrypt_bool(*message, params::tlwe_lv0::ALPHA, &alice_key.key_lv0);
assert_eq!(alice_ct.decrypt_bool(&alice_key.key_lv0), *message);
let bob_ct = reencrypt_tlwe_lv0(&alice_ct, &reenc_key);
assert_eq!(bob_ct.decrypt_bool(&bob_key.key_lv0), *message);
}
}
#[test]
fn test_proxy_reencryption_symmetric() {
let alice_key = SecretKey::new();
let bob_key = SecretKey::new();
let reenc_key = ProxyReencryptionKey::new_symmetric(&alice_key.key_lv0, &bob_key.key_lv0);
for message in &[true, false] {
let alice_ct = TLWELv0::encrypt_bool(*message, params::tlwe_lv0::ALPHA, &alice_key.key_lv0);
assert_eq!(alice_ct.decrypt_bool(&alice_key.key_lv0), *message);
let bob_ct = reencrypt_tlwe_lv0(&alice_ct, &reenc_key);
assert_eq!(bob_ct.decrypt_bool(&bob_key.key_lv0), *message);
}
}
#[test]
fn test_proxy_reencryption_asymmetric_multiple() {
let alice_key = SecretKey::new();
let bob_key = SecretKey::new();
let bob_public_key = PublicKeyLv0::new(&bob_key.key_lv0);
let reenc_key = ProxyReencryptionKey::new_asymmetric(&alice_key.key_lv0, &bob_public_key);
let mut rng = rand::thread_rng();
let mut correct = 0;
let iterations = 100;
for _ in 0..iterations {
let message = rng.gen_bool(0.5);
let alice_ct = TLWELv0::encrypt_bool(message, params::tlwe_lv0::ALPHA, &alice_key.key_lv0);
let bob_ct = reencrypt_tlwe_lv0(&alice_ct, &reenc_key);
if bob_ct.decrypt_bool(&bob_key.key_lv0) == message {
correct += 1;
}
}
let accuracy = correct as f64 / iterations as f64;
assert!(
accuracy > 0.90,
"Asymmetric accuracy {} is too low",
accuracy
);
}
#[test]
fn test_proxy_reencryption_key_generation() {
let alice_key = SecretKey::new();
let bob_key = SecretKey::new();
let reenc_key = ProxyReencryptionKey::new_symmetric(&alice_key.key_lv0, &bob_key.key_lv0);
let expected_size = reenc_key.base * reenc_key.t * params::tlwe_lv0::N;
assert_eq!(reenc_key.key_encryptions.len(), expected_size);
assert_eq!(reenc_key.base, 1 << params::trgsw_lv1::BASEBIT);
assert_eq!(reenc_key.t, params::trgsw_lv1::IKS_T);
}
#[test]
fn test_proxy_reencryption_chain_asymmetric() {
let alice_key = SecretKey::new();
let bob_key = SecretKey::new();
let carol_key = SecretKey::new();
let bob_public = PublicKeyLv0::new(&bob_key.key_lv0);
let carol_public = PublicKeyLv0::new(&carol_key.key_lv0);
let reenc_key_ab = ProxyReencryptionKey::new_asymmetric(&alice_key.key_lv0, &bob_public);
let reenc_key_bc = ProxyReencryptionKey::new_asymmetric(&bob_key.key_lv0, &carol_public);
let message = true;
let alice_ct = TLWELv0::encrypt_bool(message, params::tlwe_lv0::ALPHA, &alice_key.key_lv0);
let bob_ct = reencrypt_tlwe_lv0(&alice_ct, &reenc_key_ab);
assert_eq!(bob_ct.decrypt_bool(&bob_key.key_lv0), message);
let carol_ct = reencrypt_tlwe_lv0(&bob_ct, &reenc_key_bc);
assert_eq!(carol_ct.decrypt_bool(&carol_key.key_lv0), message);
}
#[test]
fn test_custom_params() {
let alice_key = SecretKey::new();
let bob_key = SecretKey::new();
let custom_alpha = params::KSK_ALPHA * 0.8;
let reenc_key = ProxyReencryptionKey::new_symmetric_with_params(
&alice_key.key_lv0,
&bob_key.key_lv0,
custom_alpha,
params::trgsw_lv1::BASEBIT,
params::trgsw_lv1::IKS_T,
);
let message = true;
let alice_ct = TLWELv0::encrypt_bool(message, params::tlwe_lv0::ALPHA, &alice_key.key_lv0);
let bob_ct = reencrypt_tlwe_lv0(&alice_ct, &reenc_key);
assert_eq!(bob_ct.decrypt_bool(&bob_key.key_lv0), message);
}
}