use super::utils::*;
use crate::core_crypto::commons::dispersion::StandardDev;
use crate::core_crypto::commons::math::random::DynamicDistribution as RustDynamicDistribution;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use std::os::raw::c_int;
#[repr(u64)]
#[derive(Clone, Copy)]
pub enum DynamicDistributionTag {
Gaussian = 0,
TUniform = 1,
}
impl TryFrom<u64> for DynamicDistributionTag {
type Error = &'static str;
fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Gaussian),
1 => Ok(Self::TUniform),
_ => Err("Invalid value for DynamicDistributionTag"),
}
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Gaussian {
pub std: f64,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct TUniform {
pub bound_log2: u32,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union DynamicDistributionPayload {
pub gaussian: Gaussian,
pub t_uniform: TUniform,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct DynamicDistribution {
pub tag: u64,
pub distribution: DynamicDistributionPayload,
}
impl DynamicDistribution {
pub fn new_gaussian_from_std_dev(std: f64) -> Self {
Self {
tag: DynamicDistributionTag::Gaussian as u64,
distribution: DynamicDistributionPayload {
gaussian: Gaussian { std },
},
}
}
pub fn new_t_uniform(bound_log2: u32) -> Self {
Self {
tag: DynamicDistributionTag::TUniform as u64,
distribution: DynamicDistributionPayload {
t_uniform: TUniform { bound_log2 },
},
}
}
}
impl<T: UnsignedInteger> TryFrom<DynamicDistribution> for RustDynamicDistribution<T> {
type Error = &'static str;
fn try_from(value: DynamicDistribution) -> Result<Self, Self::Error> {
let tag: DynamicDistributionTag = value.tag.try_into()?;
match tag {
DynamicDistributionTag::Gaussian => {
Ok(Self::new_gaussian_from_std_dev(StandardDev(unsafe {
value.distribution.gaussian.std
})))
}
DynamicDistributionTag::TUniform => Ok(Self::try_new_t_uniform(unsafe {
value.distribution.t_uniform.bound_log2
})?),
}
}
}
impl<T: UnsignedInteger> RustDynamicDistribution<T> {
pub const fn convert_to_c(&self) -> DynamicDistribution {
match self {
Self::Gaussian(gaussian) => DynamicDistribution {
tag: DynamicDistributionTag::Gaussian as u64,
distribution: DynamicDistributionPayload {
gaussian: Gaussian { std: gaussian.std },
},
},
Self::TUniform(t_uniform) => DynamicDistribution {
tag: DynamicDistributionTag::TUniform as u64,
distribution: DynamicDistributionPayload {
t_uniform: TUniform {
bound_log2: t_uniform.bound_log2(),
},
},
},
}
}
}
#[no_mangle]
pub unsafe extern "C" fn new_gaussian_from_std_dev(std_dev: f64) -> DynamicDistribution {
DynamicDistribution::new_gaussian_from_std_dev(std_dev)
}
#[no_mangle]
pub unsafe extern "C" fn new_t_uniform(bound_log2: u32) -> DynamicDistribution {
DynamicDistribution::new_t_uniform(bound_log2)
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_lwe_secret_key(
output_lwe_sk_ptr: *mut u64,
lwe_sk_dim: usize,
seed_low_bytes: u64,
seed_high_bytes: u64,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::commons::math::random::Seed;
use crate::core_crypto::prelude::*;
let seed_low_bytes: u128 = seed_low_bytes.into();
let seed_high_bytes: u128 = seed_high_bytes.into();
let seed = (seed_high_bytes << 64) | seed_low_bytes;
let mut secret_generator = SecretRandomGenerator::<DefaultRandomGenerator>::new(Seed(seed));
let output_lwe_sk_slice = std::slice::from_raw_parts_mut(output_lwe_sk_ptr, lwe_sk_dim);
let mut lwe_sk = LweSecretKey::from_container(output_lwe_sk_slice);
generate_binary_lwe_secret_key(&mut lwe_sk, &mut secret_generator);
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_lwe_encrypt(
output_ct_ptr: *mut u64,
pt: u64,
lwe_sk_ptr: *const u64,
lwe_sk_dim: usize,
lwe_noise_distribution: DynamicDistribution,
seed_low_bytes: u64,
seed_high_bytes: u64,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::commons::math::random::Seed;
use crate::core_crypto::prelude::*;
let lwe_sk_slice = std::slice::from_raw_parts(lwe_sk_ptr, lwe_sk_dim);
let lwe_sk = LweSecretKey::from_container(lwe_sk_slice);
let seed_low_bytes: u128 = seed_low_bytes.into();
let seed_high_bytes: u128 = seed_high_bytes.into();
let seed = (seed_high_bytes << 64) | seed_low_bytes;
let seed = Seed(seed);
let mut deterministic_seeder = DeterministicSeeder::<DefaultRandomGenerator>::new(seed);
let mut encryption_generator = EncryptionRandomGenerator::<DefaultRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let plaintext = Plaintext(pt);
let output_ct = std::slice::from_raw_parts_mut(output_ct_ptr, lwe_sk_dim + 1);
let mut ct = LweCiphertext::from_container(output_ct, CiphertextModulus::new_native());
let lwe_noise_distribution: DynamicDistribution<u64> =
lwe_noise_distribution.try_into().unwrap();
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_noise_distribution,
&mut encryption_generator,
);
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_ggsw_encrypt(
output_ct_ptr: *mut u64,
cleartext: u64,
glwe_sk_ptr: *const u64,
glwe_sk_dim: usize,
poly_size: usize,
level_count: usize,
base_log: usize,
glwe_noise_distribution: DynamicDistribution,
seed_low_bytes: u64,
seed_high_bytes: u64,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::commons::math::random::Seed;
use crate::core_crypto::prelude::*;
let glwe_sk_slice = std::slice::from_raw_parts(glwe_sk_ptr, glwe_sk_dim * poly_size);
let glwe_sk = GlweSecretKey::from_container(glwe_sk_slice, PolynomialSize(poly_size));
let seed_low_bytes: u128 = seed_low_bytes.into();
let seed_high_bytes: u128 = seed_high_bytes.into();
let seed = (seed_high_bytes << 64) | seed_low_bytes;
let seed = Seed(seed);
let mut deterministic_seeder = DeterministicSeeder::<DefaultRandomGenerator>::new(seed);
let mut encryption_generator = EncryptionRandomGenerator::<DefaultRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let cleartext = Cleartext(cleartext);
let output_ct = std::slice::from_raw_parts_mut(
output_ct_ptr,
ggsw_ciphertext_size(
GlweDimension(glwe_sk_dim).to_glwe_size(),
PolynomialSize(poly_size),
DecompositionLevelCount(level_count),
),
);
let mut ct = GgswCiphertext::from_container(
output_ct,
GlweDimension(glwe_sk_dim).to_glwe_size(),
PolynomialSize(poly_size),
DecompositionBaseLog(base_log),
CiphertextModulus::new_native(),
);
let glwe_noise_distribution: DynamicDistribution<u64> =
glwe_noise_distribution.try_into().unwrap();
encrypt_constant_ggsw_ciphertext(
&glwe_sk,
&mut ct,
cleartext,
glwe_noise_distribution,
&mut encryption_generator,
);
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_lwe_decrypt(
output_pt: *mut u64,
input_ct_ptr: *const u64,
lwe_sk_ptr: *const u64,
lwe_sk_dim: usize,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::prelude::*;
let lwe_sk_slice = std::slice::from_raw_parts(lwe_sk_ptr, lwe_sk_dim);
let lwe_sk = LweSecretKey::from_container(lwe_sk_slice);
let input_ct = std::slice::from_raw_parts(input_ct_ptr, lwe_sk_dim + 1);
let ct = LweCiphertext::from_container(input_ct, CiphertextModulus::new_native());
let plaintext = decrypt_lwe_ciphertext(&lwe_sk, &ct);
*output_pt = plaintext.0;
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_glwe_decrypt(
output_pt: *mut u64,
input_ct_ptr: *const u64,
glwe_sk_ptr: *const u64,
glwe_sk_dim: usize,
glwe_poly_size: usize,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::prelude::*;
let glwe_sk_slice = std::slice::from_raw_parts(glwe_sk_ptr, glwe_sk_dim * glwe_poly_size);
let glwe_sk = GlweSecretKey::from_container(glwe_sk_slice, PolynomialSize(glwe_poly_size));
let input_ct = std::slice::from_raw_parts(
input_ct_ptr,
glwe_ciphertext_size(
GlweDimension(glwe_sk_dim).to_glwe_size(),
PolynomialSize(glwe_poly_size),
),
);
let ct = GlweCiphertext::from_container(
input_ct,
PolynomialSize(glwe_poly_size),
CiphertextModulus::new_native(),
);
let output = std::slice::from_raw_parts_mut(output_pt, glwe_poly_size);
let mut plaintext_list = PlaintextList::from_container(output);
decrypt_glwe_ciphertext(&glwe_sk, &ct, &mut plaintext_list);
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_lwe_multi_bit_bootstrapping_key_element_size(
input_lwe_sk_dim: usize,
output_glwe_sk_dim: usize,
output_glwe_sk_poly_size: usize,
lwe_multi_bit_level_count: usize,
lwe_multi_bit_grouping_factor: usize,
result: *mut usize,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::prelude::*;
let result = get_mut_checked(result).unwrap();
let input_lwe_sk_dim = LweDimension(input_lwe_sk_dim);
let output_glwe_sk_dim = GlweDimension(output_glwe_sk_dim);
let output_glwe_sk_poly_size = PolynomialSize(output_glwe_sk_poly_size);
let lwe_multi_bit_level_count = DecompositionLevelCount(lwe_multi_bit_level_count);
let lwe_multi_bit_grouping_factor = LweBskGroupingFactor(lwe_multi_bit_grouping_factor);
*result = lwe_multi_bit_bootstrap_key_size(
input_lwe_sk_dim,
output_glwe_sk_dim.to_glwe_size(),
output_glwe_sk_poly_size,
lwe_multi_bit_level_count,
lwe_multi_bit_grouping_factor,
)
.unwrap();
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_par_generate_lwe_bootstrapping_key(
output_bsk_ptr: *mut u64,
bsk_base_log: usize,
bsk_level_count: usize,
input_lwe_sk_ptr: *const u64,
input_lwe_sk_dim: usize,
output_glwe_sk_ptr: *const u64,
output_glwe_sk_dim: usize,
output_glwe_sk_poly_size: usize,
glwe_noise_distribution: DynamicDistribution,
seed_low_bytes: u64,
seed_high_bytes: u64,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::commons::math::random::Seed;
use crate::core_crypto::prelude::*;
let input_lwe_sk_slice = std::slice::from_raw_parts(input_lwe_sk_ptr, input_lwe_sk_dim);
let input_lwe_sk = LweSecretKey::from_container(input_lwe_sk_slice);
let output_glwe_sk_dim = GlweDimension(output_glwe_sk_dim);
let output_glwe_sk_poly_size = PolynomialSize(output_glwe_sk_poly_size);
let output_glwe_sk_size =
glwe_ciphertext_mask_size(output_glwe_sk_dim, output_glwe_sk_poly_size);
let output_glwe_sk_slice =
std::slice::from_raw_parts(output_glwe_sk_ptr, output_glwe_sk_size);
let output_glwe_sk =
GlweSecretKey::from_container(output_glwe_sk_slice, output_glwe_sk_poly_size);
let seed_low_bytes: u128 = seed_low_bytes.into();
let seed_high_bytes: u128 = seed_high_bytes.into();
let seed = (seed_high_bytes << 64) | seed_low_bytes;
let mut deterministic_seeder =
DeterministicSeeder::<DefaultRandomGenerator>::new(Seed(seed));
let mut encryption_random_generator =
EncryptionRandomGenerator::<DefaultRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let lwe_base_log = DecompositionBaseLog(bsk_base_log);
let lwe_level_count = DecompositionLevelCount(bsk_level_count);
let lwe_slice_len = {
let bsk = LweBootstrapKeyOwned::new(
0u64,
output_glwe_sk.glwe_dimension().to_glwe_size(),
output_glwe_sk.polynomial_size(),
lwe_base_log,
lwe_level_count,
input_lwe_sk.lwe_dimension(),
CiphertextModulus::new_native(),
);
bsk.into_container().len()
};
let bsk_slice = std::slice::from_raw_parts_mut(output_bsk_ptr, lwe_slice_len);
let mut bsk = LweBootstrapKey::from_container(
bsk_slice,
output_glwe_sk.glwe_dimension().to_glwe_size(),
output_glwe_sk.polynomial_size(),
lwe_base_log,
lwe_level_count,
CiphertextModulus::new_native(),
);
let glwe_noise_distribution: DynamicDistribution<u64> =
glwe_noise_distribution.try_into().unwrap();
par_generate_lwe_bootstrap_key(
&input_lwe_sk,
&output_glwe_sk,
&mut bsk,
glwe_noise_distribution,
&mut encryption_random_generator,
)
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_par_generate_lwe_multi_bit_bootstrapping_key(
input_lwe_sk_ptr: *const u64,
input_lwe_sk_dim: usize,
output_glwe_sk_ptr: *const u64,
output_glwe_sk_dim: usize,
output_glwe_sk_poly_size: usize,
lwe_multi_bit_ptr: *mut u64,
lwe_multi_bit_base_log: usize,
lwe_multi_bit_level_count: usize,
lwe_multi_bit_grouping_factor: usize,
glwe_noise_distribution: DynamicDistribution,
seed_low_bytes: u64,
seed_high_bytes: u64,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::commons::math::random::Seed;
use crate::core_crypto::prelude::*;
let input_lwe_sk_slice = std::slice::from_raw_parts(input_lwe_sk_ptr, input_lwe_sk_dim);
let input_lwe_sk = LweSecretKey::from_container(input_lwe_sk_slice);
let output_glwe_sk_dim = GlweDimension(output_glwe_sk_dim);
let output_glwe_sk_poly_size = PolynomialSize(output_glwe_sk_poly_size);
let output_glwe_sk_size =
glwe_ciphertext_mask_size(output_glwe_sk_dim, output_glwe_sk_poly_size);
let output_glwe_sk_slice =
std::slice::from_raw_parts(output_glwe_sk_ptr, output_glwe_sk_size);
let output_glwe_sk =
GlweSecretKey::from_container(output_glwe_sk_slice, output_glwe_sk_poly_size);
let seed_low_bytes: u128 = seed_low_bytes.into();
let seed_high_bytes: u128 = seed_high_bytes.into();
let seed = (seed_high_bytes << 64) | seed_low_bytes;
let mut deterministic_seeder =
DeterministicSeeder::<DefaultRandomGenerator>::new(Seed(seed));
let mut encryption_random_generator =
EncryptionRandomGenerator::<DefaultRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let lwe_multi_bit_base_log = DecompositionBaseLog(lwe_multi_bit_base_log);
let lwe_multi_bit_level_count = DecompositionLevelCount(lwe_multi_bit_level_count);
let lwe_multi_bit_grouping_factor = LweBskGroupingFactor(lwe_multi_bit_grouping_factor);
let lwe_multi_bit_slice_len = {
let bsk = LweMultiBitBootstrapKeyOwned::new(
0u64,
output_glwe_sk.glwe_dimension().to_glwe_size(),
output_glwe_sk.polynomial_size(),
lwe_multi_bit_base_log,
lwe_multi_bit_level_count,
input_lwe_sk.lwe_dimension(),
lwe_multi_bit_grouping_factor,
CiphertextModulus::new_native(),
);
bsk.into_container().len()
};
let lwe_multi_bit_slice =
std::slice::from_raw_parts_mut(lwe_multi_bit_ptr, lwe_multi_bit_slice_len);
let mut bsk = LweMultiBitBootstrapKey::from_container(
lwe_multi_bit_slice,
output_glwe_sk.glwe_dimension().to_glwe_size(),
output_glwe_sk.polynomial_size(),
lwe_multi_bit_base_log,
lwe_multi_bit_level_count,
lwe_multi_bit_grouping_factor,
CiphertextModulus::new_native(),
);
let glwe_noise_distribution: DynamicDistribution<u64> =
glwe_noise_distribution.try_into().unwrap();
par_generate_lwe_multi_bit_bootstrap_key(
&input_lwe_sk,
&output_glwe_sk,
&mut bsk,
glwe_noise_distribution,
&mut encryption_random_generator,
);
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_par_generate_lwe_keyswitch_key(
output_ksk_ptr: *mut u64,
ksk_base_log: usize,
ksk_level_count: usize,
input_lwe_sk_ptr: *const u64,
input_lwe_sk_dim: usize,
output_lwe_sk_ptr: *const u64,
output_lwe_sk_dim: usize,
lwe_noise_distribution: DynamicDistribution,
seed_low_bytes: u64,
seed_high_bytes: u64,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::commons::math::random::Seed;
use crate::core_crypto::prelude::*;
let input_lwe_sk_slice = std::slice::from_raw_parts(input_lwe_sk_ptr, input_lwe_sk_dim);
let input_lwe_sk = LweSecretKey::from_container(input_lwe_sk_slice);
let output_lwe_sk_slice = std::slice::from_raw_parts(output_lwe_sk_ptr, output_lwe_sk_dim);
let output_lwe_sk = LweSecretKey::from_container(output_lwe_sk_slice);
let seed_low_bytes: u128 = seed_low_bytes.into();
let seed_high_bytes: u128 = seed_high_bytes.into();
let seed = (seed_high_bytes << 64) | seed_low_bytes;
let mut deterministic_seeder =
DeterministicSeeder::<DefaultRandomGenerator>::new(Seed(seed));
let mut encryption_random_generator =
EncryptionRandomGenerator::<DefaultRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let lwe_base_log = DecompositionBaseLog(ksk_base_log);
let lwe_level_count = DecompositionLevelCount(ksk_level_count);
let lwe_slice_len = {
let bsk = LweKeyswitchKeyOwned::new(
0u64,
lwe_base_log,
lwe_level_count,
LweDimension(input_lwe_sk_dim),
LweDimension(output_lwe_sk_dim),
CiphertextModulus::new_native(),
);
bsk.into_container().len()
};
let ksk_slice = std::slice::from_raw_parts_mut(output_ksk_ptr, lwe_slice_len);
let mut ksk = LweKeyswitchKey::from_container(
ksk_slice,
lwe_base_log,
lwe_level_count,
LweDimension(output_lwe_sk_dim).to_lwe_size(),
CiphertextModulus::new_native(),
);
let lwe_noise_distribution: DynamicDistribution<u64> =
lwe_noise_distribution.try_into().unwrap();
generate_lwe_keyswitch_key(
&input_lwe_sk,
&output_lwe_sk,
&mut ksk,
lwe_noise_distribution,
&mut encryption_random_generator,
)
})
}
#[no_mangle]
pub unsafe extern "C" fn core_crypto_par_generate_lwe_private_functional_keyswitch_key(
output_pksk_ptr: *mut u64,
pksk_base_log: usize,
pksk_level_count: usize,
input_lwe_sk_ptr: *const u64,
input_lwe_sk_dim: usize,
output_glwe_sk_ptr: *const u64,
poly_size: usize,
glwe_dim: usize,
lwe_noise_distribution: DynamicDistribution,
seed_low_bytes: u64,
seed_high_bytes: u64,
) -> c_int {
catch_panic(|| {
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::commons::math::random::Seed;
use crate::core_crypto::prelude::*;
let input_lwe_sk_slice = std::slice::from_raw_parts(input_lwe_sk_ptr, input_lwe_sk_dim);
let input_lwe_sk = LweSecretKey::from_container(input_lwe_sk_slice);
let output_glwe_sk_slice =
std::slice::from_raw_parts(output_glwe_sk_ptr, glwe_dim * poly_size);
let output_glwe_sk =
GlweSecretKey::from_container(output_glwe_sk_slice, PolynomialSize(poly_size));
let seed_low_bytes: u128 = seed_low_bytes.into();
let seed_high_bytes: u128 = seed_high_bytes.into();
let seed = (seed_high_bytes << 64) | seed_low_bytes;
let mut deterministic_seeder =
DeterministicSeeder::<DefaultRandomGenerator>::new(Seed(seed));
let mut encryption_random_generator =
EncryptionRandomGenerator::<DefaultRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let pksk_len = {
let ksk = LwePrivateFunctionalPackingKeyswitchKeyList::new(
0u64,
DecompositionBaseLog(pksk_base_log),
DecompositionLevelCount(pksk_level_count),
LweDimension(input_lwe_sk_dim),
GlweDimension(glwe_dim).to_glwe_size(),
PolynomialSize(poly_size),
FunctionalPackingKeyswitchKeyCount(glwe_dim + 1),
CiphertextModulus::new_native(),
);
ksk.into_container().len()
};
let ksk_slice = std::slice::from_raw_parts_mut(output_pksk_ptr, pksk_len);
let mut fp_ksk = LwePrivateFunctionalPackingKeyswitchKeyList::from_container(
ksk_slice,
DecompositionBaseLog(pksk_base_log),
DecompositionLevelCount(pksk_level_count),
LweDimension(input_lwe_sk_dim).to_lwe_size(),
GlweDimension(glwe_dim).to_glwe_size(),
PolynomialSize(poly_size),
CiphertextModulus::new_native(),
);
let lwe_noise_distribution: DynamicDistribution<u64> =
lwe_noise_distribution.try_into().unwrap();
generate_circuit_bootstrap_lwe_pfpksk_list(
&mut fp_ksk,
&input_lwe_sk,
&output_glwe_sk,
lwe_noise_distribution,
&mut encryption_random_generator,
)
})
}