feat(hlapi): add CompressedSquashedNoiseCiphertextList

This commit is contained in:
tmontaigu
2025-06-27 11:29:31 +02:00
parent b198c18498
commit 7203cc3564
20 changed files with 974 additions and 86 deletions

View File

@@ -2,9 +2,10 @@ use serde::{Deserialize, Serialize};
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use crate::high_level_api::booleans::{
InnerBoolean, InnerBooleanVersionOwned, InnerCompressedFheBool,
InnerBoolean, InnerBooleanVersionOwned, InnerCompressedFheBool, InnerSquashedNoiseBoolean,
InnerSquashedNoiseBooleanVersionOwned, SquashedNoiseFheBool,
};
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::{CompressedFheBool, FheBool, Tag};
use std::convert::Infallible;
@@ -72,8 +73,27 @@ pub(crate) enum InnerSquashedNoiseBooleanVersionedOwned {
V0(InnerSquashedNoiseBooleanVersionOwned),
}
#[derive(Version)]
pub struct SquashedNoiseFheBoolV0 {
pub(in crate::high_level_api) inner: InnerSquashedNoiseBoolean,
pub(in crate::high_level_api) tag: Tag,
}
impl Upgrade<SquashedNoiseFheBool> for SquashedNoiseFheBoolV0 {
type Error = Infallible;
fn upgrade(self) -> Result<SquashedNoiseFheBool, Self::Error> {
Ok(SquashedNoiseFheBool::new(
self.inner,
SquashedNoiseCiphertextState::Normal,
self.tag,
))
}
}
// Squashed Noise
#[derive(VersionsDispatch)]
pub enum SquashedNoiseFheBoolVersions {
V0(SquashedNoiseFheBool),
V0(SquashedNoiseFheBoolV0),
V1(SquashedNoiseFheBool),
}

View File

@@ -1,7 +1,14 @@
use crate::high_level_api::SquashedNoiseCiphertextState;
use std::convert::Infallible;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use crate::{CompressedCiphertextList, Tag};
use crate::{CompressedCiphertextList, CompressedSquashedNoiseCiphertextList, Tag};
#[derive(VersionsDispatch)]
#[allow(unused)]
pub(crate) enum SquashedNoiseCiphertextStateVersions {
V0(SquashedNoiseCiphertextState),
}
#[derive(Version)]
pub struct CompressedCiphertextListV0(crate::integer::ciphertext::CompressedCiphertextList);
@@ -40,3 +47,8 @@ pub enum CompressedCiphertextListVersions {
V1(CompressedCiphertextListV1),
V2(CompressedCiphertextList),
}
#[derive(VersionsDispatch)]
pub enum CompressedSquashedNoiseCiphertextListVersions {
V0(CompressedSquashedNoiseCiphertextList),
}

View File

