mod crt;
pub(crate) mod multi_crt;
mod radix;
pub(crate) mod utils;
use crate::ciphertext::{CrtCiphertext, RadixCiphertext};
use crate::client_key::utils::i_crt;
use concrete_shortint::parameters::MessageModulus;
use serde::{Deserialize, Serialize};
pub use utils::radix_decomposition;
pub use crt::CrtClientKey;
pub use multi_crt::CrtMultiClientKey;
pub use radix::RadixClientKey;
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct ClientKey {
pub(crate) key: concrete_shortint::ClientKey,
}
impl From<concrete_shortint::ClientKey> for ClientKey {
fn from(key: concrete_shortint::ClientKey) -> Self {
Self { key }
}
}
impl From<ClientKey> for concrete_shortint::ClientKey {
fn from(key: ClientKey) -> concrete_shortint::ClientKey {
key.key
}
}
impl AsRef<ClientKey> for ClientKey {
fn as_ref(&self) -> &ClientKey {
self
}
}
impl ClientKey {
pub fn new(parameter_set: concrete_shortint::Parameters) -> Self {
Self {
key: concrete_shortint::ClientKey::new(parameter_set),
}
}
pub fn parameters(&self) -> concrete_shortint::Parameters {
self.key.parameters
}
pub fn encrypt_radix(&self, message: u64, num_blocks: usize) -> RadixCiphertext {
let mut blocks = Vec::with_capacity(num_blocks);
let mask = (self.key.parameters.message_modulus.0 - 1) as u64;
let mut power = 1_u64;
for _ in 0..num_blocks {
let decomp = (message & (mask * power)) / power;
let ct = self.key.encrypt(decomp);
blocks.push(ct);
power *= self.key.parameters.message_modulus.0 as u64;
}
RadixCiphertext { blocks }
}
pub fn encrypt_radix_without_padding(
&self,
message: u64,
num_blocks: usize,
) -> RadixCiphertext {
let mut blocks = Vec::with_capacity(num_blocks);
let mask = (self.key.parameters.message_modulus.0 - 1) as u64;
let mut power = 1_u64;
for _ in 0..num_blocks {
let decomp = (message & (mask * power)) / power;
let ct = self.key.encrypt_without_padding(decomp);
blocks.push(ct);
power *= self.key.parameters.message_modulus.0 as u64;
}
RadixCiphertext { blocks }
}
pub fn encrypt_one_block(&self, message: u64) -> concrete_shortint::Ciphertext {
self.key.encrypt(message)
}
pub fn decrypt_one_block(&self, ct: &concrete_shortint::Ciphertext) -> u64 {
self.key.decrypt(ct)
}
pub fn decrypt_radix(&self, ctxt: &RadixCiphertext) -> u64 {
let mut result = 0_u64;
let mut shift = 1_u64;
let modulus = self.parameters().message_modulus.0 as u64;
for c_i in ctxt.blocks.iter() {
let block_value = self.key.decrypt_message_and_carry(c_i).wrapping_mul(shift);
result = result.wrapping_add(block_value);
shift = shift.wrapping_mul(modulus);
}
let whole_modulus = modulus.pow(ctxt.blocks.len() as u32);
result % whole_modulus
}
pub fn decrypt_radix_without_padding(&self, ctxt: &RadixCiphertext) -> u64 {
let mut result = 0_u64;
let mut shift = 1_u64;
let modulus = self.parameters().message_modulus.0 as u64;
for c_i in ctxt.blocks.iter() {
let block_value = self
.key
.decrypt_message_and_carry_without_padding(c_i)
.wrapping_mul(shift);
result = result.wrapping_add(block_value);
shift = shift.wrapping_mul(modulus);
}
let whole_modulus = modulus.pow(ctxt.blocks.len() as u32);
result % whole_modulus
}
pub fn encrypt_crt(&self, message: u64, base_vec: Vec<u64>) -> CrtCiphertext {
let mut ctxt_vect = Vec::with_capacity(base_vec.len());
for modulus in base_vec.iter().copied() {
let ct = self
.key
.encrypt_with_message_modulus(message, MessageModulus(modulus as usize));
ctxt_vect.push(ct);
}
CrtCiphertext {
blocks: ctxt_vect,
moduli: base_vec,
}
}
pub fn decrypt_crt(&self, ctxt: &CrtCiphertext) -> u64 {
let mut val: Vec<u64> = Vec::with_capacity(ctxt.blocks.len());
for (c_i, b_i) in ctxt.blocks.iter().zip(ctxt.moduli.iter()) {
val.push(self.key.decrypt_message_and_carry(c_i) % b_i);
}
println!("VAL DEC = {:?}", val);
let result = i_crt(&ctxt.moduli, &val);
let whole_modulus: u64 = ctxt.moduli.iter().copied().product();
result % whole_modulus
}
pub fn encrypt_native_crt(&self, message: u64, base_vec: Vec<u64>) -> CrtCiphertext {
let mut ct_vec = Vec::with_capacity(base_vec.len());
for modulus in base_vec.iter() {
let ct = self.key.encrypt_native_crt(message, *modulus as u8);
ct_vec.push(ct);
}
CrtCiphertext {
blocks: ct_vec,
moduli: base_vec,
}
}
pub fn decrypt_native_crt(&self, ct: &CrtCiphertext) -> u64 {
let mut val: Vec<u64> = vec![];
for (c_i, b_i) in ct.blocks.iter().zip(ct.moduli.iter()) {
val.push(self.key.decrypt_message_native_crt(c_i, *b_i as u8));
}
let result = i_crt(&ct.moduli, &val);
let whole_modulus: u64 = ct.moduli.iter().copied().product();
result % whole_modulus
}
}