feat: add ciphertexts re-randomization

This commit is contained in:
Arthur Meyre
2025-08-13 16:30:47 +02:00
committed by Nicolas Sarlin
parent 9f54777ee1
commit d5e5902f61
62 changed files with 4087 additions and 527 deletions

View File

@@ -24,7 +24,7 @@ pub struct XofSeed {
}
impl XofSeed {
const DOMAIN_SEP_LEN: usize = 8;
pub const DOMAIN_SEP_LEN: usize = 8;
// Creates a new seed of 128 bits
pub fn new_u128(seed: u128, domain_separator: [u8; Self::DOMAIN_SEP_LEN]) -> Self {

View File

@@ -70,8 +70,10 @@ aligned-vec = { workspace = true, features = ["default", "serde"] }
dyn-stack = { workspace = true, features = ["default"] }
paste = "1.0.7"
fs2 = { version = "0.4.3", optional = true }
# Used for OPRF in shortint
# Used for OPRF in shortint and rerand
sha3 = { version = "0.10", optional = true }
blake3 = { version = "1.8", optional = true }
itertools = { workspace = true }
rand_core = { version = "0.6.4", features = ["std"] }
strum = { version = "0.27", features = ["derive"], optional = true }
@@ -93,7 +95,7 @@ tfhe-hpu-backend = { version = "0.2", path = "../backends/tfhe-hpu-backend", opt
[features]
boolean = []
shortint = ["dep:sha3"]
shortint = ["dep:sha3", "dep:blake3"]
integer = ["shortint", "dep:strum"]
strings = ["integer"]
internal-keycache = ["dep:fs2"]

View File

@@ -3,6 +3,7 @@
use crate::core_crypto::commons::math::random::{
ByteRandomGenerator, RandomGenerable, RandomGenerator, Seed, Seeder, Uniform,
};
use tfhe_csprng::seeders::SeedKind;
/// Seeder backed by a CSPRNG
///
@@ -37,7 +38,7 @@ pub struct DeterministicSeeder<G: ByteRandomGenerator> {
}
impl<G: ByteRandomGenerator> DeterministicSeeder<G> {
pub fn new(seed: Seed) -> Self {
pub fn new(seed: impl Into<SeedKind>) -> Self {
Self {
generator: RandomGenerator::new(seed),
}

View File

@@ -15,6 +15,7 @@ use crate::high_level_api::array::traits::HasClear;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::{FheIntId, FheUintId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::{FheBool, FheId, FheInt, FheUint, Tag};
use std::ops::{AddAssign, Mul, RangeBounds};
use traits::{ArrayBackend, BackendDataContainer, BackendDataContainerMut};
@@ -364,7 +365,11 @@ pub fn fhe_uint_array_eq<Id: FheUintId>(lhs: &[FheUint<Id>], rhs: &[FheUint<Id>]
let result = cpu_key
.pbs_key()
.all_eq_slices_parallelized(&tmp_lhs, &tmp_rhs);
FheBool::new(result, cpu_key.tag.clone())
FheBool::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(gpu_key) => {
@@ -379,7 +384,11 @@ pub fn fhe_uint_array_eq<Id: FheUintId>(lhs: &[FheUint<Id>], rhs: &[FheUint<Id>]
.collect::<Vec<_>>();
let result = gpu_key.key.key.all_eq_slices(&tmp_lhs, &tmp_rhs, streams);
FheBool::new(result, gpu_key.tag.clone())
FheBool::new(
result,
gpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -406,7 +415,11 @@ pub fn fhe_uint_array_contains_sub_slice<Id: FheUintId>(
let result = cpu_key
.pbs_key()
.contains_sub_slice_parallelized(&tmp_lhs, &tmp_pattern);
FheBool::new(result, cpu_key.tag.clone())
FheBool::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(gpu_key) => {
@@ -424,7 +437,11 @@ pub fn fhe_uint_array_contains_sub_slice<Id: FheUintId>(
.key
.key
.contains_sub_slice(&tmp_lhs, &tmp_pattern, streams);
FheBool::new(result, gpu_key.tag.clone())
FheBool::new(
result,
gpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -512,7 +529,11 @@ where
/// ```
fn dot_product(bools: &[FheBool], clears: &[Clear]) -> Self {
let (blocks, tag) = fhe_bool_dot_product(bools, clears, Id::num_bits() as u32);
Self::new(crate::integer::RadixCiphertext::from(blocks), tag)
Self::new(
crate::integer::RadixCiphertext::from(blocks),
tag,
ReRandomizationMetadata::default(),
)
}
}
@@ -552,6 +573,10 @@ where
/// ```
fn dot_product(bools: &[FheBool], clears: &[Clear]) -> Self {
let (blocks, tag) = fhe_bool_dot_product(bools, clears, Id::num_bits() as u32);
Self::new(crate::integer::SignedRadixCiphertext::from(blocks), tag)
Self::new(
crate::integer::SignedRadixCiphertext::from(blocks),
tag,
ReRandomizationMetadata::default(),
)
}
}

View File

@@ -5,6 +5,7 @@ use crate::high_level_api::booleans::{
InnerBoolean, InnerBooleanVersionOwned, InnerCompressedFheBool, InnerSquashedNoiseBoolean,
InnerSquashedNoiseBooleanVersionOwned, SquashedNoiseFheBool,
};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::{CompressedFheBool, FheBool, Tag};
use std::convert::Infallible;
@@ -20,21 +21,42 @@ pub struct FheBoolV0 {
pub(in crate::high_level_api) ciphertext: InnerBoolean,
}
impl Upgrade<FheBool> for FheBoolV0 {
impl Upgrade<FheBoolV1> for FheBoolV0 {
type Error = Infallible;
fn upgrade(self) -> Result<FheBool, Self::Error> {
Ok(FheBool {
fn upgrade(self) -> Result<FheBoolV1, Self::Error> {
Ok(FheBoolV1 {
ciphertext: self.ciphertext,
tag: Tag::default(),
})
}
}
#[derive(Version)]
pub struct FheBoolV1 {
pub(in crate::high_level_api) ciphertext: InnerBoolean,
pub(crate) tag: Tag,
}
impl Upgrade<FheBool> for FheBoolV1 {
type Error = Infallible;
fn upgrade(self) -> Result<FheBool, Self::Error> {
let Self { ciphertext, tag } = self;
Ok(FheBool::new(
ciphertext,
tag,
ReRandomizationMetadata::default(),
))
}
}
#[derive(VersionsDispatch)]
pub enum FheBoolVersions {
V0(FheBoolV0),
V1(FheBool),
V1(FheBoolV1),
V2(FheBool),
}
#[derive(VersionsDispatch)]

View File

@@ -1,3 +1,5 @@
use crate::high_level_api::compressed_ciphertext_list::InnerCompressedCiphertextList;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::SquashedNoiseCiphertextState;
use std::convert::Infallible;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
@@ -30,13 +32,37 @@ pub struct CompressedCiphertextListV1 {
tag: Tag,
}
impl Upgrade<CompressedCiphertextList> for CompressedCiphertextListV1 {
impl Upgrade<CompressedCiphertextListV2> for CompressedCiphertextListV1 {
type Error = Infallible;
fn upgrade(self) -> Result<CompressedCiphertextListV2, Self::Error> {
Ok(CompressedCiphertextListV2 {
inner: InnerCompressedCiphertextList::Cpu(self.inner),
tag: self.tag,
})
}
}
#[derive(Version)]
pub struct CompressedCiphertextListV2 {
pub(in crate::high_level_api) inner: InnerCompressedCiphertextList,
pub(in crate::high_level_api) tag: Tag,
}
impl Upgrade<CompressedCiphertextList> for CompressedCiphertextListV2 {
type Error = Infallible;
fn upgrade(self) -> Result<CompressedCiphertextList, Self::Error> {
let Self { inner, tag } = self;
// Empty metadata for older lists which did not store any
let re_randomization_metadata =
vec![ReRandomizationMetadata::default(); inner.info().len()];
Ok(CompressedCiphertextList {
inner: crate::high_level_api::compressed_ciphertext_list::InnerCompressedCiphertextList::Cpu(self.inner),
tag: self.tag,
inner,
tag,
re_randomization_metadata,
})
}
}
@@ -45,7 +71,8 @@ impl Upgrade<CompressedCiphertextList> for CompressedCiphertextListV1 {
pub enum CompressedCiphertextListVersions {
V0(CompressedCiphertextListV0),
V1(CompressedCiphertextListV1),
V2(CompressedCiphertextList),
V2(CompressedCiphertextListV2),
V3(CompressedCiphertextList),
}
#[derive(VersionsDispatch)]

View File

@@ -0,0 +1,7 @@
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use tfhe_versionable::VersionsDispatch;
#[derive(VersionsDispatch)]
pub enum ReRandomizationMetadataVersions {
V0(ReRandomizationMetadata),
}

View File

@@ -9,6 +9,7 @@ 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::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::backward_compatibility::ciphertext::{
CompressedModulusSwitchedRadixCiphertextTFHE06,
@@ -131,11 +132,11 @@ pub struct FheIntV0<Id: FheIntId> {
pub(in crate::high_level_api) id: Id,
}
impl<Id: FheIntId> Upgrade<FheInt<Id>> for FheIntV0<Id> {
impl<Id: FheIntId> Upgrade<FheIntV1<Id>> for FheIntV0<Id> {
type Error = Infallible;
fn upgrade(self) -> Result<FheInt<Id>, Self::Error> {
Ok(FheInt {
fn upgrade(self) -> Result<FheIntV1<Id>, Self::Error> {
Ok(FheIntV1 {
ciphertext: self.ciphertext,
id: self.id,
tag: Tag::default(),
@@ -143,10 +144,37 @@ impl<Id: FheIntId> Upgrade<FheInt<Id>> for FheIntV0<Id> {
}
}
#[derive(Version)]
pub struct FheIntV1<Id: FheIntId> {
pub(in crate::high_level_api) ciphertext: SignedRadixCiphertext,
pub(in crate::high_level_api) id: Id,
pub(crate) tag: Tag,
}
impl<Id: FheIntId> Upgrade<FheInt<Id>> for FheIntV1<Id> {
type Error = Infallible;
fn upgrade(self) -> Result<FheInt<Id>, Self::Error> {
let Self {
ciphertext,
id,
tag,
} = self;
Ok(FheInt {
ciphertext,
id,
tag,
re_randomization_metadata: ReRandomizationMetadata::default(),
})
}
}
#[derive(VersionsDispatch)]
pub enum FheIntVersions<Id: FheIntId> {
V0(FheIntV0<Id>),
V1(FheInt<Id>),
V1(FheIntV1<Id>),
V2(FheInt<Id>),
}
#[derive(Version)]
@@ -182,11 +210,11 @@ pub struct FheUintV0<Id: FheUintId> {
pub(in crate::high_level_api) id: Id,
}
impl<Id: FheUintId> Upgrade<FheUint<Id>> for FheUintV0<Id> {
impl<Id: FheUintId> Upgrade<FheUintV1<Id>> for FheUintV0<Id> {
type Error = Infallible;
fn upgrade(self) -> Result<FheUint<Id>, Self::Error> {
Ok(FheUint {
fn upgrade(self) -> Result<FheUintV1<Id>, Self::Error> {
Ok(FheUintV1 {
ciphertext: self.ciphertext,
id: self.id,
tag: Tag::default(),
@@ -194,10 +222,37 @@ impl<Id: FheUintId> Upgrade<FheUint<Id>> for FheUintV0<Id> {
}
}
#[derive(Version)]
pub struct FheUintV1<Id: FheUintId> {
pub(in crate::high_level_api) ciphertext: UnsignedRadixCiphertext,
pub(in crate::high_level_api) id: Id,
pub(crate) tag: Tag,
}
impl<Id: FheUintId> Upgrade<FheUint<Id>> for FheUintV1<Id> {
type Error = Infallible;
fn upgrade(self) -> Result<FheUint<Id>, Self::Error> {
let Self {
ciphertext,
id,
tag,
} = self;
Ok(FheUint {
ciphertext,
id,
tag,
re_randomization_metadata: ReRandomizationMetadata::default(),
})
}
}
#[derive(VersionsDispatch)]
pub enum FheUintVersions<Id: FheUintId> {
V0(FheUintV0<Id>),
V1(FheUint<Id>),
V1(FheUintV1<Id>),
V2(FheUint<Id>),
}
#[derive(Version)]

View File

@@ -1,6 +1,11 @@
use crate::high_level_api::keys::*;
use crate::integer::ciphertext::{
CompressedNoiseSquashingCompressionKey, NoiseSquashingCompressionKey,
NoiseSquashingCompressionPrivateKey,
};
use crate::integer::compression_keys::{
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, DecompressionKey,
CompressedCompressionKey, CompressedDecompressionKey, CompressionKey, CompressionPrivateKeys,
DecompressionKey,
};
use crate::integer::noise_squashing::{
CompressedNoiseSquashingKey, NoiseSquashingKey, NoiseSquashingPrivateKey,
@@ -208,10 +213,40 @@ impl Upgrade<IntegerClientKeyV4> for IntegerClientKeyV3 {
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) compression_key: Option<CompressionPrivateKeys>,
pub(crate) noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
}
impl Upgrade<IntegerClientKeyV5> for IntegerClientKeyV4 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerClientKeyV5, Self::Error> {
let Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
} = self;
Ok(IntegerClientKeyV5 {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key: None,
})
}
}
#[derive(Version)]
pub(crate) struct IntegerClientKeyV5 {
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>,
pub(crate) noise_squashing_compression_private_key: Option<NoiseSquashingCompressionPrivateKey>,
}
#[derive(VersionsDispatch)]
#[allow(unused)]
pub(crate) enum IntegerClientKeyVersions {
@@ -220,10 +255,11 @@ pub(crate) enum IntegerClientKeyVersions {
V2(IntegerClientKeyV2),
V3(IntegerClientKeyV3),
V4(IntegerClientKeyV4),
V5(IntegerClientKey),
V5(IntegerClientKeyV5),
V6(IntegerClientKey),
}
impl Upgrade<IntegerClientKey> for IntegerClientKeyV4 {
impl Upgrade<IntegerClientKey> for IntegerClientKeyV5 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerClientKey, Self::Error> {
@@ -232,6 +268,7 @@ impl Upgrade<IntegerClientKey> for IntegerClientKeyV4 {
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
} = self;
Ok(IntegerClientKey {
@@ -239,7 +276,8 @@ impl Upgrade<IntegerClientKey> for IntegerClientKeyV4 {
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key: None,
noise_squashing_compression_private_key,
cpk_re_randomization_ksk_params: None,
})
}
}
@@ -289,7 +327,41 @@ pub struct IntegerServerKeyV5 {
pub(crate) noise_squashing_key: Option<NoiseSquashingKey>,
}
impl Upgrade<IntegerServerKey> for IntegerServerKeyV5 {
impl Upgrade<IntegerServerKeyV6> for IntegerServerKeyV5 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerServerKeyV6, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
} = self;
Ok(IntegerServerKeyV6 {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key: None,
})
}
}
#[derive(Version)]
pub struct IntegerServerKeyV6 {
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>,
pub(crate) noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
}
impl Upgrade<IntegerServerKey> for IntegerServerKeyV6 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerServerKey, Self::Error> {
@@ -299,6 +371,7 @@ impl Upgrade<IntegerServerKey> for IntegerServerKeyV5 {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
} = self;
Ok(IntegerServerKey {
@@ -307,7 +380,8 @@ impl Upgrade<IntegerServerKey> for IntegerServerKeyV5 {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key: None,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material: None,
})
}
}
@@ -320,7 +394,8 @@ pub enum IntegerServerKeyVersions {
V3(Deprecated<IntegerServerKey>),
V4(IntegerServerKeyV4),
V5(IntegerServerKeyV5),
V6(IntegerServerKey),
V6(IntegerServerKeyV6),
V7(IntegerServerKey),
}
impl Deprecable for IntegerCompressedServerKey {
@@ -368,16 +443,41 @@ pub struct IntegerCompressedServerKeyV3 {
pub(crate) noise_squashing_key: Option<CompressedNoiseSquashingKey>,
}
#[derive(VersionsDispatch)]
pub enum IntegerCompressedServerKeyVersions {
V0(Deprecated<IntegerCompressedServerKey>),
V1(Deprecated<IntegerCompressedServerKey>),
V2(IntegerCompressedServerKeyV2),
V3(IntegerCompressedServerKeyV3),
V4(IntegerCompressedServerKey),
impl Upgrade<IntegerCompressedServerKeyV4> for IntegerCompressedServerKeyV3 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerCompressedServerKeyV4, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
} = self;
Ok(IntegerCompressedServerKeyV4 {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key: None,
})
}
}
impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV3 {
#[derive(Version)]
pub struct IntegerCompressedServerKeyV4 {
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>,
pub(crate) noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
}
impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV4 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerCompressedServerKey, Self::Error> {
@@ -387,6 +487,7 @@ impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV3 {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
} = self;
Ok(IntegerCompressedServerKey {
@@ -395,11 +496,22 @@ impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV3 {
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key: None,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material: None,
})
}
}
#[derive(VersionsDispatch)]
pub enum IntegerCompressedServerKeyVersions {
V0(Deprecated<IntegerCompressedServerKey>),
V1(Deprecated<IntegerCompressedServerKey>),
V2(IntegerCompressedServerKeyV2),
V3(IntegerCompressedServerKeyV3),
V4(IntegerCompressedServerKeyV4),
V5(IntegerCompressedServerKey),
}
#[derive(VersionsDispatch)]
#[allow(unused)]
pub(in crate::high_level_api) enum IntegerCompactPublicKeyVersions {
@@ -422,3 +534,13 @@ pub enum KeySwitchingKeyVersions {
V0(Deprecated<KeySwitchingKey>),
V1(KeySwitchingKey),
}
#[derive(VersionsDispatch)]
pub enum ReRandomizationKeySwitchingKeyVersions {
V0(ReRandomizationKeySwitchingKey),
}
#[derive(VersionsDispatch)]
pub enum CompressedReRandomizationKeySwitchingKeyVersions {
V0(CompressedReRandomizationKeySwitchingKey),
}

View File

@@ -6,6 +6,7 @@ pub mod booleans;
pub mod compact_list;
pub mod compressed_ciphertext_list;
pub mod config;
pub mod cpk_re_randomization;
pub mod integers;
pub mod keys;
#[cfg(feature = "strings")]

View File

@@ -2,11 +2,14 @@ use super::inner::InnerBoolean;
use crate::backward_compatibility::booleans::FheBoolVersions;
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::prelude::{SignedNumeric, UnsignedNumeric};
use crate::high_level_api::global_state;
use crate::high_level_api::errors::UninitializedReRandKey;
use crate::high_level_api::integers::{FheInt, FheIntId, FheUint, FheUintId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::traits::{FheEq, IfThenElse, ScalarIfThenElse, Tagged};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::{FheEq, IfThenElse, ReRandomize, ScalarIfThenElse, Tagged};
use crate::high_level_api::{global_state, CompactPublicKey};
use crate::integer::block_decomposition::DecomposableInto;
use crate::integer::ciphertext::ReRandomizationSeed;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::boolean_value::CudaBooleanBlock;
#[cfg(feature = "gpu")]
@@ -61,6 +64,7 @@ use tfhe_hpu_backend::prelude::*;
pub struct FheBool {
pub(in crate::high_level_api) ciphertext: InnerBoolean,
pub(crate) tag: Tag,
pub(crate) re_randomization_metadata: ReRandomizationMetadata,
}
impl Named for FheBool {
@@ -93,7 +97,11 @@ impl ParameterSetConformant for FheBool {
type ParameterSet = FheBoolConformanceParams;
fn is_conformant(&self, params: &FheBoolConformanceParams) -> bool {
let Self { ciphertext, tag: _ } = self;
let Self {
ciphertext,
tag: _,
re_randomization_metadata: _,
} = self;
let BooleanBlock(block) = &*ciphertext.on_cpu();
@@ -102,10 +110,15 @@ impl ParameterSetConformant for FheBool {
}
impl FheBool {
pub(in crate::high_level_api) fn new<T: Into<InnerBoolean>>(ciphertext: T, tag: Tag) -> Self {
pub(in crate::high_level_api) fn new<T: Into<InnerBoolean>>(
ciphertext: T,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self {
Self {
ciphertext: ciphertext.into(),
tag,
re_randomization_metadata,
}
}
@@ -199,6 +212,14 @@ impl FheBool {
pub fn is_trivial(&self) -> bool {
self.ciphertext.on_cpu().is_trivial()
}
pub fn re_randomization_metadata(&self) -> &ReRandomizationMetadata {
&self.re_randomization_metadata
}
pub fn re_randomization_metadata_mut(&mut self) -> &mut ReRandomizationMetadata {
&mut self.re_randomization_metadata
}
}
impl<Id, Scalar> ScalarIfThenElse<&FheUint<Id>, Scalar> for FheBool
@@ -238,7 +259,11 @@ where
&*then_value.ciphertext.on_cpu(),
else_value,
);
FheUint::new(inner, cpu_sks.tag.clone())
FheUint::new(
inner,
cpu_sks.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -289,7 +314,11 @@ where
then_value,
&*else_value.ciphertext.on_cpu(),
);
FheUint::new(inner, cpu_sks.tag.clone())
FheUint::new(
inner,
cpu_sks.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -340,7 +369,11 @@ where
&*then_value.ciphertext.on_cpu(),
else_value,
);
FheInt::new(inner, cpu_sks.tag.clone())
FheInt::new(
inner,
cpu_sks.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -391,7 +424,11 @@ where
then_value,
&*else_value.ciphertext.on_cpu(),
);
FheInt::new(inner, cpu_sks.tag.clone())
FheInt::new(
inner,
cpu_sks.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -436,7 +473,7 @@ impl ScalarIfThenElse<&Self, &Self> for FheBool {
panic!("Hpu does not support if_then_else with clear input")
}
});
Self::new(ciphertext, tag)
Self::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -459,7 +496,11 @@ where
&*ct_then.ciphertext.on_cpu(),
&*ct_else.ciphertext.on_cpu(),
);
FheUint::new(inner, cpu_sks.tag.clone())
FheUint::new(
inner,
cpu_sks.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -471,7 +512,11 @@ where
streams,
);
FheUint::new(inner, cuda_key.tag.clone())
FheUint::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -495,7 +540,11 @@ where
)
.pop()
.unwrap();
FheUint::new(hpu_result, device.tag.clone())
FheUint::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -517,7 +566,7 @@ impl<Id: FheIntId> IfThenElse<FheInt<Id>> for FheBool {
&*ct_then.ciphertext.on_cpu(),
&*ct_else.ciphertext.on_cpu(),
);
FheInt::new(new_ct, key.tag.clone())
FheInt::new(new_ct, key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -529,7 +578,11 @@ impl<Id: FheIntId> IfThenElse<FheInt<Id>> for FheBool {
streams,
);
FheInt::new(inner, cuda_key.tag.clone())
FheInt::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -568,7 +621,7 @@ impl IfThenElse<Self> for FheBool {
panic!("Hpu does not support bool if then else")
}
});
Self::new(ciphertext, tag)
Self::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -613,7 +666,11 @@ where
other.borrow().ciphertext.on_cpu().as_ref(),
);
let ciphertext = InnerBoolean::Cpu(BooleanBlock::new_unchecked(inner));
Self::new(ciphertext, key.tag.clone())
Self::new(
ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -624,7 +681,11 @@ where
streams,
);
let ciphertext = InnerBoolean::Cuda(inner);
Self::new(ciphertext, cuda_key.tag.clone())
Self::new(
ciphertext,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -660,7 +721,11 @@ where
other.borrow().ciphertext.on_cpu().as_ref(),
);
let ciphertext = InnerBoolean::Cpu(BooleanBlock::new_unchecked(inner));
Self::new(ciphertext, key.tag.clone())
Self::new(
ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -671,7 +736,11 @@ where
streams,
);
let ciphertext = InnerBoolean::Cuda(inner);
Self::new(ciphertext, cuda_key.tag.clone())
Self::new(
ciphertext,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -727,7 +796,7 @@ impl FheEq<bool> for FheBool {
panic!("Hpu does not support FheBool::eq with a bool")
}
});
Self::new(ciphertext, tag)
Self::new(ciphertext, tag, ReRandomizationMetadata::default())
}
/// Test for equality between a [FheBool] and a [bool]
@@ -775,7 +844,7 @@ impl FheEq<bool> for FheBool {
panic!("Hpu does not support FheBool::ne with a bool")
}
});
Self::new(ciphertext, tag)
Self::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -929,7 +998,7 @@ where
panic!("Hpu does not support bitand (&)")
}
});
FheBool::new(ciphertext, tag)
FheBool::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -1058,7 +1127,7 @@ where
panic!("Hpu does not support bitor (|)")
}
});
FheBool::new(ciphertext, tag)
FheBool::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -1187,7 +1256,7 @@ where
panic!("Hpu does not support bitxor (^)")
}
});
FheBool::new(ciphertext, tag)
FheBool::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -1308,7 +1377,7 @@ impl BitAnd<bool> for &FheBool {
panic!("hpu does not bitand (&) with a bool")
}
});
FheBool::new(ciphertext, tag)
FheBool::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -1389,7 +1458,7 @@ impl BitOr<bool> for &FheBool {
panic!("hpu does not bitor (|) with a bool")
}
});
FheBool::new(ciphertext, tag)
FheBool::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -1470,7 +1539,7 @@ impl BitXor<bool> for &FheBool {
panic!("hpu does not bitxor (^) with a bool")
}
});
FheBool::new(ciphertext, tag)
FheBool::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
@@ -1969,7 +2038,48 @@ impl std::ops::Not for &FheBool {
panic!("Hpu does not support bitnot (!)")
}
});
FheBool::new(ciphertext, tag)
FheBool::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}
impl ReRandomize for FheBool {
fn add_to_re_randomization_context(
&self,
context: &mut crate::high_level_api::re_randomization::ReRandomizationContext,
) {
let on_cpu = self.ciphertext.on_cpu();
context.inner.add_ciphertext(&*on_cpu);
context
.inner
.add_bytes(self.re_randomization_metadata.data());
}
fn re_randomize(
&mut self,
compact_public_key: &CompactPublicKey,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let Some(re_randomization_key) = key.re_randomization_cpk_casting_key() else {
return Err(UninitializedReRandKey.into());
};
self.ciphertext.as_cpu_mut().re_randomize(
&compact_public_key.key.key,
&re_randomization_key,
seed,
)?;
Ok(())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_cuda_key) => panic!("GPU does not support CPKReRandomize."),
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
panic!("HPU does not support CPKReRandomize.")
}
})
}
}

View File

@@ -3,6 +3,7 @@ use crate::backward_compatibility::booleans::{
};
use crate::conformance::ParameterSetConformant;
use crate::high_level_api::global_state::with_cpu_internal_keys;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::Tagged;
use crate::integer::BooleanBlock;
use crate::named::Named;
@@ -76,7 +77,11 @@ impl CompressedFheBool {
with_cpu_internal_keys(|sk| sk.pbs_key().key.decompress(modulus_switched))
}
});
let mut ciphertext = FheBool::new(ciphertext, self.tag.clone());
let mut ciphertext = FheBool::new(
ciphertext,
self.tag.clone(),
ReRandomizationMetadata::default(),
);
ciphertext.ciphertext.move_to_device_of_server_key_if_set();

View File

@@ -2,6 +2,7 @@ use super::base::FheBool;
use crate::high_level_api::booleans::inner::InnerBoolean;
use crate::high_level_api::global_state;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::boolean_value::CudaBooleanBlock;
#[cfg(feature = "gpu")]
@@ -14,7 +15,11 @@ impl FheTryEncrypt<bool, ClientKey> for FheBool {
fn try_encrypt(value: bool, key: &ClientKey) -> Result<Self, Self::Error> {
let integer_client_key = &key.key.key;
let mut ciphertext = Self::new(integer_client_key.encrypt_bool(value), key.tag.clone());
let mut ciphertext = Self::new(
integer_client_key.encrypt_bool(value),
key.tag.clone(),
ReRandomizationMetadata::default(),
);
ciphertext.ciphertext.move_to_device_of_server_key_if_set();
Ok(ciphertext)
}
@@ -55,7 +60,11 @@ impl FheTryEncrypt<bool, CompressedPublicKey> for FheBool {
type Error = crate::Error;
fn try_encrypt(value: bool, key: &CompressedPublicKey) -> Result<Self, Self::Error> {
let mut ciphertext = Self::new(key.key.encrypt_bool(value), key.tag.clone());
let mut ciphertext = Self::new(
key.key.encrypt_bool(value),
key.tag.clone(),
ReRandomizationMetadata::default(),
);
ciphertext.ciphertext.move_to_device_of_server_key_if_set();
Ok(ciphertext)
}
@@ -65,7 +74,11 @@ impl FheTryEncrypt<bool, PublicKey> for FheBool {
type Error = crate::Error;
fn try_encrypt(value: bool, key: &PublicKey) -> Result<Self, Self::Error> {
let mut ciphertext = Self::new(key.key.encrypt_bool(value), key.tag.clone());
let mut ciphertext = Self::new(
key.key.encrypt_bool(value),
key.tag.clone(),
ReRandomizationMetadata::default(),
);
ciphertext.ciphertext.move_to_device_of_server_key_if_set();
Ok(ciphertext)
}
@@ -105,6 +118,10 @@ impl FheTryTrivialEncrypt<bool> for FheBool {
panic!("Hpu does not support trivial encryption")
}
});
Ok(Self::new(ciphertext, tag))
Ok(Self::new(
ciphertext,
tag,
ReRandomizationMetadata::default(),
))
}
}

View File

@@ -1,6 +1,7 @@
use super::{FheBool, InnerBoolean};
use crate::high_level_api::global_state;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::boolean_value::CudaBooleanBlock;
#[cfg(feature = "gpu")]
@@ -57,6 +58,6 @@ impl FheBool {
panic!("Hpu does not support random bool generation")
}
});
Self::new(ciphertext, tag)
Self::new(ciphertext, tag, ReRandomizationMetadata::default())
}
}

View File

@@ -19,6 +19,7 @@ use crate::high_level_api::global_state::device_of_internal_keys;
#[cfg(feature = "gpu")]
use crate::high_level_api::global_state::with_cuda_internal_keys;
use crate::high_level_api::integers::{FheIntId, FheUintId};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::ciphertext::{DataKind, Expandable};
use crate::integer::compression_keys::DecompressionKey;
#[cfg(feature = "gpu")]
@@ -28,6 +29,8 @@ use crate::integer::gpu::ciphertext::compressed_ciphertext_list::{
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::CudaRadixCiphertext;
#[cfg(feature = "gpu")]
use crate::integer::gpu::list_compression::server_keys::CudaDecompressionKey;
#[cfg(feature = "gpu")]
use crate::integer::parameters::LweDimension;
use crate::named::Named;
use crate::prelude::{CiphertextList, Tagged};
@@ -60,6 +63,10 @@ impl<Id: FheUintId> HlCompressible for FheUint<Id> {
}
}
}
fn get_re_randomization_metadata(&self) -> ReRandomizationMetadata {
self.re_randomization_metadata.clone()
}
}
impl<Id: FheIntId> HlCompressible for FheInt<Id> {
fn compress_into(self, messages: &mut Vec<(ToBeCompressed, DataKind)>) {
@@ -81,6 +88,10 @@ impl<Id: FheIntId> HlCompressible for FheInt<Id> {
}
}
}
fn get_re_randomization_metadata(&self) -> ReRandomizationMetadata {
self.re_randomization_metadata.clone()
}
}
impl HlCompressible for FheBool {
fn compress_into(self, messages: &mut Vec<(ToBeCompressed, DataKind)>) {
@@ -98,19 +109,47 @@ impl HlCompressible for FheBool {
InnerBoolean::Hpu(_) => panic!("HPU does not support compression"),
}
}
fn get_re_randomization_metadata(&self) -> ReRandomizationMetadata {
self.re_randomization_metadata.clone()
}
}
impl<Id: FheUintId> HlExpandable for FheUint<Id> {}
impl<Id: FheIntId> HlExpandable for FheInt<Id> {}
impl HlExpandable for FheBool {}
impl<Id: FheUintId> HlExpandable for FheUint<Id> {
fn set_re_randomization_metadata(&mut self, meta: ReRandomizationMetadata) {
self.re_randomization_metadata = meta;
}
}
impl<Id: FheIntId> HlExpandable for FheInt<Id> {
fn set_re_randomization_metadata(&mut self, meta: ReRandomizationMetadata) {
self.re_randomization_metadata = meta;
}
}
impl HlExpandable for FheBool {
fn set_re_randomization_metadata(&mut self, meta: ReRandomizationMetadata) {
self.re_randomization_metadata = meta;
}
}
#[cfg(not(feature = "gpu"))]
pub trait HlExpandable: Expandable {}
pub trait HlExpandable: Expandable {
/// Sets the metadata of the ciphertext from the ones in the compressed list
// Defined as an empty default method for backward compatibility
fn set_re_randomization_metadata(&mut self, _meta: ReRandomizationMetadata) {}
}
#[cfg(feature = "gpu")]
pub trait HlExpandable: Expandable + CudaExpandable {}
pub trait HlExpandable: Expandable + CudaExpandable {
fn set_re_randomization_metadata(&mut self, _meta: ReRandomizationMetadata) {}
}
pub trait HlCompressible {
/// Adds a ciphertext to be compressed.
///
/// This should push at most one single element at the end of the `messages` vec
fn compress_into(self, messages: &mut Vec<(ToBeCompressed, DataKind)>);
fn get_re_randomization_metadata(&self) -> ReRandomizationMetadata {
ReRandomizationMetadata::default()
}
}
pub enum ToBeCompressed {
@@ -121,19 +160,34 @@ pub enum ToBeCompressed {
pub struct CompressedCiphertextListBuilder {
inner: Vec<(ToBeCompressed, DataKind)>,
rerandomization_metadata: Vec<ReRandomizationMetadata>,
}
impl CompressedCiphertextListBuilder {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self { inner: vec![] }
Self {
inner: vec![],
rerandomization_metadata: vec![],
}
}
pub fn push<T>(&mut self, value: T) -> &mut Self
where
T: HlCompressible,
{
let size_before = self.inner.len();
let meta = value.get_re_randomization_metadata();
value.compress_into(&mut self.inner);
let size_after = self.inner.len();
// `compress_into` should only push a single element at the end of the builder
assert!(size_before <= size_after);
assert!(size_after - size_before <= 1);
if size_after - size_before == 1 {
self.rerandomization_metadata.push(meta)
}
self
}
@@ -148,6 +202,10 @@ impl CompressedCiphertextListBuilder {
}
pub fn build(&self) -> crate::Result<CompressedCiphertextList> {
if self.inner.len() != self.rerandomization_metadata.len() {
return Err(crate::Error::new("Invalid CompressedCiphertextListBuilder, ct and metadata lists should have the same length".to_owned()));
}
crate::high_level_api::global_state::try_with_internal_keys(|keys| match keys {
Some(InternalServerKey::Cpu(cpu_key)) => {
let mut flat_cpu_blocks = vec![];
@@ -188,6 +246,7 @@ impl CompressedCiphertextListBuilder {
},
),
tag: cpu_key.tag.clone(),
re_randomization_metadata: self.rerandomization_metadata.clone(),
}
})
}
@@ -231,6 +290,7 @@ impl CompressedCiphertextListBuilder {
CompressedCiphertextList {
inner: InnerCompressedCiphertextList::Cuda(compressed_list),
tag: cuda_key.tag.clone(),
re_randomization_metadata: self.rerandomization_metadata.clone(),
}
})
}
@@ -402,6 +462,14 @@ impl InnerCompressedCiphertextList {
}
}
}
pub(crate) fn info(&self) -> &[DataKind] {
match self {
Self::Cpu(compressed_ciphertext_list) => &compressed_ciphertext_list.info,
#[cfg(feature = "gpu")]
Self::Cuda(compressed_ciphertext_list) => &compressed_ciphertext_list.info,
}
}
}
impl Versionize for InnerCompressedCiphertextList {
@@ -455,6 +523,7 @@ impl Unversionize for InnerCompressedCiphertextList {
pub struct CompressedCiphertextList {
pub(in crate::high_level_api) inner: InnerCompressedCiphertextList,
pub(in crate::high_level_api) tag: Tag,
pub(in crate::high_level_api) re_randomization_metadata: Vec<ReRandomizationMetadata>,
}
impl Named for CompressedCiphertextList {
@@ -533,16 +602,12 @@ impl CiphertextList for CompressedCiphertextList {
crate::Error::new("Compression key not set in server key".to_owned())
})
.and_then(|decompression_key| {
let mut ct = {
let streams = &cuda_key.streams;
self.inner
.on_gpu(streams)
.get::<T>(index, decompression_key, streams)
};
if let Ok(Some(ct_ref)) = &mut ct {
ct_ref.tag_mut().set_data(cuda_key.tag.data())
}
ct
self.get_using_cuda_key(
index,
decompression_key,
&cuda_key.streams,
&cuda_key.tag,
)
}),
#[cfg(feature = "hpu")]
Some(InternalServerKey::Hpu(_)) => {
@@ -579,10 +644,20 @@ impl CiphertextList for CompressedCiphertextList {
}
impl CompressedCiphertextList {
pub fn into_raw_parts(self) -> (crate::integer::ciphertext::CompressedCiphertextList, Tag) {
let Self { inner, tag } = self;
pub fn into_raw_parts(
self,
) -> (
crate::integer::ciphertext::CompressedCiphertextList,
Tag,
Vec<ReRandomizationMetadata>,
) {
let Self {
inner,
tag,
re_randomization_metadata,
} = self;
match inner {
InnerCompressedCiphertextList::Cpu(inner) => (inner, tag),
InnerCompressedCiphertextList::Cpu(inner) => (inner, tag, re_randomization_metadata),
#[cfg(feature = "gpu")]
InnerCompressedCiphertextList::Cuda(inner) => (
with_cuda_internal_keys(|keys| {
@@ -590,6 +665,7 @@ impl CompressedCiphertextList {
inner.to_compressed_ciphertext_list(streams)
}),
tag,
re_randomization_metadata,
),
}
}
@@ -597,10 +673,12 @@ impl CompressedCiphertextList {
pub fn from_raw_parts(
inner: crate::integer::ciphertext::CompressedCiphertextList,
tag: Tag,
re_randomization_metadata: Vec<ReRandomizationMetadata>,
) -> Self {
Self {
inner: InnerCompressedCiphertextList::Cpu(inner),
tag,
re_randomization_metadata,
}
}
@@ -614,6 +692,19 @@ impl CompressedCiphertextList {
}
}
fn get_re_randomization_metadata(
&self,
index: usize,
) -> crate::Result<ReRandomizationMetadata> {
Ok(self
.re_randomization_metadata
.get(index)
.ok_or_else(|| {
crate::error!("Unable to retrieve metadata for ciphertext at index {index}.")
})?
.clone())
}
pub(crate) fn get_using_key<T>(
&self,
index: usize,
@@ -626,6 +717,31 @@ impl CompressedCiphertextList {
let mut ct = self.inner.on_cpu().get::<T>(index, decompression_key);
if let Ok(Some(ct_ref)) = &mut ct {
ct_ref.tag_mut().set_data(tag.data());
ct_ref.set_re_randomization_metadata(self.get_re_randomization_metadata(index)?);
}
ct
}
#[cfg(feature = "gpu")]
pub(crate) fn get_using_cuda_key<T>(
&self,
index: usize,
decompression_key: &CudaDecompressionKey,
streams: &CudaStreams,
tag: &Tag,
) -> crate::Result<Option<T>>
where
T: HlExpandable + Tagged,
{
let mut ct = self
.inner
.on_gpu(streams)
.get::<T>(index, decompression_key, streams);
if let Ok(Some(ct_ref)) = &mut ct {
ct_ref.tag_mut().set_data(tag.data());
ct_ref.set_re_randomization_metadata(self.get_re_randomization_metadata(index)?);
}
ct
}
@@ -649,7 +765,7 @@ pub mod gpu {
CudaCompressible, CudaExpandable,
};
use crate::integer::gpu::ciphertext::CudaRadixCiphertext;
use crate::{FheBool, FheInt, FheUint, Tag};
use crate::{FheBool, FheInt, FheUint, ReRandomizationMetadata, Tag};
impl<Id: FheUintId> CudaCompressible for FheUint<Id> {
fn compress_into(
@@ -711,6 +827,7 @@ pub mod gpu {
ciphertext: blocks,
},
Tag::default(),
ReRandomizationMetadata::default(),
))
} else {
Err(crate::error!(
@@ -763,6 +880,7 @@ pub mod gpu {
ciphertext: blocks,
},
Tag::default(),
ReRandomizationMetadata::default(),
))
} else {
Err(crate::error!(
@@ -809,7 +927,11 @@ pub mod gpu {
crate::shortint::ciphertext::Degree::new(1);
// The expander will be responsible for setting the correct tag
Ok(Self::new(boolean_block, Tag::default()))
Ok(Self::new(
boolean_block,
Tag::default(),
ReRandomizationMetadata::default(),
))
}
DataKind::String { .. } => Err(crate::error!(
"Tried to expand a FheBool while a FheString is stored in this slot"

View File

@@ -3,7 +3,9 @@ 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::{NoiseSquashingCompressionParameters, NoiseSquashingParameters};
use crate::shortint::parameters::{
NoiseSquashingCompressionParameters, NoiseSquashingParameters, ShortintKeySwitchingParameters,
};
/// The config type
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize, Versionize)]
@@ -71,7 +73,7 @@ impl ConfigBuilder {
///
/// # Note
///
/// This requires nose squashing to be enabled first via [Self::enable_noise_squashing]
/// This requires noise squashing to be enabled first via [Self::enable_noise_squashing]
pub fn enable_noise_squashing_compression(
mut self,
compression_parameters: NoiseSquashingCompressionParameters,
@@ -86,6 +88,24 @@ impl ConfigBuilder {
self
}
/// Enable the re-randomization of ciphertexts after compression using a
/// [crate::CompactPublicKey].
///
/// # Note
///
/// This requires dedicated [crate::CompactPublicKey] parameters to be enabled via
/// [Self::use_dedicated_compact_public_key_parameters].
pub fn enable_ciphertext_re_randomization(
mut self,
cpk_re_randomization_ksk_params: ShortintKeySwitchingParameters,
) -> Self {
self.config
.inner
.enable_ciphertext_re_randomization(cpk_re_randomization_ksk_params);
self
}
pub fn with_custom_parameters<P>(block_parameters: P) -> Self
where
P: Into<crate::shortint::atomic_pattern::AtomicPatternParameters>,

View File

@@ -66,3 +66,25 @@ impl From<UninitializedNoiseSquashing> for Error {
Self::new(format!("{value}"))
}
}
#[derive(Debug)]
pub struct UninitializedReRandKey;
impl Display for UninitializedReRandKey {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"No keyswitching key available to perform \
CompactPublicKey re-randomization. Did you forget to call \
enable_ciphertext_re_randomization on your Config?"
)
}
}
impl std::error::Error for UninitializedReRandKey {}
impl From<UninitializedReRandKey> for Error {
fn from(value: UninitializedReRandKey) -> Self {
Self::new(format!("{value}"))
}
}

View File

@@ -1,6 +1,7 @@
use super::{FheIntId, FheUint, FheUintId};
use crate::high_level_api::global_state;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::{CudaSignedRadixCiphertext, CudaUnsignedRadixCiphertext};
use crate::{FheInt, Seed};
@@ -34,7 +35,7 @@ impl<Id: FheUintId> FheUint<Id> {
Id::num_blocks(key.message_modulus()) as u64,
);
Self::new(ct, key.tag.clone())
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -48,7 +49,11 @@ impl<Id: FheUintId> FheUint<Id> {
streams,
);
Self::new(d_ct, cuda_key.tag.clone())
Self::new(
d_ct,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -119,7 +124,7 @@ impl<Id: FheUintId> FheUint<Id> {
Id::num_blocks(key.message_modulus()) as u64,
);
Self::new(ct, key.tag.clone())
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -133,7 +138,11 @@ impl<Id: FheUintId> FheUint<Id> {
Id::num_blocks(cuda_key.message_modulus()) as u64,
streams,
);
Self::new(d_ct, cuda_key.tag.clone())
Self::new(
d_ct,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -206,7 +215,7 @@ impl<Id: FheIntId> FheInt<Id> {
seed,
Id::num_blocks(key.message_modulus()) as u64,
);
Self::new(ct, key.tag.clone())
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -220,7 +229,11 @@ impl<Id: FheIntId> FheInt<Id> {
streams,
);
Self::new(d_ct, cuda_key.tag.clone())
Self::new(
d_ct,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -293,7 +306,7 @@ impl<Id: FheIntId> FheInt<Id> {
Id::num_blocks(key.message_modulus()) as u64,
);
Self::new(ct, key.tag.clone())
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -307,7 +320,11 @@ impl<Id: FheIntId> FheInt<Id> {
Id::num_blocks(cuda_key.message_modulus()) as u64,
streams,
);
Self::new(d_ct, cuda_key.tag.clone())
Self::new(
d_ct,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {

View File

@@ -4,11 +4,14 @@ use super::inner::SignedRadixCiphertext;
use crate::backward_compatibility::integers::FheIntVersions;
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::prelude::SignedNumeric;
use crate::high_level_api::errors::UninitializedReRandKey;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::{FheUint, FheUintId, IntegerId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::traits::Tagged;
use crate::high_level_api::keys::{CompactPublicKey, InternalServerKey};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::{ReRandomize, Tagged};
use crate::integer::block_decomposition::{DecomposableInto, RecomposableSignedInteger};
use crate::integer::ciphertext::ReRandomizationSeed;
use crate::integer::parameters::RadixCiphertextConformanceParams;
use crate::named::Named;
use crate::prelude::CastFrom;
@@ -38,6 +41,7 @@ pub struct FheInt<Id: FheIntId> {
pub(in crate::high_level_api) ciphertext: SignedRadixCiphertext,
pub(in crate::high_level_api) id: Id,
pub(crate) tag: Tag,
pub(crate) re_randomization_metadata: ReRandomizationMetadata,
}
#[derive(Copy, Clone)]
@@ -79,6 +83,7 @@ impl<Id: FheIntId> ParameterSetConformant for FheInt<Id> {
ciphertext,
id: _,
tag: _,
re_randomization_metadata: _,
} = self;
ciphertext.on_cpu().is_conformant(&params.params)
@@ -109,32 +114,44 @@ where
pub(in crate::high_level_api) fn new(
ciphertext: impl Into<SignedRadixCiphertext>,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self {
Self {
ciphertext: ciphertext.into(),
id: Id::default(),
tag,
re_randomization_metadata,
}
}
pub fn into_raw_parts(self) -> (crate::integer::SignedRadixCiphertext, Id, Tag) {
pub fn into_raw_parts(
self,
) -> (
crate::integer::SignedRadixCiphertext,
Id,
Tag,
ReRandomizationMetadata,
) {
let Self {
ciphertext,
id,
tag,
re_randomization_metadata,
} = self;
(ciphertext.into_cpu(), id, tag)
(ciphertext.into_cpu(), id, tag, re_randomization_metadata)
}
pub fn from_raw_parts(
ciphertext: crate::integer::SignedRadixCiphertext,
id: Id,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self {
Self {
ciphertext: ciphertext.into(),
id,
tag,
re_randomization_metadata,
}
}
@@ -192,7 +209,11 @@ where
let ciphertext = cpu_key
.pbs_key()
.abs_parallelized(&*self.ciphertext.on_cpu());
Self::new(ciphertext, cpu_key.tag.clone())
Self::new(
ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -201,7 +222,11 @@ where
.key
.key
.abs(&*self.ciphertext.on_gpu(streams), streams);
Self::new(result, cuda_key.tag.clone())
Self::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -233,7 +258,11 @@ where
let result = cpu_key
.pbs_key()
.is_even_parallelized(&*self.ciphertext.on_cpu());
FheBool::new(result, cpu_key.tag.clone())
FheBool::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -242,7 +271,11 @@ where
.key
.key
.is_even(&*self.ciphertext.on_gpu(streams), streams);
FheBool::new(result, cuda_key.tag.clone())
FheBool::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -274,7 +307,11 @@ where
let result = cpu_key
.pbs_key()
.is_odd_parallelized(&*self.ciphertext.on_cpu());
FheBool::new(result, cpu_key.tag.clone())
FheBool::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -283,7 +320,11 @@ where
.key
.key
.is_odd(&*self.ciphertext.on_gpu(streams), streams);
FheBool::new(result, cuda_key.tag.clone())
FheBool::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -319,7 +360,11 @@ where
result,
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
crate::FheUint32::new(result, cpu_key.tag.clone())
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -333,7 +378,11 @@ where
crate::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
crate::FheUint32::new(result, cuda_key.tag.clone())
crate::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -369,7 +418,11 @@ where
result,
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
crate::FheUint32::new(result, cpu_key.tag.clone())
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -383,7 +436,11 @@ where
crate::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
crate::FheUint32::new(result, cuda_key.tag.clone())
crate::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -419,7 +476,11 @@ where
result,
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
crate::FheUint32::new(result, cpu_key.tag.clone())
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -433,7 +494,11 @@ where
crate::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
crate::FheUint32::new(result, cuda_key.tag.clone())
crate::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -469,7 +534,11 @@ where
result,
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
crate::FheUint32::new(result, cpu_key.tag.clone())
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -483,7 +552,11 @@ where
crate::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
crate::FheUint32::new(result, cuda_key.tag.clone())
crate::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -520,7 +593,11 @@ where
result,
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
crate::FheUint32::new(result, cpu_key.tag.clone())
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -561,7 +638,11 @@ where
result,
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
crate::FheUint32::new(result, cpu_key.tag.clone())
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -603,7 +684,11 @@ where
result,
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
crate::FheUint32::new(result, cpu_key.tag.clone())
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -617,7 +702,11 @@ where
crate::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
crate::FheUint32::new(result, cuda_key.tag.clone())
crate::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -660,8 +749,16 @@ where
crate::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
(
crate::FheUint32::new(result, cpu_key.tag.clone()),
FheBool::new(is_ok, cpu_key.tag.clone()),
crate::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
is_ok,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -677,8 +774,16 @@ where
streams,
);
(
crate::FheUint32::new(result, cuda_key.tag.clone()),
FheBool::new(is_ok, cuda_key.tag.clone()),
crate::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
is_ok,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -753,7 +858,11 @@ where
let ct = self.ciphertext.on_cpu();
Self::new(sk.reverse_bits_parallelized(&*ct), cpu_key.tag.clone())
Self::new(
sk.reverse_bits_parallelized(&*ct),
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -804,7 +913,11 @@ where
Id::num_blocks(sk.message_modulus()),
);
Self::new(result, cpu_key.tag.clone())
Self::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -832,6 +945,14 @@ where
{
Self::if_then_else(condition, true_value, false_value)
}
pub fn re_randomization_metadata(&self) -> &ReRandomizationMetadata {
&self.re_randomization_metadata
}
pub fn re_randomization_metadata_mut(&mut self) -> &mut ReRandomizationMetadata {
&mut self.re_randomization_metadata
}
}
impl<FromId, IntoId> CastFrom<FheInt<FromId>> for FheInt<IntoId>
@@ -863,7 +984,11 @@ where
let new_ciphertext = cpu_key
.pbs_key()
.cast_to_signed(input.ciphertext.into_cpu(), target_num_blocks);
Self::new(new_ciphertext, cpu_key.tag.clone())
Self::new(
new_ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -874,7 +999,11 @@ where
target_num_blocks,
streams,
);
Self::new(new_ciphertext, cuda_key.tag.clone())
Self::new(
new_ciphertext,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -913,7 +1042,11 @@ where
input.ciphertext.on_cpu().to_owned(),
IntoId::num_blocks(cpu_key.message_modulus()),
);
Self::new(new_ciphertext, cpu_key.tag.clone())
Self::new(
new_ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -923,7 +1056,11 @@ where
IntoId::num_blocks(cuda_key.message_modulus()),
streams,
);
Self::new(new_ciphertext, cuda_key.tag.clone())
Self::new(
new_ciphertext,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -965,7 +1102,11 @@ where
Id::num_blocks(cpu_key.message_modulus()),
cpu_key.pbs_key(),
);
Self::new(ciphertext, cpu_key.tag.clone())
Self::new(
ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -975,7 +1116,11 @@ where
Id::num_blocks(cuda_key.message_modulus()),
streams,
);
Self::new(inner, cuda_key.tag.clone())
Self::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -984,3 +1129,47 @@ where
})
}
}
impl<Id> ReRandomize for FheInt<Id>
where
Id: FheIntId,
{
fn add_to_re_randomization_context(
&self,
context: &mut crate::high_level_api::re_randomization::ReRandomizationContext,
) {
let on_cpu = self.ciphertext.on_cpu();
context.inner.add_ciphertext(&*on_cpu);
context
.inner
.add_bytes(self.re_randomization_metadata.data());
}
fn re_randomize(
&mut self,
compact_public_key: &CompactPublicKey,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let Some(re_randomization_key) = key.re_randomization_cpk_casting_key() else {
return Err(UninitializedReRandKey.into());
};
self.ciphertext.as_cpu_mut().re_randomize(
&compact_public_key.key.key,
&re_randomization_key,
seed,
)?;
Ok(())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_cuda_key) => panic!("GPU does not support CPKReRandomize."),
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
panic!("HPU does not support CPKReRandomize.")
}
})
}
}

View File

@@ -8,6 +8,7 @@ use crate::core_crypto::prelude::SignedNumeric;
use crate::high_level_api::global_state::with_cpu_internal_keys;
use crate::high_level_api::integers::signed::base::FheIntConformanceParams;
use crate::high_level_api::integers::{FheInt, FheIntId};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::Tagged;
use crate::integer::block_decomposition::DecomposableInto;
use crate::integer::ciphertext::{
@@ -113,7 +114,11 @@ where
with_cpu_internal_keys(|sk| sk.pbs_key().decompress_signed_parallelized(ct))
}
};
FheInt::new(ciphertext, self.tag.clone())
FheInt::new(
ciphertext,
self.tag.clone(),
ReRandomizationMetadata::default(),
)
}
}

View File

@@ -2,6 +2,7 @@ use crate::core_crypto::prelude::SignedNumeric;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::FheIntId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::block_decomposition::{DecomposableInto, RecomposableSignedInteger};
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::CudaSignedRadixCiphertext;
@@ -52,7 +53,11 @@ where
.key
.key
.encrypt_signed_radix(value, Id::num_blocks(key.message_modulus()));
Ok(Self::new(ciphertext, key.tag.clone()))
Ok(Self::new(
ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
}
@@ -67,7 +72,11 @@ where
let ciphertext = key
.key
.encrypt_signed_radix(value, Id::num_blocks(key.message_modulus()));
Ok(Self::new(ciphertext, key.tag.clone()))
Ok(Self::new(
ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
}
@@ -82,7 +91,11 @@ where
let ciphertext = key
.key
.encrypt_signed_radix(value, Id::num_blocks(key.message_modulus()));
Ok(Self::new(ciphertext, key.tag.clone()))
Ok(Self::new(
ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
}
@@ -108,7 +121,11 @@ where
let ciphertext: crate::integer::SignedRadixCiphertext = key
.pbs_key()
.create_trivial_radix(value, Id::num_blocks(key.message_modulus()));
Ok(Self::new(ciphertext, key.tag.clone()))
Ok(Self::new(
ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -118,7 +135,11 @@ where
Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
Ok(Self::new(inner, cuda_key.tag.clone()))
Ok(Self::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_) => panic!("Hpu does not currently support signed operation"),

View File

@@ -3,6 +3,7 @@ use crate::high_level_api::details::MaybeCloned;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::{FheIntId, FheUintId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::high_level_api::traits::{
AddSizeOnGpu, BitAndSizeOnGpu, BitNotSizeOnGpu, BitOrSizeOnGpu, BitXorSizeOnGpu,
@@ -69,9 +70,13 @@ where
cpu_key.pbs_key().create_trivial_zero_radix(Id::num_blocks(
cpu_key.message_modulus(),
));
Self::new(radix, cpu_key.tag.clone())
Self::new(
radix,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
},
|ct| Self::new(ct, cpu_key.tag.clone()),
|ct| Self::new(ct, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "gpu")]
@@ -106,7 +111,11 @@ where
streams,
)
});
Self::new(inner, cuda_key.tag.clone())
Self::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
}
#[cfg(feature = "hpu")]
@@ -148,7 +157,11 @@ where
let inner_result = cpu_key
.pbs_key()
.max_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -158,7 +171,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -209,7 +226,11 @@ where
let inner_result = cpu_key
.pbs_key()
.min_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -219,7 +240,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -281,7 +306,11 @@ where
let inner_result = cpu_key
.pbs_key()
.eq_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -291,7 +320,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -325,7 +358,11 @@ where
let inner_result = cpu_key
.pbs_key()
.ne_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -335,7 +372,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -395,7 +436,11 @@ where
let inner_result = cpu_key
.pbs_key()
.lt_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -405,7 +450,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -439,7 +488,11 @@ where
let inner_result = cpu_key
.pbs_key()
.le_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -449,7 +502,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -483,7 +540,11 @@ where
let inner_result = cpu_key
.pbs_key()
.gt_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -493,7 +554,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -527,7 +592,11 @@ where
let inner_result = cpu_key
.pbs_key()
.ge_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -537,7 +606,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -612,8 +685,8 @@ where
.pbs_key()
.div_rem_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
(
FheInt::<Id>::new(q, cpu_key.tag.clone()),
FheInt::<Id>::new(r, cpu_key.tag.clone()),
FheInt::<Id>::new(q, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
FheInt::<Id>::new(r, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "gpu")]
@@ -625,8 +698,8 @@ where
streams,
);
(
FheInt::<Id>::new(q, cuda_key.tag.clone()),
FheInt::<Id>::new(r, cuda_key.tag.clone()),
FheInt::<Id>::new(q, cuda_key.tag.clone(), ReRandomizationMetadata::default()),
FheInt::<Id>::new(r, cuda_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "hpu")]
@@ -702,14 +775,14 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.add_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.add(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -749,14 +822,14 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.sub_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.sub(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -796,14 +869,14 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.mul_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.mul(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -841,14 +914,14 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.bitand_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.bitand(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -886,14 +959,14 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.bitor_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.bitor(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -931,14 +1004,14 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.bitxor_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.bitxor(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -984,7 +1057,7 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.div_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {let streams = &cuda_key.streams;
@@ -993,7 +1066,7 @@ generic_integer_impl_operation!(
.key
.key
.div(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -1039,7 +1112,7 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.rem_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheInt::new(inner_result, cpu_key.tag.clone())
FheInt::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {let streams = &cuda_key.streams;
@@ -1048,7 +1121,7 @@ generic_integer_impl_operation!(
.key
.key
.rem(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -1157,14 +1230,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.left_shift_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheInt::new(ciphertext, cpu_key.tag.clone())
FheInt::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.left_shift(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -1205,14 +1278,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.right_shift_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheInt::new(ciphertext, cpu_key.tag.clone())
FheInt::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.right_shift(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -1253,14 +1326,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.rotate_left_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheInt::new(ciphertext, cpu_key.tag.clone())
FheInt::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.rotate_left(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -1301,14 +1374,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.rotate_right_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheInt::new(ciphertext, cpu_key.tag.clone())
FheInt::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
{let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.rotate_right(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
}
#[cfg(feature = "hpu")]
@@ -2017,7 +2090,11 @@ where
let ciphertext = cpu_key
.pbs_key()
.neg_parallelized(&*self.ciphertext.on_cpu());
FheInt::new(ciphertext, cpu_key.tag.clone())
FheInt::new(
ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -2026,7 +2103,11 @@ where
.key
.key
.neg(&*self.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -2091,7 +2172,11 @@ where
global_state::with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let ciphertext = cpu_key.pbs_key().bitnot(&*self.ciphertext.on_cpu());
FheInt::new(ciphertext, cpu_key.tag.clone())
FheInt::new(
ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -2100,7 +2185,11 @@ where
.key
.key
.bitnot(&*self.ciphertext.on_gpu(streams), streams);
FheInt::new(inner_result, cuda_key.tag.clone())
FheInt::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {

View File

@@ -2,6 +2,7 @@ use crate::core_crypto::prelude::SignedNumeric;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::FheIntId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::block_decomposition::DecomposableInto;
use crate::prelude::{OverflowingAdd, OverflowingMul, OverflowingNeg, OverflowingSub};
use crate::{FheBool, FheInt};
@@ -46,8 +47,16 @@ where
&other.ciphertext.on_cpu(),
);
(
FheInt::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheInt::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -59,8 +68,16 @@ where
streams,
);
(
FheInt::new(result, cuda_key.tag.clone()),
FheBool::new(overflow, cuda_key.tag.clone()),
FheInt::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -147,8 +164,16 @@ where
.pbs_key()
.signed_overflowing_scalar_add_parallelized(&self.ciphertext.on_cpu(), other);
(
FheInt::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheInt::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -160,8 +185,16 @@ where
streams,
);
(
FheInt::new(result, cuda_key.tag.clone()),
FheBool::new(overflow, cuda_key.tag.clone()),
FheInt::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -286,8 +319,16 @@ where
&other.ciphertext.on_cpu(),
);
(
FheInt::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheInt::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -299,8 +340,16 @@ where
streams,
);
(
FheInt::new(result, cuda_key.tag.clone()),
FheBool::new(overflow, cuda_key.tag.clone()),
FheInt::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -386,8 +435,16 @@ where
.pbs_key()
.signed_overflowing_scalar_sub_parallelized(&self.ciphertext.on_cpu(), other);
(
FheInt::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheInt::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -399,8 +456,16 @@ where
streams,
);
(
FheInt::new(result, cuda_key.tag.clone()),
FheBool::new(overflow, cuda_key.tag.clone()),
FheInt::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -487,8 +552,16 @@ where
&other.ciphertext.on_cpu(),
);
(
FheInt::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheInt::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -574,8 +647,16 @@ where
.pbs_key()
.overflowing_neg_parallelized(&*self.ciphertext.on_cpu());
(
FheInt::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheInt::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -585,8 +666,16 @@ where
&cuda_key.streams,
);
(
FheInt::new(result, cuda_key.tag.clone()),
FheBool::new(overflow, cuda_key.tag.clone()),
FheInt::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]

View File

@@ -5,6 +5,7 @@ use crate::high_level_api::global_state;
use crate::high_level_api::integers::signed::inner::SignedRadixCiphertext;
use crate::high_level_api::integers::FheIntId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::high_level_api::traits::{
AddSizeOnGpu, BitAndSizeOnGpu, BitOrSizeOnGpu, BitXorSizeOnGpu, DivRemSizeOnGpu, DivSizeOnGpu,
@@ -55,7 +56,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_max_parallelized(&*self.ciphertext.on_cpu(), rhs);
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -65,7 +70,11 @@ where
.key
.key
.scalar_max(&*self.ciphertext.on_gpu(streams), rhs, streams);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -106,7 +115,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_min_parallelized(&*self.ciphertext.on_cpu(), rhs);
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -116,7 +129,11 @@ where
.key
.key
.scalar_min(&*self.ciphertext.on_gpu(streams), rhs, streams);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -156,7 +173,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_eq_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -166,7 +187,11 @@ where
.key
.key
.scalar_eq(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -200,7 +225,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_ne_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -210,7 +239,11 @@ where
.key
.key
.scalar_ne(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -249,7 +282,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_lt_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -259,7 +296,11 @@ where
.key
.key
.scalar_lt(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -292,7 +333,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_le_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -302,7 +347,11 @@ where
.key
.key
.scalar_le(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -335,7 +384,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_gt_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -345,7 +398,11 @@ where
.key
.key
.scalar_gt(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -378,7 +435,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_ge_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -388,7 +449,11 @@ where
.key
.key
.scalar_ge(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -564,8 +629,8 @@ macro_rules! generic_integer_impl_scalar_div_rem {
.pbs_key()
.signed_scalar_div_rem_parallelized(&*self.ciphertext.on_cpu(), rhs);
(
<$concrete_type>::new(q, cpu_key.tag.clone()),
<$concrete_type>::new(r, cpu_key.tag.clone())
<$concrete_type>::new(q, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
<$concrete_type>::new(r, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "gpu")]
@@ -580,8 +645,8 @@ macro_rules! generic_integer_impl_scalar_div_rem {
SignedRadixCiphertext::Cuda(inner_r),
);
(
<$concrete_type>::new(q, cuda_key.tag.clone()),
<$concrete_type>::new(r, cuda_key.tag.clone()),
<$concrete_type>::new(q, cuda_key.tag.clone(), ReRandomizationMetadata::default()),
<$concrete_type>::new(r, cuda_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "hpu")]

View File

@@ -4,12 +4,15 @@ use super::inner::RadixCiphertext;
use crate::backward_compatibility::integers::FheUintVersions;
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::prelude::{CastFrom, UnsignedInteger, UnsignedNumeric};
use crate::high_level_api::errors::UninitializedReRandKey;
use crate::high_level_api::integers::signed::{FheInt, FheIntId};
use crate::high_level_api::integers::IntegerId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::traits::{FheWait, Tagged};
use crate::high_level_api::keys::{CompactPublicKey, InternalServerKey};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::{FheWait, ReRandomize, Tagged};
use crate::high_level_api::{global_state, Device};
use crate::integer::block_decomposition::{DecomposableInto, RecomposableFrom};
use crate::integer::ciphertext::ReRandomizationSeed;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::CudaIntegerRadixCiphertext;
#[cfg(feature = "hpu")]
@@ -88,6 +91,7 @@ pub struct FheUint<Id: FheUintId> {
pub(in crate::high_level_api) ciphertext: RadixCiphertext,
pub(in crate::high_level_api) id: Id,
pub(crate) tag: Tag,
pub(crate) re_randomization_metadata: ReRandomizationMetadata,
}
#[derive(Copy, Clone)]
@@ -129,6 +133,7 @@ impl<Id: FheUintId> ParameterSetConformant for FheUint<Id> {
ciphertext,
id: _,
tag: _,
re_randomization_metadata: _,
} = self;
ciphertext.on_cpu().is_conformant(&params.params)
@@ -189,12 +194,24 @@ where
native: hpu_res
.iter()
.filter(|x| !x.0.is_boolean())
.map(|x| Self::new(x.clone(), device.tag.clone()))
.map(|x| {
Self::new(
x.clone(),
device.tag.clone(),
ReRandomizationMetadata::default(),
)
})
.collect::<Vec<_>>(),
boolean: hpu_res
.iter()
.filter(|x| x.0.is_boolean())
.map(|x| FheBool::new(x.clone(), device.tag.clone()))
.map(|x| {
FheBool::new(
x.clone(),
device.tag.clone(),
ReRandomizationMetadata::default(),
)
})
.collect::<Vec<_>>(),
imm: Vec::new(),
}
@@ -206,7 +223,11 @@ impl<Id> FheUint<Id>
where
Id: FheUintId,
{
pub(in crate::high_level_api) fn new<T>(ciphertext: T, tag: Tag) -> Self
pub(in crate::high_level_api) fn new<T>(
ciphertext: T,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self
where
T: Into<RadixCiphertext>,
{
@@ -214,26 +235,41 @@ where
ciphertext: ciphertext.into(),
id: Id::default(),
tag,
re_randomization_metadata,
}
}
pub fn into_raw_parts(self) -> (crate::integer::RadixCiphertext, Id, Tag) {
pub fn into_raw_parts(
self,
) -> (
crate::integer::RadixCiphertext,
Id,
Tag,
ReRandomizationMetadata,
) {
let Self {
ciphertext,
id,
tag,
re_randomization_metadata,
} = self;
let ciphertext = ciphertext.into_cpu();
(ciphertext, id, tag)
(ciphertext, id, tag, re_randomization_metadata)
}
pub fn from_raw_parts(ciphertext: crate::integer::RadixCiphertext, id: Id, tag: Tag) -> Self {
pub fn from_raw_parts(
ciphertext: crate::integer::RadixCiphertext,
id: Id,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self {
Self {
ciphertext: RadixCiphertext::Cpu(ciphertext),
id,
tag,
re_randomization_metadata,
}
}
@@ -301,7 +337,11 @@ where
let result = cpu_key
.pbs_key()
.is_even_parallelized(&*self.ciphertext.on_cpu());
FheBool::new(result, cpu_key.tag.clone())
FheBool::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -310,7 +350,11 @@ where
.key
.key
.is_even(&*self.ciphertext.on_gpu(streams), streams);
FheBool::new(result, cuda_key.tag.clone())
FheBool::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -342,7 +386,11 @@ where
let result = cpu_key
.pbs_key()
.is_odd_parallelized(&*self.ciphertext.on_cpu());
FheBool::new(result, cpu_key.tag.clone())
FheBool::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -351,7 +399,11 @@ where
.key
.key
.is_odd(&*self.ciphertext.on_gpu(streams), streams);
FheBool::new(result, cuda_key.tag.clone())
FheBool::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -480,7 +532,11 @@ where
result,
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
super::FheUint32::new(result, cpu_key.tag.clone())
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -494,7 +550,11 @@ where
super::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
super::FheUint32::new(result, cuda_key.tag.clone())
super::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -511,7 +571,11 @@ where
HpuRadixCiphertext::exec(proto, opcode, std::slice::from_ref(&hpu_self), &[])
.pop()
.expect("IOP_LEAD0 must return 1 value");
super::FheUint32::new(hpu_result, device.tag.clone())
super::FheUint32::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -543,7 +607,11 @@ where
result,
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
super::FheUint32::new(result, cpu_key.tag.clone())
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -557,7 +625,11 @@ where
super::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
super::FheUint32::new(result, cuda_key.tag.clone())
super::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -574,7 +646,11 @@ where
HpuRadixCiphertext::exec(proto, opcode, std::slice::from_ref(&hpu_self), &[])
.pop()
.expect("IOP_LEAD1 must return 1 value");
super::FheUint32::new(hpu_result, device.tag.clone())
super::FheUint32::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -606,7 +682,11 @@ where
result,
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
super::FheUint32::new(result, cpu_key.tag.clone())
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -620,7 +700,11 @@ where
super::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
super::FheUint32::new(result, cuda_key.tag.clone())
super::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -637,7 +721,11 @@ where
HpuRadixCiphertext::exec(proto, opcode, std::slice::from_ref(&hpu_self), &[])
.pop()
.expect("IOP_TRAIL0 must return 1 value");
super::FheUint32::new(hpu_result, device.tag.clone())
super::FheUint32::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -669,7 +757,11 @@ where
result,
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
super::FheUint32::new(result, cpu_key.tag.clone())
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -683,7 +775,11 @@ where
super::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
super::FheUint32::new(result, cuda_key.tag.clone())
super::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -700,7 +796,11 @@ where
HpuRadixCiphertext::exec(proto, opcode, std::slice::from_ref(&hpu_self), &[])
.pop()
.expect("IOP_TRAIL1 must return 1 value");
super::FheUint32::new(hpu_result, device.tag.clone())
super::FheUint32::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -733,7 +833,11 @@ where
result,
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
super::FheUint32::new(result, cpu_key.tag.clone())
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -754,7 +858,11 @@ where
HpuRadixCiphertext::exec(proto, opcode, std::slice::from_ref(&hpu_self), &[])
.pop()
.expect("IOP_COUNT0 must return 1 value");
super::FheUint32::new(hpu_result, device.tag.clone())
super::FheUint32::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -787,7 +895,11 @@ where
result,
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
super::FheUint32::new(result, cpu_key.tag.clone())
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -808,7 +920,11 @@ where
HpuRadixCiphertext::exec(proto, opcode, std::slice::from_ref(&hpu_self), &[])
.pop()
.expect("IOP_COUNT1 must return 1 value");
super::FheUint32::new(hpu_result, device.tag.clone())
super::FheUint32::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -842,7 +958,11 @@ where
result,
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
super::FheUint32::new(result, cpu_key.tag.clone())
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -856,7 +976,11 @@ where
super::FheUint32Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
super::FheUint32::new(result, cuda_key.tag.clone())
super::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -873,7 +997,11 @@ where
HpuRadixCiphertext::exec(proto, opcode, std::slice::from_ref(&hpu_self), &[])
.pop()
.expect("IOP_ILOG2 must return 1 value");
super::FheUint32::new(hpu_result, device.tag.clone())
super::FheUint32::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -912,8 +1040,16 @@ where
super::FheUint32Id::num_blocks(cpu_key.pbs_key().message_modulus()),
);
(
super::FheUint32::new(result, cpu_key.tag.clone()),
FheBool::new(is_ok, cpu_key.tag.clone()),
super::FheUint32::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
is_ok,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -929,8 +1065,16 @@ where
streams,
);
(
super::FheUint32::new(result, cuda_key.tag.clone()),
FheBool::new(is_ok, cuda_key.tag.clone()),
super::FheUint32::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
is_ok,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -996,8 +1140,16 @@ where
.pbs_key()
.cast_to_unsigned(result, target_num_blocks);
Ok((
FheUint::new(result, cpu_key.tag.clone()),
FheBool::new(matched, cpu_key.tag.clone()),
FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
matched,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
))
} else {
Err(crate::Error::new("Output type does not have enough bits to represent all possible output values".to_string()))
@@ -1014,8 +1166,16 @@ where
let target_num_blocks = OutId::num_blocks(cuda_key.key.key.message_modulus);
if target_num_blocks >= result.ciphertext.d_blocks.lwe_ciphertext_count().0 {
Ok((
FheUint::new(result, cuda_key.tag.clone()),
FheBool::new(matched, cuda_key.tag.clone()),
FheUint::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
matched,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
))
} else {
Err(crate::Error::new("Output type does not have enough bits to represent all possible output values".to_string()))
@@ -1081,7 +1241,11 @@ where
let result = cpu_key
.pbs_key()
.cast_to_unsigned(result, target_num_blocks);
Ok(FheUint::new(result, cpu_key.tag.clone()))
Ok(FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
))
} else {
Err(crate::Error::new("Output type does not have enough bits to represent all possible output values".to_string()))
}
@@ -1097,7 +1261,11 @@ where
);
let target_num_blocks = OutId::num_blocks(cuda_key.key.key.message_modulus);
if target_num_blocks >= result.ciphertext.d_blocks.lwe_ciphertext_count().0 {
Ok(FheUint::new(result, cuda_key.tag.clone()))
Ok(FheUint::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
))
} else {
Err(crate::Error::new("Output type does not have enough bits to represent all possible output values".to_string()))
}
@@ -1136,7 +1304,11 @@ where
let ct = self.ciphertext.on_cpu();
Self::new(sk.reverse_bits_parallelized(&*ct), cpu_key.tag.clone())
Self::new(
sk.reverse_bits_parallelized(&*ct),
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -1186,7 +1358,11 @@ where
Id::num_blocks(sk.message_modulus()),
);
Self::new(result, cpu_key.tag.clone())
Self::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -1214,6 +1390,14 @@ where
{
Self::if_then_else(condition, true_value, false_value)
}
pub fn re_randomization_metadata(&self) -> &ReRandomizationMetadata {
&self.re_randomization_metadata
}
pub fn re_randomization_metadata_mut(&mut self) -> &mut ReRandomizationMetadata {
&mut self.re_randomization_metadata
}
}
impl<Id> TryFrom<crate::integer::RadixCiphertext> for FheUint<Id>
@@ -1267,7 +1451,7 @@ where
}
}
let mut ciphertext = Self::new(other, Tag::default());
let mut ciphertext = Self::new(other, Tag::default(), ReRandomizationMetadata::default());
ciphertext.move_to_device_of_server_key_if_set();
Ok(ciphertext)
}
@@ -1314,7 +1498,11 @@ where
input.ciphertext.into_cpu(),
IntoId::num_blocks(cpu_key.message_modulus()),
);
Self::new(casted, cpu_key.tag.clone())
Self::new(
casted,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -1324,7 +1512,11 @@ where
IntoId::num_blocks(cuda_key.message_modulus()),
streams,
);
Self::new(casted, cuda_key.tag.clone())
Self::new(
casted,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -1363,7 +1555,11 @@ where
input.ciphertext.on_cpu().to_owned(),
IntoId::num_blocks(cpu_key.message_modulus()),
);
Self::new(casted, cpu_key.tag.clone())
Self::new(
casted,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -1373,7 +1569,11 @@ where
IntoId::num_blocks(cuda_key.message_modulus()),
streams,
);
Self::new(casted, cuda_key.tag.clone())
Self::new(
casted,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -1412,7 +1612,11 @@ where
.on_cpu()
.into_owned()
.into_radix(Id::num_blocks(cpu_key.message_modulus()), cpu_key.pbs_key());
Self::new(ciphertext, cpu_key.tag.clone())
Self::new(
ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -1422,7 +1626,11 @@ where
Id::num_blocks(cuda_key.message_modulus()),
streams,
);
Self::new(inner, cuda_key.tag.clone())
Self::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -1432,6 +1640,50 @@ where
}
}
impl<Id> ReRandomize for FheUint<Id>
where
Id: FheUintId,
{
fn add_to_re_randomization_context(
&self,
context: &mut crate::high_level_api::re_randomization::ReRandomizationContext,
) {
let on_cpu = self.ciphertext.on_cpu();
context.inner.add_ciphertext(&*on_cpu);
context
.inner
.add_bytes(self.re_randomization_metadata.data());
}
fn re_randomize(
&mut self,
compact_public_key: &CompactPublicKey,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let Some(re_randomization_key) = key.re_randomization_cpk_casting_key() else {
return Err(UninitializedReRandKey.into());
};
self.ciphertext.as_cpu_mut().re_randomize(
&compact_public_key.key.key,
&re_randomization_key,
seed,
)?;
Ok(())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_cuda_key) => panic!("GPU does not support CPKReRandomize."),
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
panic!("HPU does not support CPKReRandomize.")
}
})
}
}
#[cfg(test)]
mod test {
use super::*;

View File

@@ -9,6 +9,7 @@ use crate::high_level_api::global_state::with_cpu_internal_keys;
use crate::high_level_api::integers::unsigned::base::{
FheUint, FheUintConformanceParams, FheUintId,
};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::{FheTryEncrypt, Tagged};
use crate::high_level_api::ClientKey;
use crate::integer::block_decomposition::DecomposableInto;
@@ -111,7 +112,8 @@ where
}
};
let mut ciphertext = FheUint::new(inner, self.tag.clone());
let mut ciphertext =
FheUint::new(inner, self.tag.clone(), ReRandomizationMetadata::default());
ciphertext.move_to_device_of_server_key_if_set();
ciphertext

View File

@@ -2,6 +2,7 @@ use crate::core_crypto::prelude::UnsignedNumeric;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::FheUintId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::block_decomposition::{DecomposableInto, RecomposableFrom};
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::CudaUnsignedRadixCiphertext;
@@ -52,7 +53,11 @@ where
.key
.key
.encrypt_radix(value, Id::num_blocks(key.message_modulus()));
let mut ciphertext = Self::new(cpu_ciphertext, key.tag.clone());
let mut ciphertext = Self::new(
cpu_ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
);
ciphertext.move_to_device_of_server_key_if_set();
@@ -71,7 +76,11 @@ where
let cpu_ciphertext = key
.key
.encrypt_radix(value, Id::num_blocks(key.message_modulus()));
let mut ciphertext = Self::new(cpu_ciphertext, key.tag.clone());
let mut ciphertext = Self::new(
cpu_ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
);
ciphertext.move_to_device_of_server_key_if_set();
@@ -90,7 +99,11 @@ where
let cpu_ciphertext = key
.key
.encrypt_radix(value, Id::num_blocks(key.message_modulus()));
let mut ciphertext = Self::new(cpu_ciphertext, key.tag.clone());
let mut ciphertext = Self::new(
cpu_ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
);
ciphertext.move_to_device_of_server_key_if_set();
Ok(ciphertext)
@@ -110,7 +123,11 @@ where
let ciphertext: crate::integer::RadixCiphertext = key
.pbs_key()
.create_trivial_radix(value, Id::num_blocks(key.message_modulus()));
Ok(Self::new(ciphertext, key.tag.clone()))
Ok(Self::new(
ciphertext,
key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -120,7 +137,11 @@ where
Id::num_blocks(cuda_key.key.key.message_modulus),
streams,
);
Ok(Self::new(inner, cuda_key.tag.clone()))
Ok(Self::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {

View File

@@ -8,6 +8,7 @@ use crate::high_level_api::details::MaybeCloned;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::FheUintId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::high_level_api::traits::{
AddSizeOnGpu, BitAndSizeOnGpu, BitNotSizeOnGpu, BitOrSizeOnGpu, BitXorSizeOnGpu,
@@ -77,9 +78,10 @@ where
Id::num_blocks(cpu_key.message_modulus()),
)),
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
},
|ct| Self::new(ct, cpu_key.tag.clone()),
|ct| Self::new(ct, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "gpu")]
@@ -100,7 +102,11 @@ where
streams,
)
});
Self::new(inner, cuda_key.tag.clone())
Self::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -109,7 +115,11 @@ where
for o in iter {
result += o.ciphertext.into_hpu(device);
}
Self::new(result, device.tag.clone())
Self::new(
result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -165,9 +175,10 @@ where
.create_trivial_zero_radix(Id::num_blocks(msg_mod)),
),
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
},
|ct| Self::new(ct, cpu_key.tag.clone()),
|ct| Self::new(ct, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "gpu")]
@@ -202,7 +213,11 @@ where
streams,
)
});
Self::new(inner, cuda_key.tag.clone())
Self::new(
inner,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
}
#[cfg(feature = "hpu")]
@@ -211,14 +226,22 @@ where
let first = iter.next().unwrap().ciphertext.on_hpu(device);
let Some(second) = iter.next() else {
return Self::new(first.clone(), device.tag.clone());
return Self::new(
first.clone(),
device.tag.clone(),
ReRandomizationMetadata::default(),
);
};
let mut result = &*first + &*second.ciphertext.on_hpu(device);
for o in iter {
result += &*o.ciphertext.on_hpu(device);
}
Self::new(result, device.tag.clone())
Self::new(
result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -255,7 +278,11 @@ where
let inner_result = cpu_key
.pbs_key()
.max_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -265,7 +292,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -318,7 +349,11 @@ where
let inner_result = cpu_key
.pbs_key()
.min_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -328,7 +363,11 @@ where
&*rhs.ciphertext.on_gpu(streams),
streams,
);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -392,7 +431,11 @@ where
let inner_result = cpu_key
.pbs_key()
.eq_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -402,7 +445,11 @@ where
&rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -424,7 +471,11 @@ where
)
.pop()
.unwrap();
FheBool::new(hpu_result, device.tag.clone())
FheBool::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -454,7 +505,11 @@ where
let inner_result = cpu_key
.pbs_key()
.ne_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -464,7 +519,11 @@ where
&rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -486,7 +545,11 @@ where
)
.pop()
.unwrap();
FheBool::new(hpu_result, device.tag.clone())
FheBool::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -542,7 +605,11 @@ where
let inner_result = cpu_key
.pbs_key()
.lt_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -552,7 +619,11 @@ where
&rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -574,7 +645,11 @@ where
)
.pop()
.unwrap();
FheBool::new(hpu_result, device.tag.clone())
FheBool::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -604,7 +679,11 @@ where
let inner_result = cpu_key
.pbs_key()
.le_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -614,7 +693,11 @@ where
&rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -636,7 +719,11 @@ where
)
.pop()
.unwrap();
FheBool::new(hpu_result, device.tag.clone())
FheBool::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -666,7 +753,11 @@ where
let inner_result = cpu_key
.pbs_key()
.gt_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -676,7 +767,11 @@ where
&rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -698,7 +793,11 @@ where
)
.pop()
.unwrap();
FheBool::new(hpu_result, device.tag.clone())
FheBool::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -728,7 +827,11 @@ where
let inner_result = cpu_key
.pbs_key()
.ge_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -738,7 +841,11 @@ where
&rhs.ciphertext.on_gpu(streams),
streams,
);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -760,7 +867,11 @@ where
)
.pop()
.unwrap();
FheBool::new(hpu_result, device.tag.clone())
FheBool::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -832,8 +943,8 @@ where
.pbs_key()
.div_rem_parallelized(&*self.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
(
FheUint::<Id>::new(q, cpu_key.tag.clone()),
FheUint::<Id>::new(r, cpu_key.tag.clone()),
FheUint::<Id>::new(q, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
FheUint::<Id>::new(r, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "gpu")]
@@ -845,8 +956,16 @@ where
streams,
);
(
FheUint::<Id>::new(inner_result.0, cuda_key.tag.clone()),
FheUint::<Id>::new(inner_result.1, cuda_key.tag.clone()),
FheUint::<Id>::new(
inner_result.0,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheUint::<Id>::new(
inner_result.1,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -871,8 +990,16 @@ where
let remainder = hpu_result.pop().expect("IOP_DIV must return 2 value");
let quotient = hpu_result.pop().expect("IOP_DIV must return 2 value");
(
FheUint::new(quotient, device.tag.clone()),
FheUint::new(remainder, device.tag.clone()),
FheUint::new(
quotient,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
FheUint::new(
remainder,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
})
@@ -946,20 +1073,20 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.add_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.add(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
let hpu_lhs = lhs.ciphertext.on_hpu(device);
let hpu_rhs = rhs.ciphertext.on_hpu(device);
FheUint::new(&*hpu_lhs + &*hpu_rhs, device.tag.clone())
FheUint::new(&*hpu_lhs + &*hpu_rhs, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -994,20 +1121,20 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.sub_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.sub(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
let hpu_lhs = lhs.ciphertext.on_hpu(device);
let hpu_rhs = rhs.ciphertext.on_hpu(device);
FheUint::new(&*hpu_lhs - &*hpu_rhs, device.tag.clone())
FheUint::new(&*hpu_lhs - &*hpu_rhs, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -1042,20 +1169,20 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.mul_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.mul(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
let hpu_lhs = lhs.ciphertext.on_hpu(device);
let hpu_rhs = rhs.ciphertext.on_hpu(device);
FheUint::new(&*hpu_lhs * &*hpu_rhs, device.tag.clone())
FheUint::new(&*hpu_lhs * &*hpu_rhs, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -1088,20 +1215,20 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.bitand_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.bitand(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
let hpu_lhs = lhs.ciphertext.on_hpu(device);
let hpu_rhs = rhs.ciphertext.on_hpu(device);
FheUint::new(&*hpu_lhs & &*hpu_rhs, device.tag.clone())
FheUint::new(&*hpu_lhs & &*hpu_rhs, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -1134,20 +1261,20 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.bitor_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.bitor(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
let hpu_lhs = lhs.ciphertext.on_hpu(device);
let hpu_rhs = rhs.ciphertext.on_hpu(device);
FheUint::new(&*hpu_lhs | &*hpu_rhs, device.tag.clone())
FheUint::new(&*hpu_lhs | &*hpu_rhs, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -1180,20 +1307,20 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.bitxor_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.bitxor(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
let hpu_lhs = lhs.ciphertext.on_hpu(device);
let hpu_rhs = rhs.ciphertext.on_hpu(device);
FheUint::new(&*hpu_lhs ^ &*hpu_rhs, device.tag.clone())
FheUint::new(&*hpu_lhs ^ &*hpu_rhs, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -1234,7 +1361,7 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.div_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -1244,7 +1371,7 @@ generic_integer_impl_operation!(
.key
.key
.div(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -1267,7 +1394,7 @@ generic_integer_impl_operation!(
);
let _remainder = hpu_result.pop().expect("IOP_DIV must return 2 value");
let quotient = hpu_result.pop().expect("IOP_DIV must return 2 value");
FheUint::new(quotient, device.tag.clone())
FheUint::new(quotient, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -1309,7 +1436,7 @@ generic_integer_impl_operation!(
let inner_result = cpu_key
.pbs_key()
.rem_parallelized(&*lhs.ciphertext.on_cpu(), &*rhs.ciphertext.on_cpu());
FheUint::new(inner_result, cpu_key.tag.clone())
FheUint::new(inner_result, cpu_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) =>
@@ -1320,7 +1447,7 @@ generic_integer_impl_operation!(
.key
.key
.rem(&*lhs.ciphertext.on_gpu(streams), &*rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
},
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -1342,7 +1469,7 @@ generic_integer_impl_operation!(
&[],
);
let remainder = hpu_result.pop().expect("IOP_MOD must return 1 value");
FheUint::new(remainder, device.tag.clone())
FheUint::new(remainder, device.tag.clone(), ReRandomizationMetadata::default())
}
})
}
@@ -1447,14 +1574,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.left_shift_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheUint::new(ciphertext, cpu_key.tag.clone())
FheUint::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.left_shift(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -1475,7 +1602,7 @@ generic_integer_impl_shift_rotate!(
&[hpu_lhs.clone(), hpu_rhs.clone()],
&[],
).pop().expect("IOP_SHIFT_L must return 1 value");
FheUint::new(hpu_result, device.tag.clone())
FheUint::new(hpu_result, device.tag.clone(), ReRandomizationMetadata::default())
}
}
})
@@ -1511,14 +1638,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.right_shift_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheUint::new(ciphertext, cpu_key.tag.clone())
FheUint::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.right_shift(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -1539,7 +1666,7 @@ generic_integer_impl_shift_rotate!(
&[hpu_lhs.clone(), hpu_rhs.clone()],
&[],
).pop().expect("IOP_SHIFT_R must return 1 value");
FheUint::new(hpu_result, device.tag.clone())
FheUint::new(hpu_result, device.tag.clone(), ReRandomizationMetadata::default())
}
}
})
@@ -1575,14 +1702,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.rotate_left_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheUint::new(ciphertext, cpu_key.tag.clone())
FheUint::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.rotate_left(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -1603,7 +1730,7 @@ generic_integer_impl_shift_rotate!(
&[hpu_lhs.clone(), hpu_rhs.clone()],
&[],
).pop().expect("IOP_ROT_L must return 1 value");
FheUint::new(hpu_result, device.tag.clone())
FheUint::new(hpu_result, device.tag.clone(), ReRandomizationMetadata::default())
}
}
})
@@ -1639,14 +1766,14 @@ generic_integer_impl_shift_rotate!(
let ciphertext = cpu_key
.pbs_key()
.rotate_right_parallelized(&*lhs.ciphertext.on_cpu(), &rhs.ciphertext.on_cpu());
FheUint::new(ciphertext, cpu_key.tag.clone())
FheUint::new(ciphertext, cpu_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let inner_result = cuda_key.key.key
.rotate_right(&*lhs.ciphertext.on_gpu(streams), &rhs.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(inner_result, cuda_key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -1667,7 +1794,7 @@ generic_integer_impl_shift_rotate!(
&[hpu_lhs.clone(), hpu_rhs.clone()],
&[],
).pop().expect("IOP_ROT_R must return 1 value");
FheUint::new(hpu_result, device.tag.clone())
FheUint::new(hpu_result, device.tag.clone(), ReRandomizationMetadata::default())
}
}
})
@@ -2492,7 +2619,11 @@ where
let ciphertext = cpu_key
.pbs_key()
.neg_parallelized(&*self.ciphertext.on_cpu());
FheUint::new(ciphertext, cpu_key.tag.clone())
FheUint::new(
ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -2501,7 +2632,11 @@ where
.key
.key
.neg(&*self.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
@@ -2522,7 +2657,11 @@ where
)
.pop()
.expect("SSUB must return a single value");
FheUint::new(hpu_result, device.tag.clone())
FheUint::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
@@ -2583,7 +2722,11 @@ where
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(cpu_key) => {
let ciphertext = cpu_key.pbs_key().bitnot(&*self.ciphertext.on_cpu());
FheUint::new(ciphertext, cpu_key.tag.clone())
FheUint::new(
ciphertext,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -2592,7 +2735,11 @@ where
.key
.key
.bitnot(&*self.ciphertext.on_gpu(streams), streams);
FheUint::new(inner_result, cuda_key.tag.clone())
FheUint::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {

View File

@@ -2,6 +2,7 @@ use crate::core_crypto::prelude::UnsignedNumeric;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::FheUintId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::block_decomposition::DecomposableInto;
use crate::prelude::{CastInto, OverflowingAdd, OverflowingMul, OverflowingNeg, OverflowingSub};
use crate::{FheBool, FheUint};
@@ -51,8 +52,16 @@ where
&other.ciphertext.on_cpu(),
);
(
FheUint::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -64,8 +73,16 @@ where
streams,
);
(
FheUint::<Id>::new(inner_result.0, cuda_key.tag.clone()),
FheBool::new(inner_result.1, cuda_key.tag.clone()),
FheUint::<Id>::new(
inner_result.0,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
inner_result.1,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -90,8 +107,16 @@ where
let overflow = hpu_result.pop().expect("IOP_OVF_ADD must return 2 value");
let result = hpu_result.pop().expect("IOP_OVF_ADD must return 2 value");
(
FheUint::new(result, device.tag.clone()),
FheBool::new(overflow, device.tag.clone()),
FheUint::new(
result,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
})
@@ -174,8 +199,16 @@ where
.pbs_key()
.unsigned_overflowing_scalar_add_parallelized(&self.ciphertext.on_cpu(), other);
(
FheUint::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -187,8 +220,16 @@ where
streams,
);
(
FheUint::<Id>::new(inner_result.0, cuda_key.tag.clone()),
FheBool::new(inner_result.1, cuda_key.tag.clone()),
FheUint::<Id>::new(
inner_result.0,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
inner_result.1,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -215,8 +256,16 @@ where
let overflow = hpu_result.pop().expect("IOP_OVF_ADDS must return 2 value");
let result = hpu_result.pop().expect("IOP_OVF_ADDS must return 2 value");
(
FheUint::new(result, device.tag.clone()),
FheBool::new(overflow, device.tag.clone()),
FheUint::new(
result,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
})
@@ -339,8 +388,16 @@ where
&other.ciphertext.on_cpu(),
);
(
FheUint::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -352,8 +409,16 @@ where
streams,
);
(
FheUint::<Id>::new(inner_result.0, cuda_key.tag.clone()),
FheBool::new(inner_result.1, cuda_key.tag.clone()),
FheUint::<Id>::new(
inner_result.0,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
inner_result.1,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]
@@ -378,8 +443,16 @@ where
let overflow = hpu_result.pop().expect("IOP_OVF_SUB must return 2 value");
let result = hpu_result.pop().expect("IOP_OVF_SUB must return 2 value");
(
FheUint::new(result, device.tag.clone()),
FheBool::new(overflow, device.tag.clone()),
FheUint::new(
result,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
})
@@ -462,8 +535,16 @@ where
.pbs_key()
.unsigned_overflowing_scalar_sub_parallelized(&self.ciphertext.on_cpu(), other);
(
FheUint::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -494,8 +575,16 @@ where
let overflow = hpu_result.pop().expect("IOP_OVF_SUBS must return 2 value");
let result = hpu_result.pop().expect("IOP_OVF_SUBS must return 2 value");
(
FheUint::new(result, device.tag.clone()),
FheBool::new(overflow, device.tag.clone()),
FheUint::new(
result,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
})
@@ -577,8 +666,16 @@ where
&other.ciphertext.on_cpu(),
);
(
FheUint::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -607,8 +704,16 @@ where
let overflow = hpu_result.pop().expect("IOP_OVF_MUL must return 2 value");
let result = hpu_result.pop().expect("IOP_OVF_MUL must return 2 value");
(
FheUint::new(result, device.tag.clone()),
FheBool::new(overflow, device.tag.clone()),
FheUint::new(
result,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
device.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
})
@@ -663,8 +768,16 @@ where
.pbs_key()
.overflowing_neg_parallelized(&*self.ciphertext.on_cpu());
(
FheUint::new(result, cpu_key.tag.clone()),
FheBool::new(overflow, cpu_key.tag.clone()),
FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -674,8 +787,16 @@ where
&cuda_key.streams,
);
(
FheUint::new(result, cuda_key.tag.clone()),
FheBool::new(overflow, cuda_key.tag.clone()),
FheUint::new(
result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
overflow,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "hpu")]

View File

@@ -9,6 +9,7 @@ use crate::high_level_api::errors::UnwrapResultExt;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::FheUintId;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::high_level_api::traits::{
AddSizeOnGpu, BitAndSizeOnGpu, BitOrSizeOnGpu, BitXorSizeOnGpu, DivRemSizeOnGpu, DivSizeOnGpu,
@@ -65,7 +66,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_eq_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -75,7 +80,11 @@ where
.key
.key
.scalar_eq(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -109,7 +118,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_ne_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -119,7 +132,11 @@ where
.key
.key
.scalar_ne(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -159,7 +176,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_lt_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -169,7 +190,11 @@ where
.key
.key
.scalar_lt(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -203,7 +228,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_le_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -213,7 +242,11 @@ where
.key
.key
.scalar_le(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -247,7 +280,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_gt_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -257,7 +294,11 @@ where
.key
.key
.scalar_gt(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -291,7 +332,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_ge_parallelized(&*self.ciphertext.on_cpu(), rhs);
FheBool::new(inner_result, cpu_key.tag.clone())
FheBool::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -301,7 +346,11 @@ where
.key
.key
.scalar_ge(&*self.ciphertext.on_gpu(streams), rhs, streams);
FheBool::new(inner_result, cuda_key.tag.clone())
FheBool::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -478,7 +527,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_max_parallelized(&*self.ciphertext.on_cpu(), rhs);
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -488,7 +541,11 @@ where
.key
.key
.scalar_max(&*self.ciphertext.on_gpu(streams), rhs, streams);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -530,7 +587,11 @@ where
let inner_result = cpu_key
.pbs_key()
.scalar_min_parallelized(&*self.ciphertext.on_cpu(), rhs);
Self::new(inner_result, cpu_key.tag.clone())
Self::new(
inner_result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(cuda_key) => {
@@ -540,7 +601,11 @@ where
.key
.key
.scalar_min(&*self.ciphertext.on_gpu(streams), rhs, streams);
Self::new(inner_result, cuda_key.tag.clone())
Self::new(
inner_result,
cuda_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
@@ -590,7 +655,11 @@ where
let result = cpu_key
.pbs_key()
.scalar_bitslice_parallelized(&self.ciphertext.on_cpu(), range)?;
Ok(FheUint::new(result, cpu_key.tag.clone()))
Ok(FheUint::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -674,8 +743,8 @@ macro_rules! generic_integer_impl_scalar_div_rem {
InternalServerKey::Cpu(cpu_key) => {
let (q, r) = cpu_key.pbs_key().scalar_div_rem_parallelized(&*self.ciphertext.on_cpu(), rhs);
(
<$concrete_type>::new(q, cpu_key.tag.clone()),
<$concrete_type>::new(r, cpu_key.tag.clone())
<$concrete_type>::new(q, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
<$concrete_type>::new(r, cpu_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "gpu")]
@@ -688,8 +757,8 @@ macro_rules! generic_integer_impl_scalar_div_rem {
};
let (q, r) = (RadixCiphertext::Cuda(inner_q), RadixCiphertext::Cuda(inner_r));
(
<$concrete_type>::new(q, cuda_key.tag.clone()),
<$concrete_type>::new(r, cuda_key.tag.clone())
<$concrete_type>::new(q, cuda_key.tag.clone(), ReRandomizationMetadata::default()),
<$concrete_type>::new(r, cuda_key.tag.clone(), ReRandomizationMetadata::default()),
)
}
#[cfg(feature = "hpu")]
@@ -712,8 +781,8 @@ macro_rules! generic_integer_impl_scalar_div_rem {
let remainder = hpu_result.pop().expect("IOP_DIVS must return 2 value");
let quotient = hpu_result.pop().expect("IOP_DIVS must return 2 value");
(
FheUint::new(quotient, device.tag.clone()),
FheUint::new(remainder, device.tag.clone()),
FheUint::new(quotient, device.tag.clone(), ReRandomizationMetadata::default()),
FheUint::new(remainder, device.tag.clone(), ReRandomizationMetadata::default()),
)
}
}
@@ -757,7 +826,7 @@ macro_rules! generic_integer_impl_scalar_operation {
fn $rust_trait_method(self, rhs: $scalar_type) -> Self::Output {
let inner_result = $closure(self, rhs);
let tag = global_state::tag_of_internal_server_key().unwrap_display();
<$concrete_type>::new(inner_result, tag)
<$concrete_type>::new(inner_result, tag, ReRandomizationMetadata::default())
}
}
)* // Closing second repeating pattern
@@ -855,7 +924,7 @@ macro_rules! generic_integer_impl_scalar_left_operation {
fn $rust_trait_method(self, rhs: &$concrete_type) -> Self::Output {
let inner_result = $closure(*self, rhs);
let tag = global_state::tag_of_internal_server_key().unwrap_display();
<$concrete_type>::new(inner_result, tag)
<$concrete_type>::new(inner_result, tag, ReRandomizationMetadata::default())
}
}
)* // Closing second repeating pattern

View File

@@ -12,6 +12,7 @@ use crate::integer::compression_keys::CompressionPrivateKeys;
use crate::integer::noise_squashing::{NoiseSquashingPrivateKey, NoiseSquashingPrivateKeyView};
use crate::named::Named;
use crate::prelude::Tagged;
use crate::shortint::parameters::ShortintKeySwitchingParameters;
use crate::shortint::MessageModulus;
use crate::Tag;
use tfhe_csprng::seeders::Seed;
@@ -77,6 +78,7 @@ impl ClientKey {
self.key.block_parameters()
}
#[allow(clippy::type_complexity)]
pub fn into_raw_parts(
self,
) -> (
@@ -85,10 +87,11 @@ impl ClientKey {
Option<CompressionPrivateKeys>,
Option<NoiseSquashingPrivateKey>,
Option<NoiseSquashingCompressionPrivateKey>,
Option<ShortintKeySwitchingParameters>,
Tag,
) {
let (cks, cpk, cppk, nsk, nscpk) = self.key.into_raw_parts();
(cks, cpk, cppk, nsk, nscpk, self.tag)
let (cks, cpk, cppk, nsk, nscpk, cpkrndp) = self.key.into_raw_parts();
(cks, cpk, cppk, nsk, nscpk, cpkrndp, self.tag)
}
pub fn from_raw_parts(
@@ -100,6 +103,7 @@ impl ClientKey {
compression_key: Option<CompressionPrivateKeys>,
noise_squashing_key: Option<NoiseSquashingPrivateKey>,
noise_squashing_compression_key: Option<NoiseSquashingCompressionPrivateKey>,
cpk_re_randomization_ksk_params: Option<ShortintKeySwitchingParameters>,
tag: Tag,
) -> Self {
Self {
@@ -109,6 +113,7 @@ impl ClientKey {
compression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_ksk_params,
),
tag,
}

View File

@@ -0,0 +1,31 @@
use crate::high_level_api::backward_compatibility::keys::{
CompressedReRandomizationKeySwitchingKeyVersions, ReRandomizationKeySwitchingKeyVersions,
};
use tfhe_versionable::Versionize;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Versionize)]
#[versionize(ReRandomizationKeySwitchingKeyVersions)]
pub enum ReRandomizationKeySwitchingKey {
UseCPKEncryptionKSK,
DedicatedKSK(crate::integer::key_switching_key::KeySwitchingKeyMaterial),
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Versionize)]
#[versionize(CompressedReRandomizationKeySwitchingKeyVersions)]
pub enum CompressedReRandomizationKeySwitchingKey {
UseCPKEncryptionKSK,
DedicatedKSK(crate::integer::key_switching_key::CompressedKeySwitchingKeyMaterial),
}
impl CompressedReRandomizationKeySwitchingKey {
pub fn decompress(&self) -> ReRandomizationKeySwitchingKey {
match self {
Self::UseCPKEncryptionKSK => ReRandomizationKeySwitchingKey::UseCPKEncryptionKSK,
Self::DedicatedKSK(compressed_key_switching_key_material) => {
ReRandomizationKeySwitchingKey::DedicatedKSK(
compressed_key_switching_key_material.decompress(),
)
}
}
}
}

View File

@@ -2,6 +2,9 @@ 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::high_level_api::keys::cpk_re_randomization::{
CompressedReRandomizationKeySwitchingKey, ReRandomizationKeySwitchingKey,
};
use crate::integer::ciphertext::{
CompressedNoiseSquashingCompressionKey, NoiseSquashingCompressionKey,
NoiseSquashingCompressionPrivateKey,
@@ -33,12 +36,13 @@ use tfhe_versionable::Versionize;
pub(crate) struct IntegerConfig {
pub(crate) block_parameters: crate::shortint::atomic_pattern::AtomicPatternParameters,
pub(crate) dedicated_compact_public_key_parameters: Option<(
crate::shortint::parameters::CompactPublicKeyEncryptionParameters,
crate::shortint::parameters::ShortintKeySwitchingParameters,
CompactPublicKeyEncryptionParameters,
ShortintKeySwitchingParameters,
)>,
pub(crate) compression_parameters: Option<CompressionParameters>,
pub(crate) noise_squashing_parameters: Option<NoiseSquashingParameters>,
pub(crate) noise_squashing_compression_parameters: Option<NoiseSquashingCompressionParameters>,
pub(crate) cpk_re_randomization_ksk_params: Option<ShortintKeySwitchingParameters>,
}
impl IntegerConfig {
@@ -51,6 +55,7 @@ impl IntegerConfig {
compression_parameters: None,
noise_squashing_parameters: None,
noise_squashing_compression_parameters: None,
cpk_re_randomization_ksk_params: None,
}
}
@@ -76,6 +81,24 @@ impl IntegerConfig {
self.noise_squashing_compression_parameters = Some(compression_parameters);
}
pub(crate) fn enable_ciphertext_re_randomization(
&mut self,
cpk_re_randomization_ksk_params: ShortintKeySwitchingParameters,
) {
assert_ne!(
self.dedicated_compact_public_key_parameters, None,
"Dedicated Compact Public Key parameters must be provided to enable re-randomization."
);
assert!(
matches!(
cpk_re_randomization_ksk_params.destination_key,
EncryptionKeyChoice::Big
),
"CompactPublicKey re-randomization can only be enabled targeting the large key."
);
self.cpk_re_randomization_ksk_params = Some(cpk_re_randomization_ksk_params);
}
pub(crate) fn public_key_encryption_parameters(
&self,
) -> Result<crate::shortint::parameters::CompactPublicKeyEncryptionParameters, crate::Error>
@@ -103,6 +126,7 @@ impl Default for IntegerConfig {
compression_parameters: None,
noise_squashing_parameters: None,
noise_squashing_compression_parameters: None,
cpk_re_randomization_ksk_params: None,
}
}
}
@@ -120,6 +144,10 @@ pub(crate) struct IntegerClientKey {
pub(crate) compression_key: Option<CompressionPrivateKeys>,
pub(crate) noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
pub(crate) noise_squashing_compression_private_key: Option<NoiseSquashingCompressionPrivateKey>,
// The re-randomization happens between a dedicated compact private key and the post PBS secret
// key, it needs additional information on how to create the required key switching key, hence
// this optional field
pub(crate) cpk_re_randomization_ksk_params: Option<ShortintKeySwitchingParameters>,
}
impl IntegerClientKey {
@@ -150,15 +178,19 @@ impl IntegerClientKey {
.noise_squashing_compression_parameters
.map(NoiseSquashingCompressionPrivateKey::new);
let cpk_re_randomization_ksk_params = config.cpk_re_randomization_ksk_params;
Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_ksk_params,
}
}
#[allow(clippy::type_complexity)]
/// Deconstruct an [`IntegerClientKey`] into its constituents.
pub fn into_raw_parts(
self,
@@ -168,6 +200,7 @@ impl IntegerClientKey {
Option<CompressionPrivateKeys>,
Option<NoiseSquashingPrivateKey>,
Option<NoiseSquashingCompressionPrivateKey>,
Option<ShortintKeySwitchingParameters>,
) {
let Self {
key,
@@ -175,6 +208,7 @@ impl IntegerClientKey {
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_ksk_params,
} = self;
(
key,
@@ -182,6 +216,7 @@ impl IntegerClientKey {
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_ksk_params,
)
}
@@ -196,6 +231,7 @@ impl IntegerClientKey {
compression_key: Option<CompressionPrivateKeys>,
noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
noise_squashing_compression_private_key: Option<NoiseSquashingCompressionPrivateKey>,
cpk_re_randomization_ksk_params: Option<ShortintKeySwitchingParameters>,
) -> Self {
let shortint_cks: &crate::shortint::ClientKey = key.as_ref();
@@ -224,6 +260,7 @@ impl IntegerClientKey {
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_ksk_params,
}
}
@@ -257,12 +294,15 @@ impl From<IntegerConfig> for IntegerClientKey {
.noise_squashing_compression_parameters
.map(NoiseSquashingCompressionPrivateKey::new);
let cpk_re_randomization_ksk_params = config.cpk_re_randomization_ksk_params;
Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_ksk_params,
}
}
}
@@ -281,6 +321,8 @@ pub struct IntegerServerKey {
pub(crate) decompression_key: Option<DecompressionKey>,
pub(crate) noise_squashing_key: Option<NoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
pub(crate) cpk_re_randomization_key_switching_key_material:
Option<ReRandomizationKeySwitchingKey>,
}
impl IntegerServerKey {
@@ -330,6 +372,39 @@ impl IntegerServerKey {
},
);
let cpk_re_randomization_key_switching_key_material = match (
&client_key.dedicated_compact_private_key,
client_key.cpk_re_randomization_ksk_params,
) {
(Some(compact_private_key), Some(cpk_re_randomization_ksk_params)) => {
assert!(
matches!(
cpk_re_randomization_ksk_params.destination_key,
EncryptionKeyChoice::Big
),
"CompactPublicKey re-randomization can only be enabled \
targeting the large secret key."
);
if cpk_re_randomization_ksk_params == compact_private_key.1 {
Some(ReRandomizationKeySwitchingKey::UseCPKEncryptionKSK)
} else {
let build_helper =
crate::integer::key_switching_key::KeySwitchingKeyBuildHelper::new(
(&compact_private_key.0, None),
(cks, &base_integer_key),
cpk_re_randomization_ksk_params,
);
Some(ReRandomizationKeySwitchingKey::DedicatedKSK(
build_helper.into(),
))
}
}
(_, None) => None,
_ => panic!("Inconsistent ClientKey set-up for CompactPublicKey re-randomization."),
};
Self {
key: base_integer_key,
cpk_key_switching_key_material,
@@ -337,6 +412,7 @@ impl IntegerServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
}
}
@@ -356,6 +432,22 @@ impl IntegerServerKey {
})
}
pub(in crate::high_level_api) fn re_randomization_cpk_casting_key(
&self,
) -> Option<crate::integer::key_switching_key::KeySwitchingKeyMaterialView<'_>> {
self.cpk_re_randomization_key_switching_key_material
.as_ref()
.and_then(|key| match key {
ReRandomizationKeySwitchingKey::UseCPKEncryptionKSK => self
.cpk_key_switching_key_material
.as_ref()
.map(|k| k.as_view()),
ReRandomizationKeySwitchingKey::DedicatedKSK(key_switching_key_material) => {
Some(key_switching_key_material.as_view())
}
})
}
pub(in crate::high_level_api) fn message_modulus(&self) -> MessageModulus {
self.key.message_modulus()
}
@@ -388,6 +480,8 @@ pub struct IntegerCompressedServerKey {
pub(crate) decompression_key: Option<CompressedDecompressionKey>,
pub(crate) noise_squashing_key: Option<CompressedNoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
pub(crate) cpk_re_randomization_key_switching_key_material:
Option<CompressedReRandomizationKeySwitchingKey>,
}
impl IntegerCompressedServerKey {
@@ -440,6 +534,39 @@ impl IntegerCompressedServerKey {
(Some(noise_squashing_key), noise_squashing_compression_key)
});
let cpk_re_randomization_key_switching_key_material = match (
&client_key.dedicated_compact_private_key,
client_key.cpk_re_randomization_ksk_params,
) {
(Some(compact_private_key), Some(cpk_re_randomization_ksk_params)) => {
assert!(
matches!(
cpk_re_randomization_ksk_params.destination_key,
EncryptionKeyChoice::Big
),
"CompactPublicKey re-randomization can only be enabled \
targeting the large secret key."
);
if cpk_re_randomization_ksk_params == compact_private_key.1 {
Some(CompressedReRandomizationKeySwitchingKey::UseCPKEncryptionKSK)
} else {
let build_helper =
crate::integer::key_switching_key::CompressedKeySwitchingKeyBuildHelper::new(
(&compact_private_key.0, None),
(cks, &key),
cpk_re_randomization_ksk_params,
);
Some(CompressedReRandomizationKeySwitchingKey::DedicatedKSK(
build_helper.into(),
))
}
}
(_, None) => None,
_ => panic!("Inconsistent ClientKey set-up for CompactPublicKey re-randomization."),
};
Self {
key,
cpk_key_switching_key_material,
@@ -447,9 +574,11 @@ impl IntegerCompressedServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
}
}
#[allow(clippy::type_complexity)]
pub fn into_raw_parts(
self,
) -> (
@@ -457,12 +586,28 @@ impl IntegerCompressedServerKey {
Option<crate::integer::key_switching_key::CompressedKeySwitchingKeyMaterial>,
Option<CompressedCompressionKey>,
Option<CompressedDecompressionKey>,
Option<CompressedNoiseSquashingKey>,
Option<CompressedNoiseSquashingCompressionKey>,
Option<CompressedReRandomizationKeySwitchingKey>,
) {
let Self {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
} = self;
(
self.key,
self.cpk_key_switching_key_material,
self.compression_key,
self.decompression_key,
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
)
}
@@ -475,6 +620,9 @@ impl IntegerCompressedServerKey {
decompression_key: Option<CompressedDecompressionKey>,
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
cpk_re_randomization_key_switching_key_material: Option<
CompressedReRandomizationKeySwitchingKey,
>,
) -> Self {
Self {
key,
@@ -483,6 +631,7 @@ impl IntegerCompressedServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
}
}
@@ -507,6 +656,11 @@ impl IntegerCompressedServerKey {
.as_ref()
.map(CompressedNoiseSquashingCompressionKey::decompress);
let cpk_re_randomization_key_switching_key_material = self
.cpk_re_randomization_key_switching_key_material
.as_ref()
.map(CompressedReRandomizationKeySwitchingKey::decompress);
IntegerServerKey {
key: self.key.decompress(),
cpk_key_switching_key_material: self.cpk_key_switching_key_material.as_ref().map(
@@ -516,6 +670,7 @@ impl IntegerCompressedServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
}
}
}
@@ -605,6 +760,7 @@ pub struct IntegerServerKeyConformanceParams {
pub compression_param: Option<CompressionParameters>,
pub noise_squashing_param: Option<NoiseSquashingParameters>,
pub noise_squashing_compression_param: Option<NoiseSquashingCompressionParameters>,
pub cpk_re_randomization_ksk_params: Option<ShortintKeySwitchingParameters>,
}
impl<C: Into<Config>> From<C> for IntegerServerKeyConformanceParams {
@@ -616,6 +772,7 @@ impl<C: Into<Config>> From<C> for IntegerServerKeyConformanceParams {
compression_param: config.inner.compression_parameters,
noise_squashing_param: config.inner.noise_squashing_parameters,
noise_squashing_compression_param: config.inner.noise_squashing_compression_parameters,
cpk_re_randomization_ksk_params: config.inner.cpk_re_randomization_ksk_params,
}
}
}
@@ -676,6 +833,7 @@ impl ParameterSetConformant for IntegerServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
} = self;
let cpk_key_switching_key_material_is_ok = match (
@@ -747,11 +905,39 @@ impl ParameterSetConformant for IntegerServerKey {
_ => return false,
};
let cpk_re_randomization_key_is_ok = match (
cpk_key_switching_key_material.as_ref(),
cpk_re_randomization_key_switching_key_material.as_ref(),
parameter_set.cpk_param,
parameter_set.cpk_re_randomization_ksk_params,
) {
// We need cpk_ksk, to be present when we have the re-randomization key
(
Some(cpk_ksk),
Some(re_rand_ksk),
Some((cpk_params, _cpk_ksk_params)),
Some(re_rand_ks_params),
) => (parameter_set.sk_param, cpk_params, re_rand_ks_params)
.try_into()
.is_ok_and(|re_rand_param| {
let key_to_check = match re_rand_ksk {
ReRandomizationKeySwitchingKey::UseCPKEncryptionKSK => cpk_ksk,
ReRandomizationKeySwitchingKey::DedicatedKSK(key) => key,
};
key_to_check.is_conformant(&re_rand_param)
}),
// No re-randomization key and no parameters for the key -> ok
(_, None, _, None) => true,
_ => 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
&& cpk_re_randomization_key_is_ok
}
}
@@ -766,6 +952,7 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
} = self;
let cpk_key_switching_key_material_is_ok = match (
@@ -837,11 +1024,39 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
_ => return false,
};
let cpk_re_randomization_key_is_ok = match (
cpk_key_switching_key_material.as_ref(),
cpk_re_randomization_key_switching_key_material.as_ref(),
parameter_set.cpk_param,
parameter_set.cpk_re_randomization_ksk_params,
) {
// We need cpk_ksk, to be present when we have the re-randomization key
(
Some(cpk_ksk),
Some(re_rand_ksk),
Some((cpk_params, _cpk_ksk_params)),
Some(re_rand_ks_params),
) => (parameter_set.sk_param, cpk_params, re_rand_ks_params)
.try_into()
.is_ok_and(|re_rand_param| {
let key_to_check = match re_rand_ksk {
CompressedReRandomizationKeySwitchingKey::UseCPKEncryptionKSK => cpk_ksk,
CompressedReRandomizationKeySwitchingKey::DedicatedKSK(key) => key,
};
key_to_check.is_conformant(&re_rand_param)
}),
// No re-randomization key and no parameters for the key -> ok
(_, None, _, None) => true,
_ => 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
&& cpk_re_randomization_key_is_ok
}
}

View File

@@ -2,6 +2,7 @@ use tfhe_versionable::Versionize;
use crate::backward_compatibility::keys::KeySwitchingKeyVersions;
use crate::high_level_api::integers::{FheIntId, FheUintId};
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::BooleanBlock;
use crate::named::Named;
use crate::prelude::FheKeyswitch;
@@ -82,7 +83,11 @@ where
fn keyswitch(&self, input: &FheUint<Id>) -> FheUint<Id> {
let radix = input.ciphertext.on_cpu();
let casted = self.key.cast(&*radix);
FheUint::new(casted, self.tag_out.clone())
FheUint::new(
casted,
self.tag_out.clone(),
ReRandomizationMetadata::default(),
)
}
}
@@ -93,7 +98,11 @@ where
fn keyswitch(&self, input: &FheInt<Id>) -> FheInt<Id> {
let radix = input.ciphertext.on_cpu();
let casted = self.key.cast(&*radix);
FheInt::new(casted, self.tag_out.clone())
FheInt::new(
casted,
self.tag_out.clone(),
ReRandomizationMetadata::default(),
)
}
}
@@ -101,7 +110,11 @@ impl FheKeyswitch<FheBool> for KeySwitchingKey {
fn keyswitch(&self, input: &FheBool) -> FheBool {
let boolean_block = input.ciphertext.on_cpu();
let casted = self.key.key.cast(boolean_block.as_ref());
FheBool::new(BooleanBlock::new_unchecked(casted), self.tag_out.clone())
FheBool::new(
BooleanBlock::new_unchecked(casted),
self.tag_out.clone(),
ReRandomizationMetadata::default(),
)
}
}

View File

@@ -2,11 +2,15 @@ mod client;
mod public;
mod server;
mod cpk_re_randomization;
mod inner;
mod key_switching_key;
use crate::high_level_api::config::Config;
pub use client::ClientKey;
pub use cpk_re_randomization::{
CompressedReRandomizationKeySwitchingKey, ReRandomizationKeySwitchingKey,
};
pub(crate) use inner::CompactPrivateKey;
pub use key_switching_key::KeySwitchingKey;
pub use public::{CompactPublicKey, CompressedCompactPublicKey, CompressedPublicKey, PublicKey};

View File

@@ -7,7 +7,10 @@ use crate::core_crypto::gpu::lwe_keyswitch_key::CudaLweKeyswitchKey;
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::high_level_api::keys::{
CompressedReRandomizationKeySwitchingKey, IntegerCompressedServerKey, IntegerServerKey,
ReRandomizationKeySwitchingKey,
};
use crate::integer::ciphertext::{
CompressedNoiseSquashingCompressionKey, NoiseSquashingCompressionKey,
};
@@ -65,6 +68,7 @@ impl ServerKey {
Option<DecompressionKey>,
Option<NoiseSquashingKey>,
Option<NoiseSquashingCompressionKey>,
Option<ReRandomizationKeySwitchingKey>,
Tag,
) {
let IntegerServerKey {
@@ -74,6 +78,7 @@ impl ServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
} = (*self.key).clone();
(
@@ -83,10 +88,12 @@ impl ServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
self.tag,
)
}
#[allow(clippy::too_many_arguments)]
pub fn from_raw_parts(
key: crate::integer::ServerKey,
cpk_key_switching_key_material: Option<
@@ -96,6 +103,7 @@ impl ServerKey {
decompression_key: Option<DecompressionKey>,
noise_squashing_key: Option<NoiseSquashingKey>,
noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
cpk_re_randomization_key_switching_key_material: Option<ReRandomizationKeySwitchingKey>,
tag: Tag,
) -> Self {
Self {
@@ -106,6 +114,7 @@ impl ServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
}),
tag,
}
@@ -126,6 +135,12 @@ impl ServerKey {
self.key.cpk_casting_key()
}
pub(in crate::high_level_api) fn re_randomization_cpk_casting_key(
&self,
) -> Option<crate::integer::key_switching_key::KeySwitchingKeyMaterialView<'_>> {
self.key.re_randomization_cpk_casting_key()
}
pub fn noise_squashing_key(
&self,
) -> Option<&crate::integer::noise_squashing::NoiseSquashingKey> {
@@ -245,6 +260,7 @@ impl CompressedServerKey {
}
}
#[allow(clippy::type_complexity)]
pub fn into_raw_parts(
self,
) -> (
@@ -252,12 +268,16 @@ impl CompressedServerKey {
Option<crate::integer::key_switching_key::CompressedKeySwitchingKeyMaterial>,
Option<CompressedCompressionKey>,
Option<CompressedDecompressionKey>,
Option<CompressedNoiseSquashingKey>,
Option<CompressedNoiseSquashingCompressionKey>,
Option<CompressedReRandomizationKeySwitchingKey>,
Tag,
) {
let (a, b, c, d) = self.integer_key.into_raw_parts();
(a, b, c, d, self.tag)
let (a, b, c, d, e, f, g) = self.integer_key.into_raw_parts();
(a, b, c, d, e, f, g, self.tag)
}
#[allow(clippy::too_many_arguments)]
pub fn from_raw_parts(
integer_key: crate::integer::CompressedServerKey,
cpk_key_switching_key_material: Option<
@@ -267,6 +287,9 @@ impl CompressedServerKey {
decompression_key: Option<CompressedDecompressionKey>,
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
cpk_re_randomization_key_switching_key_material: Option<
CompressedReRandomizationKeySwitchingKey,
>,
tag: Tag,
) -> Self {
Self {
@@ -277,6 +300,7 @@ impl CompressedServerKey {
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key_switching_key_material,
),
tag,
}
@@ -576,6 +600,7 @@ mod test {
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_KEYSWITCH_TO_BIG_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,
};
@@ -662,11 +687,15 @@ mod test {
let noise_squashing_compression_params =
NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let cpk_re_randomization_ksk_params =
PARAM_KEYSWITCH_TO_BIG_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)
.enable_ciphertext_re_randomization(cpk_re_randomization_ksk_params)
.build();
let ck = ClientKey::generate(config);
@@ -709,6 +738,7 @@ mod test {
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_ksk_params: None,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -738,6 +768,7 @@ mod test {
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_ksk_params: None,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -823,11 +854,15 @@ mod test {
let noise_squashing_compression_params =
NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let cpk_re_randomization_ksk_params =
PARAM_KEYSWITCH_TO_BIG_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)
.enable_ciphertext_re_randomization(cpk_re_randomization_ksk_params)
.build();
let ck = ClientKey::generate(config);
@@ -870,6 +905,7 @@ mod test {
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_ksk_params: None,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -899,6 +935,7 @@ mod test {
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_ksk_params: None,
};
assert!(!sk.is_conformant(&conformance_params));

View File

@@ -63,7 +63,8 @@ pub use integers::{
pub use keys::CudaServerKey;
pub use keys::{
generate_keys, ClientKey, CompactPublicKey, CompressedCompactPublicKey, CompressedPublicKey,
CompressedServerKey, KeySwitchingKey, PublicKey, ServerKey,
CompressedReRandomizationKeySwitchingKey, CompressedServerKey, KeySwitchingKey, PublicKey,
ReRandomizationKeySwitchingKey, ServerKey,
};
use strum::FromRepr;
@@ -129,6 +130,9 @@ pub use compressed_noise_squashed_ciphertext_list::{
CompressedSquashedNoiseCiphertextList, CompressedSquashedNoiseCiphertextListBuilder,
HlSquashedNoiseCompressible, HlSquashedNoiseExpandable,
};
pub use re_randomization::{
ReRandomizationContext, ReRandomizationMetadata, ReRandomizationSeedGen,
};
#[cfg(feature = "strings")]
pub use strings::ascii::{EncryptableString, FheAsciiString, FheStringIsEmpty, FheStringLen};
pub use tag::Tag;
@@ -141,6 +145,7 @@ mod errors;
mod global_state;
mod integers;
mod keys;
mod re_randomization;
#[cfg(feature = "strings")]
mod strings;
mod traits;

View File

@@ -9,8 +9,8 @@
pub use crate::high_level_api::traits::{
BitSlice, CiphertextList, DivRem, FheDecrypt, FheEncrypt, FheEq, FheKeyswitch, FheMax, FheMin,
FheOrd, FheTrivialEncrypt, FheTryEncrypt, FheTryTrivialEncrypt, FheWait, IfThenElse,
OverflowingAdd, OverflowingMul, OverflowingNeg, OverflowingSub, RotateLeft, RotateLeftAssign,
RotateRight, RotateRightAssign, ScalarIfThenElse, SquashNoise, Tagged,
OverflowingAdd, OverflowingMul, OverflowingNeg, OverflowingSub, ReRandomize, RotateLeft,
RotateLeftAssign, RotateRight, RotateRightAssign, ScalarIfThenElse, SquashNoise, Tagged,
};
#[cfg(feature = "hpu")]
pub use crate::high_level_api::traits::{FheHpu, HpuHandle};

View File

@@ -0,0 +1,234 @@
use crate::backward_compatibility::cpk_re_randomization::ReRandomizationMetadataVersions;
use crate::core_crypto::commons::math::random::XofSeed;
use crate::high_level_api::keys::CompactPublicKey;
use crate::high_level_api::tag::SmallVec;
use crate::integer::ciphertext::{ReRandomizationSeed, ReRandomizationSeedHasher};
use tfhe_versionable::Versionize;
/// Re-Randomization adds randomness to an existing ciphertext without changing the value it
/// encrypts.
///
/// It can be used to achieve sIND-CPAD security and needs to be called on every function inputs.
///
/// This works by encrypting zeros using a public key, then adding theses zeros to the ciphertext.
/// This process is seeded using the [`ReRandomizationContext`] and thus can be made deterministic.
///
/// The randomization seeds are built from the ciphertexts encrypted values, some metadata that tie
/// them to their origin (such as a zk-pok) and a sequence of bytes that uniquely describe the
/// function that will be applied to them.
///
/// More precisely, the hash function will be updated with, in order:
/// - the rerand seeder domain separator (e.g: TFHE_Rrd)
/// - the ciphertexts encrypted values
/// - the ciphertexts metadata
/// - the function description (e.g: "FheUint64+FheUint64" + a unique random nonce)
/// - a unique counter for each seed
///
/// For example, if we want to re-randomize the inputs of a function with two arguments ct1 and ct2,
/// respectively associated to metadata meta1 and meta2, what happens conceptually is:
///
/// ```text
/// seed1 = hash(rerand_domain_separator, ct1, ct2, meta1, meta2, fn_description, 0)
/// seed2 = hash(rerand_domain_separator, ct1, ct2, meta1, meta2, fn_description, 1)
/// ct1_rerand = ct1 + encrypt(0, pubkey, public_encryption_domain_separator, seed1)
/// ct2_rerand = ct2 + encrypt(0, pubkey, public_encryption_domain_separator, seed2)
/// function(ct1_rerand, ct2_rerand)
/// ```
///
/// # Example
///
/// ```rust
/// use tfhe::prelude::*;
/// use tfhe::shortint::parameters::*;
/// use tfhe::{
/// generate_keys, set_server_key, CompactPublicKey, ConfigBuilder, FheUint64,
/// ReRandomizationContext,
/// };
///
/// let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
/// let cpk_params = (
/// PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
/// PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
/// );
/// let re_rand_ks_params = PARAM_KEYSWITCH_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
///
/// let config = ConfigBuilder::with_custom_parameters(params)
/// .use_dedicated_compact_public_key_parameters(cpk_params)
/// .enable_ciphertext_re_randomization(re_rand_ks_params)
/// .build();
///
/// let (cks, sks) = generate_keys(config);
/// let cpk = CompactPublicKey::new(&cks);
///
/// let compact_public_encryption_domain_separator = *b"TFHE_Enc";
/// let rerand_domain_separator = *b"TFHE_Rrd";
///
/// set_server_key(sks);
///
/// let clear_a = 12u64;
/// let clear_b = 37u64;
/// let mut a = FheUint64::encrypt(clear_a, &cks);
/// let mut b = FheUint64::encrypt(clear_b, &cks);
///
/// // Simulate a 256 bits hash added as metadata
/// let rand_a: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
/// let rand_b: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
/// a.re_randomization_metadata_mut().set_data(&rand_a);
/// b.re_randomization_metadata_mut().set_data(&rand_b);
///
/// // Simulate a 256 bits nonce
/// let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
///
/// let mut re_rand_context = ReRandomizationContext::new(
/// rerand_domain_separator,
/// // First is the function description, second is a nonce
/// [b"FheUint64+FheUint64".as_slice(), nonce.as_slice()],
/// compact_public_encryption_domain_separator,
/// );
///
/// // Add ciphertexts to the context
/// re_rand_context.add_ciphertext(&a);
/// re_rand_context.add_ciphertext(&b);
///
/// let mut seed_gen = re_rand_context.finalize();
///
/// a.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
/// b.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
///
/// let c = a + b;
/// let dec: u64 = c.decrypt(&cks);
///
/// assert_eq!(clear_a.wrapping_add(clear_b), dec);
/// ```
pub trait ReRandomize
where
Self: Sized,
{
fn add_to_re_randomization_context(&self, context: &mut ReRandomizationContext);
/// Re-randomize the ciphertext using the provided public key and seed.
///
/// The random elements of the ciphertexts will be changed but it will still encrypt the same
/// value.
fn re_randomize(
&mut self,
compact_public_key: &CompactPublicKey,
seed: ReRandomizationSeed,
) -> crate::Result<()>;
}
/// The context in which the ciphertexts to re-randomized will be used.
///
/// It can be updated with user provided ciphertexts and will then be finalized into a
/// [`ReRandomizationSeedGen`].
pub struct ReRandomizationContext {
pub(in crate::high_level_api) inner: crate::integer::ciphertext::ReRandomizationContext,
}
impl ReRandomizationContext {
/// Create a new re-randomization context with the default seed hasher (blake3).
///
/// `rerand_seeder_domain_separator` is the domain separator that will be fed into the
/// seed generator.
/// `public_encryption_domain_separator` is the domain separator that will be used along this
/// seed to generate the encryptions of zero.
/// `fn_description` is a unique sequence of bytes that represents the functions called on the
/// re-randomized values.
///
/// (See [`XofSeed`] for more information)
///
/// # Example
/// ```rust
/// use tfhe::ReRandomizationContext;
/// // Simulate a 256 bits nonce
/// let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
/// let _re_rand_context = ReRandomizationContext::new(
/// *b"TFHE_Rrd",
/// [b"FheUint64+FheUint64".as_slice(), &nonce],
/// *b"TFHE_Enc"
/// );
pub fn new<'a>(
rerand_seeder_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
fn_description: impl IntoIterator<Item = &'a [u8]>,
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
) -> Self {
Self {
inner: crate::integer::ciphertext::ReRandomizationContext::new(
rerand_seeder_domain_separator,
fn_description,
public_encryption_domain_separator,
),
}
}
/// Create a new re-randomization context with the provided seed hasher.
pub fn new_with_hasher<'a>(
fn_description: impl IntoIterator<Item = &'a [u8]>,
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
seed_hasher: ReRandomizationSeedHasher,
) -> Self {
Self {
inner: crate::integer::ciphertext::ReRandomizationContext::new_with_hasher(
fn_description,
public_encryption_domain_separator,
seed_hasher,
),
}
}
/// Adds a new ciphertext to the re-randomization context
pub fn add_ciphertext<Data: ReRandomize>(&mut self, data: &Data) {
data.add_to_re_randomization_context(self);
}
/// Consumes the context to create a seed generator
pub fn finalize(self) -> ReRandomizationSeedGen {
ReRandomizationSeedGen {
inner: self.inner.finalize(),
}
}
}
/// A generator that can be used to obtain seeds needed to re-randomize individual ciphertexts.
///
/// It should only be used to create one seed per ciphertext that was added to the context
pub struct ReRandomizationSeedGen {
inner: crate::integer::ciphertext::ReRandomizationSeedGen,
}
impl ReRandomizationSeedGen {
/// Generate the next seed from the seeder.
///
/// Returns an error if more seeds have been generated than the number of ciphertext added into
/// the context.
pub fn next_seed(&mut self) -> crate::Result<ReRandomizationSeed> {
self.inner.next_seed()
}
}
/// Metadata linked to a ciphertext that will be used when updating the [`ReRandomizationContext`]
#[derive(
Default, Clone, Debug, serde::Serialize, serde::Deserialize, Versionize, PartialEq, Eq,
)]
#[versionize(ReRandomizationMetadataVersions)]
pub struct ReRandomizationMetadata {
inner: SmallVec,
}
impl ReRandomizationMetadata {
pub fn new(data: &[u8]) -> Self {
let mut inner = SmallVec::default();
inner.set_data(data);
Self { inner }
}
pub fn data(&self) -> &[u8] {
self.inner.data()
}
pub fn set_data(&mut self, data: &[u8]) {
self.inner.set_data(data);
}
}

View File

@@ -1,5 +1,6 @@
use crate::high_level_api::global_state::with_internal_keys;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::strings::ascii::FheAsciiString;
use crate::prelude::{FheEq, FheEqIgnoreCase, FheOrd};
use crate::strings::ciphertext::ClearString;
@@ -12,7 +13,11 @@ impl FheEq<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.eq(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -31,7 +36,11 @@ impl FheEq<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.ne(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -50,7 +59,11 @@ impl FheEq<&ClearString> for FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().eq(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -67,7 +80,11 @@ impl FheEq<&ClearString> for FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().ne(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -88,7 +105,11 @@ impl FheOrd<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.lt(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -107,7 +128,11 @@ impl FheOrd<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.le(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -126,7 +151,11 @@ impl FheOrd<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.gt(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -145,7 +174,11 @@ impl FheOrd<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.ge(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -164,7 +197,11 @@ impl FheOrd<&ClearString> for FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().lt(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -181,7 +218,11 @@ impl FheOrd<&ClearString> for FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().le(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -198,7 +239,11 @@ impl FheOrd<&ClearString> for FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().gt(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -215,7 +260,11 @@ impl FheOrd<&ClearString> for FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().ge(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -255,7 +304,11 @@ impl FheEqIgnoreCase for FheAsciiString {
let inner = cpu_key
.string_key()
.eq_ignore_case(&self.inner.on_cpu(), (&*rhs.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -295,7 +348,11 @@ impl FheEqIgnoreCase<ClearString> for FheAsciiString {
let inner = cpu_key
.string_key()
.eq_ignore_case(&self.inner.on_cpu(), rhs.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {

View File

@@ -1,5 +1,6 @@
use crate::high_level_api::global_state::with_internal_keys;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::strings::ascii::FheAsciiString;
use crate::high_level_api::strings::traits::FheStringMatching;
use crate::strings::ciphertext::ClearString;
@@ -31,7 +32,11 @@ impl FheStringMatching<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.contains(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -69,7 +74,11 @@ impl FheStringMatching<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.starts_with(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -107,7 +116,11 @@ impl FheStringMatching<&Self> for FheAsciiString {
let inner = cpu_key
.string_key()
.ends_with(&self.inner.on_cpu(), (&*other.inner.on_cpu()).into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -128,7 +141,11 @@ impl FheStringMatching<&ClearString> for FheAsciiString {
let inner = cpu_key
.string_key()
.contains(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -147,7 +164,11 @@ impl FheStringMatching<&ClearString> for FheAsciiString {
let inner = cpu_key
.string_key()
.starts_with(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -166,7 +187,11 @@ impl FheStringMatching<&ClearString> for FheAsciiString {
let inner = cpu_key
.string_key()
.ends_with(&self.inner.on_cpu(), other.into());
FheBool::new(inner, cpu_key.tag.clone())
FheBool::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {

View File

@@ -1,5 +1,6 @@
use crate::high_level_api::global_state::with_internal_keys;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::strings::ascii::FheAsciiString;
use crate::high_level_api::strings::traits::FheStringFind;
use crate::strings::ciphertext::ClearString;
@@ -35,8 +36,16 @@ impl FheStringFind<&Self> for FheAsciiString {
.string_key()
.find(&self.inner.on_cpu(), (&*pat.inner.on_cpu()).into());
(
FheUint32::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
FheUint32::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -79,8 +88,16 @@ impl FheStringFind<&Self> for FheAsciiString {
.string_key()
.rfind(&self.inner.on_cpu(), (&*pat.inner.on_cpu()).into());
(
FheUint32::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
FheUint32::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -123,8 +140,16 @@ impl FheStringFind<&ClearString> for FheAsciiString {
InternalServerKey::Cpu(cpu_key) => {
let (inner, block) = cpu_key.string_key().find(&self.inner.on_cpu(), pat.into());
(
FheUint32::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
FheUint32::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -165,8 +190,16 @@ impl FheStringFind<&ClearString> for FheAsciiString {
InternalServerKey::Cpu(cpu_key) => {
let (inner, block) = cpu_key.string_key().rfind(&self.inner.on_cpu(), pat.into());
(
FheUint32::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
FheUint32::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]

View File

@@ -7,10 +7,12 @@ mod strip;
mod trim;
pub use crate::high_level_api::backward_compatibility::strings::FheAsciiStringVersions;
use crate::high_level_api::compressed_ciphertext_list::ToBeCompressed;
use crate::high_level_api::details::MaybeCloned;
use crate::high_level_api::errors::UninitializedServerKey;
use crate::high_level_api::global_state;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::ciphertext::{Compressible, DataKind, Expandable};
use crate::named::Named;
use crate::prelude::{FheDecrypt, FheTryEncrypt, FheTryTrivialEncrypt, Tagged};
@@ -128,6 +130,7 @@ impl Unversionize for AsciiDevice {
pub struct FheAsciiString {
pub(crate) inner: AsciiDevice,
pub(crate) tag: Tag,
pub(crate) re_randomization_metadata: ReRandomizationMetadata,
}
impl Named for FheAsciiString {
@@ -145,10 +148,15 @@ impl Tagged for FheAsciiString {
}
impl FheAsciiString {
pub(crate) fn new(inner: impl Into<AsciiDevice>, tag: Tag) -> Self {
pub(crate) fn new(
inner: impl Into<AsciiDevice>,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self {
Self {
inner: inner.into(),
tag,
re_randomization_metadata,
}
}
@@ -308,6 +316,14 @@ impl FheAsciiString {
pub fn is_trivial(&self) -> bool {
self.inner.on_cpu().is_trivial()
}
pub fn re_randomization_metadata(&self) -> &ReRandomizationMetadata {
&self.re_randomization_metadata
}
pub fn re_randomization_metadata_mut(&mut self) -> &mut ReRandomizationMetadata {
&mut self.re_randomization_metadata
}
}
impl<'a> FheTryEncrypt<EncryptableString<'a>, ClientKey> for FheAsciiString {
@@ -325,6 +341,7 @@ impl<'a> FheTryEncrypt<EncryptableString<'a>, ClientKey> for FheAsciiString {
Ok(Self {
inner: inner.into(),
tag: key.tag.clone(),
re_randomization_metadata: ReRandomizationMetadata::default(),
})
}
}
@@ -360,7 +377,11 @@ impl<'a> FheTryTrivialEncrypt<EncryptableString<'a>> for FheAsciiString {
global_state::try_with_internal_keys(|keys| match keys {
Some(InternalServerKey::Cpu(cpu_key)) => {
let inner = cpu_key.string_key().trivial_encrypt_ascii(str, padding);
Ok(Self::new(inner, cpu_key.tag.clone()))
Ok(Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
))
}
#[cfg(feature = "gpu")]
Some(InternalServerKey::Cuda(_)) => Err(crate::error!("CUDA does not support string")),
@@ -398,8 +419,13 @@ impl Expandable for FheAsciiString {
blocks: Vec<crate::shortint::Ciphertext>,
kind: DataKind,
) -> crate::Result<Self> {
FheString::from_expanded_blocks(blocks, kind)
.map(|cpu_string| Self::new(cpu_string, Tag::default()))
FheString::from_expanded_blocks(blocks, kind).map(|cpu_string| {
Self::new(
cpu_string,
Tag::default(),
ReRandomizationMetadata::default(),
)
})
}
}
@@ -418,29 +444,26 @@ impl crate::integer::gpu::ciphertext::compressed_ciphertext_list::CudaExpandable
}
}
impl HlExpandable for FheAsciiString {}
impl crate::HlCompressible for FheAsciiString {
fn compress_into(
self,
messages: &mut Vec<(
crate::high_level_api::compressed_ciphertext_list::ToBeCompressed,
DataKind,
)>,
) {
fn compress_into(self, messages: &mut Vec<(ToBeCompressed, DataKind)>) {
match self.inner {
AsciiDevice::Cpu(fhe_string) => {
let mut blocks = vec![];
let data_kind = fhe_string.compress_into(&mut blocks);
if let Some(data_kind) = data_kind {
messages.push((
crate::high_level_api::compressed_ciphertext_list::ToBeCompressed::Cpu(
blocks,
),
data_kind,
));
messages.push((ToBeCompressed::Cpu(blocks), data_kind));
}
}
}
}
fn get_re_randomization_metadata(&self) -> ReRandomizationMetadata {
self.re_randomization_metadata.clone()
}
}
impl HlExpandable for FheAsciiString {
fn set_re_randomization_metadata(&mut self, meta: ReRandomizationMetadata) {
self.re_randomization_metadata = meta;
}
}

View File

@@ -1,6 +1,7 @@
use crate::high_level_api::global_state::with_internal_keys;
use crate::high_level_api::integers::FheUint16;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::strings::ascii::FheAsciiString;
use crate::high_level_api::traits::FheTrivialEncrypt;
use crate::prelude::FheStringRepeat;
@@ -29,9 +30,11 @@ impl From<crate::strings::server_key::FheStringLen> for FheStringLen {
fn from(value: crate::strings::server_key::FheStringLen) -> Self {
match value {
crate::strings::server_key::FheStringLen::NoPadding(v) => Self::NoPadding(v as u16),
crate::strings::server_key::FheStringLen::Padding(v) => {
Self::Padding(FheUint16::new(v, Tag::default()))
}
crate::strings::server_key::FheStringLen::Padding(v) => Self::Padding(FheUint16::new(
v,
Tag::default(),
ReRandomizationMetadata::default(),
)),
}
}
}
@@ -58,7 +61,11 @@ impl From<crate::strings::server_key::FheStringIsEmpty> for FheStringIsEmpty {
match value {
crate::strings::server_key::FheStringIsEmpty::NoPadding(v) => Self::NoPadding(v),
crate::strings::server_key::FheStringIsEmpty::Padding(bool_block) => {
Self::Padding(FheBool::new(bool_block, Tag::default()))
Self::Padding(FheBool::new(
bool_block,
Tag::default(),
ReRandomizationMetadata::default(),
))
}
}
}
@@ -182,7 +189,11 @@ impl FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().to_lowercase(&self.inner.on_cpu());
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -216,7 +227,11 @@ impl FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().to_uppercase(&self.inner.on_cpu());
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -253,7 +268,11 @@ impl FheAsciiString {
let inner = cpu_key
.string_key()
.concat(&self.inner.on_cpu(), &other.inner.on_cpu());
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -312,7 +331,11 @@ impl FheStringRepeat<u16> for FheAsciiString {
let inner = cpu_key
.string_key()
.repeat(&self.inner.on_cpu(), &UIntArg::Clear(count));
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -360,7 +383,11 @@ impl FheStringRepeat<(FheUint16, u16)> for FheAsciiString {
&self.inner.on_cpu(),
&UIntArg::Enc(EncU16::new(count.ciphertext.into_cpu(), Some(bound))),
);
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {

View File

@@ -1,5 +1,6 @@
use crate::high_level_api::global_state::with_internal_keys;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::strings::ascii::FheAsciiString;
use crate::high_level_api::strings::traits::FheStringReplace;
use crate::prelude::FheStringReplaceN;
@@ -36,7 +37,11 @@ impl FheStringReplace<&Self> for FheAsciiString {
(&*from.inner.on_cpu()).into(),
&to.inner.on_cpu(),
);
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -79,7 +84,11 @@ impl FheStringReplace<&ClearString> for FheAsciiString {
from.into(),
&to.inner.on_cpu(),
);
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -121,7 +130,11 @@ impl FheStringReplaceN<&Self, u16> for FheAsciiString {
&to.inner.on_cpu(),
&UIntArg::Clear(count),
);
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -145,7 +158,11 @@ impl FheStringReplaceN<&Self, (FheUint16, u16)> for FheAsciiString {
&to.inner.on_cpu(),
&UIntArg::Enc(EncU16::new(count.ciphertext.into_cpu(), Some(max))),
);
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -187,7 +204,11 @@ impl FheStringReplaceN<&ClearString, u16> for FheAsciiString {
&to.inner.on_cpu(),
&UIntArg::Clear(count),
);
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -211,7 +232,11 @@ impl FheStringReplaceN<&ClearString, (FheUint16, u16)> for FheAsciiString {
&to.inner.on_cpu(),
&UIntArg::Enc(EncU16::new(count.ciphertext.into_cpu(), Some(max))),
);
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {

View File

@@ -1,5 +1,6 @@
use crate::high_level_api::global_state::with_internal_keys;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::strings::ascii::FheAsciiString;
use crate::high_level_api::strings::traits::FheStringStrip;
use crate::high_level_api::FheBool;
@@ -38,8 +39,16 @@ impl FheStringStrip<&Self> for FheAsciiString {
.string_key()
.strip_prefix(&self.inner.on_cpu(), (&*pat.inner.on_cpu()).into());
(
Self::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -85,8 +94,16 @@ impl FheStringStrip<&Self> for FheAsciiString {
.string_key()
.strip_suffix(&self.inner.on_cpu(), (&*pat.inner.on_cpu()).into());
(
Self::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -134,8 +151,16 @@ impl FheStringStrip<&ClearString> for FheAsciiString {
.string_key()
.strip_prefix(&self.inner.on_cpu(), pat.into());
(
Self::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]
@@ -181,8 +206,16 @@ impl FheStringStrip<&ClearString> for FheAsciiString {
.string_key()
.strip_suffix(&self.inner.on_cpu(), pat.into());
(
Self::new(inner, cpu_key.tag.clone()),
FheBool::new(block, cpu_key.tag.clone()),
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
FheBool::new(
block,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
),
)
}
#[cfg(feature = "gpu")]

View File

@@ -1,5 +1,6 @@
use crate::high_level_api::global_state::with_internal_keys;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::strings::ascii::FheAsciiString;
impl FheAsciiString {
@@ -23,7 +24,11 @@ impl FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().trim_start(&self.inner.on_cpu());
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -56,7 +61,11 @@ impl FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().trim_end(&self.inner.on_cpu());
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
@@ -89,7 +98,11 @@ impl FheAsciiString {
with_internal_keys(|keys| match keys {
InternalServerKey::Cpu(cpu_key) => {
let inner = cpu_key.string_key().trim(&self.inner.on_cpu());
Self::new(inner, cpu_key.tag.clone())
Self::new(
inner,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {

View File

@@ -0,0 +1,194 @@
use crate::high_level_api::prelude::*;
use crate::high_level_api::{
generate_keys, CompactPublicKey, CompressedCiphertextListBuilder, ConfigBuilder, FheBool,
FheInt8, FheUint64, ReRandomizationContext,
};
use crate::set_server_key;
use crate::shortint::parameters::{
COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_KEYSWITCH_TO_BIG_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,
};
#[test]
fn test_re_rand() {
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let cpk_params = (
PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
);
let comp_params = COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let re_rand_ks_params = PARAM_KEYSWITCH_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(params)
.use_dedicated_compact_public_key_parameters(cpk_params)
.enable_compression(comp_params)
.enable_ciphertext_re_randomization(re_rand_ks_params)
.build();
let (cks, sks) = generate_keys(config);
let cpk = CompactPublicKey::new(&cks);
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let rerand_domain_separator = *b"TFHE_Rrd";
set_server_key(sks);
// Case where we want to compute FheUint64 + FheUint64 and re-randomize those inputs
{
let clear_a = rand::random::<u64>();
let clear_b = rand::random::<u64>();
let mut a = FheUint64::encrypt(clear_a, &cks);
let mut b = FheUint64::encrypt(clear_b, &cks);
// Simulate a 256 bits hash added as metadata
let rand_a: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let rand_b: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
a.re_randomization_metadata_mut().set_data(&rand_a);
b.re_randomization_metadata_mut().set_data(&rand_b);
let mut builder = CompressedCiphertextListBuilder::new();
builder.push(a);
builder.push(b);
let list = builder.build().unwrap();
let mut a: FheUint64 = list.get(0).unwrap().unwrap();
let mut b: FheUint64 = list.get(1).unwrap().unwrap();
assert_eq!(a.re_randomization_metadata().data(), &rand_a);
assert_eq!(b.re_randomization_metadata().data(), &rand_b);
// Simulate a 256 bits nonce
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
// First is the function description, second is a nonce
[b"FheUint64+FheUint64".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
// Add ciphertexts to the context
re_rand_context.add_ciphertext(&a);
re_rand_context.add_ciphertext(&b);
let mut seed_gen = re_rand_context.finalize();
a.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
b.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
let c = a + b;
let dec: u64 = c.decrypt(&cks);
assert_eq!(clear_a.wrapping_add(clear_b), dec);
}
// Case where we want to compute FheInt8 + FheInt8 and re-randomize those inputs
{
let clear_a = rand::random::<i8>();
let clear_b = rand::random::<i8>();
let mut a = FheInt8::encrypt(clear_a, &cks);
let mut b = FheInt8::encrypt(clear_b, &cks);
// Simulate a 256 bits hash added as metadata
let rand_a: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let rand_b: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
a.re_randomization_metadata_mut().set_data(&rand_a);
b.re_randomization_metadata_mut().set_data(&rand_b);
let mut builder = CompressedCiphertextListBuilder::new();
builder.push(a);
builder.push(b);
let list = builder.build().unwrap();
let mut a: FheInt8 = list.get(0).unwrap().unwrap();
let mut b: FheInt8 = list.get(1).unwrap().unwrap();
assert_eq!(a.re_randomization_metadata().data(), &rand_a);
assert_eq!(b.re_randomization_metadata().data(), &rand_b);
// Simulate a 256 bits nonce
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
// First is the function description, second is a nonce
[b"FheInt8+FheInt8".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
// Add ciphertexts to the context
re_rand_context.add_ciphertext(&a);
re_rand_context.add_ciphertext(&b);
let mut seed_gen = re_rand_context.finalize();
a.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
b.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
let c = a + b;
let dec: i8 = c.decrypt(&cks);
assert_eq!(clear_a.wrapping_add(clear_b), dec);
}
// Case where we want to compute FheBool && FheBool and re-randomize those inputs
{
for clear_a in [false, true] {
for clear_b in [false, true] {
let mut a = FheBool::encrypt(clear_a, &cks);
let mut b = FheBool::encrypt(clear_b, &cks);
// Simulate a 256 bits hash added as metadata
let rand_a: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let rand_b: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
a.re_randomization_metadata_mut().set_data(&rand_a);
b.re_randomization_metadata_mut().set_data(&rand_b);
let mut builder = CompressedCiphertextListBuilder::new();
builder.push(a);
builder.push(b);
let list = builder.build().unwrap();
let mut a: FheBool = list.get(0).unwrap().unwrap();
let mut b: FheBool = list.get(1).unwrap().unwrap();
assert_eq!(a.re_randomization_metadata().data(), &rand_a);
assert_eq!(b.re_randomization_metadata().data(), &rand_b);
// Simulate a 256 bits nonce
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
// First is the function description, second is a nonce
[b"FheBool&FheBool".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
// Add ciphertexts to the context
re_rand_context.add_ciphertext(&a);
re_rand_context.add_ciphertext(&b);
let mut seed_gen = re_rand_context.finalize();
a.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
b.re_randomize(&cpk, seed_gen.next_seed().unwrap()).unwrap();
let c = a & b;
let dec: bool = c.decrypt(&cks);
assert_eq!(clear_a && clear_b, dec);
}
}
}
}

View File

@@ -1,3 +1,4 @@
mod cpk_re_randomization;
#[cfg(feature = "gpu")]
mod gpu_selection;
mod noise_distribution;
@@ -197,8 +198,15 @@ 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, None, Tag::default());
let client_key = ClientKey::from_raw_parts(
shortint_key.into(),
None,
None,
None,
None,
None,
Tag::default(),
);
let sks = ServerKey::new(&client_key);
let clear_a = 1344u32;

View File

@@ -1,6 +1,7 @@
use std::ops::RangeBounds;
use crate::error::InvalidRangeError;
pub use crate::high_level_api::re_randomization::ReRandomize;
use crate::high_level_api::ClientKey;
use crate::{FheBool, Tag};

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, _, nsk, cnsk, tag) = ck.into_raw_parts();
let ck = ClientKey::from_raw_parts(cks, pk, common_cck, nsk, cnsk, tag);
let (cks, pk, _, nsk, cnsk, cpkrndp, tag) = ck.into_raw_parts();
let ck = ClientKey::from_raw_parts(cks, pk, common_cck, nsk, cnsk, cpkrndp, tag);
let sk = CompressedServerKey::new(&ck);
assert_eq!(sk.tag().as_u64(), 0);

View File

@@ -1,5 +1,6 @@
use crate::high_level_api::integers::signed::FheIntId;
use crate::high_level_api::integers::unsigned::FheUintId;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::ciphertext::{DataKind, Expandable};
use crate::integer::BooleanBlock;
use crate::shortint::Ciphertext;
@@ -18,10 +19,11 @@ impl<Id: FheUintId> Expandable for FheUint<Id> {
DataKind::Unsigned(_) => {
let stored_num_bits = num_bits_of_blocks(&blocks) as usize;
if stored_num_bits == Id::num_bits() {
// The expander will be responsible for setting the correct tag
// The expander will be responsible for setting the correct tag and metadata
Ok(Self::new(
crate::integer::RadixCiphertext::from(blocks),
Tag::default(),
ReRandomizationMetadata::default(),
))
} else {
Err(crate::error!(
@@ -69,6 +71,7 @@ impl<Id: FheIntId> Expandable for FheInt<Id> {
Ok(Self::new(
crate::integer::SignedRadixCiphertext::from(blocks),
Tag::default(),
ReRandomizationMetadata::default(),
))
} else {
Err(crate::error!(
@@ -110,8 +113,12 @@ impl Expandable for FheBool {
// We know the value is a boolean one (via the data kind)
boolean_block.0.degree = crate::shortint::ciphertext::Degree::new(1);
// The expander will be responsible for setting the correct tag
Ok(Self::new(boolean_block, Tag::default()))
// The expander will be responsible for setting the correct tag and metadata
Ok(Self::new(
boolean_block,
Tag::default(),
ReRandomizationMetadata::default(),
))
}
DataKind::String { .. } => Err(crate::Error::new(
"Tried to expand a FheBool while a string is stored in this slot".to_string(),

View File

@@ -7,6 +7,9 @@ use crate::integer::backward_compatibility::ciphertext::{
use crate::integer::block_decomposition::{
BlockRecomposer, RecomposableFrom, RecomposableSignedInteger,
};
use crate::integer::ciphertext::{re_randomize_ciphertext_blocks, ReRandomizationSeed};
use crate::integer::key_switching_key::KeySwitchingKeyMaterialView;
use crate::integer::CompactPublicKey;
use crate::shortint::ciphertext::NotTrivialCiphertextError;
use crate::shortint::parameters::CiphertextConformanceParams;
use crate::shortint::Ciphertext;
@@ -119,6 +122,22 @@ impl RadixCiphertext {
bits_in_block,
))
}
pub fn re_randomize(
&mut self,
compact_public_key: &CompactPublicKey,
key_switching_key_material: &KeySwitchingKeyMaterialView,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
re_randomize_ciphertext_blocks(
&mut self.blocks,
compact_public_key,
key_switching_key_material,
seed,
)?;
Ok(())
}
}
/// Structure containing a ciphertext in radix decomposition
@@ -227,6 +246,22 @@ impl SignedRadixCiphertext {
bits_in_block,
))
}
pub fn re_randomize(
&mut self,
compact_public_key: &CompactPublicKey,
key_switching_key_material: &KeySwitchingKeyMaterialView,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
re_randomize_ciphertext_blocks(
&mut self.blocks,
compact_public_key,
key_switching_key_material,
seed,
)?;
Ok(())
}
}
/// Structure containing a ciphertext in CRT decomposition.

View File

@@ -1,6 +1,8 @@
use super::{IntegerCiphertext, IntegerRadixCiphertext};
use crate::integer::backward_compatibility::ciphertext::BooleanBlockVersions;
use crate::integer::{RadixCiphertext, ServerKey};
use crate::integer::ciphertext::{re_randomize_ciphertext_blocks, ReRandomizationSeed};
use crate::integer::key_switching_key::KeySwitchingKeyMaterialView;
use crate::integer::{CompactPublicKey, RadixCiphertext, ServerKey};
use crate::shortint::ciphertext::NotTrivialCiphertextError;
use crate::shortint::Ciphertext;
use serde::{Deserialize, Serialize};
@@ -168,6 +170,22 @@ impl BooleanBlock {
pub fn is_trivial(&self) -> bool {
self.0.is_trivial()
}
pub fn re_randomize(
&mut self,
compact_public_key: &CompactPublicKey,
key_switching_key_material: &KeySwitchingKeyMaterialView,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
re_randomize_ciphertext_blocks(
core::slice::from_mut(&mut self.0),
compact_public_key,
key_switching_key_material,
seed,
)?;
Ok(())
}
}
impl AsRef<Ciphertext> for BooleanBlock {

View File

@@ -96,3 +96,21 @@ impl IntegerCiphertext for CrtCiphertext {
self.moduli.clone()
}
}
// Yet another trait, this is to avoid breaking the logic with IntegerCiphertext which BooleanBlock
// does not implement for good reasons IIRC.
pub trait AsShortintCiphertextSlice {
fn as_ciphertext_slice(&self) -> &[Ciphertext];
}
impl<T: IntegerCiphertext> AsShortintCiphertextSlice for T {
fn as_ciphertext_slice(&self) -> &[Ciphertext] {
self.blocks()
}
}
impl AsShortintCiphertextSlice for super::BooleanBlock {
fn as_ciphertext_slice(&self) -> &[Ciphertext] {
core::slice::from_ref(&self.0)
}
}

View File

@@ -6,7 +6,10 @@ mod compressed_ciphertext_list;
mod compressed_modulus_switched_ciphertext;
mod compressed_noise_squashed_ciphertext_list;
mod integer_ciphertext;
mod re_randomization;
mod squashed_noise;
#[cfg(test)]
mod test;
mod utils;
pub use base::*;
@@ -17,5 +20,6 @@ pub use compressed_ciphertext_list::*;
pub use compressed_modulus_switched_ciphertext::*;
pub use compressed_noise_squashed_ciphertext_list::*;
pub use integer_ciphertext::*;
pub use re_randomization::*;
pub use squashed_noise::*;
pub use utils::*;

View File

@@ -0,0 +1,154 @@
// This is linked to the standard ciphertext but has special code in it
use crate::core_crypto::commons::math::random::XofSeed;
use crate::integer::ciphertext::AsShortintCiphertextSlice;
use crate::integer::key_switching_key::KeySwitchingKeyMaterialView;
use crate::integer::CompactPublicKey;
pub use crate::shortint::ciphertext::{ReRandomizationSeed, ReRandomizationSeedHasher};
use crate::shortint::Ciphertext;
use crate::Result;
/// The context that will be hashed and used to generate unique [`ReRandomizationSeed`].
pub struct ReRandomizationContext {
/// The inner hasher
inner_context: crate::shortint::ciphertext::ReRandomizationContext,
/// The number of integer ciphertexts added to the context. This will define the number of
/// seeds that can be drawn from it
ct_count: u64,
/// Temporary buffer with all the individual shortint cts coefficients that will be hashed in
/// the context
ct_coeffs_buffer: Vec<u64>,
/// Temporary buffer with all the ciphertext metadata
meta_buffer: Vec<u8>,
/// A piece of data that should be unique to the function being called
fn_description: Vec<u8>,
}
impl ReRandomizationContext {
/// Create a new re-randomization context with the default seed hasher (blake3).
///
/// `rerand_seeder_domain_separator` is the domain separator that will be fed into the
/// seed generator.
/// `public_encryption_domain_separator` is the domain separator that will be used along this
/// seed to generate the encryptions of zero.
/// `fn_description` is a unique sequence of bytes that represents the functions called on the
/// re-randomized values.
///
/// (See [`XofSeed`] for more information)
///
/// # Example
/// ```rust
/// use tfhe::integer::ciphertext::ReRandomizationContext;
/// // Simulate a 256 bits nonce
/// let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
/// let _re_rand_context = ReRandomizationContext::new(
/// *b"TFHE_Rrd",
/// [b"FheUint64+FheUint64".as_slice(), &nonce],
/// *b"TFHE_Enc"
/// );
pub fn new<'a>(
rerand_seeder_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
fn_description: impl IntoIterator<Item = &'a [u8]>,
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
) -> Self {
Self {
inner_context: crate::shortint::ciphertext::ReRandomizationContext::new(
rerand_seeder_domain_separator,
public_encryption_domain_separator,
),
ct_coeffs_buffer: Vec::new(),
ct_count: 0,
meta_buffer: Vec::new(),
fn_description: fn_description.into_iter().flatten().copied().collect(),
}
}
/// Create a new re-randomization context with the provided seed hasher.
pub fn new_with_hasher<'a>(
fn_description: impl IntoIterator<Item = &'a [u8]>,
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
seed_hasher: ReRandomizationSeedHasher,
) -> Self {
Self {
inner_context: crate::shortint::ciphertext::ReRandomizationContext::new_with_hasher(
public_encryption_domain_separator,
seed_hasher,
),
ct_coeffs_buffer: Vec::new(),
ct_count: 0,
meta_buffer: Vec::new(),
fn_description: fn_description.into_iter().flatten().copied().collect(),
}
}
/// Add a new integer ciphertext to the context.
///
/// The ciphertexts added like this will be stored in a temporary buffer and only hashed during
/// the "finalize" step
pub fn add_ciphertext<T: AsShortintCiphertextSlice>(&mut self, ciphertext: &T) {
self.ct_coeffs_buffer.extend(
ciphertext
.as_ciphertext_slice()
.iter()
.flat_map(|ct| ct.ct.as_ref()),
);
self.ct_count += 1;
}
/// Add a metadata buffer to the context.
///
/// These bytes will be added to a temporary buffer and will only be hashed during the
/// "finalize" step
pub fn add_bytes(&mut self, data: &[u8]) {
self.meta_buffer.extend_from_slice(data);
}
/// Consumes the context to instantiate a seed generator
pub fn finalize(mut self) -> ReRandomizationSeedGen {
self.inner_context
.add_ciphertext_data_slice(&self.ct_coeffs_buffer);
self.inner_context.add_bytes(&self.meta_buffer);
self.inner_context.add_bytes(&self.fn_description);
ReRandomizationSeedGen {
inner: self.inner_context.finalize(),
remaining_seeds_count: self.ct_count,
}
}
}
/// A generator that can be used to obtain seeds needed to re-randomize individual ciphertexts.
///
/// This will refuse to generate more seeds than the number of ciphertext added into the context.
pub struct ReRandomizationSeedGen {
inner: crate::shortint::ciphertext::ReRandomizationSeedGen,
remaining_seeds_count: u64,
}
impl ReRandomizationSeedGen {
/// Generate the next seed from the seeder.
///
/// Returns an error if more seeds have been generated than the number of ciphertext added into
/// the context.
pub fn next_seed(&mut self) -> Result<ReRandomizationSeed> {
if self.remaining_seeds_count > 0 {
self.remaining_seeds_count -= 1;
Ok(self.inner.next_seed())
} else {
Err(crate::error!("Trying to draw more seeds than the number of ciphertexts that were added to the context"))
}
}
}
pub(crate) fn re_randomize_ciphertext_blocks(
blocks: &mut [Ciphertext],
compact_public_key: &CompactPublicKey,
key_switching_key_material: &KeySwitchingKeyMaterialView,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
compact_public_key.key.re_randomize_ciphertexts(
blocks,
&key_switching_key_material.material,
seed,
)
}

View File

@@ -0,0 +1,162 @@
use crate::integer::ciphertext::compressed_ciphertext_list::*;
use crate::integer::ciphertext::ReRandomizationContext;
use crate::integer::key_switching_key::{KeySwitchingKeyBuildHelper, KeySwitchingKeyMaterial};
use crate::integer::{
gen_keys, BooleanBlock, CompactPrivateKey, CompactPublicKey, IntegerKeyKind, RadixCiphertext,
SignedRadixCiphertext,
};
use crate::shortint::parameters::test_params::{
TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2,
};
use crate::shortint::ShortintParameterSet;
use itertools::Itertools;
use rand::Rng;
const NB_TESTS: usize = 10;
const NUM_BLOCKS: usize = 32;
#[test]
fn test_ciphertext_re_randomization_after_compression() {
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into();
let comp_params = TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let cpk_params = TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let ks_params = TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let (cks, sks) = gen_keys::<ShortintParameterSet>(params, IntegerKeyKind::Radix);
let private_compression_key = cks.new_compression_private_key(comp_params);
let (compression_key, decompression_key) =
cks.new_compression_decompression_keys(&private_compression_key);
let cpk_private_key = CompactPrivateKey::new(cpk_params);
let cpk = CompactPublicKey::new(&cpk_private_key);
let ksk_material: KeySwitchingKeyMaterial =
KeySwitchingKeyBuildHelper::new((&cpk_private_key, None), (&cks, &sks), ks_params).into();
let ksk_material = ksk_material.as_view();
let rerand_domain_separator = *b"TFHE_Rrd";
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let metadata = b"lol".as_slice();
let mut rng = rand::thread_rng();
let message_modulus: u128 = cks.parameters().message_modulus().0 as u128;
// Unsigned
let modulus = message_modulus.pow(NUM_BLOCKS as u32);
for _ in 0..NB_TESTS {
let message = rng.gen::<u128>() % modulus;
let ct = cks.encrypt_radix(message, NUM_BLOCKS);
let mut builder = CompressedCiphertextListBuilder::new();
builder.push(ct);
let compressed = builder.build(&compression_key);
let decompressed: RadixCiphertext = compressed.get(0, &decompression_key).unwrap().unwrap();
let mut re_randomizer_context = ReRandomizationContext::new(
rerand_domain_separator,
[metadata],
compact_public_encryption_domain_separator,
);
re_randomizer_context.add_ciphertext(&decompressed);
let mut seed_gen = re_randomizer_context.finalize();
let mut re_randomized = decompressed.clone();
re_randomized
.re_randomize(&cpk, &ksk_material, seed_gen.next_seed().unwrap())
.unwrap();
assert_ne!(decompressed, re_randomized);
let decrypted: u128 = cks.decrypt_radix(&re_randomized);
assert_eq!(decrypted, message);
}
// Signed
let modulus = message_modulus.pow((NUM_BLOCKS - 1) as u32) as i128;
for _ in 0..NB_TESTS {
let message = rng.gen::<i128>() % modulus;
let ct = cks.encrypt_signed_radix(message, NUM_BLOCKS);
let mut builder = CompressedCiphertextListBuilder::new();
builder.push(ct);
let compressed = builder.build(&compression_key);
let decompressed: SignedRadixCiphertext =
compressed.get(0, &decompression_key).unwrap().unwrap();
let mut re_randomizer_context = ReRandomizationContext::new(
rerand_domain_separator,
[metadata],
compact_public_encryption_domain_separator,
);
re_randomizer_context.add_ciphertext(&decompressed);
let mut seed_gen = re_randomizer_context.finalize();
let mut re_randomized = decompressed.clone();
re_randomized
.re_randomize(&cpk, &ksk_material, seed_gen.next_seed().unwrap())
.unwrap();
assert_ne!(decompressed, re_randomized);
let decrypted: i128 = cks.decrypt_signed_radix(&decompressed);
assert_eq!(decrypted, message);
}
// Boolean
for _ in 0..NB_TESTS {
let messages = [false, true];
let cts = messages
.iter()
.map(|message| cks.encrypt_bool(*message))
.collect_vec();
let mut builder = CompressedCiphertextListBuilder::new();
builder.extend(cts.into_iter());
let compressed = builder.build(&compression_key);
for (i, message) in messages.iter().enumerate() {
let decompressed: BooleanBlock =
compressed.get(i, &decompression_key).unwrap().unwrap();
let mut re_randomizer_context = ReRandomizationContext::new(
rerand_domain_separator,
[metadata],
compact_public_encryption_domain_separator,
);
re_randomizer_context.add_ciphertext(&decompressed);
let mut seed_gen = re_randomizer_context.finalize();
let mut re_randomized = decompressed.clone();
re_randomized
.re_randomize(&cpk, &ksk_material, seed_gen.next_seed().unwrap())
.unwrap();
assert_ne!(decompressed, re_randomized);
let decrypted = cks.decrypt_bool(&decompressed);
assert_eq!(decrypted, *message);
}
}
}

View File

@@ -3,6 +3,7 @@ mod compact_list;
mod compressed;
mod compressed_ciphertext_list;
mod compressed_modulus_switched_ciphertext;
mod re_randomization;
mod squashed_noise;
mod standard;
#[cfg(feature = "zk-pok")]
@@ -13,6 +14,7 @@ pub use compact_list::*;
pub use compressed::*;
pub use compressed_ciphertext_list::*;
pub use compressed_modulus_switched_ciphertext::*;
pub use re_randomization::*;
pub use squashed_noise::*;
pub use standard::*;
#[cfg(feature = "zk-pok")]

View File

@@ -0,0 +1,431 @@
//! Update the random elements (mask and noise) of a ciphertext without changing its plaintext value
//!
//! This works by generating encrypted zeros using a public key, that will be added to the input
//! ciphertexts
use crate::core_crypto::algorithms::{
encrypt_lwe_compact_ciphertext_list_with_compact_public_key, keyswitch_lwe_ciphertext,
lwe_ciphertext_add_assign,
};
use crate::core_crypto::commons::generators::{
DeterministicSeeder, EncryptionRandomGenerator, SecretRandomGenerator,
};
use crate::core_crypto::commons::math::random::{DefaultRandomGenerator, Seeder, XofSeed};
use crate::core_crypto::commons::parameters::{LweCiphertextCount, PlaintextCount};
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::{LweCiphertext, LweCompactCiphertextList, PlaintextList};
use crate::shortint::ciphertext::NoiseLevel;
use crate::shortint::key_switching_key::KeySwitchingKeyMaterialView;
use crate::shortint::{Ciphertext, CompactPublicKey, PBSOrder};
use rayon::prelude::*;
use sha3::digest::{ExtendableOutput, Update};
use std::io::Read;
/// Size of the re-randomization seed in bits
const RERAND_SEED_BITS: usize = 256;
/// The XoF algorithm used to generate the re-randomization seed
#[derive(Copy, Clone, Default)]
pub enum ReRandomizationHashAlgo {
/// Used for NIST compliance
Shake256,
/// Faster, should be preferred unless you have specific requirements
#[default]
Blake3,
}
/// The hash state used for the re-randomization seed generation
#[derive(Clone)]
// blake3 is the larger variant but we expect it to be used more in performance sensitive contexts
#[allow(clippy::large_enum_variant)]
pub enum ReRandomizationSeedHasher {
Shake256(sha3::Shake256),
Blake3(blake3::Hasher),
}
impl ReRandomizationSeedHasher {
/// Create a new hash state for the provided algorithm
pub fn new(
algo: ReRandomizationHashAlgo,
rerand_root_seed_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
) -> Self {
let mut hasher = match algo {
ReRandomizationHashAlgo::Shake256 => Self::Shake256(sha3::Shake256::default()),
ReRandomizationHashAlgo::Blake3 => Self::Blake3(blake3::Hasher::default()),
};
hasher.update(&rerand_root_seed_domain_separator);
hasher
}
/// Update the hash state with new data
fn update(&mut self, data: &[u8]) {
match self {
Self::Shake256(hasher) => hasher.update(data),
Self::Blake3(hasher) => {
hasher.update(data);
}
}
}
/// Consume the state to generate a seed
fn finalize(self) -> [u8; RERAND_SEED_BITS / 8] {
let mut res = [0; RERAND_SEED_BITS / 8];
match self {
Self::Shake256(hasher) => {
let mut reader = hasher.finalize_xof();
reader
.read_exact(&mut res)
.expect("XoF reader should not EoF");
}
Self::Blake3(hasher) => {
let mut reader = hasher.finalize_xof();
reader
.read_exact(&mut res)
.expect("XoF reader should not EoF");
}
}
res
}
}
impl From<sha3::Shake256> for ReRandomizationSeedHasher {
fn from(value: sha3::Shake256) -> Self {
Self::Shake256(value)
}
}
impl From<blake3::Hasher> for ReRandomizationSeedHasher {
fn from(value: blake3::Hasher) -> Self {
Self::Blake3(value)
}
}
/// A seed that can be used to re-randomize a ciphertext
///
/// This type cannot be cloned or copied, as a seed should only be used once.
pub struct ReRandomizationSeed(pub(crate) XofSeed);
/// The context that will be hashed and used to generate unique [`ReRandomizationSeed`].
///
/// At this level, the context will directly hash any data passed to it.
/// This means that the order in which the data will be hashed matches exactly the order in which
/// the different `add_*` functions are called
pub struct ReRandomizationContext {
hash_state: ReRandomizationSeedHasher,
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
}
impl ReRandomizationContext {
/// Create a new re-randomization context with the default seed hasher (blake3).
///
/// `rerand_seeder_domain_separator` is the domain separator that will be fed into the
/// seed generator.
/// `public_encryption_domain_separator` is the domain separator that will be used along this
/// seed to generate the encryptions of zero.
///
/// (See [`XofSeed`] for more information)
///
/// # Example
/// ```rust
/// use tfhe::shortint::ciphertext::ReRandomizationContext;
/// // Simulate a 256 bits nonce
/// let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
/// let _re_rand_context = ReRandomizationContext::new(
/// *b"TFHE_Rrd",
/// *b"TFHE_Enc"
/// );
pub fn new(
rerand_seeder_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
) -> Self {
let seed_hasher = ReRandomizationSeedHasher::new(
ReRandomizationHashAlgo::default(),
rerand_seeder_domain_separator,
);
Self::new_with_hasher(public_encryption_domain_separator, seed_hasher)
}
/// Create a new re-randomization context with the provided seed hasher.
pub fn new_with_hasher(
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
seed_hasher: ReRandomizationSeedHasher,
) -> Self {
Self {
hash_state: seed_hasher,
public_encryption_domain_separator,
}
}
/// Adds a new ciphertext to the re-randomization context
pub fn add_ciphertext(&mut self, ciphertext: &Ciphertext) {
self.add_ciphertext_iterator([ciphertext]);
}
/// Adds bytes to the re-randomization context
pub fn add_bytes(&mut self, data: &[u8]) {
self.hash_state.update(data);
}
pub fn add_ciphertext_iterator<'a, I>(&mut self, iter: I)
where
I: IntoIterator<Item = &'a Ciphertext>,
{
// Blake3 algorithm is faster when fed with larger chunks of data, so we copy all the
// ciphertexts into a single buffer.
// We try to estimate the buffer size and preallocate it. This is an estimate based on the
// following assumptions:
// - all ciphertexts have the same size
// - the iterator size hint is correct
// This is not critical as a bad estimate only results in reallocations in the worst case.
let mut iter = iter.into_iter();
let Some(first) = iter.next() else {
return;
};
let hint = iter.size_hint();
// Use the max iterator size if it exists, or default to the min one.
let iter_len = hint.1.unwrap_or(hint.0);
let tot_len = first.ct.as_ref().len() * iter_len;
let mut copied: Vec<u64> = Vec::with_capacity(tot_len);
copied.extend(first.ct.as_ref());
for ciphertext in iter {
copied.extend(ciphertext.ct.as_ref());
}
self.add_ciphertext_data_slice(&copied);
}
pub(crate) fn add_ciphertext_data_slice(&mut self, slice: &[u64]) {
self.hash_state.update(bytemuck::cast_slice(slice));
}
/// Consumes the context to create a seed generator
pub fn finalize(self) -> ReRandomizationSeedGen {
let Self {
hash_state,
public_encryption_domain_separator,
} = self;
ReRandomizationSeedGen {
hash_state,
next_seed_index: 0,
public_encryption_domain_separator,
}
}
}
/// A generator that can be used to obtain seeds needed to re-randomize individual ciphertexts
pub struct ReRandomizationSeedGen {
hash_state: ReRandomizationSeedHasher,
next_seed_index: u64,
public_encryption_domain_separator: [u8; XofSeed::DOMAIN_SEP_LEN],
}
impl ReRandomizationSeedGen {
pub fn next_seed(&mut self) -> ReRandomizationSeed {
let current_seed_index = self.next_seed_index;
self.next_seed_index += 1;
let mut hash_state = self.hash_state.clone();
hash_state.update(&current_seed_index.to_le_bytes());
let seed_256 = hash_state.finalize();
ReRandomizationSeed(XofSeed::new(
seed_256.to_vec(),
self.public_encryption_domain_separator,
))
}
}
impl CompactPublicKey {
/// Re-randomize a list of ciphertexts using the provided seed and compact public key
///
/// The key and seed are used to generate encryptions of zero that will be added to the input
/// ciphertexts
pub fn re_randomize_ciphertexts(
&self,
cts: &mut [Ciphertext],
key_switching_key_material: &KeySwitchingKeyMaterialView,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
let ksk_pbs_order = key_switching_key_material.destination_key.into_pbs_order();
let ksk_output_lwe_size = key_switching_key_material
.key_switching_key
.output_lwe_size();
if let Some(msg) = cts.iter().find_map(|ct| {
if ct.atomic_pattern.pbs_order() != ksk_pbs_order {
Some(
"Mismatched PBSOrder between Ciphertext being re-randomized and provided \
KeySwitchingKeyMaterialView.",
)
} else if ksk_output_lwe_size != ct.ct.lwe_size() {
Some(
"Mismatched LweSwize between Ciphertext being re-randomized and provided \
KeySwitchingKeyMaterialView.",
)
} else if ct.noise_level() != NoiseLevel::NOMINAL {
Some("Tried to re-randomize a Ciphertext with non-nominal NoiseLevel.")
} else {
None
}
}) {
return Err(crate::error!("{}", msg));
}
if ksk_pbs_order != PBSOrder::KeyswitchBootstrap {
// message is ok since we know that ksk order == cts order
return Err(crate::error!(
"Tried to re-randomize a Ciphertext with unsupported PBSOrder. \
Required PBSOrder::KeyswitchBootstrap.",
));
}
if key_switching_key_material.cast_rshift != 0 {
return Err(crate::error!(
"Tried to re-randomize a Ciphertext using KeySwitchingKeyMaterialView \
with non-zero cast_rshift, this is unsupported.",
));
}
if key_switching_key_material
.key_switching_key
.input_key_lwe_dimension()
!= self.parameters().encryption_lwe_dimension
{
return Err(crate::error!(
"Mismatched LweDimension between provided CompactPublicKey and \
KeySwitchingKeyMaterialView input LweDimension.",
));
}
// TODO: what do we do about this ?
let mut deterministic_seeder = DeterministicSeeder::<DefaultRandomGenerator>::new(seed.0);
let mut secret_generator =
SecretRandomGenerator::<DefaultRandomGenerator>::new(deterministic_seeder.seed());
let mut encryption_generator = EncryptionRandomGenerator::<DefaultRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let mut encryption_of_zero = LweCompactCiphertextList::new(
0,
self.parameters().encryption_lwe_dimension.to_lwe_size(),
LweCiphertextCount(cts.len()),
self.parameters().ciphertext_modulus,
);
let plaintext_list = PlaintextList::new(
0,
PlaintextCount(encryption_of_zero.lwe_ciphertext_count().0),
);
let cpk_encryption_noise_distribution = self.parameters().encryption_noise_distribution;
encrypt_lwe_compact_ciphertext_list_with_compact_public_key(
&self.key,
&mut encryption_of_zero,
&plaintext_list,
cpk_encryption_noise_distribution,
cpk_encryption_noise_distribution,
&mut secret_generator,
&mut encryption_generator,
);
let zero_lwes = encryption_of_zero.expand_into_lwe_ciphertext_list();
cts.par_iter_mut()
.zip(zero_lwes.par_iter())
.for_each(|(ct, lwe_randomizer_cpk)| {
let mut lwe_randomizer_ksed = LweCiphertext::new(
0,
key_switching_key_material
.key_switching_key
.output_lwe_size(),
key_switching_key_material
.key_switching_key
.ciphertext_modulus(),
);
// Keyswitch used to convert from the cpk params to the compute ones.
// In theory, with a cpk made from the compute secret key, this keyswitch could be
// removed at the cost of an additional key.
keyswitch_lwe_ciphertext(
key_switching_key_material.key_switching_key,
&lwe_randomizer_cpk,
&mut lwe_randomizer_ksed,
);
lwe_ciphertext_add_assign(&mut ct.ct, &lwe_randomizer_ksed);
});
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::shortint::parameters::test_params::{
TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2,
};
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
use crate::shortint::{gen_keys, CompactPrivateKey, KeySwitchingKey};
/// Test the case where we rerand more ciphertexts that what can be stored in one cpk lwe
#[test]
fn test_rerand_large_ct_count_ci_run_filter() {
let compute_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let pke_params = TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let ks_params = TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let (cks, sks) = gen_keys(compute_params);
let privk = CompactPrivateKey::new(pke_params);
let pubk = CompactPublicKey::new(&privk);
let ksk = KeySwitchingKey::new((&privk, None), (&cks, &sks), ks_params);
let pke_lwe_dim = pke_params.encryption_lwe_dimension.0;
let msg1 = 1;
let msg2 = 2;
let mut cts = Vec::with_capacity(pke_lwe_dim * 2);
for _ in 0..pke_lwe_dim {
let ct1 = cks.encrypt(msg1);
cts.push(ct1);
let ct2 = cks.encrypt(msg2);
cts.push(ct2);
}
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let mut re_rand_context = ReRandomizationContext::new(*b"TFHE_Rrd", *b"TFHE_Enc");
re_rand_context.add_ciphertext_iterator(&cts);
re_rand_context.add_bytes(b"ct_radix");
re_rand_context.add_bytes(b"FheUint4".as_slice());
re_rand_context.add_bytes(&nonce);
let mut seeder = re_rand_context.finalize();
pubk.re_randomize_ciphertexts(
&mut cts,
&ksk.key_switching_key_material.as_view(),
seeder.next_seed(),
)
.unwrap();
for pair in cts.chunks(2) {
let sum = sks.add(&pair[0], &pair[1]);
let dec = cks.decrypt(&sum);
assert_eq!(dec, msg1 + msg2);
}
}
}

View File

@@ -5,7 +5,10 @@ use crate::conformance::ParameterSetConformant;
use crate::core_crypto::entities::*;
use crate::core_crypto::prelude::{allocate_and_trivially_encrypt_new_lwe_ciphertext, LweSize};
use crate::shortint::backward_compatibility::ciphertext::CiphertextVersions;
use crate::shortint::ciphertext::ReRandomizationSeed;
use crate::shortint::key_switching_key::KeySwitchingKeyMaterialView;
use crate::shortint::parameters::{AtomicPatternKind, CarryModulus, MessageModulus};
use crate::shortint::public_key::compact::CompactPublicKey;
use crate::shortint::{CiphertextModulus, PaddingBit, ShortintEncoding};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
@@ -249,6 +252,30 @@ impl Ciphertext {
Err(NotTrivialCiphertextError)
}
}
/// This function can be called after decompressing a [`Ciphertext`] from a
/// [`CompressedCiphertextList`](super::compressed_ciphertext_list::CompressedCiphertextList) to
/// re-randomize it before any computations.
///
/// This function only supports [`PBSOrder::KeyswitchBootstrap`] ordered
/// [`Ciphertext`]/[`ServerKey`](crate::shortint::ServerKey).
///
/// It uses a [`CompactPublicKey`] to generate a new encryption of 0, a
/// [`KeySwitchingKeyMaterialView`] is required to keyswitch between the secret key used to
/// generate the [`CompactPublicKey`] to the "big"/post PBS/GLWE secret key from the
/// [`ServerKey`](crate::shortint::ServerKey).
pub fn re_randomize_with_compact_public_key_encryption(
&mut self,
compact_public_key: &CompactPublicKey,
key_switching_key_material: &KeySwitchingKeyMaterialView<'_>,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
compact_public_key.re_randomize_ciphertexts(
std::slice::from_mut(self),
key_switching_key_material,
seed,
)
}
}
pub(crate) fn unchecked_create_trivial_with_lwe_size(
@@ -285,6 +312,16 @@ pub(crate) fn unchecked_create_trivial_with_lwe_size(
#[cfg(test)]
mod tests {
use super::*;
use crate::shortint::ciphertext::ReRandomizationContext;
use crate::shortint::key_switching_key::KeySwitchingKeyBuildHelper;
use crate::shortint::keycache::KEY_CACHE;
use crate::shortint::parameters::test_params::{
TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2,
};
use crate::shortint::public_key::compact::CompactPrivateKey;
use crate::shortint::CiphertextModulus;
#[test]
@@ -382,4 +419,56 @@ mod tests {
c1.clone_from(&c2);
assert_eq!(c1, c2);
}
#[test]
fn test_re_randomize_ciphertext_ci_run_filter() {
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let comp_params = TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let cpk_params = TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let ks_params = TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let key_entry = KEY_CACHE.get_from_param(params);
// Generate the client key and the server key:
let (cks, sks) = (key_entry.client_key(), key_entry.server_key());
let cpk_private_key = CompactPrivateKey::new(cpk_params);
let cpk = CompactPublicKey::new(&cpk_private_key);
let ksk_material =
KeySwitchingKeyBuildHelper::new((&cpk_private_key, None), (cks, sks), ks_params)
.key_switching_key_material;
let ksk_material = ksk_material.as_view();
let private_compression_key = cks.new_compression_private_key(comp_params);
let (compression_key, decompression_key) =
cks.new_compression_decompression_keys(&private_compression_key);
let msg = cks.parameters().message_modulus().0 - 1;
for _ in 0..10 {
let ct = cks.encrypt(msg);
let compressed = compression_key.compress_ciphertexts_into_list(&[ct]);
let decompressed = decompression_key.unpack(&compressed, 0).unwrap();
let mut re_randomizer_context = ReRandomizationContext::new(*b"TFHE_Rrd", *b"TFHE_Enc");
re_randomizer_context.add_ciphertext(&decompressed);
let mut seed_gen = re_randomizer_context.finalize();
let seed = seed_gen.next_seed();
let mut re_randomized = decompressed.clone();
re_randomized
.re_randomize_with_compact_public_key_encryption(&cpk, &ksk_material, seed)
.unwrap();
assert_ne!(decompressed, re_randomized);
let pbsed = sks.bitand(&re_randomized, &re_randomized);
let dec = cks.decrypt_message_and_carry(&pbsed);
assert_eq!(dec, msg);
}
}
}

View File

@@ -14,7 +14,10 @@ use current_params::classic::gaussian::p_fail_2_minus_64::ks_pbs::V1_4_PARAM_MES
use current_params::classic::tuniform::p_fail_2_minus_128::ks_pbs::V1_4_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use current_params::classic::tuniform::p_fail_2_minus_64::ks_pbs::V1_4_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
use current_params::compact_public_key_only::p_fail_2_minus_128::ks_pbs::V1_4_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use current_params::key_switching::p_fail_2_minus_128::ks_pbs::V1_4_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use current_params::key_switching::p_fail_2_minus_128::ks_pbs::{
V1_4_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
V1_4_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
use current_params::list_compression::p_fail_2_minus_128::{
V1_4_COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
V1_4_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
@@ -114,8 +117,16 @@ pub const PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128: CompactPublicKeyEnc
// PKE To Compute Keyswitch
pub const PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128: ShortintKeySwitchingParameters =
PARAM_KEYSWITCH_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
pub const PARAM_KEYSWITCH_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
ShortintKeySwitchingParameters =
V1_4_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
pub const PARAM_KEYSWITCH_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
ShortintKeySwitchingParameters =
V1_4_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
// Noise squashing
pub const NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128: NoiseSquashingParameters =
V1_4_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;