mirror of
https://github.com/zama-ai/concrete.git
synced 2026-02-08 11:35:02 -05:00
chore(cpu): introduce Polynomial container
This commit is contained in:
@@ -8,7 +8,7 @@ use super::polynomial::{
|
||||
update_with_wrapping_monic_monomial_mul, update_with_wrapping_unit_monomial_div,
|
||||
};
|
||||
use super::types::*;
|
||||
use super::{zip_eq, Split};
|
||||
use super::zip_eq;
|
||||
|
||||
impl<'a> BootstrapKey<&'a [f64]> {
|
||||
pub fn blind_rotate_scratch(
|
||||
@@ -49,7 +49,7 @@ impl<'a> BootstrapKey<&'a [f64]> {
|
||||
let lut_poly_size = lut.glwe_params.polynomial_size;
|
||||
let modulus_switched_body = pbs_modulus_switch(*lwe_body, lut_poly_size, 0, 0);
|
||||
|
||||
for polynomial in lut.as_mut_view().into_data().into_chunks(lut_poly_size) {
|
||||
for polynomial in lut.as_mut_view().into_polynomial_list().iter_polynomial() {
|
||||
update_with_wrapping_unit_monomial_div(polynomial, modulus_switched_body);
|
||||
}
|
||||
|
||||
@@ -66,10 +66,9 @@ impl<'a> BootstrapKey<&'a [f64]> {
|
||||
let mut ct1 = GlweCiphertext::new(&mut *ct1, ct0.glwe_params);
|
||||
|
||||
// We rotate ct_1 by performing ct_1 <- ct_1 * X^{modulus_switched_mask_element}
|
||||
let polynomial_size = ct1.glwe_params.polynomial_size;
|
||||
let modulus_switched_mask_element =
|
||||
pbs_modulus_switch(*lwe_mask_element, lut_poly_size, 0, 0);
|
||||
for polynomial in ct1.as_mut_view().into_data().into_chunks(polynomial_size) {
|
||||
for polynomial in ct1.as_mut_view().into_polynomial_list().iter_polynomial() {
|
||||
update_with_wrapping_monic_monomial_mul(
|
||||
polynomial,
|
||||
modulus_switched_mask_element,
|
||||
@@ -237,7 +236,7 @@ mod tests {
|
||||
csprng: CsprngMut,
|
||||
pt: u64,
|
||||
encryption_variance: f64,
|
||||
lut: &[u64],
|
||||
lut: GlweCiphertext<&[u64]>,
|
||||
) -> u64 {
|
||||
let mut input = LweCiphertext::zero(self.in_dim);
|
||||
|
||||
@@ -248,15 +247,14 @@ mod tests {
|
||||
.encrypt_lwe(input.as_mut_view(), pt, encryption_variance, csprng);
|
||||
|
||||
assert_eq!(
|
||||
lut.len(),
|
||||
lut.data.len(),
|
||||
(self.glwe_params.dimension + 1) * self.glwe_params.polynomial_size
|
||||
);
|
||||
let accumulator = GlweCiphertext::new(lut, self.glwe_params);
|
||||
|
||||
self.fourier_bsk.as_view().bootstrap(
|
||||
output.as_mut_view(),
|
||||
input.as_view(),
|
||||
accumulator,
|
||||
lut,
|
||||
self.fft.as_view(),
|
||||
DynStack::new(&mut self.stack),
|
||||
);
|
||||
@@ -274,13 +272,15 @@ mod tests {
|
||||
let log2_poly_size = 10;
|
||||
let polynomial_size = 1 << log2_poly_size;
|
||||
|
||||
let glwe_params = GlweParams {
|
||||
dimension: glwe_dim,
|
||||
polynomial_size,
|
||||
};
|
||||
|
||||
let mut keyset = KeySet::new(
|
||||
to_generic(&mut csprng),
|
||||
600,
|
||||
GlweParams {
|
||||
dimension: glwe_dim,
|
||||
polynomial_size,
|
||||
},
|
||||
glwe_params,
|
||||
DecompParams {
|
||||
level: 3,
|
||||
base_log: 10,
|
||||
@@ -321,8 +321,12 @@ mod tests {
|
||||
|
||||
let pt = (lut_index as f64 + 0.5) / (2. * lut_case_number as f64) * 2.0_f64.powi(64);
|
||||
|
||||
let image =
|
||||
keyset.bootstrap(to_generic(&mut csprng), pt as u64, 0.0000000001, &raw_lut);
|
||||
let image = keyset.bootstrap(
|
||||
to_generic(&mut csprng),
|
||||
pt as u64,
|
||||
0.0000000001,
|
||||
GlweCiphertext::new(&raw_lut, glwe_params),
|
||||
);
|
||||
|
||||
let diff = image.wrapping_sub(expected_image) as i64;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::decomposition::DecompositionTerm;
|
||||
use super::fpks::LweKeyBitDecomposition;
|
||||
use super::polynomial::{update_with_wrapping_add_mul, update_with_wrapping_sub_mul};
|
||||
use super::types::polynomial::Polynomial;
|
||||
use super::types::*;
|
||||
use super::{from_torus, zip_eq};
|
||||
use core::slice;
|
||||
@@ -256,7 +257,7 @@ impl PackingKeyswitchKey<&mut [u64]> {
|
||||
variance: f64,
|
||||
mut csprng: CsprngMut,
|
||||
f: impl Fn(u64) -> u64,
|
||||
polynomial: &[u64],
|
||||
polynomial: Polynomial<&[u64]>,
|
||||
) {
|
||||
// We instantiate a buffer
|
||||
let mut messages = vec![0_u64; self.decomp_params.level * self.glwe_params.polynomial_size];
|
||||
@@ -288,7 +289,7 @@ impl PackingKeyswitchKey<&mut [u64]> {
|
||||
f(1).wrapping_mul(input_key_bit),
|
||||
)
|
||||
.to_recomposition_summand();
|
||||
for (self_i, other_i) in zip_eq(message, polynomial) {
|
||||
for (self_i, other_i) in zip_eq(message, polynomial.as_ref().into_data()) {
|
||||
*self_i = (*self_i).wrapping_add(other_i.wrapping_mul(multiplier));
|
||||
}
|
||||
}
|
||||
@@ -319,7 +320,7 @@ impl<'a> PackingKeyswitchKey<&'a mut [u64]> {
|
||||
variance: f64,
|
||||
mut csprng: CsprngMut,
|
||||
f: impl Sync + Fn(u64) -> u64,
|
||||
polynomial: &[u64],
|
||||
polynomial: Polynomial<&[u64]>,
|
||||
) {
|
||||
// We retrieve decomposition arguments
|
||||
let decomp_level_count = self.decomp_params.level;
|
||||
@@ -365,7 +366,7 @@ impl<'a> PackingKeyswitchKey<&'a mut [u64]> {
|
||||
f(1).wrapping_mul(input_key_bit),
|
||||
)
|
||||
.to_recomposition_summand();
|
||||
for (self_i, other_i) in zip_eq(message, polynomial) {
|
||||
for (self_i, other_i) in zip_eq(message, polynomial.as_ref().into_data()) {
|
||||
*self_i = (*self_i).wrapping_add(other_i.wrapping_mul(multiplier));
|
||||
}
|
||||
}
|
||||
@@ -503,10 +504,11 @@ impl GlweSecretKey<&[u64]> {
|
||||
fill_with_random_gaussian(body.as_mut_view().into_data(), variance, csprng);
|
||||
|
||||
let mask = mask.as_view();
|
||||
let body = body.into_data();
|
||||
|
||||
for idx in 0..mask.glwe_params.dimension {
|
||||
let poly = mask.get_polynomial(idx);
|
||||
let bin_poly = self.get_polynomial(idx);
|
||||
let body = body.as_mut_view();
|
||||
update_with_wrapping_add_mul(body, poly, bin_poly)
|
||||
}
|
||||
}
|
||||
@@ -518,7 +520,11 @@ impl GlweSecretKey<&[u64]> {
|
||||
for idx in 0..mask.glwe_params.dimension {
|
||||
let poly = mask.get_polynomial(idx);
|
||||
let bin_poly = self.get_polynomial(idx);
|
||||
update_with_wrapping_sub_mul(out, poly, bin_poly)
|
||||
update_with_wrapping_sub_mul(
|
||||
Polynomial::new(out, encrypted.glwe_params.polynomial_size),
|
||||
poly,
|
||||
bin_poly,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,14 +613,13 @@ impl GlweSecretKey<&[u64]> {
|
||||
}
|
||||
|
||||
pub fn encrypt_zero_glwe_noise_full(self, encrypted: GlweCiphertext<&mut [u64]>) {
|
||||
let (mask, body) = encrypted.into_mask_and_body();
|
||||
let (mask, mut body) = encrypted.into_mask_and_body();
|
||||
|
||||
let mask = mask.as_view();
|
||||
let body = body.into_data();
|
||||
for idx in 0..mask.glwe_params.dimension {
|
||||
let poly = mask.get_polynomial(idx);
|
||||
let bin_poly = self.get_polynomial(idx);
|
||||
update_with_wrapping_add_mul(body, poly, bin_poly)
|
||||
update_with_wrapping_add_mul(body.as_mut_view(), poly, bin_poly)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,15 +27,9 @@ impl PackingKeyswitchKey<&[u64]> {
|
||||
// Loop over the number of levels:
|
||||
// We compute the multiplication of a ciphertext from the private functional
|
||||
// keyswitching key with a piece of the decomposition and subtract it to the buffer
|
||||
for (level_key_cipher, decomposed) in zip_eq(
|
||||
block
|
||||
.data
|
||||
.chunks_exact(
|
||||
(self.glwe_params.dimension + 1) * self.glwe_params.polynomial_size,
|
||||
)
|
||||
.rev(),
|
||||
decomp,
|
||||
) {
|
||||
for (level_key_cipher, decomposed) in
|
||||
zip_eq(block.into_glwe_list().into_glwe_iter().rev(), decomp)
|
||||
{
|
||||
after
|
||||
.as_mut_view()
|
||||
.update_with_wrapping_sub_element_mul(level_key_cipher, decomposed.value());
|
||||
|
||||
@@ -1,18 +1,37 @@
|
||||
pub fn update_with_wrapping_unit_monomial_div(polynomial: &mut [u64], monomial_degree: usize) {
|
||||
use super::types::polynomial::Polynomial;
|
||||
|
||||
pub fn update_with_wrapping_unit_monomial_div(
|
||||
mut polynomial: Polynomial<&mut [u64]>,
|
||||
monomial_degree: usize,
|
||||
) {
|
||||
let full_cycles_count = monomial_degree / polynomial.len();
|
||||
if full_cycles_count % 2 != 0 {
|
||||
for a in polynomial.iter_mut() {
|
||||
for a in polynomial.as_mut_view().into_data().iter_mut() {
|
||||
*a = a.wrapping_neg()
|
||||
}
|
||||
}
|
||||
let remaining_degree = monomial_degree % polynomial.len();
|
||||
polynomial.rotate_left(remaining_degree);
|
||||
for a in polynomial.iter_mut().rev().take(remaining_degree) {
|
||||
polynomial
|
||||
.as_mut_view()
|
||||
.into_data()
|
||||
.rotate_left(remaining_degree);
|
||||
|
||||
for a in polynomial
|
||||
.into_data()
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.take(remaining_degree)
|
||||
{
|
||||
*a = a.wrapping_neg()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_monic_monomial_mul(polynomial: &mut [u64], monomial_degree: usize) {
|
||||
pub fn update_with_wrapping_monic_monomial_mul(
|
||||
polynomial: Polynomial<&mut [u64]>,
|
||||
monomial_degree: usize,
|
||||
) {
|
||||
let polynomial = polynomial.into_data();
|
||||
|
||||
let full_cycles_count = monomial_degree / polynomial.len();
|
||||
if full_cycles_count % 2 != 0 {
|
||||
for a in polynomial.iter_mut() {
|
||||
@@ -27,20 +46,22 @@ pub fn update_with_wrapping_monic_monomial_mul(polynomial: &mut [u64], monomial_
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_add_mul(
|
||||
polynomial: &mut [u64],
|
||||
lhs_polynomial: &[u64],
|
||||
rhs_bin_polynomial: &[u64],
|
||||
polynomial: Polynomial<&mut [u64]>,
|
||||
lhs_polynomial: Polynomial<&[u64]>,
|
||||
rhs_bin_polynomial: Polynomial<&[u64]>,
|
||||
) {
|
||||
debug_assert_eq!(polynomial.len(), lhs_polynomial.len());
|
||||
debug_assert_eq!(polynomial.len(), rhs_bin_polynomial.len());
|
||||
|
||||
let polynomial = polynomial.into_data();
|
||||
|
||||
// TODO: optimize performance, while keeping constant time, so as not to leak information about
|
||||
// the secret key.
|
||||
let dim = polynomial.len();
|
||||
for (i, lhs) in lhs_polynomial.iter().enumerate() {
|
||||
let lhs = *lhs;
|
||||
|
||||
for (j, rhs) in rhs_bin_polynomial.iter().enumerate() {
|
||||
for (j, rhs) in rhs_bin_polynomial.as_ref().iter().enumerate() {
|
||||
let target_degree = i + j;
|
||||
|
||||
if target_degree < dim {
|
||||
@@ -55,20 +76,22 @@ pub fn update_with_wrapping_add_mul(
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_sub_mul(
|
||||
polynomial: &mut [u64],
|
||||
lhs_polynomial: &[u64],
|
||||
rhs_bin_polynomial: &[u64],
|
||||
polynomial: Polynomial<&mut [u64]>,
|
||||
lhs_polynomial: Polynomial<&[u64]>,
|
||||
rhs_bin_polynomial: Polynomial<&[u64]>,
|
||||
) {
|
||||
debug_assert_eq!(polynomial.len(), lhs_polynomial.len());
|
||||
debug_assert_eq!(polynomial.len(), rhs_bin_polynomial.len());
|
||||
|
||||
let polynomial = polynomial.into_data();
|
||||
|
||||
// TODO: optimize performance, while keeping constant time, so as not to leak information about
|
||||
// the secret key.
|
||||
let dim = polynomial.len();
|
||||
for (i, lhs) in lhs_polynomial.iter().enumerate() {
|
||||
let lhs = *lhs;
|
||||
|
||||
for (j, rhs) in rhs_bin_polynomial.iter().enumerate() {
|
||||
for (j, rhs) in rhs_bin_polynomial.as_ref().iter().enumerate() {
|
||||
let target_degree = i + j;
|
||||
|
||||
if target_degree < dim {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::implementation::{zip_eq, Container, ContainerMut, Split};
|
||||
|
||||
use super::polynomial::Polynomial;
|
||||
use super::polynomial_list::PolynomialList;
|
||||
use super::GlweParams;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
@@ -16,13 +18,6 @@ pub struct GlweMask<C: Container> {
|
||||
pub glwe_params: GlweParams,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[readonly::make]
|
||||
pub struct GlweBody<C: Container> {
|
||||
pub data: C,
|
||||
pub polynomial_size: usize,
|
||||
}
|
||||
|
||||
impl<C: Container> GlweCiphertext<C> {
|
||||
pub fn data_len(glwe_params: GlweParams) -> usize {
|
||||
glwe_params.polynomial_size * (glwe_params.dimension + 1)
|
||||
@@ -60,11 +55,19 @@ impl<C: Container> GlweCiphertext<C> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_polynomial_list(self) -> PolynomialList<C> {
|
||||
PolynomialList {
|
||||
data: self.data,
|
||||
count: self.glwe_params.dimension + 1,
|
||||
polynomial_size: self.glwe_params.polynomial_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_data(self) -> C {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn into_mask_and_body(self) -> (GlweMask<C>, GlweBody<C>)
|
||||
pub fn into_mask_and_body(self) -> (GlweMask<C>, Polynomial<C>)
|
||||
where
|
||||
C: Split,
|
||||
{
|
||||
@@ -77,13 +80,10 @@ impl<C: Container> GlweCiphertext<C> {
|
||||
data: mask,
|
||||
glwe_params: self.glwe_params,
|
||||
},
|
||||
GlweBody {
|
||||
data: body,
|
||||
polynomial_size: self.glwe_params.polynomial_size,
|
||||
},
|
||||
Polynomial::new(body, self.glwe_params.polynomial_size),
|
||||
)
|
||||
}
|
||||
pub fn into_body(self) -> GlweBody<C>
|
||||
pub fn into_body(self) -> Polynomial<C>
|
||||
where
|
||||
C: Split,
|
||||
{
|
||||
@@ -92,8 +92,12 @@ impl<C: Container> GlweCiphertext<C> {
|
||||
}
|
||||
|
||||
impl GlweCiphertext<&mut [u64]> {
|
||||
pub fn update_with_wrapping_sub_element_mul(self, other: &[u64], multiplier: u64) {
|
||||
for (a, b) in zip_eq(self.data, other) {
|
||||
pub fn update_with_wrapping_sub_element_mul(
|
||||
self,
|
||||
other: GlweCiphertext<&[u64]>,
|
||||
multiplier: u64,
|
||||
) {
|
||||
for (a, b) in zip_eq(self.data, other.into_data()) {
|
||||
*a = a.wrapping_sub(b.wrapping_mul(multiplier));
|
||||
}
|
||||
}
|
||||
@@ -138,58 +142,16 @@ impl<C: Container> GlweMask<C> {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn get_polynomial(self, idx: usize) -> C
|
||||
pub fn get_polynomial(self, idx: usize) -> Polynomial<C>
|
||||
where
|
||||
C: Split,
|
||||
{
|
||||
self.data.chunk(
|
||||
idx * self.glwe_params.polynomial_size,
|
||||
(idx + 1) * self.glwe_params.polynomial_size,
|
||||
Polynomial::new(
|
||||
self.data.chunk(
|
||||
idx * self.glwe_params.polynomial_size,
|
||||
(idx + 1) * self.glwe_params.polynomial_size,
|
||||
),
|
||||
self.glwe_params.polynomial_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Container> GlweBody<C> {
|
||||
pub fn data_len(polynomial_size: usize) -> usize {
|
||||
polynomial_size
|
||||
}
|
||||
|
||||
pub fn new(data: C, polynomial_size: usize) -> Self {
|
||||
debug_assert_eq!(data.len(), Self::data_len(polynomial_size));
|
||||
Self {
|
||||
data,
|
||||
polynomial_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_raw_parts(data: C::Pointer, polynomial_size: usize) -> Self
|
||||
where
|
||||
C: Split,
|
||||
{
|
||||
Self {
|
||||
data: C::from_raw_parts(data, Self::data_len(polynomial_size)),
|
||||
polynomial_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_view(&self) -> GlweBody<&[C::Item]> {
|
||||
GlweBody {
|
||||
data: self.data.as_ref(),
|
||||
polynomial_size: self.polynomial_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut_view(&mut self) -> GlweBody<&mut [C::Item]>
|
||||
where
|
||||
C: ContainerMut,
|
||||
{
|
||||
GlweBody {
|
||||
data: self.data.as_mut(),
|
||||
polynomial_size: self.polynomial_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_data(self) -> C {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::polynomial::Polynomial;
|
||||
use super::{GlweParams, LweSecretKey};
|
||||
use crate::implementation::{Container, ContainerMut, Split};
|
||||
|
||||
@@ -49,13 +50,16 @@ impl<C: Container> GlweSecretKey<C> {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn get_polynomial(self, idx: usize) -> C
|
||||
pub fn get_polynomial(self, idx: usize) -> Polynomial<C>
|
||||
where
|
||||
C: Split,
|
||||
{
|
||||
self.data.chunk(
|
||||
idx * self.glwe_params.polynomial_size,
|
||||
(idx + 1) * self.glwe_params.polynomial_size,
|
||||
Polynomial::new(
|
||||
self.data.chunk(
|
||||
idx * self.glwe_params.polynomial_size,
|
||||
(idx + 1) * self.glwe_params.polynomial_size,
|
||||
),
|
||||
self.glwe_params.polynomial_size,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -64,3 +68,11 @@ impl<C: Container> GlweSecretKey<C> {
|
||||
LweSecretKey::new(self.data, self.glwe_params.lwe_dimension())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> GlweSecretKey<&'a [u64]> {
|
||||
pub fn iter(self) -> impl 'a + DoubleEndedIterator<Item = Polynomial<&'a [u64]>> {
|
||||
self.data
|
||||
.chunks_exact(self.glwe_params.polynomial_size)
|
||||
.map(move |slice| Polynomial::new(slice, self.glwe_params.polynomial_size))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,5 @@ pub use csprng::*;
|
||||
|
||||
pub mod ciphertext_list;
|
||||
pub mod glev_ciphertext;
|
||||
pub mod polynomial;
|
||||
pub mod polynomial_list;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::implementation::types::polynomial::Polynomial;
|
||||
use crate::implementation::{zip_eq, Container, ContainerMut, Split};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
@@ -117,12 +118,13 @@ impl PackingKeyswitchKeyList<&mut [u64]> {
|
||||
// the loop avoiding branching
|
||||
last_polynomial[0] = u64::MAX;
|
||||
|
||||
let last_polynomial = Polynomial::new(last_polynomial.as_slice(), polynomial_size);
|
||||
|
||||
for (mut fpksk, polynomial_to_encrypt) in zip_eq(
|
||||
self.as_mut_view().into_ppksk_key(),
|
||||
output_glwe_key
|
||||
.data
|
||||
.chunks_exact(polynomial_size)
|
||||
.chain(std::iter::once(last_polynomial.as_slice())),
|
||||
.iter()
|
||||
.chain(std::iter::once(last_polynomial)),
|
||||
) {
|
||||
fpksk.fill_with_private_functional_packing_keyswitch_key(
|
||||
input_lwe_key,
|
||||
@@ -151,12 +153,13 @@ impl PackingKeyswitchKeyList<&mut [u64]> {
|
||||
// the loop avoiding branching
|
||||
last_polynomial[0] = u64::MAX;
|
||||
|
||||
let last_polynomial = Polynomial::new(last_polynomial.as_slice(), polynomial_size);
|
||||
|
||||
for (mut fpksk, polynomial_to_encrypt) in zip_eq(
|
||||
self.as_mut_view().into_ppksk_key(),
|
||||
output_glwe_key
|
||||
.data
|
||||
.chunks_exact(polynomial_size)
|
||||
.chain(std::iter::once(last_polynomial.as_slice())),
|
||||
.iter()
|
||||
.chain(std::iter::once(last_polynomial)),
|
||||
) {
|
||||
fpksk.fill_with_private_functional_packing_keyswitch_key_par(
|
||||
input_lwe_key,
|
||||
|
||||
51
backends/concrete-cpu/src/implementation/types/polynomial.rs
Normal file
51
backends/concrete-cpu/src/implementation/types/polynomial.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use crate::implementation::Container;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Polynomial<C: Container> {
|
||||
data: C,
|
||||
pub polynomial_size: usize,
|
||||
}
|
||||
|
||||
impl<C: Container> Polynomial<C> {
|
||||
pub fn new(data: C, polynomial_size: usize) -> Self {
|
||||
debug_assert_eq!(data.len(), polynomial_size);
|
||||
Self {
|
||||
data,
|
||||
polynomial_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
pub fn into_data(self) -> C {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Polynomial<&'a [u64]> {
|
||||
pub fn iter(self) -> impl DoubleEndedIterator<Item = &'a u64> {
|
||||
self.data.iter()
|
||||
}
|
||||
|
||||
pub fn as_ref(&'a self) -> Self {
|
||||
Self {
|
||||
data: self.data,
|
||||
polynomial_size: self.polynomial_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Polynomial<&'a mut [u64]> {
|
||||
fn iter(self) -> impl DoubleEndedIterator<Item = &'a mut u64> {
|
||||
self.data.iter_mut()
|
||||
}
|
||||
|
||||
pub fn as_mut_view(&mut self) -> Polynomial<&mut [u64]> {
|
||||
Polynomial {
|
||||
data: self.data,
|
||||
polynomial_size: self.polynomial_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::implementation::Container;
|
||||
|
||||
use super::polynomial::Polynomial;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PolynomialList<C: Container> {
|
||||
pub data: C,
|
||||
@@ -23,8 +25,10 @@ impl<C: Container> PolynomialList<C> {
|
||||
}
|
||||
|
||||
impl PolynomialList<&[u64]> {
|
||||
pub fn iter_polynomial(&self) -> impl DoubleEndedIterator<Item = &'_ [u64]> {
|
||||
self.data.chunks_exact(self.polynomial_size)
|
||||
pub fn iter_polynomial(&self) -> impl DoubleEndedIterator<Item = Polynomial<&'_ [u64]>> {
|
||||
self.data
|
||||
.chunks_exact(self.polynomial_size)
|
||||
.map(|a| Polynomial::new(a, self.polynomial_size))
|
||||
}
|
||||
|
||||
// Creates an iterator over borrowed sub-lists.
|
||||
@@ -45,3 +49,13 @@ impl PolynomialList<&[u64]> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PolynomialList<&mut [u64]> {
|
||||
pub fn iter_polynomial(
|
||||
&mut self,
|
||||
) -> impl DoubleEndedIterator<Item = Polynomial<&'_ mut [u64]>> {
|
||||
self.data
|
||||
.chunks_exact_mut(self.polynomial_size)
|
||||
.map(|a| Polynomial::new(a, self.polynomial_size))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use super::fft::FftView;
|
||||
use super::polynomial::update_with_wrapping_unit_monomial_div;
|
||||
use super::types::ciphertext_list::LweCiphertextList;
|
||||
use super::types::packing_keyswitch_key_list::PackingKeyswitchKeyList;
|
||||
use super::types::polynomial::Polynomial;
|
||||
use super::types::polynomial_list::PolynomialList;
|
||||
use super::types::{
|
||||
BootstrapKey, DecompParams, GgswCiphertext, GlweParams, LweCiphertext, LweKeyswitchKey,
|
||||
@@ -596,12 +597,12 @@ pub fn cmux_tree_memory_optimized(
|
||||
t0_j.as_mut_view()
|
||||
.into_body()
|
||||
.into_data()
|
||||
.copy_from_slice(lut_2i);
|
||||
.copy_from_slice(lut_2i.into_data());
|
||||
|
||||
t1_j.as_mut_view()
|
||||
.into_body()
|
||||
.into_data()
|
||||
.copy_from_slice(lut_2i_plus_1);
|
||||
.copy_from_slice(lut_2i_plus_1.into_data());
|
||||
|
||||
t_fill[0] = 2;
|
||||
|
||||
@@ -840,7 +841,7 @@ fn log2(a: usize) -> usize {
|
||||
|
||||
// GGSW ciphertexts are stored from the msb (vec_ggsw[0]) to the lsb (vec_ggsw[last])
|
||||
pub fn vertical_packing(
|
||||
lut: &[u64],
|
||||
lut: Polynomial<&[u64]>,
|
||||
lwe_out: LweCiphertext<&mut [u64]>,
|
||||
ggsw_list: FourierGgswCiphertextListView,
|
||||
fft: FftView,
|
||||
@@ -872,7 +873,7 @@ pub fn vertical_packing(
|
||||
.into_data()
|
||||
.fill_with(|| 0_u64);
|
||||
cmux_tree_lut_res.as_mut_view().into_body().into_data()[0..lut.len()]
|
||||
.copy_from_slice(lut);
|
||||
.copy_from_slice(lut.into_data());
|
||||
ggsw_list
|
||||
}
|
||||
Ordering::Equal => {
|
||||
@@ -884,7 +885,7 @@ pub fn vertical_packing(
|
||||
.as_mut_view()
|
||||
.into_body()
|
||||
.into_data()
|
||||
.copy_from_slice(lut);
|
||||
.copy_from_slice(lut.into_data());
|
||||
ggsw_list
|
||||
}
|
||||
Ordering::Greater => {
|
||||
@@ -895,8 +896,11 @@ pub fn vertical_packing(
|
||||
let (cmux_ggsw, br_ggsw) = ggsw_list.split_at(log_number_of_luts_for_cmux_tree);
|
||||
debug_assert_eq!(br_ggsw.count, log_poly_size);
|
||||
|
||||
let small_luts =
|
||||
PolynomialList::new(lut, polynomial_size, 1 << (log_lut_number - log_poly_size));
|
||||
let small_luts = PolynomialList::new(
|
||||
lut.into_data(),
|
||||
polynomial_size,
|
||||
1 << (log_lut_number - log_poly_size),
|
||||
);
|
||||
|
||||
cmux_tree_memory_optimized(
|
||||
cmux_tree_lut_res.as_mut_view(),
|
||||
@@ -951,11 +955,7 @@ pub fn blind_rotate(
|
||||
.collect_aligned(CACHELINE_ALIGN, ct_0.as_view().into_data().iter().copied());
|
||||
let mut ct_1 = GlweCiphertext::new(&mut *ct1_data, ct_0.glwe_params);
|
||||
|
||||
for a in ct_1
|
||||
.as_mut_view()
|
||||
.into_data()
|
||||
.chunks_exact_mut(ct_0.glwe_params.polynomial_size)
|
||||
{
|
||||
for a in ct_1.as_mut_view().into_polynomial_list().iter_polynomial() {
|
||||
update_with_wrapping_unit_monomial_div(a, monomial_degree);
|
||||
}
|
||||
monomial_degree <<= 1;
|
||||
|
||||
Reference in New Issue
Block a user