@@ -3,8 +3,13 @@ use std::convert::Infallible;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use self::signed::SignedRadixCiphertext;
use self::unsigned::RadixCiphertext as UnsignedRadixCiphertext;
use crate::high_level_api::global_state::with_cpu_internal_keys;
use crate::high_level_api::integers::signed::InnerSquashedNoiseSignedRadixCiphertext;
use crate::high_level_api::integers::unsigned::InnerSquashedNoiseRadixCiphertext;
use crate::high_level_api::integers::*;
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::backward_compatibility::ciphertext::{
CompressedModulusSwitchedRadixCiphertextTFHE06,
CompressedModulusSwitchedSignedRadixCiphertextTFHE06,
@@ -19,9 +24,6 @@ use crate::shortint::{Ciphertext, ServerKey};
use crate::Tag;
use serde::{Deserialize, Serialize};
use self::signed::SignedRadixCiphertext;
use self::unsigned::RadixCiphertext as UnsignedRadixCiphertext;
// Manual impl
#[derive(Serialize, Deserialize)]
pub(crate) enum SignedRadixCiphertextVersionedOwned {
@@ -228,9 +230,28 @@ pub(crate) enum InnerSquashedNoiseRadixCiphertextVersionedOwned {
V0(InnerSquashedNoiseRadixCiphertextVersionOwned),
}
#[derive(Version)]
pub struct SquashedNoiseFheUintV0 {
pub(in crate::high_level_api) inner: InnerSquashedNoiseRadixCiphertext,
pub(in crate::high_level_api) tag: Tag,
}
impl Upgrade<SquashedNoiseFheUint> for SquashedNoiseFheUintV0 {
type Error = Infallible;
fn upgrade(self) -> Result<SquashedNoiseFheUint, Self::Error> {
Ok(SquashedNoiseFheUint::new(
self.inner,
SquashedNoiseCiphertextState::Normal,
self.tag,
))
}
}
#[derive(VersionsDispatch)]
pub enum SquashedNoiseFheUintVersions {
V0(SquashedNoiseFheUint),
V0(SquashedNoiseFheUintV0),
V1(SquashedNoiseFheUint),
}
// Manual impl
@@ -239,7 +260,26 @@ pub(crate) enum InnerSquashedNoiseSignedRadixCiphertextVersionedOwned {
V0(InnerSquashedNoiseSignedRadixCiphertextVersionOwned),
}
#[derive(Version)]
pub struct SquashedNoiseFheIntV0 {
pub(in crate::high_level_api) inner: InnerSquashedNoiseSignedRadixCiphertext,
pub(in crate::high_level_api) tag: Tag,
}
impl Upgrade<SquashedNoiseFheInt> for SquashedNoiseFheIntV0 {
type Error = Infallible;
fn upgrade(self) -> Result<SquashedNoiseFheInt, Self::Error> {
Ok(SquashedNoiseFheInt::new(
self.inner,
SquashedNoiseCiphertextState::Normal,
self.tag,
))
}
}
#[derive(VersionsDispatch)]
pub enum SquashedNoiseFheIntVersions {
V0(SquashedNoiseFheInt),
V0(SquashedNoiseFheIntV0),
V1(SquashedNoiseFheInt),
}

View File

@@ -2,6 +2,9 @@ use crate::high_level_api::keys::*;
use crate::integer::compression_keys::{
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, DecompressionKey,
};
use crate::integer::noise_squashing::{
CompressedNoiseSquashingKey, NoiseSquashingKey, NoiseSquashingPrivateKey,
};
use crate::Tag;
use std::convert::Infallible;
use tfhe_versionable::deprecation::{Deprecable, Deprecated};
@@ -182,17 +185,17 @@ pub(crate) struct IntegerClientKeyV3 {
pub(crate) compression_key: Option<crate::integer::compression_keys::CompressionPrivateKeys>,
}
impl Upgrade<IntegerClientKey> for IntegerClientKeyV3 {
impl Upgrade<IntegerClientKeyV4> for IntegerClientKeyV3 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerClientKey, Self::Error> {
fn upgrade(self) -> Result<IntegerClientKeyV4, Self::Error> {
let Self {
key,
dedicated_compact_private_key,
compression_key,
} = self;
Ok(IntegerClientKey {
Ok(IntegerClientKeyV4 {
key,
dedicated_compact_private_key,
compression_key,
@@ -201,6 +204,14 @@ impl Upgrade<IntegerClientKey> for IntegerClientKeyV3 {
}
}
#[derive(Version)]
pub(crate) struct IntegerClientKeyV4 {
pub(crate) key: crate::integer::ClientKey,
pub(crate) dedicated_compact_private_key: Option<CompactPrivateKey>,
pub(crate) compression_key: Option<crate::integer::compression_keys::CompressionPrivateKeys>,
pub(crate) noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
}
#[derive(VersionsDispatch)]
#[allow(unused)]
pub(crate) enum IntegerClientKeyVersions {
@@ -208,7 +219,29 @@ pub(crate) enum IntegerClientKeyVersions {
V1(Deprecated<IntegerClientKey>),
V2(IntegerClientKeyV2),
V3(IntegerClientKeyV3),
V4(IntegerClientKey),
V4(IntegerClientKeyV4),
V5(IntegerClientKey),
}
impl Upgrade<IntegerClientKey> for IntegerClientKeyV4 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerClientKey, Self::Error> {
let Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
} = self;
Ok(IntegerClientKey {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key: None,
})
}
}
impl Deprecable for IntegerServerKey {
@@ -225,7 +258,38 @@ pub struct IntegerServerKeyV4 {
pub(crate) decompression_key: Option<DecompressionKey>,
}
impl Upgrade<IntegerServerKey> for IntegerServerKeyV4 {
impl Upgrade<IntegerServerKeyV5> for IntegerServerKeyV4 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerServerKeyV5, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
} = self;
Ok(IntegerServerKeyV5 {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key: None,
})
}
}
#[derive(Version)]
pub struct IntegerServerKeyV5 {
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>,
pub(crate) noise_squashing_key: Option<NoiseSquashingKey>,
}
impl Upgrade<IntegerServerKey> for IntegerServerKeyV5 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerServerKey, Self::Error> {
@@ -234,6 +298,7 @@ impl Upgrade<IntegerServerKey> for IntegerServerKeyV4 {
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
} = self;
Ok(IntegerServerKey {
@@ -241,7 +306,8 @@ impl Upgrade<IntegerServerKey> for IntegerServerKeyV4 {
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key: None,
noise_squashing_key,
noise_squashing_compression_key: None,
})
}
}
@@ -253,7 +319,8 @@ pub enum IntegerServerKeyVersions {
V2(Deprecated<IntegerServerKey>),
V3(Deprecated<IntegerServerKey>),
V4(IntegerServerKeyV4),
V5(IntegerServerKey),
V5(IntegerServerKeyV5),
V6(IntegerServerKey),
}
impl Deprecable for IntegerCompressedServerKey {
@@ -270,10 +337,10 @@ pub struct IntegerCompressedServerKeyV2 {
pub(crate) decompression_key: Option<CompressedDecompressionKey>,
}
impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV2 {
impl Upgrade<IntegerCompressedServerKeyV3> for IntegerCompressedServerKeyV2 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerCompressedServerKey, Self::Error> {
fn upgrade(self) -> Result<IntegerCompressedServerKeyV3, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
@@ -281,7 +348,7 @@ impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV2 {
decompression_key,
} = self;
Ok(IntegerCompressedServerKey {
Ok(IntegerCompressedServerKeyV3 {
key,
cpk_key_switching_key_material,
compression_key,
@@ -291,12 +358,46 @@ impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV2 {
}
}
#[derive(Version)]
pub struct IntegerCompressedServerKeyV3 {
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>,
pub(crate) noise_squashing_key: Option<CompressedNoiseSquashingKey>,
}
#[derive(VersionsDispatch)]
pub enum IntegerCompressedServerKeyVersions {
V0(Deprecated<IntegerCompressedServerKey>),
V1(Deprecated<IntegerCompressedServerKey>),
V2(IntegerCompressedServerKeyV2),
V3(IntegerCompressedServerKey),
V3(IntegerCompressedServerKeyV3),
V4(IntegerCompressedServerKey),
}
impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV3 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerCompressedServerKey, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
} = self;
Ok(IntegerCompressedServerKey {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key: None,
})
}
}
#[derive(VersionsDispatch)]

View File

@@ -4,7 +4,9 @@ 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;
pub(in crate::high_level_api) use squashed_noise::{
InnerSquashedNoiseBoolean, InnerSquashedNoiseBooleanVersionOwned,
};
mod base;
mod compressed;

View File

@@ -6,7 +6,8 @@ use crate::high_level_api::details::MaybeCloned;
use crate::high_level_api::errors::UninitializedNoiseSquashing;
use crate::high_level_api::global_state::{self, with_internal_keys};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::traits::{FheDecrypt, SquashNoise};
use crate::high_level_api::traits::{FheDecrypt, SquashNoise, Tagged};
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::ciphertext::SquashedNoiseBooleanBlock;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::boolean_value::CudaBooleanBlock;
@@ -125,10 +126,21 @@ impl InnerSquashedNoiseBoolean {
#[derive(Clone, serde::Deserialize, serde::Serialize, Versionize)]
#[versionize(SquashedNoiseFheBoolVersions)]
pub struct SquashedNoiseFheBool {
inner: InnerSquashedNoiseBoolean,
pub(in crate::high_level_api) inner: InnerSquashedNoiseBoolean,
pub(in crate::high_level_api) state: SquashedNoiseCiphertextState,
tag: Tag,
}
impl SquashedNoiseFheBool {
pub(in crate::high_level_api) fn new(
inner: InnerSquashedNoiseBoolean,
state: SquashedNoiseCiphertextState,
tag: Tag,
) -> Self {
Self { inner, state, tag }
}
}
impl Named for SquashedNoiseFheBool {
const NAME: &'static str = "high_level_api::SquashedNoiseFheBool";
}
@@ -143,20 +155,23 @@ impl SquashedNoiseFheBool {
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?",
)
let noise_squashing_private_key = key.private_noise_squashing_decryption_key(self.state);
noise_squashing_private_key
.decrypt_bool(&self.inner.on_cpu())
.unwrap()
}
}
impl Tagged for SquashedNoiseFheBool {
fn tag(&self) -> &Tag {
&self.tag
}
fn tag_mut(&mut self) -> &mut Tag {
&mut self.tag
}
}
impl SquashNoise for FheBool {
type Output = SquashedNoiseFheBool;
@@ -176,6 +191,7 @@ impl SquashNoise for FheBool {
&self.ciphertext.on_cpu(),
)?,
),
state: SquashedNoiseCiphertextState::Normal,
tag: server_key.tag.clone(),
})
}
@@ -211,6 +227,7 @@ impl SquashNoise for FheBool {
Ok(SquashedNoiseFheBool {
inner: InnerSquashedNoiseBoolean::Cpu(cpu_squashed_block),
state: SquashedNoiseCiphertextState::Normal,
tag: cuda_key.tag.clone(),
})
}

View File

@@ -0,0 +1,432 @@
use crate::backward_compatibility::compressed_ciphertext_list::CompressedSquashedNoiseCiphertextListVersions;
use crate::high_level_api::booleans::InnerSquashedNoiseBoolean;
use crate::high_level_api::global_state::try_with_internal_keys;
use crate::high_level_api::integers::signed::InnerSquashedNoiseSignedRadixCiphertext;
use crate::high_level_api::integers::unsigned::InnerSquashedNoiseRadixCiphertext;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::traits::Tagged;
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::ciphertext::{
CompressedSquashedNoiseCiphertextList as IntegerCompressedSquashedNoiseCiphertextList,
DataKind, SquashedNoiseBooleanBlock, SquashedNoiseExpandable, SquashedNoiseRadixCiphertext,
SquashedNoiseSignedRadixCiphertext,
};
use crate::named::Named;
use crate::shortint::ciphertext::SquashedNoiseCiphertext;
use crate::{SquashedNoiseFheBool, SquashedNoiseFheInt, SquashedNoiseFheUint, Tag, Versionize};
use serde::{Deserialize, Serialize};
use tfhe_versionable::{Unversionize, UnversionizeError, VersionizeOwned};
pub(in crate::high_level_api) enum InnerCompressedSquashedNoiseCiphertextList {
Cpu(IntegerCompressedSquashedNoiseCiphertextList),
}
impl Versionize for InnerCompressedSquashedNoiseCiphertextList {
type Versioned<'vers>
= <IntegerCompressedSquashedNoiseCiphertextList as Versionize>::Versioned<'vers>
where
Self: 'vers;
fn versionize(&self) -> Self::Versioned<'_> {
self.on_cpu().versionize()
}
}
impl VersionizeOwned for InnerCompressedSquashedNoiseCiphertextList {
type VersionedOwned =
<IntegerCompressedSquashedNoiseCiphertextList as VersionizeOwned>::VersionedOwned;
fn versionize_owned(self) -> Self::VersionedOwned {
self.into_cpu().versionize_owned()
}
}
impl Unversionize for InnerCompressedSquashedNoiseCiphertextList {
fn unversionize(versioned: Self::VersionedOwned) -> Result<Self, UnversionizeError> {
IntegerCompressedSquashedNoiseCiphertextList::unversionize(versioned).map(Self::Cpu)
}
}
impl Serialize for InnerCompressedSquashedNoiseCiphertextList {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.on_cpu().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for InnerCompressedSquashedNoiseCiphertextList {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut new = IntegerCompressedSquashedNoiseCiphertextList::deserialize(deserializer)
.map(Self::Cpu)?;
if let Some(device) = crate::high_level_api::global_state::device_of_internal_keys() {
new.move_to_device(device)
.map_err(serde::de::Error::custom)?;
}
Ok(new)
}
}
impl InnerCompressedSquashedNoiseCiphertextList {
fn on_cpu(&self) -> &IntegerCompressedSquashedNoiseCiphertextList {
match self {
Self::Cpu(inner) => inner,
}
}
fn into_cpu(self) -> IntegerCompressedSquashedNoiseCiphertextList {
match self {
Self::Cpu(inner) => inner,
}
}
fn current_device(&self) -> crate::Device {
match self {
Self::Cpu(_) => crate::Device::Cpu,
}
}
#[allow(clippy::unnecessary_wraps, reason = "It depends on activated features")]
fn move_to_device(&mut self, target_device: crate::Device) -> crate::Result<()> {
let current_device = self.current_device();
if current_device == target_device {
return Ok(());
}
let cpu_ct = self.on_cpu();
match target_device {
crate::Device::Cpu => {
*self = Self::Cpu(cpu_ct.to_owned());
Ok(())
}
#[cfg(feature = "gpu")]
crate::Device::CudaGpu => Err(crate::error!(
"Cuda does not support CompressedSquashedNoiseCiphertextList"
)),
#[cfg(feature = "hpu")]
crate::Device::Hpu => Err(crate::error!(
"Hpu does not support CompressedSquashedNoiseCiphertextList"
)),
}
}
}
#[derive(Serialize, Deserialize, Versionize)]
#[versionize(CompressedSquashedNoiseCiphertextListVersions)]
pub struct CompressedSquashedNoiseCiphertextList {
pub(in crate::high_level_api) inner: InnerCompressedSquashedNoiseCiphertextList,
pub(crate) tag: Tag,
}
impl Named for CompressedSquashedNoiseCiphertextList {
const NAME: &'static str = "high_level_api::CompressedSquashedNoiseCiphertextList";
}
impl CompressedSquashedNoiseCiphertextList {
pub fn builder() -> CompressedSquashedNoiseCiphertextListBuilder {
CompressedSquashedNoiseCiphertextListBuilder::new()
}
pub fn len(&self) -> usize {
match &self.inner {
InnerCompressedSquashedNoiseCiphertextList::Cpu(inner) => inner.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get<T>(&self, index: usize) -> crate::Result<Option<T>>
where
T: HlSquashedNoiseExpandable + Tagged,
{
let mut r = match &self.inner {
InnerCompressedSquashedNoiseCiphertextList::Cpu(inner) => inner.get::<T>(index),
};
if let Ok(Some(ct)) = &mut r {
*ct.tag_mut() = self.tag.clone();
}
r
}
}
pub trait HlSquashedNoiseExpandable: SquashedNoiseExpandable {}
fn create_error_message(tried: DataKind, actual: DataKind) -> crate::Error {
fn name(kind: DataKind) -> &'static str {
match kind {
DataKind::Unsigned(_) => "SquashedNoiseFheUint",
DataKind::Signed(_) => "SquashedNoiseFheInt",
DataKind::Boolean => "SquashedNoiseFheBool",
DataKind::String { .. } => "SquashedNoiseFheString",
}
}
crate::error!(
"Tried to expand a {}, but a {} is stored in this slot",
name(tried),
name(actual)
)
}
impl SquashedNoiseExpandable for SquashedNoiseFheBool {
fn from_expanded_blocks(
blocks: Vec<SquashedNoiseCiphertext>,
kind: DataKind,
) -> crate::Result<Self> {
if kind == DataKind::Boolean {
SquashedNoiseBooleanBlock::from_expanded_blocks(blocks, kind).map(|v| {
Self::new(
InnerSquashedNoiseBoolean::Cpu(v),
SquashedNoiseCiphertextState::PostDecompression,
Tag::default(),
)
})
} else {
Err(create_error_message(DataKind::Boolean, kind))
}
}
}
impl SquashedNoiseExpandable for SquashedNoiseFheUint {
fn from_expanded_blocks(
blocks: Vec<SquashedNoiseCiphertext>,
kind: DataKind,
) -> crate::Result<Self> {
if matches!(kind, DataKind::Unsigned(_)) {
SquashedNoiseRadixCiphertext::from_expanded_blocks(blocks, kind).map(|v| {
Self::new(
InnerSquashedNoiseRadixCiphertext::Cpu(v),
SquashedNoiseCiphertextState::PostDecompression,
Tag::default(),
)
})
} else {
Err(create_error_message(DataKind::Unsigned(0), kind))
}
}
}
impl SquashedNoiseExpandable for SquashedNoiseFheInt {
fn from_expanded_blocks(
blocks: Vec<SquashedNoiseCiphertext>,
kind: DataKind,
) -> crate::Result<Self> {
if matches!(kind, DataKind::Signed(_)) {
SquashedNoiseSignedRadixCiphertext::from_expanded_blocks(blocks, kind).map(|v| {
Self::new(
InnerSquashedNoiseSignedRadixCiphertext::Cpu(v),
SquashedNoiseCiphertextState::PostDecompression,
Tag::default(),
)
})
} else {
Err(create_error_message(DataKind::Signed(0), kind))
}
}
}
impl HlSquashedNoiseExpandable for SquashedNoiseFheBool {}
impl HlSquashedNoiseExpandable for SquashedNoiseFheUint {}
impl HlSquashedNoiseExpandable for SquashedNoiseFheInt {}
mod private {
use crate::shortint::ciphertext::SquashedNoiseCiphertext;
pub enum SquashedNoiseToBeCompressed {
Cpu(Vec<SquashedNoiseCiphertext>),
}
}
pub trait HlSquashedNoiseCompressible {
fn compress_into(self, messages: &mut Vec<(private::SquashedNoiseToBeCompressed, DataKind)>);
}
impl HlSquashedNoiseCompressible for SquashedNoiseFheBool {
fn compress_into(self, messages: &mut Vec<(private::SquashedNoiseToBeCompressed, DataKind)>) {
let kind = DataKind::Boolean;
match self.inner {
InnerSquashedNoiseBoolean::Cpu(cpu_ct) => messages.push((
private::SquashedNoiseToBeCompressed::Cpu(vec![cpu_ct.ciphertext]),
kind,
)),
}
}
}
impl HlSquashedNoiseCompressible for SquashedNoiseFheUint {
fn compress_into(self, messages: &mut Vec<(private::SquashedNoiseToBeCompressed, DataKind)>) {
match self.inner {
InnerSquashedNoiseRadixCiphertext::Cpu(cpu_ct) => {
let kind = DataKind::Unsigned(cpu_ct.original_block_count);
messages.push((
private::SquashedNoiseToBeCompressed::Cpu(cpu_ct.packed_blocks),
kind,
))
}
}
}
}
impl HlSquashedNoiseCompressible for SquashedNoiseFheInt {
fn compress_into(self, messages: &mut Vec<(private::SquashedNoiseToBeCompressed, DataKind)>) {
match self.inner {
InnerSquashedNoiseSignedRadixCiphertext::Cpu(cpu_ct) => {
let kind = DataKind::Signed(cpu_ct.original_block_count);
messages.push((
private::SquashedNoiseToBeCompressed::Cpu(cpu_ct.packed_blocks),
kind,
))
}
}
}
}
pub struct CompressedSquashedNoiseCiphertextListBuilder {
inner: Vec<(private::SquashedNoiseToBeCompressed, DataKind)>,
}
impl Default for CompressedSquashedNoiseCiphertextListBuilder {
fn default() -> Self {
Self::new()
}
}
impl CompressedSquashedNoiseCiphertextListBuilder {
pub fn new() -> Self {
Self { inner: vec![] }
}
pub fn push<T>(&mut self, value: T) -> &mut Self
where
T: HlSquashedNoiseCompressible,
{
value.compress_into(&mut self.inner);
self
}
pub fn build(&self) -> crate::Result<CompressedSquashedNoiseCiphertextList> {
try_with_internal_keys(|keys| match keys {
Some(InternalServerKey::Cpu(cpu_key)) => {
let mut flat_cpu_blocks = vec![];
for (element, _) in &self.inner {
match element {
private::SquashedNoiseToBeCompressed::Cpu(cpu_blocks) => {
flat_cpu_blocks.extend_from_slice(cpu_blocks.as_slice());
}
}
}
cpu_key
.key
.noise_squashing_compression_key
.as_ref()
.ok_or_else(|| {
crate::Error::new(
"Compression key for squashed noise data not set in server key"
.to_owned(),
)
})
.map(|compression_key| {
let compressed_list = compression_key
.key
.compress_noise_squashed_ciphertexts_into_list(&flat_cpu_blocks);
let info = self.inner.iter().map(|(_, kind)| *kind).collect();
CompressedSquashedNoiseCiphertextList {
inner: InnerCompressedSquashedNoiseCiphertextList::Cpu(
IntegerCompressedSquashedNoiseCiphertextList {
list: compressed_list,
info,
},
),
tag: cpu_key.tag.clone(),
}
})
}
#[cfg(feature = "gpu")]
Some(InternalServerKey::Cuda(_)) => Err(crate::error!(
"Cuda GPU does not support compression of squashed noise ciphertexts"
)),
#[cfg(feature = "hpu")]
Some(InternalServerKey::Hpu(_)) => Err(crate::error!(
"HPU does not support compression of squashed noise ciphertexts"
)),
None => Err(crate::high_level_api::errors::UninitializedServerKey.into()),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
use crate::safe_serialization::{safe_deserialize, safe_serialize};
use crate::shortint::parameters::current_params::*;
use crate::{generate_keys, set_server_key, ConfigBuilder, FheBool, FheInt32, FheUint32};
use rand::Rng;
#[test]
fn test_compressed_squashed_noise_ciphertext_list() {
let params = V1_3_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_params =
V1_3_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_compression_params =
V1_3_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(params)
.enable_noise_squashing(noise_squashing_params)
.enable_noise_squashing_compression(noise_squashing_compression_params)
.build();
let (cks, sks) = generate_keys(config);
let mut rng = rand::thread_rng();
let clear_a = rng.gen::<i32>();
let clear_b = rng.gen::<u32>();
let clear_c = rng.gen_bool(0.5);
let a = FheInt32::encrypt(clear_a, &cks);
let b = FheUint32::encrypt(clear_b, &cks);
let c = FheBool::encrypt(clear_c, &cks);
set_server_key(sks);
let ns_a = a.squash_noise().unwrap();
let ns_b = b.squash_noise().unwrap();
let ns_c = c.squash_noise().unwrap();
let list = CompressedSquashedNoiseCiphertextList::builder()
.push(ns_a)
.push(ns_b)
.push(ns_c)
.build()
.unwrap();
let mut serialized_list = vec![];
safe_serialize(&list, &mut serialized_list, 1 << 24).unwrap();
let list: CompressedSquashedNoiseCiphertextList =
safe_deserialize(serialized_list.as_slice(), 1 << 24).unwrap();
let ns_a: SquashedNoiseFheInt = list.get(0).unwrap().unwrap();
let ns_b: SquashedNoiseFheUint = list.get(1).unwrap().unwrap();
let ns_c: SquashedNoiseFheBool = list.get(2).unwrap().unwrap();
let decrypted: i32 = ns_a.decrypt(&cks);
assert_eq!(decrypted, clear_a);
let decrypted: u32 = ns_b.decrypt(&cks);
assert_eq!(decrypted, clear_b);
let decrypted: bool = ns_c.decrypt(&cks);
assert_eq!(decrypted, clear_c);
}
}

View File

@@ -3,7 +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;
use crate::shortint::parameters::{NoiseSquashingCompressionParameters, NoiseSquashingParameters};
/// The config type
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize, Versionize)]
@@ -67,6 +67,20 @@ impl ConfigBuilder {
self
}
pub fn enable_noise_squashing_compression(
mut self,
compression_parameters: NoiseSquashingCompressionParameters,
) -> Self {
assert_ne!(
self.config.inner.noise_squashing_parameters, None,
"Noise squashing must be enabled first"
);
self.config
.inner
.enable_noise_squashing_compression(compression_parameters);
self
}
pub fn with_custom_parameters<P>(block_parameters: P) -> Self
where
P: Into<crate::shortint::atomic_pattern::AtomicPatternParameters>,

View File

@@ -17,8 +17,10 @@ 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;
pub(in crate::high_level_api) use squashed_noise::{
InnerSquashedNoiseSignedRadixCiphertext, InnerSquashedNoiseSignedRadixCiphertextVersionOwned,
};
expand_pub_use_fhe_type!(
pub use static_{

View File

@@ -7,8 +7,10 @@ use crate::high_level_api::errors::UninitializedNoiseSquashing;
use crate::high_level_api::global_state::{self, with_internal_keys};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::traits::{FheDecrypt, SquashNoise};
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::block_decomposition::{RecomposableFrom, SignExtendable};
use crate::named::Named;
use crate::prelude::Tagged;
use crate::{ClientKey, Device, Tag};
use serde::{Deserializer, Serializer};
use tfhe_versionable::{Unversionize, UnversionizeError, Versionize, VersionizeOwned};
@@ -129,7 +131,8 @@ impl InnerSquashedNoiseSignedRadixCiphertext {
#[derive(Clone, serde::Deserialize, serde::Serialize, Versionize)]
#[versionize(SquashedNoiseFheIntVersions)]
pub struct SquashedNoiseFheInt {
inner: InnerSquashedNoiseSignedRadixCiphertext,
pub(in crate::high_level_api) inner: InnerSquashedNoiseSignedRadixCiphertext,
pub(in crate::high_level_api) state: SquashedNoiseCiphertextState,
tag: Tag,
}
@@ -138,6 +141,14 @@ impl Named for SquashedNoiseFheInt {
}
impl SquashedNoiseFheInt {
pub(in crate::high_level_api) fn new(
inner: InnerSquashedNoiseSignedRadixCiphertext,
state: SquashedNoiseCiphertextState,
tag: Tag,
) -> Self {
Self { inner, state, tag }
}
pub fn underlying_squashed_noise_ciphertext(
&self,
) -> MaybeCloned<'_, crate::integer::ciphertext::SquashedNoiseSignedRadixCiphertext> {
@@ -158,20 +169,24 @@ 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?",
)
let noise_squashing_private_key = key.private_noise_squashing_decryption_key(self.state);
noise_squashing_private_key
.decrypt_signed_radix(&self.inner.on_cpu())
.unwrap()
}
}
impl Tagged for SquashedNoiseFheInt {
fn tag(&self) -> &Tag {
&self.tag
}
fn tag_mut(&mut self) -> &mut Tag {
&mut self.tag
}
}
impl<Id: FheIntId> SquashNoise for FheInt<Id> {
type Output = SquashedNoiseFheInt;
@@ -191,6 +206,7 @@ impl<Id: FheIntId> SquashNoise for FheInt<Id> {
&self.ciphertext.on_cpu(),
)?,
),
state: SquashedNoiseCiphertextState::Normal,
tag: server_key.tag.clone(),
})
}
@@ -213,6 +229,7 @@ impl<Id: FheIntId> SquashNoise for FheInt<Id> {
cuda_squashed_ct.to_squashed_noise_signed_radix_ciphertext(streams);
Ok(SquashedNoiseFheInt {
inner: InnerSquashedNoiseSignedRadixCiphertext::Cpu(cpu_squashed_ct),
state: SquashedNoiseCiphertextState::Normal,
tag: cuda_key.tag.clone(),
})
}

View File

@@ -22,7 +22,9 @@ 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;
pub(in crate::high_level_api) use squashed_noise::{
InnerSquashedNoiseRadixCiphertext, InnerSquashedNoiseRadixCiphertextVersionOwned,
};
mod base;
mod compressed;

View File

@@ -7,7 +7,8 @@ use crate::high_level_api::details::MaybeCloned;
use crate::high_level_api::errors::UninitializedNoiseSquashing;
use crate::high_level_api::global_state::{self, with_internal_keys};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::traits::{FheDecrypt, SquashNoise};
use crate::high_level_api::traits::{FheDecrypt, SquashNoise, Tagged};
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::block_decomposition::RecomposableFrom;
use crate::named::Named;
use crate::{ClientKey, Device, Tag};
@@ -124,7 +125,8 @@ impl InnerSquashedNoiseRadixCiphertext {
#[derive(Clone, serde::Deserialize, serde::Serialize, Versionize)]
#[versionize(SquashedNoiseFheUintVersions)]
pub struct SquashedNoiseFheUint {
inner: InnerSquashedNoiseRadixCiphertext,
pub(in crate::high_level_api) inner: InnerSquashedNoiseRadixCiphertext,
pub(in crate::high_level_api) state: SquashedNoiseCiphertextState,
tag: Tag,
}
@@ -133,6 +135,14 @@ impl Named for SquashedNoiseFheUint {
}
impl SquashedNoiseFheUint {
pub(in crate::high_level_api) fn new(
inner: InnerSquashedNoiseRadixCiphertext,
state: SquashedNoiseCiphertextState,
tag: Tag,
) -> Self {
Self { inner, state, tag }
}
pub fn underlying_squashed_noise_ciphertext(
&self,
) -> MaybeCloned<'_, crate::integer::ciphertext::SquashedNoiseRadixCiphertext> {
@@ -153,20 +163,23 @@ 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?",
)
let noise_squashing_private_key = key.private_noise_squashing_decryption_key(self.state);
noise_squashing_private_key
.decrypt_radix(&self.inner.on_cpu())
.unwrap()
}
}
impl Tagged for SquashedNoiseFheUint {
fn tag(&self) -> &Tag {
&self.tag
}
fn tag_mut(&mut self) -> &mut Tag {
&mut self.tag
}
}
impl<Id: FheUintId> SquashNoise for FheUint<Id> {
type Output = SquashedNoiseFheUint;
@@ -186,6 +199,7 @@ impl<Id: FheUintId> SquashNoise for FheUint<Id> {
&self.ciphertext.on_cpu(),
)?,
),
state: SquashedNoiseCiphertextState::Normal,
tag: server_key.tag.clone(),
})
}
@@ -207,6 +221,7 @@ impl<Id: FheUintId> SquashNoise for FheUint<Id> {
let squashed_ct = cuda_squashed_ct.to_squashed_noise_radix_ciphertext(streams);
Ok(SquashedNoiseFheUint {
inner: InnerSquashedNoiseRadixCiphertext::Cpu(squashed_ct),
state: SquashedNoiseCiphertextState::Normal,
tag: cuda_key.tag.clone(),
})
}

