mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 14:47:56 -05:00
feat: add ciphertexts re-randomization
This commit is contained in:
committed by
Nicolas Sarlin
parent
9f54777ee1
commit
d5e5902f61
@@ -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 {
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
|
||||
use tfhe_versionable::VersionsDispatch;
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum ReRandomizationMetadataVersions {
|
||||
V0(ReRandomizationMetadata),
|
||||
}
|
||||
@@ -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)]
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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.")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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}"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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(¶ms.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.")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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(¶ms.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::*;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
31
tfhe/src/high_level_api/keys/cpk_re_randomization.rs
Normal file
31
tfhe/src/high_level_api/keys/cpk_re_randomization.rs
Normal 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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(¶meter_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(¶meter_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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
234
tfhe/src/high_level_api/re_randomization.rs
Normal file
234
tfhe/src/high_level_api/re_randomization.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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(_) => {
|
||||
|
||||
@@ -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(_) => {
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(_) => {
|
||||
|
||||
@@ -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(_) => {
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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(_) => {
|
||||
|
||||
194
tfhe/src/high_level_api/tests/cpk_re_randomization.rs
Normal file
194
tfhe/src/high_level_api/tests/cpk_re_randomization.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
154
tfhe/src/integer/ciphertext/re_randomization.rs
Normal file
154
tfhe/src/integer/ciphertext/re_randomization.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
162
tfhe/src/integer/ciphertext/test.rs
Normal file
162
tfhe/src/integer/ciphertext/test.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")]
|
||||
|
||||
431
tfhe/src/shortint/ciphertext/re_randomization.rs
Normal file
431
tfhe/src/shortint/ciphertext/re_randomization.rs
Normal 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(¤t_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user