mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 14:47:56 -05:00
feat(hl): add noise squashing primitives to the HL API
This commit is contained in:
@@ -269,8 +269,7 @@ pub fn test_hl_clientkey(
|
||||
let test_params = load_hl_params(&test.parameters);
|
||||
|
||||
let key: ClientKey = load_and_unversionize(dir, test, format)?;
|
||||
let (integer_key, _, _, _) = key.into_raw_parts();
|
||||
let key_params = integer_key.parameters();
|
||||
let key_params = key.computation_parameters();
|
||||
|
||||
if test_params != key_params {
|
||||
Err(test.failure(
|
||||
|
||||
@@ -3,6 +3,7 @@ use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
|
||||
|
||||
use crate::high_level_api::booleans::{
|
||||
InnerBoolean, InnerBooleanVersionOwned, InnerCompressedFheBool,
|
||||
InnerSquashedNoiseBooleanVersionOwned, SquashedNoiseFheBool,
|
||||
};
|
||||
use crate::{CompressedFheBool, FheBool, Tag};
|
||||
use std::convert::Infallible;
|
||||
@@ -63,3 +64,16 @@ pub enum CompressedFheBoolVersions {
|
||||
V0(CompressedFheBoolV0),
|
||||
V1(CompressedFheBool),
|
||||
}
|
||||
|
||||
// Squashed Noise
|
||||
// Manual impl
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) enum InnerSquashedNoiseBooleanVersionedOwned {
|
||||
V0(InnerSquashedNoiseBooleanVersionOwned),
|
||||
}
|
||||
|
||||
// Squashed Noise
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum SquashedNoiseFheBoolVersions {
|
||||
V0(SquashedNoiseFheBool),
|
||||
}
|
||||
|
||||
@@ -220,3 +220,26 @@ pub enum CompressedFheUintVersions<Id: FheUintId> {
|
||||
V0(CompressedFheUintV0<Id>),
|
||||
V1(CompressedFheUint<Id>),
|
||||
}
|
||||
|
||||
// Squashed Noise
|
||||
// Manual impl
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) enum InnerSquashedNoiseRadixCiphertextVersionedOwned {
|
||||
V0(InnerSquashedNoiseRadixCiphertextVersionOwned),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum SquashedNoiseFheUintVersions {
|
||||
V0(SquashedNoiseFheUint),
|
||||
}
|
||||
|
||||
// Manual impl
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) enum InnerSquashedNoiseSignedRadixCiphertextVersionedOwned {
|
||||
V0(InnerSquashedNoiseSignedRadixCiphertextVersionOwned),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum SquashedNoiseFheIntVersions {
|
||||
V0(SquashedNoiseFheInt),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::high_level_api::keys::*;
|
||||
use crate::integer::compression_keys::{
|
||||
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, DecompressionKey,
|
||||
};
|
||||
use crate::Tag;
|
||||
use std::convert::Infallible;
|
||||
use tfhe_versionable::deprecation::{Deprecable, Deprecated};
|
||||
@@ -158,11 +161,11 @@ pub(crate) struct IntegerClientKeyV2 {
|
||||
pub(crate) compression_key: Option<crate::shortint::list_compression::CompressionPrivateKeys>,
|
||||
}
|
||||
|
||||
impl Upgrade<IntegerClientKey> for IntegerClientKeyV2 {
|
||||
impl Upgrade<IntegerClientKeyV3> for IntegerClientKeyV2 {
|
||||
type Error = Infallible;
|
||||
|
||||
fn upgrade(self) -> Result<IntegerClientKey, Self::Error> {
|
||||
Ok(IntegerClientKey {
|
||||
fn upgrade(self) -> Result<IntegerClientKeyV3, Self::Error> {
|
||||
Ok(IntegerClientKeyV3 {
|
||||
key: self.key,
|
||||
dedicated_compact_private_key: self.dedicated_compact_private_key,
|
||||
compression_key: self
|
||||
@@ -172,13 +175,40 @@ impl Upgrade<IntegerClientKey> for IntegerClientKeyV2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Version)]
|
||||
pub(crate) struct IntegerClientKeyV3 {
|
||||
pub(crate) key: crate::integer::ClientKey,
|
||||
pub(crate) dedicated_compact_private_key: Option<CompactPrivateKey>,
|
||||
pub(crate) compression_key: Option<crate::integer::compression_keys::CompressionPrivateKeys>,
|
||||
}
|
||||
|
||||
impl Upgrade<IntegerClientKey> for IntegerClientKeyV3 {
|
||||
type Error = Infallible;
|
||||
|
||||
fn upgrade(self) -> Result<IntegerClientKey, Self::Error> {
|
||||
let Self {
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
} = self;
|
||||
|
||||
Ok(IntegerClientKey {
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
noise_squashing_private_key: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
#[allow(unused)]
|
||||
pub(crate) enum IntegerClientKeyVersions {
|
||||
V0(Deprecated<IntegerClientKey>),
|
||||
V1(Deprecated<IntegerClientKey>),
|
||||
V2(IntegerClientKeyV2),
|
||||
V3(IntegerClientKey),
|
||||
V3(IntegerClientKeyV3),
|
||||
V4(IntegerClientKey),
|
||||
}
|
||||
|
||||
impl Deprecable for IntegerServerKey {
|
||||
@@ -186,13 +216,44 @@ impl Deprecable for IntegerServerKey {
|
||||
const MIN_SUPPORTED_APP_VERSION: &'static str = "TFHE-rs v0.10";
|
||||
}
|
||||
|
||||
#[derive(Version)]
|
||||
pub struct IntegerServerKeyV4 {
|
||||
pub(crate) key: crate::integer::ServerKey,
|
||||
pub(crate) cpk_key_switching_key_material:
|
||||
Option<crate::integer::key_switching_key::KeySwitchingKeyMaterial>,
|
||||
pub(crate) compression_key: Option<CompressionKey>,
|
||||
pub(crate) decompression_key: Option<DecompressionKey>,
|
||||
}
|
||||
|
||||
impl Upgrade<IntegerServerKey> for IntegerServerKeyV4 {
|
||||
type Error = Infallible;
|
||||
|
||||
fn upgrade(self) -> Result<IntegerServerKey, Self::Error> {
|
||||
let Self {
|
||||
key,
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
} = self;
|
||||
|
||||
Ok(IntegerServerKey {
|
||||
key,
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum IntegerServerKeyVersions {
|
||||
V0(Deprecated<IntegerServerKey>),
|
||||
V1(Deprecated<IntegerServerKey>),
|
||||
V2(Deprecated<IntegerServerKey>),
|
||||
V3(Deprecated<IntegerServerKey>),
|
||||
V4(IntegerServerKey),
|
||||
V4(IntegerServerKeyV4),
|
||||
V5(IntegerServerKey),
|
||||
}
|
||||
|
||||
impl Deprecable for IntegerCompressedServerKey {
|
||||
@@ -200,11 +261,42 @@ impl Deprecable for IntegerCompressedServerKey {
|
||||
const MIN_SUPPORTED_APP_VERSION: &'static str = "TFHE-rs v0.10";
|
||||
}
|
||||
|
||||
#[derive(Version)]
|
||||
pub struct IntegerCompressedServerKeyV2 {
|
||||
pub(crate) key: crate::integer::CompressedServerKey,
|
||||
pub(crate) cpk_key_switching_key_material:
|
||||
Option<crate::integer::key_switching_key::CompressedKeySwitchingKeyMaterial>,
|
||||
pub(crate) compression_key: Option<CompressedCompressionKey>,
|
||||
pub(crate) decompression_key: Option<CompressedDecompressionKey>,
|
||||
}
|
||||
|
||||
impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV2 {
|
||||
type Error = Infallible;
|
||||
|
||||
fn upgrade(self) -> Result<IntegerCompressedServerKey, Self::Error> {
|
||||
let Self {
|
||||
key,
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
} = self;
|
||||
|
||||
Ok(IntegerCompressedServerKey {
|
||||
key,
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum IntegerCompressedServerKeyVersions {
|
||||
V0(Deprecated<IntegerCompressedServerKey>),
|
||||
V1(Deprecated<IntegerCompressedServerKey>),
|
||||
V2(IntegerCompressedServerKey),
|
||||
V2(IntegerCompressedServerKeyV2),
|
||||
V3(IntegerCompressedServerKey),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
pub use base::{FheBool, FheBoolConformanceParams};
|
||||
pub use compressed::CompressedFheBool;
|
||||
pub use squashed_noise::SquashedNoiseFheBool;
|
||||
|
||||
pub(in crate::high_level_api) use compressed::InnerCompressedFheBool;
|
||||
pub(in crate::high_level_api) use inner::{InnerBoolean, InnerBooleanVersionOwned};
|
||||
pub(in crate::high_level_api) use squashed_noise::InnerSquashedNoiseBooleanVersionOwned;
|
||||
|
||||
mod base;
|
||||
mod compressed;
|
||||
mod encrypt;
|
||||
mod inner;
|
||||
mod oprf;
|
||||
mod squashed_noise;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
185
tfhe/src/high_level_api/booleans/squashed_noise.rs
Normal file
185
tfhe/src/high_level_api/booleans/squashed_noise.rs
Normal file
@@ -0,0 +1,185 @@
|
||||
use super::base::FheBool;
|
||||
use crate::backward_compatibility::booleans::{
|
||||
InnerSquashedNoiseBooleanVersionedOwned, SquashedNoiseFheBoolVersions,
|
||||
};
|
||||
use crate::high_level_api::details::MaybeCloned;
|
||||
use crate::high_level_api::errors::UninitializedNoiseSquashing;
|
||||
use crate::high_level_api::global_state;
|
||||
use crate::high_level_api::global_state::with_internal_keys;
|
||||
use crate::high_level_api::keys::InternalServerKey;
|
||||
use crate::high_level_api::traits::{FheDecrypt, SquashNoise};
|
||||
use crate::integer::ciphertext::SquashedNoiseBooleanBlock;
|
||||
use crate::named::Named;
|
||||
use crate::{ClientKey, Device, Tag};
|
||||
use serde::{Deserializer, Serializer};
|
||||
use tfhe_versionable::{Unversionize, UnversionizeError, Versionize, VersionizeOwned};
|
||||
|
||||
/// Enum that manages the current inner representation of a boolean.
|
||||
pub(in crate::high_level_api) enum InnerSquashedNoiseBoolean {
|
||||
Cpu(SquashedNoiseBooleanBlock),
|
||||
}
|
||||
|
||||
impl Clone for InnerSquashedNoiseBoolean {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Cpu(inner) => Self::Cpu(inner.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl serde::Serialize for InnerSquashedNoiseBoolean {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.on_cpu().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for InnerSquashedNoiseBoolean {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let mut deserialized = Self::Cpu(
|
||||
crate::integer::ciphertext::SquashedNoiseBooleanBlock::deserialize(deserializer)?,
|
||||
);
|
||||
deserialized.move_to_device_of_server_key_if_set();
|
||||
Ok(deserialized)
|
||||
}
|
||||
}
|
||||
|
||||
// Only CPU data are serialized so we only versionize the CPU type.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) struct InnerSquashedNoiseBooleanVersionOwned(
|
||||
<crate::integer::ciphertext::SquashedNoiseBooleanBlock as VersionizeOwned>::VersionedOwned,
|
||||
);
|
||||
|
||||
impl Versionize for InnerSquashedNoiseBoolean {
|
||||
type Versioned<'vers> = InnerSquashedNoiseBooleanVersionedOwned;
|
||||
|
||||
fn versionize(&self) -> Self::Versioned<'_> {
|
||||
let data = self.on_cpu();
|
||||
let versioned = data.into_owned().versionize_owned();
|
||||
InnerSquashedNoiseBooleanVersionedOwned::V0(InnerSquashedNoiseBooleanVersionOwned(
|
||||
versioned,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl VersionizeOwned for InnerSquashedNoiseBoolean {
|
||||
type VersionedOwned = InnerSquashedNoiseBooleanVersionedOwned;
|
||||
|
||||
fn versionize_owned(self) -> Self::VersionedOwned {
|
||||
let cpu_data = self.on_cpu();
|
||||
InnerSquashedNoiseBooleanVersionedOwned::V0(InnerSquashedNoiseBooleanVersionOwned(
|
||||
cpu_data.into_owned().versionize_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Unversionize for InnerSquashedNoiseBoolean {
|
||||
fn unversionize(versioned: Self::VersionedOwned) -> Result<Self, UnversionizeError> {
|
||||
match versioned {
|
||||
InnerSquashedNoiseBooleanVersionedOwned::V0(v0) => {
|
||||
let mut unversioned = Self::Cpu(
|
||||
crate::integer::ciphertext::SquashedNoiseBooleanBlock::unversionize(v0.0)?,
|
||||
);
|
||||
unversioned.move_to_device_of_server_key_if_set();
|
||||
Ok(unversioned)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InnerSquashedNoiseBoolean {
|
||||
/// Returns the inner cpu ciphertext if self is on the CPU, otherwise, returns a copy
|
||||
/// that is on the CPU
|
||||
pub(crate) fn on_cpu(&self) -> MaybeCloned<'_, SquashedNoiseBooleanBlock> {
|
||||
match self {
|
||||
Self::Cpu(ct) => MaybeCloned::Borrowed(ct),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||
pub(crate) fn move_to_device(&mut self, device: Device) {
|
||||
match (&self, device) {
|
||||
(Self::Cpu(_), Device::Cpu) => {
|
||||
// Nothing to do, we already are on the correct device
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
_ => panic!("Cuda devices do not support noise squashing yet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn move_to_device_of_server_key_if_set(&mut self) {
|
||||
if let Some(device) = global_state::device_of_internal_keys() {
|
||||
self.move_to_device(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, serde::Deserialize, serde::Serialize, Versionize)]
|
||||
#[versionize(SquashedNoiseFheBoolVersions)]
|
||||
pub struct SquashedNoiseFheBool {
|
||||
inner: InnerSquashedNoiseBoolean,
|
||||
tag: Tag,
|
||||
}
|
||||
|
||||
impl Named for SquashedNoiseFheBool {
|
||||
const NAME: &'static str = "high_level_api::SquashedNoiseFheBool";
|
||||
}
|
||||
|
||||
impl SquashedNoiseFheBool {
|
||||
pub fn underlying_squashed_noise_ciphertext(
|
||||
&self,
|
||||
) -> MaybeCloned<'_, SquashedNoiseBooleanBlock> {
|
||||
self.inner.on_cpu()
|
||||
}
|
||||
}
|
||||
|
||||
impl FheDecrypt<bool> for SquashedNoiseFheBool {
|
||||
fn decrypt(&self, key: &ClientKey) -> bool {
|
||||
key.key
|
||||
.noise_squashing_private_key
|
||||
.as_ref()
|
||||
.map(|noise_squashing_private_key| {
|
||||
noise_squashing_private_key.decrypt_bool(&self.inner.on_cpu())
|
||||
})
|
||||
.expect(
|
||||
"No noise squashing private key in your ClientKey, cannot decrypt. \
|
||||
Did you call `enable_noise_squashing` when creating your Config?",
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl SquashNoise for FheBool {
|
||||
type Output = SquashedNoiseFheBool;
|
||||
|
||||
fn squash_noise(&self) -> crate::Result<Self::Output> {
|
||||
with_internal_keys(|keys| match keys {
|
||||
InternalServerKey::Cpu(server_key) => {
|
||||
let noise_squashing_key = server_key
|
||||
.key
|
||||
.noise_squashing_key
|
||||
.as_ref()
|
||||
.ok_or(UninitializedNoiseSquashing)?;
|
||||
|
||||
Ok(SquashedNoiseFheBool {
|
||||
inner: InnerSquashedNoiseBoolean::Cpu(
|
||||
noise_squashing_key.squash_boolean_block_noise(
|
||||
server_key.key.pbs_key(),
|
||||
&self.ciphertext.on_cpu(),
|
||||
)?,
|
||||
),
|
||||
tag: server_key.tag.clone(),
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
InternalServerKey::Cuda(_) => Err(crate::error!(
|
||||
"Cuda devices do not support noise squashing yet"
|
||||
)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ use tfhe_versionable::Versionize;
|
||||
use crate::backward_compatibility::config::ConfigVersions;
|
||||
use crate::high_level_api::keys::IntegerConfig;
|
||||
use crate::shortint::parameters::list_compression::CompressionParameters;
|
||||
use crate::shortint::parameters::NoiseSquashingParameters;
|
||||
|
||||
/// The config type
|
||||
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize, Versionize)]
|
||||
@@ -48,13 +49,24 @@ impl ConfigBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn enable_noise_squashing(
|
||||
mut self,
|
||||
noise_squashing_parameters: NoiseSquashingParameters,
|
||||
) -> Self {
|
||||
self.config
|
||||
.inner
|
||||
.enable_noise_squashing(noise_squashing_parameters);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_parameters<P>(block_parameters: P) -> Self
|
||||
where
|
||||
P: Into<crate::shortint::PBSParameters>,
|
||||
{
|
||||
Self {
|
||||
config: Config {
|
||||
inner: IntegerConfig::new(block_parameters.into(), None),
|
||||
inner: IntegerConfig::new(block_parameters.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -75,7 +87,7 @@ impl ConfigBuilder {
|
||||
where
|
||||
P: Into<crate::shortint::PBSParameters>,
|
||||
{
|
||||
self.config.inner = IntegerConfig::new(block_parameters.into(), None);
|
||||
self.config.inner = IntegerConfig::new(block_parameters.into());
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
/// 'smart-pointer' that holds either a borrowed T, or an owned T.
|
||||
pub(crate) enum MaybeCloned<'a, T> {
|
||||
///
|
||||
/// This is essentially like a Cow, except T does not need to be ToOwned
|
||||
pub enum MaybeCloned<'a, T> {
|
||||
Borrowed(&'a T),
|
||||
#[allow(dead_code)]
|
||||
Cloned(T),
|
||||
}
|
||||
|
||||
|
||||
@@ -45,3 +45,24 @@ impl From<UninitializedServerKey> for Error {
|
||||
Self::new(format!("{value}"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UninitializedNoiseSquashing;
|
||||
|
||||
impl Display for UninitializedNoiseSquashing {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Noise squashing key not set in server key, \
|
||||
did you forget to call `enable_noise_squashing` when building your Config?",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for UninitializedNoiseSquashing {}
|
||||
|
||||
impl From<UninitializedNoiseSquashing> for Error {
|
||||
fn from(value: UninitializedNoiseSquashing) -> Self {
|
||||
Self::new(format!("{value}"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,17 +31,18 @@ expand_pub_use_fhe_type!(
|
||||
);
|
||||
|
||||
pub(in crate::high_level_api) use signed::{
|
||||
CompressedSignedRadixCiphertext, FheIntId, SignedRadixCiphertextVersionOwned,
|
||||
CompressedSignedRadixCiphertext, FheIntId, InnerSquashedNoiseSignedRadixCiphertextVersionOwned,
|
||||
SignedRadixCiphertextVersionOwned,
|
||||
};
|
||||
pub(in crate::high_level_api) use unsigned::{
|
||||
CompressedRadixCiphertext, FheUintId,
|
||||
CompressedRadixCiphertext, FheUintId, InnerSquashedNoiseRadixCiphertextVersionOwned,
|
||||
RadixCiphertextVersionOwned as UnsignedRadixCiphertextVersionOwned,
|
||||
};
|
||||
// These are pub-exported so that their doc can appear in generated rust docs
|
||||
use crate::high_level_api::traits::FheId;
|
||||
use crate::shortint::MessageModulus;
|
||||
pub use signed::{CompressedFheInt, FheInt};
|
||||
pub use unsigned::{CompressedFheUint, FheUint};
|
||||
pub use signed::{CompressedFheInt, FheInt, SquashedNoiseFheInt};
|
||||
pub use unsigned::{CompressedFheUint, FheUint, SquashedNoiseFheUint};
|
||||
|
||||
pub mod oprf;
|
||||
pub(super) mod signed;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod base;
|
||||
mod compressed;
|
||||
mod squashed_noise;
|
||||
|
||||
mod encrypt;
|
||||
mod inner;
|
||||
@@ -16,6 +17,8 @@ pub(in crate::high_level_api) use compressed::CompressedSignedRadixCiphertext;
|
||||
pub(in crate::high_level_api) use inner::{
|
||||
SignedRadixCiphertext, SignedRadixCiphertextVersionOwned,
|
||||
};
|
||||
pub(in crate::high_level_api) use squashed_noise::InnerSquashedNoiseSignedRadixCiphertextVersionOwned;
|
||||
pub use squashed_noise::SquashedNoiseFheInt;
|
||||
|
||||
expand_pub_use_fhe_type!(
|
||||
pub use static_{
|
||||
|
||||
204
tfhe/src/high_level_api/integers/signed/squashed_noise.rs
Normal file
204
tfhe/src/high_level_api/integers/signed/squashed_noise.rs
Normal file
@@ -0,0 +1,204 @@
|
||||
use super::base::{FheInt, FheIntId};
|
||||
use crate::backward_compatibility::integers::{
|
||||
InnerSquashedNoiseSignedRadixCiphertextVersionedOwned, SquashedNoiseFheIntVersions,
|
||||
};
|
||||
use crate::high_level_api::details::MaybeCloned;
|
||||
use crate::high_level_api::errors::UninitializedNoiseSquashing;
|
||||
use crate::high_level_api::global_state;
|
||||
use crate::high_level_api::global_state::with_internal_keys;
|
||||
use crate::high_level_api::keys::InternalServerKey;
|
||||
use crate::high_level_api::traits::{FheDecrypt, SquashNoise};
|
||||
use crate::integer::block_decomposition::{RecomposableFrom, SignExtendable};
|
||||
use crate::named::Named;
|
||||
use crate::{ClientKey, Device, Tag};
|
||||
use serde::{Deserializer, Serializer};
|
||||
use tfhe_versionable::{Unversionize, UnversionizeError, Versionize, VersionizeOwned};
|
||||
|
||||
/// Enum that manages the current inner representation of a squashed noise FheInt .
|
||||
pub(in crate::high_level_api) enum InnerSquashedNoiseSignedRadixCiphertext {
|
||||
Cpu(crate::integer::ciphertext::SquashedNoiseSignedRadixCiphertext),
|
||||
}
|
||||
|
||||
impl Clone for InnerSquashedNoiseSignedRadixCiphertext {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Cpu(inner) => Self::Cpu(inner.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl serde::Serialize for InnerSquashedNoiseSignedRadixCiphertext {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.on_cpu().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for InnerSquashedNoiseSignedRadixCiphertext {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let mut deserialized = Self::Cpu(
|
||||
crate::integer::ciphertext::SquashedNoiseSignedRadixCiphertext::deserialize(
|
||||
deserializer,
|
||||
)?,
|
||||
);
|
||||
deserialized.move_to_device_of_server_key_if_set();
|
||||
Ok(deserialized)
|
||||
}
|
||||
}
|
||||
|
||||
// Only CPU data are serialized so we only versionize the CPU type.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) struct InnerSquashedNoiseSignedRadixCiphertextVersionOwned(
|
||||
<crate::integer::ciphertext::SquashedNoiseSignedRadixCiphertext as VersionizeOwned>::VersionedOwned,
|
||||
);
|
||||
|
||||
impl Versionize for InnerSquashedNoiseSignedRadixCiphertext {
|
||||
type Versioned<'vers> = InnerSquashedNoiseSignedRadixCiphertextVersionedOwned;
|
||||
|
||||
fn versionize(&self) -> Self::Versioned<'_> {
|
||||
let data = self.on_cpu();
|
||||
let versioned = data.into_owned().versionize_owned();
|
||||
InnerSquashedNoiseSignedRadixCiphertextVersionedOwned::V0(
|
||||
InnerSquashedNoiseSignedRadixCiphertextVersionOwned(versioned),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl VersionizeOwned for InnerSquashedNoiseSignedRadixCiphertext {
|
||||
type VersionedOwned = InnerSquashedNoiseSignedRadixCiphertextVersionedOwned;
|
||||
|
||||
fn versionize_owned(self) -> Self::VersionedOwned {
|
||||
let cpu_data = self.on_cpu();
|
||||
InnerSquashedNoiseSignedRadixCiphertextVersionedOwned::V0(
|
||||
InnerSquashedNoiseSignedRadixCiphertextVersionOwned(
|
||||
cpu_data.into_owned().versionize_owned(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Unversionize for InnerSquashedNoiseSignedRadixCiphertext {
|
||||
fn unversionize(versioned: Self::VersionedOwned) -> Result<Self, UnversionizeError> {
|
||||
match versioned {
|
||||
InnerSquashedNoiseSignedRadixCiphertextVersionedOwned::V0(v0) => {
|
||||
let mut unversioned = Self::Cpu(
|
||||
crate::integer::ciphertext::SquashedNoiseSignedRadixCiphertext::unversionize(
|
||||
v0.0,
|
||||
)?,
|
||||
);
|
||||
unversioned.move_to_device_of_server_key_if_set();
|
||||
Ok(unversioned)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InnerSquashedNoiseSignedRadixCiphertext {
|
||||
/// Returns the inner cpu ciphertext if self is on the CPU, otherwise, returns a copy
|
||||
/// that is on the CPU
|
||||
pub(crate) fn on_cpu(
|
||||
&self,
|
||||
) -> MaybeCloned<'_, crate::integer::ciphertext::SquashedNoiseSignedRadixCiphertext> {
|
||||
match self {
|
||||
Self::Cpu(ct) => MaybeCloned::Borrowed(ct),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||
pub(crate) fn move_to_device(&mut self, device: Device) {
|
||||
match (&self, device) {
|
||||
(Self::Cpu(_), Device::Cpu) => {
|
||||
// Nothing to do, we already are on the correct device
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
_ => panic!("Cuda devices do not support noise squashing yet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn move_to_device_of_server_key_if_set(&mut self) {
|
||||
if let Some(device) = global_state::device_of_internal_keys() {
|
||||
self.move_to_device(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, serde::Deserialize, serde::Serialize, Versionize)]
|
||||
#[versionize(SquashedNoiseFheIntVersions)]
|
||||
pub struct SquashedNoiseFheInt {
|
||||
inner: InnerSquashedNoiseSignedRadixCiphertext,
|
||||
tag: Tag,
|
||||
}
|
||||
|
||||
impl Named for SquashedNoiseFheInt {
|
||||
const NAME: &'static str = "high_level_api::SquashedNoiseFheInt";
|
||||
}
|
||||
|
||||
impl SquashedNoiseFheInt {
|
||||
pub fn underlying_squashed_noise_ciphertext(
|
||||
&self,
|
||||
) -> MaybeCloned<'_, crate::integer::ciphertext::SquashedNoiseSignedRadixCiphertext> {
|
||||
self.inner.on_cpu()
|
||||
}
|
||||
|
||||
pub fn num_bits(&self) -> usize {
|
||||
match &self.inner {
|
||||
InnerSquashedNoiseSignedRadixCiphertext::Cpu(on_cpu) => {
|
||||
on_cpu.original_block_count * on_cpu.packed_blocks[0].message_modulus().0 as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Clear> FheDecrypt<Clear> for SquashedNoiseFheInt
|
||||
where
|
||||
Clear: RecomposableFrom<u128> + SignExtendable,
|
||||
{
|
||||
fn decrypt(&self, key: &ClientKey) -> Clear {
|
||||
key.key
|
||||
.noise_squashing_private_key
|
||||
.as_ref()
|
||||
.map(|noise_squashing_private_key| {
|
||||
noise_squashing_private_key.decrypt_signed_radix(&self.inner.on_cpu())
|
||||
})
|
||||
.expect(
|
||||
"No noise squashing private key in your ClientKey, cannot decrypt. \
|
||||
Did you call `enable_noise_squashing` when creating your Config?",
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Id: FheIntId> SquashNoise for FheInt<Id> {
|
||||
type Output = SquashedNoiseFheInt;
|
||||
|
||||
fn squash_noise(&self) -> crate::Result<Self::Output> {
|
||||
with_internal_keys(|keys| match keys {
|
||||
InternalServerKey::Cpu(server_key) => {
|
||||
let noise_squashing_key = server_key
|
||||
.key
|
||||
.noise_squashing_key
|
||||
.as_ref()
|
||||
.ok_or(UninitializedNoiseSquashing)?;
|
||||
|
||||
Ok(SquashedNoiseFheInt {
|
||||
inner: InnerSquashedNoiseSignedRadixCiphertext::Cpu(
|
||||
noise_squashing_key.squash_signed_radix_ciphertext_noise(
|
||||
server_key.key.pbs_key(),
|
||||
&self.ciphertext.on_cpu(),
|
||||
)?,
|
||||
),
|
||||
tag: server_key.tag.clone(),
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
InternalServerKey::Cuda(_) => Err(crate::error!(
|
||||
"Cuda devices do not support noise squashing yet"
|
||||
)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,15 @@ expand_pub_use_fhe_type!(
|
||||
);
|
||||
|
||||
pub use compressed::CompressedFheUint;
|
||||
pub use squashed_noise::SquashedNoiseFheUint;
|
||||
|
||||
pub(in crate::high_level_api) use compressed::CompressedRadixCiphertext;
|
||||
pub(in crate::high_level_api) use inner::{RadixCiphertext, RadixCiphertextVersionOwned};
|
||||
pub(in crate::high_level_api) use squashed_noise::InnerSquashedNoiseRadixCiphertextVersionOwned;
|
||||
|
||||
mod base;
|
||||
mod compressed;
|
||||
mod squashed_noise;
|
||||
mod static_;
|
||||
|
||||
mod encrypt;
|
||||
|
||||
199
tfhe/src/high_level_api/integers/unsigned/squashed_noise.rs
Normal file
199
tfhe/src/high_level_api/integers/unsigned/squashed_noise.rs
Normal file
@@ -0,0 +1,199 @@
|
||||
use super::base::{FheUint, FheUintId};
|
||||
use crate::backward_compatibility::integers::{
|
||||
InnerSquashedNoiseRadixCiphertextVersionedOwned, SquashedNoiseFheUintVersions,
|
||||
};
|
||||
use crate::core_crypto::commons::numeric::UnsignedNumeric;
|
||||
use crate::high_level_api::details::MaybeCloned;
|
||||
use crate::high_level_api::errors::UninitializedNoiseSquashing;
|
||||
use crate::high_level_api::global_state;
|
||||
use crate::high_level_api::global_state::with_internal_keys;
|
||||
use crate::high_level_api::keys::InternalServerKey;
|
||||
use crate::high_level_api::traits::{FheDecrypt, SquashNoise};
|
||||
use crate::integer::block_decomposition::RecomposableFrom;
|
||||
use crate::named::Named;
|
||||
use crate::{ClientKey, Device, Tag};
|
||||
use serde::{Deserializer, Serializer};
|
||||
use tfhe_versionable::{Unversionize, UnversionizeError, Versionize, VersionizeOwned};
|
||||
|
||||
/// Enum that manages the current inner representation of a squashed noise FheUint .
|
||||
pub(in crate::high_level_api) enum InnerSquashedNoiseRadixCiphertext {
|
||||
Cpu(crate::integer::ciphertext::SquashedNoiseRadixCiphertext),
|
||||
}
|
||||
|
||||
impl Clone for InnerSquashedNoiseRadixCiphertext {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Cpu(inner) => Self::Cpu(inner.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl serde::Serialize for InnerSquashedNoiseRadixCiphertext {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.on_cpu().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for InnerSquashedNoiseRadixCiphertext {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let mut deserialized = Self::Cpu(
|
||||
crate::integer::ciphertext::SquashedNoiseRadixCiphertext::deserialize(deserializer)?,
|
||||
);
|
||||
deserialized.move_to_device_of_server_key_if_set();
|
||||
Ok(deserialized)
|
||||
}
|
||||
}
|
||||
|
||||
// Only CPU data are serialized so we only versionize the CPU type.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) struct InnerSquashedNoiseRadixCiphertextVersionOwned(
|
||||
<crate::integer::ciphertext::SquashedNoiseRadixCiphertext as VersionizeOwned>::VersionedOwned,
|
||||
);
|
||||
|
||||
impl Versionize for InnerSquashedNoiseRadixCiphertext {
|
||||
type Versioned<'vers> = InnerSquashedNoiseRadixCiphertextVersionedOwned;
|
||||
|
||||
fn versionize(&self) -> Self::Versioned<'_> {
|
||||
let data = self.on_cpu();
|
||||
let versioned = data.into_owned().versionize_owned();
|
||||
InnerSquashedNoiseRadixCiphertextVersionedOwned::V0(
|
||||
InnerSquashedNoiseRadixCiphertextVersionOwned(versioned),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl VersionizeOwned for InnerSquashedNoiseRadixCiphertext {
|
||||
type VersionedOwned = InnerSquashedNoiseRadixCiphertextVersionedOwned;
|
||||
|
||||
fn versionize_owned(self) -> Self::VersionedOwned {
|
||||
let cpu_data = self.on_cpu();
|
||||
InnerSquashedNoiseRadixCiphertextVersionedOwned::V0(
|
||||
InnerSquashedNoiseRadixCiphertextVersionOwned(cpu_data.into_owned().versionize_owned()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Unversionize for InnerSquashedNoiseRadixCiphertext {
|
||||
fn unversionize(versioned: Self::VersionedOwned) -> Result<Self, UnversionizeError> {
|
||||
match versioned {
|
||||
InnerSquashedNoiseRadixCiphertextVersionedOwned::V0(v0) => {
|
||||
let mut unversioned = Self::Cpu(
|
||||
crate::integer::ciphertext::SquashedNoiseRadixCiphertext::unversionize(v0.0)?,
|
||||
);
|
||||
unversioned.move_to_device_of_server_key_if_set();
|
||||
Ok(unversioned)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InnerSquashedNoiseRadixCiphertext {
|
||||
/// Returns the inner cpu ciphertext if self is on the CPU, otherwise, returns a copy
|
||||
/// that is on the CPU
|
||||
pub(crate) fn on_cpu(
|
||||
&self,
|
||||
) -> MaybeCloned<'_, crate::integer::ciphertext::SquashedNoiseRadixCiphertext> {
|
||||
match self {
|
||||
Self::Cpu(ct) => MaybeCloned::Borrowed(ct),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||
pub(crate) fn move_to_device(&mut self, device: Device) {
|
||||
match (&self, device) {
|
||||
(Self::Cpu(_), Device::Cpu) => {
|
||||
// Nothing to do, we already are on the correct device
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
_ => panic!("Cuda devices do not support noise squashing yet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn move_to_device_of_server_key_if_set(&mut self) {
|
||||
if let Some(device) = global_state::device_of_internal_keys() {
|
||||
self.move_to_device(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, serde::Deserialize, serde::Serialize, Versionize)]
|
||||
#[versionize(SquashedNoiseFheUintVersions)]
|
||||
pub struct SquashedNoiseFheUint {
|
||||
inner: InnerSquashedNoiseRadixCiphertext,
|
||||
tag: Tag,
|
||||
}
|
||||
|
||||
impl Named for SquashedNoiseFheUint {
|
||||
const NAME: &'static str = "high_level_api::SquashedNoiseFheUint";
|
||||
}
|
||||
|
||||
impl SquashedNoiseFheUint {
|
||||
pub fn underlying_squashed_noise_ciphertext(
|
||||
&self,
|
||||
) -> MaybeCloned<'_, crate::integer::ciphertext::SquashedNoiseRadixCiphertext> {
|
||||
self.inner.on_cpu()
|
||||
}
|
||||
|
||||
pub fn num_bits(&self) -> usize {
|
||||
match &self.inner {
|
||||
InnerSquashedNoiseRadixCiphertext::Cpu(on_cpu) => {
|
||||
on_cpu.original_block_count * on_cpu.packed_blocks[0].message_modulus().0 as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Clear> FheDecrypt<Clear> for SquashedNoiseFheUint
|
||||
where
|
||||
Clear: RecomposableFrom<u128> + UnsignedNumeric,
|
||||
{
|
||||
fn decrypt(&self, key: &ClientKey) -> Clear {
|
||||
key.key
|
||||
.noise_squashing_private_key
|
||||
.as_ref()
|
||||
.map(|noise_squashing_private_key| {
|
||||
noise_squashing_private_key.decrypt_radix(&self.inner.on_cpu())
|
||||
})
|
||||
.expect(
|
||||
"No noise squashing private key in your ClientKey, cannot decrypt. \
|
||||
Did you call `enable_noise_squashing` when creating your Config?",
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Id: FheUintId> SquashNoise for FheUint<Id> {
|
||||
type Output = SquashedNoiseFheUint;
|
||||
|
||||
fn squash_noise(&self) -> crate::Result<Self::Output> {
|
||||
with_internal_keys(|keys| match keys {
|
||||
InternalServerKey::Cpu(server_key) => {
|
||||
let noise_squashing_key = server_key
|
||||
.key
|
||||
.noise_squashing_key
|
||||
.as_ref()
|
||||
.ok_or(UninitializedNoiseSquashing)?;
|
||||
|
||||
Ok(SquashedNoiseFheUint {
|
||||
inner: InnerSquashedNoiseRadixCiphertext::Cpu(
|
||||
noise_squashing_key.squash_radix_ciphertext_noise(
|
||||
server_key.key.pbs_key(),
|
||||
&self.ciphertext.on_cpu(),
|
||||
)?,
|
||||
),
|
||||
tag: server_key.tag.clone(),
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
InternalServerKey::Cuda(_) => Err(crate::error!(
|
||||
"Cuda devices do not support noise squashing yet"
|
||||
)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use crate::high_level_api::backward_compatibility::keys::ClientKeyVersions;
|
||||
use crate::high_level_api::config::Config;
|
||||
use crate::high_level_api::keys::{CompactPrivateKey, IntegerClientKey};
|
||||
use crate::integer::compression_keys::CompressionPrivateKeys;
|
||||
use crate::integer::noise_squashing::NoiseSquashingPrivateKey;
|
||||
use crate::named::Named;
|
||||
use crate::prelude::Tagged;
|
||||
use crate::shortint::MessageModulus;
|
||||
@@ -80,10 +81,11 @@ impl ClientKey {
|
||||
crate::integer::ClientKey,
|
||||
Option<CompactPrivateKey>,
|
||||
Option<CompressionPrivateKeys>,
|
||||
Option<NoiseSquashingPrivateKey>,
|
||||
Tag,
|
||||
) {
|
||||
let (cks, cpk, cppk) = self.key.into_raw_parts();
|
||||
(cks, cpk, cppk, self.tag)
|
||||
let (cks, cpk, cppk, nsk) = self.key.into_raw_parts();
|
||||
(cks, cpk, cppk, nsk, self.tag)
|
||||
}
|
||||
|
||||
pub fn from_raw_parts(
|
||||
@@ -93,6 +95,7 @@ impl ClientKey {
|
||||
crate::shortint::parameters::key_switching::ShortintKeySwitchingParameters,
|
||||
)>,
|
||||
compression_key: Option<CompressionPrivateKeys>,
|
||||
noise_squashing_key: Option<NoiseSquashingPrivateKey>,
|
||||
tag: Tag,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -100,6 +103,7 @@ impl ClientKey {
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
noise_squashing_key,
|
||||
),
|
||||
tag,
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@ use crate::integer::compression_keys::{
|
||||
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, CompressionPrivateKeys,
|
||||
DecompressionKey,
|
||||
};
|
||||
use crate::integer::noise_squashing::{
|
||||
CompressedNoiseSquashingKey, NoiseSquashingKey, NoiseSquashingPrivateKey,
|
||||
};
|
||||
use crate::integer::public_key::CompactPublicKey;
|
||||
use crate::integer::CompressedCompactPublicKey;
|
||||
use crate::shortint::key_switching_key::KeySwitchingKeyConformanceParams;
|
||||
use crate::shortint::parameters::list_compression::CompressionParameters;
|
||||
use crate::shortint::parameters::{
|
||||
CompactPublicKeyEncryptionParameters, ShortintKeySwitchingParameters,
|
||||
CompactPublicKeyEncryptionParameters, NoiseSquashingParameters, ShortintKeySwitchingParameters,
|
||||
};
|
||||
use crate::shortint::{EncryptionKeyChoice, MessageModulus, PBSParameters};
|
||||
use crate::{Config, Error};
|
||||
@@ -30,28 +33,31 @@ pub(crate) struct IntegerConfig {
|
||||
crate::shortint::parameters::ShortintKeySwitchingParameters,
|
||||
)>,
|
||||
pub(crate) compression_parameters: Option<CompressionParameters>,
|
||||
pub(crate) noise_squashing_parameters: Option<NoiseSquashingParameters>,
|
||||
}
|
||||
|
||||
impl IntegerConfig {
|
||||
pub(crate) fn new(
|
||||
block_parameters: crate::shortint::PBSParameters,
|
||||
dedicated_compact_public_key_parameters: Option<(
|
||||
crate::shortint::parameters::CompactPublicKeyEncryptionParameters,
|
||||
crate::shortint::parameters::ShortintKeySwitchingParameters,
|
||||
)>,
|
||||
) -> Self {
|
||||
pub(crate) fn new(block_parameters: crate::shortint::PBSParameters) -> Self {
|
||||
Self {
|
||||
block_parameters,
|
||||
dedicated_compact_public_key_parameters,
|
||||
dedicated_compact_public_key_parameters: None,
|
||||
compression_parameters: None,
|
||||
noise_squashing_parameters: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_compression(&mut self, compression_parameters: CompressionParameters) {
|
||||
pub(crate) fn enable_compression(&mut self, compression_parameters: CompressionParameters) {
|
||||
self.compression_parameters = Some(compression_parameters);
|
||||
}
|
||||
|
||||
pub fn public_key_encryption_parameters(
|
||||
pub(crate) fn enable_noise_squashing(
|
||||
&mut self,
|
||||
compression_parameters: NoiseSquashingParameters,
|
||||
) {
|
||||
self.noise_squashing_parameters = Some(compression_parameters);
|
||||
}
|
||||
|
||||
pub(crate) fn public_key_encryption_parameters(
|
||||
&self,
|
||||
) -> Result<crate::shortint::parameters::CompactPublicKeyEncryptionParameters, crate::Error>
|
||||
{
|
||||
@@ -76,6 +82,7 @@ impl Default for IntegerConfig {
|
||||
block_parameters: params,
|
||||
dedicated_compact_public_key_parameters: None,
|
||||
compression_parameters: None,
|
||||
noise_squashing_parameters: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,6 +98,7 @@ pub(crate) struct IntegerClientKey {
|
||||
pub(crate) key: crate::integer::ClientKey,
|
||||
pub(crate) dedicated_compact_private_key: Option<CompactPrivateKey>,
|
||||
pub(crate) compression_key: Option<CompressionPrivateKeys>,
|
||||
pub(crate) noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
|
||||
}
|
||||
|
||||
impl IntegerClientKey {
|
||||
@@ -112,10 +120,16 @@ impl IntegerClientKey {
|
||||
let dedicated_compact_private_key = config
|
||||
.dedicated_compact_public_key_parameters
|
||||
.map(|p| (crate::integer::CompactPrivateKey::new(p.0), p.1));
|
||||
|
||||
let noise_squashing_private_key = config
|
||||
.noise_squashing_parameters
|
||||
.map(NoiseSquashingPrivateKey::new);
|
||||
|
||||
Self {
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
noise_squashing_private_key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,13 +140,20 @@ impl IntegerClientKey {
|
||||
crate::integer::ClientKey,
|
||||
Option<CompactPrivateKey>,
|
||||
Option<CompressionPrivateKeys>,
|
||||
Option<NoiseSquashingPrivateKey>,
|
||||
) {
|
||||
let Self {
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
noise_squashing_private_key,
|
||||
} = self;
|
||||
(key, dedicated_compact_private_key, compression_key)
|
||||
(
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
noise_squashing_private_key,
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct a, [`IntegerClientKey`] from its constituents.
|
||||
@@ -144,6 +165,7 @@ impl IntegerClientKey {
|
||||
key: crate::integer::ClientKey,
|
||||
dedicated_compact_private_key: Option<CompactPrivateKey>,
|
||||
compression_key: Option<CompressionPrivateKeys>,
|
||||
noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
|
||||
) -> Self {
|
||||
let shortint_cks: &crate::shortint::ClientKey = key.as_ref();
|
||||
|
||||
@@ -170,6 +192,7 @@ impl IntegerClientKey {
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
noise_squashing_private_key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,10 +218,15 @@ impl From<IntegerConfig> for IntegerClientKey {
|
||||
.compression_parameters
|
||||
.map(|params| key.new_compression_private_key(params));
|
||||
|
||||
let noise_squashing_private_key = config
|
||||
.noise_squashing_parameters
|
||||
.map(NoiseSquashingPrivateKey::new);
|
||||
|
||||
Self {
|
||||
key,
|
||||
dedicated_compact_private_key,
|
||||
compression_key,
|
||||
noise_squashing_private_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,6 +243,7 @@ pub struct IntegerServerKey {
|
||||
Option<crate::integer::key_switching_key::KeySwitchingKeyMaterial>,
|
||||
pub(crate) compression_key: Option<CompressionKey>,
|
||||
pub(crate) decompression_key: Option<DecompressionKey>,
|
||||
pub(crate) noise_squashing_key: Option<NoiseSquashingKey>,
|
||||
}
|
||||
|
||||
impl IntegerServerKey {
|
||||
@@ -246,11 +275,18 @@ impl IntegerServerKey {
|
||||
|
||||
build_helper.into()
|
||||
});
|
||||
|
||||
let noise_squashing_key = client_key
|
||||
.noise_squashing_private_key
|
||||
.as_ref()
|
||||
.map(|key| NoiseSquashingKey::new(cks, key));
|
||||
|
||||
Self {
|
||||
key: base_integer_key,
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,6 +328,7 @@ pub struct IntegerCompressedServerKey {
|
||||
Option<crate::integer::key_switching_key::CompressedKeySwitchingKeyMaterial>,
|
||||
pub(crate) compression_key: Option<CompressedCompressionKey>,
|
||||
pub(crate) decompression_key: Option<CompressedDecompressionKey>,
|
||||
pub(crate) noise_squashing_key: Option<CompressedNoiseSquashingKey>,
|
||||
}
|
||||
|
||||
impl IntegerCompressedServerKey {
|
||||
@@ -327,11 +364,20 @@ impl IntegerCompressedServerKey {
|
||||
(Some(compression_keys), Some(decompression_keys))
|
||||
});
|
||||
|
||||
let noise_squashing_key =
|
||||
client_key
|
||||
.noise_squashing_private_key
|
||||
.as_ref()
|
||||
.map(|noise_squashing_private_key| {
|
||||
noise_squashing_private_key.new_compressed_noise_squashing_key(&client_key.key)
|
||||
});
|
||||
|
||||
Self {
|
||||
key,
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,12 +404,14 @@ impl IntegerCompressedServerKey {
|
||||
>,
|
||||
compression_key: Option<CompressedCompressionKey>,
|
||||
decompression_key: Option<CompressedDecompressionKey>,
|
||||
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
|
||||
) -> Self {
|
||||
Self {
|
||||
key,
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,6 +426,11 @@ impl IntegerCompressedServerKey {
|
||||
.as_ref()
|
||||
.map(CompressedDecompressionKey::decompress);
|
||||
|
||||
let noise_squashing_key = self
|
||||
.noise_squashing_key
|
||||
.as_ref()
|
||||
.map(CompressedNoiseSquashingKey::decompress);
|
||||
|
||||
IntegerServerKey {
|
||||
key: self.key.decompress(),
|
||||
cpk_key_switching_key_material: self.cpk_key_switching_key_material.as_ref().map(
|
||||
@@ -385,6 +438,7 @@ impl IntegerCompressedServerKey {
|
||||
),
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -473,14 +527,17 @@ pub struct IntegerServerKeyConformanceParams {
|
||||
ShortintKeySwitchingParameters,
|
||||
)>,
|
||||
pub compression_param: Option<CompressionParameters>,
|
||||
pub noise_squashing_param: Option<NoiseSquashingParameters>,
|
||||
}
|
||||
|
||||
impl From<Config> for IntegerServerKeyConformanceParams {
|
||||
fn from(value: Config) -> Self {
|
||||
impl<C: Into<Config>> From<C> for IntegerServerKeyConformanceParams {
|
||||
fn from(value: C) -> Self {
|
||||
let config: Config = value.into();
|
||||
Self {
|
||||
sk_param: value.inner.block_parameters,
|
||||
cpk_param: value.inner.dedicated_compact_public_key_parameters,
|
||||
compression_param: value.inner.compression_parameters,
|
||||
sk_param: config.inner.block_parameters,
|
||||
cpk_param: config.inner.dedicated_compact_public_key_parameters,
|
||||
compression_param: config.inner.compression_parameters,
|
||||
noise_squashing_param: config.inner.noise_squashing_parameters,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -539,6 +596,7 @@ impl ParameterSetConformant for IntegerServerKey {
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
} = self;
|
||||
|
||||
let cpk_key_switching_key_material_is_ok = match (
|
||||
@@ -572,9 +630,27 @@ impl ParameterSetConformant for IntegerServerKey {
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let noise_squashing_key_is_ok = match (
|
||||
parameter_set.noise_squashing_param.as_ref(),
|
||||
noise_squashing_key.as_ref(),
|
||||
) {
|
||||
(None, None) => true,
|
||||
(Some(noise_squashing_param), Some(noise_squashing_key)) => {
|
||||
let noise_squashing_param =
|
||||
(parameter_set.sk_param, *noise_squashing_param).try_into();
|
||||
if let Ok(noise_squashing_param) = noise_squashing_param {
|
||||
noise_squashing_key.is_conformant(&noise_squashing_param)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
key.is_conformant(¶meter_set.sk_param)
|
||||
&& cpk_key_switching_key_material_is_ok
|
||||
&& compression_is_ok
|
||||
&& noise_squashing_key_is_ok
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,6 +663,7 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
} = self;
|
||||
|
||||
let cpk_key_switching_key_material_is_ok = match (
|
||||
@@ -620,9 +697,27 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let noise_squashing_key_is_ok = match (
|
||||
parameter_set.noise_squashing_param.as_ref(),
|
||||
noise_squashing_key.as_ref(),
|
||||
) {
|
||||
(None, None) => true,
|
||||
(Some(noise_squashing_param), Some(noise_squashing_key)) => {
|
||||
let noise_squashing_param =
|
||||
(parameter_set.sk_param, *noise_squashing_param).try_into();
|
||||
if let Ok(noise_squashing_param) = noise_squashing_param {
|
||||
noise_squashing_key.is_conformant(&noise_squashing_param)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
key.is_conformant(¶meter_set.sk_param)
|
||||
&& cpk_key_switching_key_material_is_ok
|
||||
&& compression_is_ok
|
||||
&& noise_squashing_key_is_ok
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::high_level_api::keys::{IntegerCompressedServerKey, IntegerServerKey};
|
||||
use crate::integer::compression_keys::{
|
||||
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, DecompressionKey,
|
||||
};
|
||||
use crate::integer::noise_squashing::{CompressedNoiseSquashingKey, NoiseSquashingKey};
|
||||
use crate::integer::parameters::IntegerCompactCiphertextListExpansionMode;
|
||||
use crate::named::Named;
|
||||
use crate::prelude::Tagged;
|
||||
@@ -53,6 +54,7 @@ impl ServerKey {
|
||||
Option<crate::integer::key_switching_key::KeySwitchingKeyMaterial>,
|
||||
Option<CompressionKey>,
|
||||
Option<DecompressionKey>,
|
||||
Option<NoiseSquashingKey>,
|
||||
Tag,
|
||||
) {
|
||||
let IntegerServerKey {
|
||||
@@ -60,6 +62,7 @@ impl ServerKey {
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
} = (*self.key).clone();
|
||||
|
||||
(
|
||||
@@ -67,6 +70,7 @@ impl ServerKey {
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
self.tag,
|
||||
)
|
||||
}
|
||||
@@ -78,6 +82,7 @@ impl ServerKey {
|
||||
>,
|
||||
compression_key: Option<CompressionKey>,
|
||||
decompression_key: Option<DecompressionKey>,
|
||||
noise_squashing_key: Option<NoiseSquashingKey>,
|
||||
tag: Tag,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -86,6 +91,7 @@ impl ServerKey {
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
}),
|
||||
tag,
|
||||
}
|
||||
@@ -239,6 +245,7 @@ impl CompressedServerKey {
|
||||
>,
|
||||
compression_key: Option<CompressedCompressionKey>,
|
||||
decompression_key: Option<CompressedDecompressionKey>,
|
||||
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
|
||||
tag: Tag,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -247,6 +254,7 @@ impl CompressedServerKey {
|
||||
cpk_key_switching_key_material,
|
||||
compression_key,
|
||||
decompression_key,
|
||||
noise_squashing_key,
|
||||
),
|
||||
tag,
|
||||
}
|
||||
@@ -432,6 +440,7 @@ mod test {
|
||||
use crate::prelude::ParameterSetConformant;
|
||||
use crate::shortint::parameters::{
|
||||
COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
@@ -450,13 +459,7 @@ mod test {
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = ServerKey::new(&ck);
|
||||
|
||||
let sk_param = PBSParameters::PBS(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
|
||||
let conformance_params = IntegerServerKeyConformanceParams {
|
||||
sk_param,
|
||||
cpk_param: None,
|
||||
compression_param: None,
|
||||
};
|
||||
let conformance_params = config.into();
|
||||
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
@@ -470,13 +473,7 @@ mod test {
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = ServerKey::new(&ck);
|
||||
|
||||
let sk_param = PBSParameters::PBS(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
|
||||
let conformance_params = IntegerServerKeyConformanceParams {
|
||||
sk_param,
|
||||
cpk_param: None,
|
||||
compression_param: Some(COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128),
|
||||
};
|
||||
let conformance_params = config.into();
|
||||
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
@@ -488,18 +485,56 @@ mod test {
|
||||
let casting_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params));
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params))
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = ServerKey::new(&ck);
|
||||
|
||||
let sk_param = PBSParameters::PBS(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
let conformance_params = config.into();
|
||||
|
||||
let conformance_params = IntegerServerKeyConformanceParams {
|
||||
sk_param,
|
||||
cpk_param: Some((cpk_params, casting_params)),
|
||||
compression_param: None,
|
||||
};
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
{
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let noise_squashing_params =
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.enable_noise_squashing(noise_squashing_params)
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = ServerKey::new(&ck);
|
||||
|
||||
let conformance_params = config.into();
|
||||
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
// Full blockchain configuration
|
||||
{
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let cpk_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let casting_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let comp_params = COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let noise_squashing_params =
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params))
|
||||
.enable_compression(comp_params)
|
||||
.enable_noise_squashing(noise_squashing_params)
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = ServerKey::new(&ck);
|
||||
|
||||
let conformance_params = config.into();
|
||||
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
@@ -534,6 +569,7 @@ mod test {
|
||||
sk_param,
|
||||
cpk_param: None,
|
||||
compression_param: None,
|
||||
noise_squashing_param: None,
|
||||
};
|
||||
|
||||
assert!(!sk.is_conformant(&conformance_params));
|
||||
@@ -547,7 +583,8 @@ mod test {
|
||||
let casting_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params));
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params))
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = ServerKey::new(&ck);
|
||||
@@ -560,6 +597,7 @@ mod test {
|
||||
sk_param,
|
||||
cpk_param: Some((cpk_params, casting_params)),
|
||||
compression_param: None,
|
||||
noise_squashing_param: None,
|
||||
};
|
||||
|
||||
assert!(!sk.is_conformant(&conformance_params));
|
||||
@@ -577,13 +615,7 @@ mod test {
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = CompressedServerKey::new(&ck);
|
||||
|
||||
let sk_param = PBSParameters::PBS(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
|
||||
let conformance_params = IntegerServerKeyConformanceParams {
|
||||
sk_param,
|
||||
cpk_param: None,
|
||||
compression_param: None,
|
||||
};
|
||||
let conformance_params = config.into();
|
||||
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
@@ -597,14 +629,7 @@ mod test {
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = CompressedServerKey::new(&ck);
|
||||
|
||||
let sk_param = PBSParameters::PBS(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
|
||||
let conformance_params = IntegerServerKeyConformanceParams {
|
||||
sk_param,
|
||||
cpk_param: None,
|
||||
compression_param: Some(COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128),
|
||||
};
|
||||
|
||||
let conformance_params = config.into();
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
{
|
||||
@@ -615,18 +640,56 @@ mod test {
|
||||
let casting_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params));
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params))
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = CompressedServerKey::new(&ck);
|
||||
|
||||
let sk_param = PBSParameters::PBS(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
let conformance_params = config.into();
|
||||
|
||||
let conformance_params = IntegerServerKeyConformanceParams {
|
||||
sk_param,
|
||||
cpk_param: Some((cpk_params, casting_params)),
|
||||
compression_param: None,
|
||||
};
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
{
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let noise_squashing_params =
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.enable_noise_squashing(noise_squashing_params)
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = CompressedServerKey::new(&ck);
|
||||
|
||||
let conformance_params = config.into();
|
||||
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
// Full blockchain configuration
|
||||
{
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let cpk_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let casting_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let comp_params = COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let noise_squashing_params =
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params))
|
||||
.enable_compression(comp_params)
|
||||
.enable_noise_squashing(noise_squashing_params)
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = CompressedServerKey::new(&ck);
|
||||
|
||||
let conformance_params = config.into();
|
||||
|
||||
assert!(sk.is_conformant(&conformance_params));
|
||||
}
|
||||
@@ -661,6 +724,7 @@ mod test {
|
||||
sk_param,
|
||||
cpk_param: None,
|
||||
compression_param: None,
|
||||
noise_squashing_param: None,
|
||||
};
|
||||
|
||||
assert!(!sk.is_conformant(&conformance_params));
|
||||
@@ -674,7 +738,8 @@ mod test {
|
||||
let casting_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let config = ConfigBuilder::with_custom_parameters(params)
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params));
|
||||
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params))
|
||||
.build();
|
||||
|
||||
let ck = ClientKey::generate(config);
|
||||
let sk = CompressedServerKey::new(&ck);
|
||||
@@ -687,6 +752,7 @@ mod test {
|
||||
sk_param,
|
||||
cpk_param: Some((cpk_params, casting_params)),
|
||||
compression_param: None,
|
||||
noise_squashing_param: None,
|
||||
};
|
||||
|
||||
assert!(!sk.is_conformant(&conformance_params));
|
||||
|
||||
@@ -54,7 +54,10 @@ pub use config::{Config, ConfigBuilder};
|
||||
pub use global_state::CudaGpuChoice;
|
||||
pub use global_state::{set_server_key, unset_server_key, with_server_key_as_context};
|
||||
|
||||
pub use integers::{CompressedFheInt, CompressedFheUint, FheInt, FheUint, IntegerId};
|
||||
pub use integers::{
|
||||
CompressedFheInt, CompressedFheUint, FheInt, FheUint, IntegerId, SquashedNoiseFheInt,
|
||||
SquashedNoiseFheUint,
|
||||
};
|
||||
#[cfg(feature = "gpu")]
|
||||
pub use keys::CudaServerKey;
|
||||
pub use keys::{
|
||||
@@ -66,7 +69,9 @@ use strum::FromRepr;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use crate::high_level_api::booleans::{CompressedFheBool, FheBool, FheBoolConformanceParams};
|
||||
pub use crate::high_level_api::booleans::{
|
||||
CompressedFheBool, FheBool, FheBoolConformanceParams, SquashedNoiseFheBool,
|
||||
};
|
||||
|
||||
#[cfg(feature = "extended-types")]
|
||||
expand_pub_use_fhe_type!(
|
||||
|
||||
@@ -10,7 +10,7 @@ pub use crate::high_level_api::traits::{
|
||||
BitSlice, CiphertextList, DivRem, FheDecrypt, FheEncrypt, FheEq, FheKeyswitch, FheMax, FheMin,
|
||||
FheOrd, FheTrivialEncrypt, FheTryEncrypt, FheTryTrivialEncrypt, IfThenElse, OverflowingAdd,
|
||||
OverflowingMul, OverflowingSub, RotateLeft, RotateLeftAssign, RotateRight, RotateRightAssign,
|
||||
ScalarIfThenElse, Tagged,
|
||||
ScalarIfThenElse, SquashNoise, Tagged,
|
||||
};
|
||||
|
||||
pub use crate::conformance::ParameterSetConformant;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#[cfg(feature = "gpu")]
|
||||
mod gpu_selection;
|
||||
mod noise_squashing;
|
||||
mod tags_on_entities;
|
||||
|
||||
use crate::high_level_api::prelude::*;
|
||||
@@ -194,7 +195,8 @@ fn test_try_from_single_lwe_encryption_key() {
|
||||
|
||||
let shortint_key =
|
||||
crate::shortint::ClientKey::try_from_lwe_encryption_key(lwe_sk, parameters).unwrap();
|
||||
let client_key = ClientKey::from_raw_parts(shortint_key.into(), None, None, Tag::default());
|
||||
let client_key =
|
||||
ClientKey::from_raw_parts(shortint_key.into(), None, None, None, Tag::default());
|
||||
let sks = ServerKey::new(&client_key);
|
||||
|
||||
let clear_a = 1344u32;
|
||||
|
||||
75
tfhe/src/high_level_api/tests/noise_squashing.rs
Normal file
75
tfhe/src/high_level_api/tests/noise_squashing.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use crate::high_level_api::prelude::*;
|
||||
use crate::high_level_api::{
|
||||
generate_keys, ConfigBuilder, FheBool, FheInt10, FheInt8, FheUint256, FheUint32,
|
||||
};
|
||||
use crate::integer::U256;
|
||||
use crate::set_server_key;
|
||||
use crate::shortint::parameters::{
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
};
|
||||
use rand::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_noise_squashing() {
|
||||
let config =
|
||||
ConfigBuilder::with_custom_parameters(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128)
|
||||
.enable_noise_squashing(NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128)
|
||||
.build();
|
||||
let (cks, sks) = generate_keys(config);
|
||||
|
||||
set_server_key(sks);
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// Non native type for clear
|
||||
let clear: U256 = rng.gen();
|
||||
let enc = FheUint256::encrypt(clear, &cks);
|
||||
let bitand = &enc & &enc;
|
||||
|
||||
let squashed = bitand.squash_noise().unwrap();
|
||||
|
||||
let recovered: U256 = squashed.decrypt(&cks);
|
||||
assert_eq!(clear, recovered);
|
||||
|
||||
// Native unsigned
|
||||
let clear: u32 = rng.gen();
|
||||
let enc = FheUint32::encrypt(clear, &cks);
|
||||
let bitand = &enc & &enc;
|
||||
|
||||
let squashed = bitand.squash_noise().unwrap();
|
||||
|
||||
let recovered: u32 = squashed.decrypt(&cks);
|
||||
assert_eq!(clear, recovered);
|
||||
|
||||
// Non native signed with proper input range
|
||||
let clear: i16 = rng.gen_range(-1 << 9..1 << 9);
|
||||
let enc = FheInt10::encrypt(clear, &cks);
|
||||
let bitand = &enc & &enc;
|
||||
|
||||
let squashed = bitand.squash_noise().unwrap();
|
||||
|
||||
let recovered: i16 = squashed.decrypt(&cks);
|
||||
assert_eq!(clear, recovered);
|
||||
|
||||
// Native signed
|
||||
let clear: i8 = rng.gen();
|
||||
let enc = FheInt8::encrypt(clear, &cks);
|
||||
let bitand = &enc & &enc;
|
||||
|
||||
let squashed = bitand.squash_noise().unwrap();
|
||||
|
||||
let recovered: i8 = squashed.decrypt(&cks);
|
||||
assert_eq!(clear, recovered);
|
||||
|
||||
// Booleans
|
||||
for clear in [false, true] {
|
||||
let enc = FheBool::encrypt(clear, &cks);
|
||||
let bitand = &enc & &enc;
|
||||
|
||||
let squashed = bitand.squash_noise().unwrap();
|
||||
|
||||
let recovered: bool = squashed.decrypt(&cks);
|
||||
assert_eq!(clear, recovered);
|
||||
}
|
||||
}
|
||||
@@ -204,3 +204,9 @@ pub trait CiphertextList {
|
||||
}
|
||||
|
||||
pub trait FheId: Copy + Default {}
|
||||
|
||||
pub trait SquashNoise {
|
||||
type Output;
|
||||
|
||||
fn squash_noise(&self) -> crate::Result<Self::Output>;
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ where
|
||||
/// to the final result.
|
||||
///
|
||||
/// Input is expected in little endian order.
|
||||
pub(crate) fn recompose_unsigned<U>(input: impl Iterator<Item = U>, bits_in_block: u32) -> T
|
||||
pub fn recompose_unsigned<U>(input: impl Iterator<Item = U>, bits_in_block: u32) -> T
|
||||
where
|
||||
T: RecomposableFrom<U>,
|
||||
{
|
||||
@@ -425,7 +425,7 @@ where
|
||||
/// to the final result.
|
||||
///
|
||||
/// Input is expected in little endian order.
|
||||
pub(crate) fn recompose_signed<U>(input: impl Iterator<Item = U>, bits_in_block: u32) -> T
|
||||
pub fn recompose_signed<U>(input: impl Iterator<Item = U>, bits_in_block: u32) -> T
|
||||
where
|
||||
T: RecomposableFrom<U> + SignExtendable,
|
||||
{
|
||||
@@ -448,7 +448,7 @@ where
|
||||
/// the last limb are ignored.
|
||||
///
|
||||
/// Input is expected in little endian order.
|
||||
pub(crate) fn recompose_signed_with_size<U>(
|
||||
pub fn recompose_signed_with_size<U>(
|
||||
input: impl Iterator<Item = U>,
|
||||
bits_in_block: u32,
|
||||
signed_integer_size: u32,
|
||||
|
||||
@@ -25,3 +25,29 @@ pub struct SquashedNoiseSignedRadixCiphertext {
|
||||
pub struct SquashedNoiseBooleanBlock {
|
||||
pub(crate) ciphertext: SquashedNoiseCiphertext,
|
||||
}
|
||||
|
||||
impl SquashedNoiseRadixCiphertext {
|
||||
pub fn packed_blocks(&self) -> &[SquashedNoiseCiphertext] {
|
||||
&self.packed_blocks
|
||||
}
|
||||
|
||||
pub fn original_block_count(&self) -> usize {
|
||||
self.original_block_count
|
||||
}
|
||||
}
|
||||
|
||||
impl SquashedNoiseSignedRadixCiphertext {
|
||||
pub fn packed_blocks(&self) -> &[SquashedNoiseCiphertext] {
|
||||
&self.packed_blocks
|
||||
}
|
||||
|
||||
pub fn original_block_count(&self) -> usize {
|
||||
self.original_block_count
|
||||
}
|
||||
}
|
||||
|
||||
impl SquashedNoiseBooleanBlock {
|
||||
pub fn packed_blocks(&self) -> &SquashedNoiseCiphertext {
|
||||
&self.ciphertext
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user