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;
#[cfg(feature = "zk-pok")]
use super::ProvenCompactCiphertextList;
#[derive(Clone, Copy)]
pub enum ReRandomizationKey<'key> {
LegacyDedicatedCPK {
cpk: &'key CompactPublicKey,
ksk: KeySwitchingKeyMaterialView<'key>,
},
DerivedCPKWithoutKeySwitch {
cpk: &'key CompactPublicKey,
},
}
pub struct ReRandomizationContext {
inner_context: crate::shortint::ciphertext::ReRandomizationContext,
ct_count: u64,
ct_coeffs_buffer: Vec<u64>,
meta_buffer: Vec<u8>,
fn_description: Vec<u8>,
}
impl ReRandomizationContext {
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(),
}
}
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(),
}
}
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;
}
#[cfg(feature = "zk-pok")]
pub fn add_proven_ciphertext_list(&mut self, list: &ProvenCompactCiphertextList) {
self.ct_coeffs_buffer.extend(
list.ct_list
.proved_lists
.iter()
.flat_map(|list| list.0.ct_list.as_ref()),
);
self.meta_buffer.extend(
list.ct_list
.proved_lists
.iter()
.flat_map(|list| list.1.to_le_bytes()),
);
self.ct_count += 1;
}
pub fn add_bytes(&mut self, data: &[u8]) {
self.meta_buffer.extend_from_slice(data);
}
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,
}
}
}
pub struct ReRandomizationSeedGen {
inner: crate::shortint::ciphertext::ReRandomizationSeedGen,
remaining_seeds_count: u64,
}
impl ReRandomizationSeedGen {
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],
re_randomization_key: ReRandomizationKey<'_>,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
let (compact_public_key, key_switching_key_material) = match re_randomization_key {
ReRandomizationKey::LegacyDedicatedCPK { cpk, ksk } => (cpk, Some(ksk)),
ReRandomizationKey::DerivedCPKWithoutKeySwitch { cpk } => (cpk, None),
};
compact_public_key.key.re_randomize_ciphertexts(
blocks,
key_switching_key_material.map(|k| k.material).as_ref(),
seed,
)
}