use crate::polynomial::Polynomial;
use crate::keygen::{PublicKey, SecretKey};
use crate::utils::{encode, decode, mod_reduce,encode_string,decode_string,mod_reduce_string};
#[derive(Debug, Clone)]
pub struct CkksParameters {
pub degree: usize, pub modulus: i64, }
impl CkksParameters {
pub fn new(degree: usize, modulus: i64) -> Self {
CkksParameters { degree, modulus }
}
}
pub struct CKKSEncryptor {
pub pub_key: PublicKey, pub params: CkksParameters, }
impl CKKSEncryptor {
pub fn new(pub_key: PublicKey, params: CkksParameters) -> Self {
Self { pub_key, params }
}
pub fn encrypt_collection<T>(&self, plaintext: &[T]) -> Polynomial
where
T: Into<f64> + Copy, {
let scaling_factor = 1e7;
let plaintext_f64: Vec<f64> = plaintext.iter().map(|&x| x.into()).collect(); let encoded = encode(&plaintext_f64, scaling_factor);
let encrypted_poly: Vec<i64> = encoded.coeffs.iter()
.zip(&self.pub_key.pk_0)
.zip(&self.pub_key.pk_1)
.map(|((&e, &pk0), &pk1)| e + pk0 * pk1) .collect();
let encrypted_polynomial = Polynomial::new(encrypted_poly);
let ciphertext = mod_reduce(&encrypted_polynomial, self.params.modulus);
ciphertext }
pub fn encrypt_value<T>(&self, plaintext: T) -> Polynomial
where
T: Into<f64> + Copy, {
let plaintext_vec: Vec<f64> = vec![plaintext.into()];
let scaling_factor = 1e7; let encoded = encode(&plaintext_vec, scaling_factor);
let encrypted_poly: Vec<i64> = encoded.coeffs.iter()
.zip(&self.pub_key.pk_0)
.zip(&self.pub_key.pk_1)
.map(|((&e, &pk0), &pk1)| e + pk0 * pk1) .collect();
let encrypted_polynomial = Polynomial::new(encrypted_poly);
let ciphertext = mod_reduce(&encrypted_polynomial, self.params.modulus);
ciphertext }
pub fn encrypt_string(&self, plaintext: &str) -> Polynomial {
let scaling_factor = 1e9;
let encoded = encode_string(plaintext, scaling_factor);
if self.pub_key.pk_0.len() < encoded.coeffs.len() || self.pub_key.pk_1.len() < encoded.coeffs.len() {
panic!("Public key length is insufficient for encryption.");
}
let encrypted_poly: Vec<i64> = encoded.coeffs.iter()
.zip(&self.pub_key.pk_0)
.zip(&self.pub_key.pk_1)
.map(|((e, pk0), pk1)| e + pk0 * pk1) .collect();
let encrypted_polynomial = Polynomial::new(encrypted_poly);
let ciphertext = mod_reduce_string(&encrypted_polynomial, self.params.modulus);
ciphertext }
}
pub struct CKKSDecryptor {
sec_key: SecretKey, params: CkksParameters, }
impl CKKSDecryptor {
pub fn new(sec_key: SecretKey, params: CkksParameters) -> Self {
Self { sec_key, params }
}
pub fn decrypt_as_int(&self, ciphertext: &Polynomial) -> Vec<i64> {
let reduced_poly = mod_reduce(ciphertext, self.params.modulus);
let decrypted_poly: Vec<i64> = reduced_poly.coeffs.iter()
.zip(&self.sec_key.poly)
.map(|(&c, &sk)| c - sk) .collect();
let decrypted_polynomial = Polynomial::new(decrypted_poly);
let decoded = decrypted_polynomial.decode();
decoded
}
pub fn decrypt(&self, ciphertext: &Polynomial) -> Vec<f64> {
let reduced_poly = mod_reduce(ciphertext, self.params.modulus);
let decrypted_poly: Vec<i64> = reduced_poly.coeffs.iter()
.zip(&self.sec_key.poly)
.map(|(&c, &sk)| c - sk) .collect();
let decrypted_polynomial = Polynomial::new(decrypted_poly);
let scaling_factor = 1e7; let decoded = decode(&decrypted_polynomial, scaling_factor);
decoded }
pub fn decrypt_string(&self, ciphertext: &Polynomial) -> String {
let scaling_factor = 1e9;
let reduced_poly = mod_reduce_string(ciphertext, self.params.modulus);
let decrypted_poly: Vec<i64> = reduced_poly.coeffs.iter()
.zip(&self.sec_key.poly)
.map(|(&c, &sk)| c - sk) .collect();
let decrypted_polynomial = Polynomial::new(decrypted_poly);
let decoded_string = decode_string(&decrypted_polynomial, scaling_factor); decoded_string }
}