feat: make XofKeySet serializable

This commit is contained in:
Thomas Montaigu
2025-09-22 16:54:56 +02:00
committed by tmontaigu
parent e4b230aaf1
commit 736185bb31
6 changed files with 120 additions and 9 deletions

View File

@@ -19,9 +19,11 @@ pub use tfhe_csprng::seeders::{Seed, Seeder, XofSeed};
/// Module to proxy the serialization for `tfhe-csprng::Seed` to avoid adding serde as a
/// dependency to `tfhe-csprng`
pub mod serialization_proxy {
// use crate::core_crypto::backward_compatibility::commons::math::random::{
// XofSeedSerdeDefVersioned, XofSeedSerdeDefVersionedOwned,
// };
pub(crate) use serde::{Deserialize, Serialize};
pub(crate) use tfhe_csprng::seeders::Seed;
pub(crate) use tfhe_csprng::seeders::{Seed, XofSeed};
// See https://serde.rs/remote-derive.html
// Serde calls this the definition of the remote type. It is just a copy of the remote data
// structure. The `remote` attribute gives the path to the actual type we intend to derive code
@@ -29,6 +31,16 @@ pub mod serialization_proxy {
#[derive(Serialize, Deserialize)]
#[serde(remote = "Seed")]
pub(crate) struct SeedSerdeDef(pub u128);
#[derive(Serialize, Deserialize)]
#[serde(remote = "XofSeed")]
pub(crate) struct XofSeedSerdeDef(#[serde(getter = "XofSeed::bytes")] Vec<u8>);
impl From<XofSeedSerdeDef> for XofSeed {
fn from(value: XofSeedSerdeDef) -> Self {
Self::from_bytes(value.0)
}
}
}
pub(crate) use serialization_proxy::*;

View File

@@ -12,3 +12,4 @@ pub mod keys;
#[cfg(feature = "strings")]
pub mod strings;
pub mod tag;
pub mod xof_key_set;

View File

@@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};
use tfhe_versionable::VersionsDispatch;
use crate::high_level_api::xof_key_set::{CompressedXofKeySet, XofKeySet};
#[derive(Serialize)]
pub enum CompressedXofKeySetVersioned<'vers> {
V0(&'vers CompressedXofKeySet),
}
#[derive(Serialize, Deserialize)]
pub enum CompressedXofKeySetVersionedOwned {
V0(CompressedXofKeySet),
}
#[derive(VersionsDispatch)]
pub enum XofKeySetVersions {
V0(XofKeySet),
}

View File

@@ -17,6 +17,7 @@ use crate::integer::compression_keys::CompressionPrivateKeys;
use crate::integer::noise_squashing::CompressedNoiseSquashingKey;
#[cfg(test)]
use crate::integer::noise_squashing::NoiseSquashingPrivateKey;
use crate::named::Named;
#[cfg(test)]
use crate::shortint::atomic_pattern::compressed::{
CompressedAtomicPatternServerKey, CompressedStandardAtomicPatternServerKey,
@@ -49,7 +50,12 @@ use serde::{Deserialize, Serialize};
use tfhe_csprng::seeders::Seed;
use tfhe_csprng::seeders::XofSeed;
use tfhe_fft::c64;
use tfhe_versionable::{Unversionize, Versionize, VersionizeOwned};
use crate::core_crypto::commons::math::random::XofSeedSerdeDef;
use crate::high_level_api::backward_compatibility::xof_key_set::{
CompressedXofKeySetVersioned, CompressedXofKeySetVersionedOwned, XofKeySetVersions,
};
use crate::integer::compression_keys::CompressionKey;
use crate::integer::key_switching_key::{
CompressedKeySwitchingKeyMaterial, KeySwitchingKeyMaterial,
@@ -74,12 +80,44 @@ use crate::shortint::noise_squashing::{
/// regarding the random generator used, and the order of key generation
///
/// [NIST document]: https://eprint.iacr.org/2025/699
#[derive(Clone, Serialize, Deserialize)]
pub struct CompressedXofKeySet {
#[serde(with = "XofSeedSerdeDef")]
seed: XofSeed,
compressed_public_key: CompressedCompactPublicKey,
compressed_server_key: CompressedServerKey,
}
impl Versionize for CompressedXofKeySet {
type Versioned<'vers> = CompressedXofKeySetVersioned<'vers>;
fn versionize(&self) -> Self::Versioned<'_> {
CompressedXofKeySetVersioned::V0(self)
}
}
impl VersionizeOwned for CompressedXofKeySet {
type VersionedOwned = CompressedXofKeySetVersionedOwned;
fn versionize_owned(self) -> Self::VersionedOwned {
CompressedXofKeySetVersionedOwned::V0(self)
}
}
impl Unversionize for CompressedXofKeySet {
fn unversionize(
versioned: Self::VersionedOwned,
) -> Result<Self, tfhe_versionable::UnversionizeError> {
match versioned {
CompressedXofKeySetVersionedOwned::V0(v0) => Ok(v0),
}
}
}
impl Named for CompressedXofKeySet {
const NAME: &'static str = "CompressedXofKeySet";
}
impl CompressedXofKeySet {
#[cfg(test)]
fn with_seed(pub_seed: XofSeed, priv_seed: XofSeed, ck: &ClientKey) -> crate::Result<Self> {
@@ -550,12 +588,17 @@ impl CompressedXofKeySet {
/// To create such key set, first create a [CompressedXofKeySet] then decompress it
///
/// [NIST document]: https://eprint.iacr.org/2025/699
#[derive(Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize, Versionize)]
#[versionize(XofKeySetVersions)]
pub struct XofKeySet {
public_key: CompactPublicKey,
server_key: ServerKey,
}
impl Named for XofKeySet {
const NAME: &'static str = "XofKeySet";
}
impl XofKeySet {
pub fn into_raw_parts(self) -> (CompactPublicKey, ServerKey) {
(self.public_key, self.server_key)
@@ -1190,7 +1233,7 @@ where
mod test {
use crate::core_crypto::prelude::new_seeder;
use crate::prelude::*;
use crate::xof_key_set::CompressedXofKeySet;
use crate::xof_key_set::{CompressedXofKeySet, XofKeySet};
use crate::{XofSeed, *};
#[test]
@@ -1227,8 +1270,26 @@ mod test {
let compressed_key_set = CompressedXofKeySet::with_seed(pub_seed, priv_seed, &cks).unwrap();
let compressed_size_limit = 1 << 30;
let mut data = vec![];
crate::safe_serialization::safe_serialize(
&compressed_key_set,
&mut data,
compressed_size_limit,
)
.unwrap();
let compressed_key_set: CompressedXofKeySet =
crate::safe_serialization::safe_deserialize(data.as_slice(), compressed_size_limit)
.unwrap();
let key_set = compressed_key_set.decompress();
let size_limit = 1 << 32;
let mut data = vec![];
crate::safe_serialization::safe_serialize(&key_set, &mut data, size_limit).unwrap();
let key_set: XofKeySet =
crate::safe_serialization::safe_deserialize(data.as_slice(), size_limit).unwrap();
let (pk, sk) = key_set.into_raw_parts();
assert!(sk.is_conformant(&config.into()));

View File

@@ -120,11 +120,6 @@ impl CompressedStandardAtomicPatternServerKey {
&self.bootstrapping_key
}
#[cfg(all(feature = "integer", test))]
pub(crate) fn bootstrapping_key_mut(&mut self) -> &mut ShortintCompressedBootstrappingKey<u64> {
&mut self.bootstrapping_key
}
pub fn pbs_order(&self) -> PBSOrder {
self.pbs_order
}