use crate::core_crypto::entities::{LweCiphertextList, LweCiphertextOwned};
use crate::core_crypto::gpu::lwe_ciphertext_list::CudaLweCiphertextList;
use crate::core_crypto::gpu::vec::{CudaVec, GpuIndex};
use crate::core_crypto::gpu::CudaStreams;
use crate::core_crypto::prelude::{CiphertextModulus, LweSize};
use crate::integer::gpu::ciphertext::info::{CudaBlockInfo, CudaRadixCiphertextInfo};
use crate::integer::gpu::ciphertext::{CudaRadixCiphertext, CudaUnsignedRadixCiphertext};
use crate::integer::BooleanBlock;
use crate::shortint::Ciphertext;
use super::CudaIntegerRadixCiphertext;
pub struct CudaBooleanBlock(pub CudaUnsignedRadixCiphertext);
impl CudaBooleanBlock {
pub fn from_cuda_radix_ciphertext(ct: CudaRadixCiphertext) -> Self {
assert_eq!(
ct.info.blocks.len(),
1,
"CudaBooleanBlock needs to have 1 block, got {}",
ct.info.blocks.len()
);
assert!(
ct.info.blocks.first().unwrap().degree.get() <= 1,
"CudaBooleanBlock needs to have degree <= 1, got {}",
ct.info.blocks.first().unwrap().degree.get()
);
assert_eq!(
ct.d_blocks.0.lwe_ciphertext_count.0, 1,
"CudaBooleanBlock needs to have 1 block, got {}",
ct.d_blocks.0.lwe_ciphertext_count.0
);
assert_eq!(
ct.d_blocks.0.d_vec.len(),
ct.d_blocks.0.lwe_dimension.0 + 1,
"CudaBooleanBlock needs to have a length of LWE size, got {}",
ct.d_blocks.0.lwe_dimension.0 + 1
);
Self(CudaUnsignedRadixCiphertext { ciphertext: ct })
}
pub fn from_boolean_block(boolean_block: &BooleanBlock, streams: &CudaStreams) -> Self {
let mut h_boolean_block = boolean_block.clone();
let lwe_size = boolean_block.0.ct.as_ref().len();
let h_ct = LweCiphertextList::from_container(
h_boolean_block.0.ct.as_mut(),
LweSize(lwe_size),
CiphertextModulus::new_native(),
);
let d_blocks = CudaLweCiphertextList::from_lwe_ciphertext_list(&h_ct, streams);
let info = CudaBlockInfo {
degree: boolean_block.0.degree,
message_modulus: boolean_block.0.message_modulus,
carry_modulus: boolean_block.0.carry_modulus,
atomic_pattern: boolean_block.0.atomic_pattern,
noise_level: boolean_block.0.noise_level(),
};
let radix_info = vec![info; 1];
let info = CudaRadixCiphertextInfo { blocks: radix_info };
Self(CudaUnsignedRadixCiphertext {
ciphertext: CudaRadixCiphertext { d_blocks, info },
})
}
pub fn copy_from_boolean_block(&mut self, boolean_block: &BooleanBlock, streams: &CudaStreams) {
unsafe {
self.0.ciphertext.d_blocks.0.d_vec.copy_from_cpu_async(
boolean_block.0.ct.as_ref(),
streams,
0,
);
}
streams.synchronize();
let info = CudaBlockInfo {
degree: boolean_block.0.degree,
message_modulus: boolean_block.0.message_modulus,
carry_modulus: boolean_block.0.carry_modulus,
atomic_pattern: boolean_block.0.atomic_pattern,
noise_level: boolean_block.0.noise_level(),
};
let radix_info = vec![info; 1];
self.0.ciphertext.info = CudaRadixCiphertextInfo { blocks: radix_info };
}
pub fn to_boolean_block(&self, streams: &CudaStreams) -> BooleanBlock {
let h_lwe_ciphertext_list = self.0.ciphertext.d_blocks.to_lwe_ciphertext_list(streams);
let ciphertext_modulus = h_lwe_ciphertext_list.ciphertext_modulus();
let block = Ciphertext::new(
LweCiphertextOwned::from_container(
h_lwe_ciphertext_list.into_container(),
ciphertext_modulus,
),
self.0.ciphertext.info.blocks[0].degree,
self.0.ciphertext.info.blocks[0].noise_level,
self.0.ciphertext.info.blocks[0].message_modulus,
self.0.ciphertext.info.blocks[0].carry_modulus,
self.0.ciphertext.info.blocks[0].atomic_pattern,
);
BooleanBlock::new_unchecked(block)
}
pub(crate) unsafe fn duplicate_async(&self, streams: &CudaStreams) -> Self {
let lwe_ciphertext_count = self.0.ciphertext.d_blocks.lwe_ciphertext_count();
let ciphertext_modulus = self.0.ciphertext.d_blocks.ciphertext_modulus();
let mut d_ct = CudaVec::new_async(self.0.ciphertext.d_blocks.0.d_vec.len(), streams, 0);
d_ct.copy_from_gpu_async(&self.0.ciphertext.d_blocks.0.d_vec, streams, 0);
let d_blocks =
CudaLweCiphertextList::from_cuda_vec(d_ct, lwe_ciphertext_count, ciphertext_modulus);
Self(CudaUnsignedRadixCiphertext {
ciphertext: CudaRadixCiphertext {
d_blocks,
info: self.0.ciphertext.info.clone(),
},
})
}
pub fn duplicate(&self, streams: &CudaStreams) -> Self {
let ct = unsafe { self.duplicate_async(streams) };
streams.synchronize();
ct
}
pub fn move_to_stream(self, streams: &CudaStreams) -> Self {
Self(self.0.move_to_stream(streams))
}
pub fn gpu_indexes(&self) -> &[GpuIndex] {
self.0.gpu_indexes()
}
}
impl AsRef<CudaUnsignedRadixCiphertext> for CudaBooleanBlock {
fn as_ref(&self) -> &CudaUnsignedRadixCiphertext {
&self.0
}
}
impl AsMut<CudaUnsignedRadixCiphertext> for CudaBooleanBlock {
fn as_mut(&mut self) -> &mut CudaUnsignedRadixCiphertext {
&mut self.0
}
}