View File

@@ -6,8 +6,10 @@ use super::{CompressedServerKey, ServerKey};
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::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::ciphertext::NoiseSquashingCompressionPrivateKey;
use crate::integer::compression_keys::CompressionPrivateKeys;
use crate::integer::noise_squashing::NoiseSquashingPrivateKey;
use crate::integer::noise_squashing::{NoiseSquashingPrivateKey, NoiseSquashingPrivateKeyView};
use crate::named::Named;
use crate::prelude::Tagged;
use crate::shortint::MessageModulus;
@@ -82,10 +84,11 @@ impl ClientKey {
Option<CompactPrivateKey>,
Option<CompressionPrivateKeys>,
Option<NoiseSquashingPrivateKey>,
Option<NoiseSquashingCompressionPrivateKey>,
Tag,
) {
let (cks, cpk, cppk, nsk) = self.key.into_raw_parts();
(cks, cpk, cppk, nsk, self.tag)
let (cks, cpk, cppk, nsk, nscpk) = self.key.into_raw_parts();
(cks, cpk, cppk, nsk, nscpk, self.tag)
}
pub fn from_raw_parts(
@@ -96,6 +99,7 @@ impl ClientKey {
)>,
compression_key: Option<CompressionPrivateKeys>,
noise_squashing_key: Option<NoiseSquashingPrivateKey>,
noise_squashing_compression_key: Option<NoiseSquashingCompressionPrivateKey>,
tag: Tag,
) -> Self {
Self {
@@ -104,6 +108,7 @@ impl ClientKey {
dedicated_compact_private_key,
compression_key,
noise_squashing_key,
noise_squashing_compression_key,
),
tag,
}
@@ -125,6 +130,38 @@ impl ClientKey {
pub(crate) fn message_modulus(&self) -> MessageModulus {
self.key.block_parameters().message_modulus()
}
/// Returns a view of the private key to be used to decrypt a squashed noise
/// ciphertext depending on its state
///
/// # Panics
///
/// Panics if the key supposed to be used for the given state cannot be found
pub(crate) fn private_noise_squashing_decryption_key(
&self,
state: SquashedNoiseCiphertextState,
) -> NoiseSquashingPrivateKeyView<'_> {
match state {
SquashedNoiseCiphertextState::Normal => self
.key
.noise_squashing_private_key
.as_ref()
.map(|key| key.as_view())
.expect(
"No noise squashing private key in your ClientKey, cannot decrypt. \
Did you call `enable_noise_squashing` when creating your Config?",
),
SquashedNoiseCiphertextState::PostDecompression => self
.key
.noise_squashing_compression_private_key
.as_ref()
.map(|key| key.private_key_view())
.expect(
"No noise squashing private key in your ClientKey, cannot decrypt. \
Did you call `enable_noise_squashing_compression` when creating your Config?",
),
}
}
}
impl Tagged for ClientKey {

View File

@@ -2,6 +2,10 @@ use crate::conformance::ParameterSetConformant;
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::prelude::{DefaultRandomGenerator, LweKeyswitchKeyConformanceParams};
use crate::high_level_api::backward_compatibility::keys::*;
use crate::integer::ciphertext::{
CompressedNoiseSquashingCompressionKey, NoiseSquashingCompressionKey,
NoiseSquashingCompressionPrivateKey,
};
use crate::integer::compression_keys::{
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, CompressionPrivateKeys,
DecompressionKey,
@@ -15,7 +19,8 @@ use crate::shortint::atomic_pattern::AtomicPatternParameters;
use crate::shortint::key_switching_key::KeySwitchingKeyConformanceParams;
use crate::shortint::parameters::list_compression::CompressionParameters;
use crate::shortint::parameters::{
CompactPublicKeyEncryptionParameters, NoiseSquashingParameters, ShortintKeySwitchingParameters,
CompactPublicKeyEncryptionParameters, NoiseSquashingCompressionParameters,
NoiseSquashingParameters, ShortintKeySwitchingParameters,
};
use crate::shortint::{EncryptionKeyChoice, MessageModulus};
use crate::{Config, Error};
@@ -33,6 +38,7 @@ pub(crate) struct IntegerConfig {
)>,
pub(crate) compression_parameters: Option<CompressionParameters>,
pub(crate) noise_squashing_parameters: Option<NoiseSquashingParameters>,
pub(crate) noise_squashing_compression_parameters: Option<NoiseSquashingCompressionParameters>,
}
impl IntegerConfig {
@@ -44,6 +50,7 @@ impl IntegerConfig {
dedicated_compact_public_key_parameters: None,
compression_parameters: None,
noise_squashing_parameters: None,
noise_squashing_compression_parameters: None,
}
}
@@ -58,6 +65,17 @@ impl IntegerConfig {
self.noise_squashing_parameters = Some(compression_parameters);
}
pub(crate) fn enable_noise_squashing_compression(
&mut self,
compression_parameters: NoiseSquashingCompressionParameters,
) {
assert_ne!(
self.noise_squashing_parameters, None,
"Noise squashing must be enabled first"
);
self.noise_squashing_compression_parameters = Some(compression_parameters);
}
pub(crate) fn public_key_encryption_parameters(
&self,
) -> Result<crate::shortint::parameters::CompactPublicKeyEncryptionParameters, crate::Error>
@@ -84,6 +102,7 @@ impl Default for IntegerConfig {
dedicated_compact_public_key_parameters: None,
compression_parameters: None,
noise_squashing_parameters: None,
noise_squashing_compression_parameters: None,
}
}
}
@@ -100,6 +119,7 @@ pub(crate) struct IntegerClientKey {
pub(crate) dedicated_compact_private_key: Option<CompactPrivateKey>,
pub(crate) compression_key: Option<CompressionPrivateKeys>,
pub(crate) noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
pub(crate) noise_squashing_compression_private_key: Option<NoiseSquashingCompressionPrivateKey>,
}
impl IntegerClientKey {
@@ -126,11 +146,16 @@ impl IntegerClientKey {
.noise_squashing_parameters
.map(NoiseSquashingPrivateKey::new);
let noise_squashing_compression_private_key = config
.noise_squashing_compression_parameters
.map(NoiseSquashingCompressionPrivateKey::new);
Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
}
}
@@ -142,18 +167,21 @@ impl IntegerClientKey {
Option<CompactPrivateKey>,
Option<CompressionPrivateKeys>,
Option<NoiseSquashingPrivateKey>,
Option<NoiseSquashingCompressionPrivateKey>,
) {
let Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
} = self;
(
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
)
}
@@ -167,6 +195,7 @@ impl IntegerClientKey {
dedicated_compact_private_key: Option<CompactPrivateKey>,
compression_key: Option<CompressionPrivateKeys>,
noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
noise_squashing_compression_private_key: Option<NoiseSquashingCompressionPrivateKey>,
) -> Self {
let shortint_cks: &crate::shortint::ClientKey = key.as_ref();
@@ -194,6 +223,7 @@ impl IntegerClientKey {
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
}
}
@@ -223,11 +253,16 @@ impl From<IntegerConfig> for IntegerClientKey {
.noise_squashing_parameters
.map(NoiseSquashingPrivateKey::new);
let noise_squashing_compression_private_key = config
.noise_squashing_compression_parameters
.map(NoiseSquashingCompressionPrivateKey::new);
Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
}
}
}
@@ -245,6 +280,7 @@ pub struct IntegerServerKey {
pub(crate) compression_key: Option<CompressionKey>,
pub(crate) decompression_key: Option<DecompressionKey>,
pub(crate) noise_squashing_key: Option<NoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
}
impl IntegerServerKey {
@@ -277,10 +313,22 @@ impl IntegerServerKey {
build_helper.into()
});
let noise_squashing_key = client_key
.noise_squashing_private_key
.as_ref()
.map(|key| NoiseSquashingKey::new(cks, key));
let (noise_squashing_key, noise_squashing_compression_key) =
client_key.noise_squashing_private_key.as_ref().map_or_else(
|| (None, None),
|noise_squashing_private_key| {
let noise_squashing_key =
NoiseSquashingKey::new(cks, noise_squashing_private_key);
let noise_squashing_compression_key = client_key
.noise_squashing_compression_private_key
.as_ref()
.map(|comp_private_key| {
noise_squashing_private_key
.new_noise_squashing_compression_key(comp_private_key)
});
(Some(noise_squashing_key), noise_squashing_compression_key)
},
);
Self {
key: base_integer_key,
@@ -288,6 +336,7 @@ impl IntegerServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
}
}
@@ -335,6 +384,7 @@ pub struct IntegerCompressedServerKey {
pub(crate) compression_key: Option<CompressedCompressionKey>,
pub(crate) decompression_key: Option<CompressedDecompressionKey>,
pub(crate) noise_squashing_key: Option<CompressedNoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
}
impl IntegerCompressedServerKey {
@@ -370,13 +420,22 @@ 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)
});
let (noise_squashing_key, noise_squashing_compression_key) = client_key
.noise_squashing_private_key
.as_ref()
.map_or((None, None), |noise_squashing_private_key| {
let noise_squashing_key =
noise_squashing_private_key.new_compressed_noise_squashing_key(&client_key.key);
let noise_squashing_compression_key = client_key
.noise_squashing_compression_private_key
.as_ref()
.map(|comp_private_key| {
noise_squashing_private_key
.new_compressed_noise_squashing_compression_key(comp_private_key)
});
(Some(noise_squashing_key), noise_squashing_compression_key)
});
Self {
key,
@@ -384,6 +443,7 @@ impl IntegerCompressedServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
}
}
@@ -411,6 +471,7 @@ impl IntegerCompressedServerKey {
compression_key: Option<CompressedCompressionKey>,
decompression_key: Option<CompressedDecompressionKey>,
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
) -> Self {
Self {
key,
@@ -418,6 +479,7 @@ impl IntegerCompressedServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
}
}
@@ -437,6 +499,11 @@ impl IntegerCompressedServerKey {
.as_ref()
.map(CompressedNoiseSquashingKey::decompress);
let noise_squashing_compression_key = self
.noise_squashing_compression_key
.as_ref()
.map(CompressedNoiseSquashingCompressionKey::decompress);
IntegerServerKey {
key: self.key.decompress(),
cpk_key_switching_key_material: self.cpk_key_switching_key_material.as_ref().map(
@@ -445,6 +512,7 @@ impl IntegerCompressedServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
}
}
}
@@ -533,6 +601,7 @@ pub struct IntegerServerKeyConformanceParams {
)>,
pub compression_param: Option<CompressionParameters>,
pub noise_squashing_param: Option<NoiseSquashingParameters>,
pub noise_squashing_compression_param: Option<NoiseSquashingCompressionParameters>,
}
impl<C: Into<Config>> From<C> for IntegerServerKeyConformanceParams {
@@ -543,6 +612,7 @@ impl<C: Into<Config>> From<C> for IntegerServerKeyConformanceParams {
cpk_param: config.inner.dedicated_compact_public_key_parameters,
compression_param: config.inner.compression_parameters,
noise_squashing_param: config.inner.noise_squashing_parameters,
noise_squashing_compression_param: config.inner.noise_squashing_compression_parameters,
}
}
}
@@ -602,6 +672,7 @@ impl ParameterSetConformant for IntegerServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
} = self;
let cpk_key_switching_key_material_is_ok = match (
@@ -652,10 +723,32 @@ impl ParameterSetConformant for IntegerServerKey {
_ => return false,
};
let noise_squashing_compression_key_is_ok = match (
parameter_set.noise_squashing_param.as_ref(),
parameter_set.noise_squashing_compression_param.as_ref(),
noise_squashing_compression_key.as_ref(),
) {
(None, None, None) | (Some(_), None, None) => true,
(
Some(noise_squashing_parameters),
Some(noise_squashing_compression_param),
Some(noise_squashing_compression_key),
) => {
let noise_squashing_compression_param = (
*noise_squashing_parameters,
*noise_squashing_compression_param,
)
.into();
noise_squashing_compression_key.is_conformant(&noise_squashing_compression_param)
}
_ => return false,
};
key.is_conformant(&parameter_set.sk_param)
&& cpk_key_switching_key_material_is_ok
&& compression_is_ok
&& noise_squashing_key_is_ok
&& noise_squashing_compression_key_is_ok
}
}
@@ -669,6 +762,7 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
} = self;
let cpk_key_switching_key_material_is_ok = match (
@@ -719,10 +813,32 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
_ => return false,
};
let noise_squashing_compression_key_is_ok = match (
parameter_set.noise_squashing_param.as_ref(),
parameter_set.noise_squashing_compression_param.as_ref(),
noise_squashing_compression_key.as_ref(),
) {
(None, None, None) | (Some(_), None, None) => true,
(
Some(noise_squashing_parameters),
Some(noise_squashing_compression_param),
Some(noise_squashing_compression_key),
) => {
let noise_squashing_compression_param = (
*noise_squashing_parameters,
*noise_squashing_compression_param,
)
.into();
noise_squashing_compression_key.is_conformant(&noise_squashing_compression_param)
}
_ => return false,
};
key.is_conformant(&parameter_set.sk_param)
&& cpk_key_switching_key_material_is_ok
&& compression_is_ok
&& noise_squashing_key_is_ok
&& noise_squashing_compression_key_is_ok
}
}

View File

@@ -1,9 +1,3 @@
#[cfg(feature = "hpu")]
pub(in crate::high_level_api) use hpu::HpuTaggedDevice;
#[cfg(feature = "hpu")]
use tfhe_hpu_backend::prelude::HpuDevice;
use tfhe_versionable::Versionize;
use super::ClientKey;
use crate::backward_compatibility::keys::{CompressedServerKeyVersions, ServerKeyVersions};
use crate::conformance::ParameterSetConformant;
@@ -14,6 +8,9 @@ use crate::core_crypto::gpu::{synchronize_devices, CudaStreams};
#[cfg(feature = "gpu")]
use crate::high_level_api::keys::inner::IntegerCudaServerKey;
use crate::high_level_api::keys::{IntegerCompressedServerKey, IntegerServerKey};
use crate::integer::ciphertext::{
CompressedNoiseSquashingCompressionKey, NoiseSquashingCompressionKey,
};
use crate::integer::compression_keys::{
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, DecompressionKey,
};
@@ -25,7 +22,12 @@ use crate::shortint::MessageModulus;
#[cfg(feature = "gpu")]
use crate::GpuIndex;
use crate::{Device, Tag};
#[cfg(feature = "hpu")]
pub(in crate::high_level_api) use hpu::HpuTaggedDevice;
use std::sync::Arc;
#[cfg(feature = "hpu")]
use tfhe_hpu_backend::prelude::HpuDevice;
use tfhe_versionable::Versionize;
/// Key of the server
///
@@ -53,6 +55,7 @@ impl ServerKey {
}
}
#[allow(clippy::type_complexity)]
pub fn into_raw_parts(
self,
) -> (
@@ -61,6 +64,7 @@ impl ServerKey {
Option<CompressionKey>,
Option<DecompressionKey>,
Option<NoiseSquashingKey>,
Option<NoiseSquashingCompressionKey>,
Tag,
) {
let IntegerServerKey {
@@ -69,6 +73,7 @@ impl ServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
} = (*self.key).clone();
(
@@ -77,6 +82,7 @@ impl ServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
self.tag,
)
}
@@ -89,6 +95,7 @@ impl ServerKey {
compression_key: Option<CompressionKey>,
decompression_key: Option<DecompressionKey>,
noise_squashing_key: Option<NoiseSquashingKey>,
noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
tag: Tag,
) -> Self {
Self {
@@ -98,6 +105,7 @@ impl ServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
}),
tag,
}
@@ -258,6 +266,7 @@ impl CompressedServerKey {
compression_key: Option<CompressedCompressionKey>,
decompression_key: Option<CompressedDecompressionKey>,
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
tag: Tag,
) -> Self {
Self {
@@ -267,6 +276,7 @@ impl CompressedServerKey {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
),
tag,
}
@@ -546,6 +556,7 @@ mod test {
use crate::prelude::ParameterSetConformant;
use crate::shortint::parameters::{
COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
NOISE_SQUASHING_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,
@@ -631,10 +642,14 @@ mod test {
let noise_squashing_params =
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_compression_params =
NOISE_SQUASHING_COMP_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)
.enable_noise_squashing_compression(noise_squashing_compression_params)
.build();
let ck = ClientKey::generate(config);
@@ -676,6 +691,7 @@ mod test {
cpk_param: None,
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -704,6 +720,7 @@ mod test {
cpk_param: Some((cpk_params, casting_params)),
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -786,10 +803,14 @@ mod test {
let noise_squashing_params =
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_compression_params =
NOISE_SQUASHING_COMP_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)
.enable_noise_squashing_compression(noise_squashing_compression_params)
.build();
let ck = ClientKey::generate(config);
@@ -831,6 +852,7 @@ mod test {
cpk_param: None,
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -859,6 +881,7 @@ mod test {
cpk_param: Some((cpk_params, casting_params)),
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
};
assert!(!sk.is_conformant(&conformance_params));

View File

@@ -48,7 +48,8 @@ macro_rules! export_concrete_array_types {
pub use crate::core_crypto::commons::math::random::Seed;
pub use crate::integer::server_key::MatchValues;
use crate::{error, Error};
use crate::{error, Error, Versionize};
use backward_compatibility::compressed_ciphertext_list::SquashedNoiseCiphertextStateVersions;
pub use config::{Config, ConfigBuilder};
#[cfg(feature = "gpu")]
pub use global_state::CudaGpuChoice;
@@ -124,6 +125,10 @@ pub use compact_list::{
pub use compressed_ciphertext_list::{
CompressedCiphertextList, CompressedCiphertextListBuilder, HlCompressible, HlExpandable,
};
pub use compressed_noise_squashed_ciphertext_list::{
CompressedSquashedNoiseCiphertextList, CompressedSquashedNoiseCiphertextListBuilder,
HlSquashedNoiseCompressible, HlSquashedNoiseExpandable,
};
#[cfg(feature = "strings")]
pub use strings::ascii::{EncryptableString, FheAsciiString, FheStringIsEmpty, FheStringLen};
pub use tag::Tag;
@@ -152,6 +157,7 @@ mod tag;
#[cfg(feature = "gpu")]
pub use crate::core_crypto::gpu::vec::GpuIndex;
mod compressed_noise_squashed_ciphertext_list;
pub(in crate::high_level_api) mod details;
/// The tfhe prelude.
pub mod prelude;
@@ -271,3 +277,10 @@ impl TryFrom<i32> for FheTypes {
Self::from_repr(value).ok_or_else(|| error!("Invalid value for FheTypes: {}", value))
}
}
#[derive(serde::Serialize, serde::Deserialize, Copy, Clone, Versionize)]
#[versionize(SquashedNoiseCiphertextStateVersions)]
pub(crate) enum SquashedNoiseCiphertextState {
Normal,
PostDecompression,
}

View File

@@ -198,7 +198,7 @@ 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, None, Tag::default());
ClientKey::from_raw_parts(shortint_key.into(), None, None, None, None, Tag::default());
let sks = ServerKey::new(&client_key);
let clear_a = 1344u32;

View File

@@ -828,8 +828,8 @@ mod tests {
// We need the private compression key to be common between GPU and CPU
// for the rest of the test to work. This is the only way to do it
// until a more convenient API is added
let (cks, pk, _, cnsk, tag) = ck.into_raw_parts();
let ck = ClientKey::from_raw_parts(cks, pk, common_cck, cnsk, tag);
let (cks, pk, _, nsk, cnsk, tag) = ck.into_raw_parts();
let ck = ClientKey::from_raw_parts(cks, pk, common_cck, nsk, cnsk, tag);
let sk = CompressedServerKey::new(&ck);
assert_eq!(sk.tag().as_u64(), 0);

View File

@@ -2,6 +2,7 @@ use super::{
DataKind, SquashedNoiseBooleanBlock, SquashedNoiseRadixCiphertext,
SquashedNoiseSignedRadixCiphertext,
};
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::commons::math::random::{Deserialize, Serialize};
use crate::integer::backward_compatibility::list_compression::{
CompressedNoiseSquashingCompressionKeyVersions, CompressedSquashedNoiseCiphertextListVersions,
@@ -16,6 +17,7 @@ use crate::shortint::ciphertext::{
use crate::shortint::list_compression::{
CompressedNoiseSquashingCompressionKey as ShortintCompressedNoiseSquashingCompressionKey,
NoiseSquashingCompressionKey as ShortintNoiseSquashingCompressionKey,
NoiseSquashingCompressionKeyConformanceParams,
NoiseSquashingCompressionPrivateKey as ShortintNoiseSquashingCompressionPrivateKey,
};
use crate::shortint::parameters::NoiseSquashingCompressionParameters;
@@ -53,6 +55,15 @@ pub struct CompressedNoiseSquashingCompressionKey {
pub(crate) key: ShortintCompressedNoiseSquashingCompressionKey,
}
impl ParameterSetConformant for CompressedNoiseSquashingCompressionKey {
type ParameterSet = NoiseSquashingCompressionKeyConformanceParams;
fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool {
let Self { key } = self;
key.is_conformant(parameter_set)
}
}
impl CompressedNoiseSquashingCompressionKey {
pub fn decompress(&self) -> NoiseSquashingCompressionKey {
let key = self.key.decompress();
@@ -74,6 +85,15 @@ impl Named for NoiseSquashingCompressionKey {
const NAME: &'static str = "integer::NoiseSquashingCompressionKey";
}
impl ParameterSetConformant for NoiseSquashingCompressionKey {
type ParameterSet = NoiseSquashingCompressionKeyConformanceParams;
fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool {
let Self { key } = self;
key.is_conformant(parameter_set)
}
}
impl NoiseSquashingPrivateKey {
pub fn new_noise_squashing_compression_key(
&self,
@@ -102,8 +122,8 @@ impl NoiseSquashingPrivateKey {
#[derive(Clone, Debug, Serialize, Deserialize, Versionize)]
#[versionize(CompressedSquashedNoiseCiphertextListVersions)]
pub struct CompressedSquashedNoiseCiphertextList {
list: ShortintCompressedSquashedNoiseCiphertextList,
info: Vec<DataKind>,
pub(crate) list: ShortintCompressedSquashedNoiseCiphertextList,
pub(crate) info: Vec<DataKind>,
}
impl Named for CompressedSquashedNoiseCiphertextList {
@@ -175,6 +195,10 @@ mod sealed {
impl Sealed for SquashedNoiseRadixCiphertext {}
impl Sealed for SquashedNoiseSignedRadixCiphertext {}
impl Sealed for SquashedNoiseBooleanBlock {}
impl Sealed for crate::SquashedNoiseFheBool {}
impl Sealed for crate::SquashedNoiseFheUint {}
impl Sealed for crate::SquashedNoiseFheInt {}
}
pub trait SquashedNoiseCompressible: sealed::Sealed {

View File

@@ -9,5 +9,6 @@ pub use compressed_server_keys::{
};
pub use private_key::{CompressionPrivateKeys, NoiseSquashingCompressionPrivateKey};
pub use server_keys::{
CompressionKey, CompressionKeyConformanceParams, DecompressionKey, NoiseSquashingCompressionKey,
CompressionKey, CompressionKeyConformanceParams, DecompressionKey,
NoiseSquashingCompressionKey, NoiseSquashingCompressionKeyConformanceParams,
};