Added more serialization tests + generalize methods to any n

This commit is contained in:
Pro7ech
2025-08-13 15:28:52 +02:00
parent 068470783e
commit 940742ce6c
117 changed files with 3658 additions and 2577 deletions

View File

@@ -10,6 +10,7 @@ use crate::{
impl GGSWCiphertext<Vec<u8>> {
pub fn automorphism_scratch_space<B: Backend>(
module: &Module<B>,
n: usize,
basek: usize,
k_out: usize,
k_in: usize,
@@ -23,15 +24,16 @@ impl GGSWCiphertext<Vec<u8>> {
Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
{
let out_size: usize = k_out.div_ceil(basek);
let ci_dft: usize = module.vec_znx_dft_alloc_bytes(rank + 1, out_size);
let ci_dft: usize = module.vec_znx_dft_alloc_bytes(n, rank + 1, out_size);
let ks_internal: usize =
GLWECiphertext::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits_ksk, rank, rank);
let expand: usize = GGSWCiphertext::expand_row_scratch_space(module, basek, k_out, k_tsk, digits_tsk, rank);
GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_out, k_in, k_ksk, digits_ksk, rank, rank);
let expand: usize = GGSWCiphertext::expand_row_scratch_space(module, n, basek, k_out, k_tsk, digits_tsk, rank);
ci_dft + (ks_internal | expand)
}
pub fn automorphism_inplace_scratch_space<B: Backend>(
module: &Module<B>,
n: usize,
basek: usize,
k_out: usize,
k_ksk: usize,
@@ -44,7 +46,7 @@ impl GGSWCiphertext<Vec<u8>> {
Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
{
GGSWCiphertext::automorphism_scratch_space(
module, basek, k_out, k_out, k_ksk, digits_ksk, k_tsk, digits_tsk, rank,
module, n, basek, k_out, k_out, k_ksk, digits_ksk, k_tsk, digits_tsk, rank,
)
}
}
@@ -65,6 +67,9 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
{
use crate::Infos;
assert_eq!(self.n(), auto_key.n());
assert_eq!(lhs.n(), auto_key.n());
assert_eq!(
self.rank(),
lhs.rank(),
@@ -90,6 +95,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
scratch.available()
>= GGSWCiphertext::automorphism_scratch_space(
module,
self.n(),
self.basek(),
self.k(),
lhs.k(),
@@ -102,6 +108,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
)
};
let n: usize = auto_key.n();
let rank: usize = self.rank();
let cols: usize = rank + 1;
@@ -113,7 +120,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
.automorphism(module, &lhs.at(row_i, 0), auto_key, scratch);
// Isolates DFT(AUTO(a[i]))
let (mut ci_dft, scratch1) = scratch.take_vec_znx_dft(module, cols, self.size());
let (mut ci_dft, scratch1) = scratch.take_vec_znx_dft(n, cols, self.size());
(0..cols).for_each(|i| {
module.vec_znx_dft_from_vec_znx(1, 0, &mut ci_dft, i, &self.at(row_i, 0).data, i);
});

View File

@@ -1,8 +1,6 @@
use backend::hal::{
api::{
ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, VecZnxAllocBytes, VecZnxNormalizeInplace, ZnxZero,
},
layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch},
api::{ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, VecZnxNormalizeInplace, ZnxZero},
layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch, VecZnx},
};
use sampling::source::Source;
@@ -14,15 +12,15 @@ use crate::{
pub trait GGSWEncryptSkFamily<B: Backend> = GLWEEncryptSkFamily<B>;
impl GGSWCiphertext<Vec<u8>> {
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> usize
where
Module<B>: GGSWEncryptSkFamily<B> + VecZnxAllocBytes,
Module<B>: GGSWEncryptSkFamily<B>,
{
let size = k.div_ceil(basek);
GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
+ module.vec_znx_alloc_bytes(rank + 1, size)
+ module.vec_znx_alloc_bytes(1, size)
+ module.vec_znx_dft_alloc_bytes(rank + 1, size)
GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, k)
+ VecZnx::alloc_bytes(n, rank + 1, size)
+ VecZnx::alloc_bytes(n, 1, size)
+ module.vec_znx_dft_alloc_bytes(n, rank + 1, size)
}
}
@@ -38,16 +36,15 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
scratch: &mut Scratch<B>,
) where
Module<B>: GGSWEncryptSkFamily<B> + VecZnxAddScalarInplace,
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
{
#[cfg(debug_assertions)]
{
use backend::hal::api::ZnxInfos;
assert_eq!(self.rank(), sk.rank());
assert_eq!(self.n(), module.n());
assert_eq!(pt.n(), module.n());
assert_eq!(sk.n(), module.n());
assert_eq!(self.n(), sk.n());
assert_eq!(pt.n(), sk.n());
}
let basek: usize = self.basek();
@@ -55,7 +52,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
let rank: usize = self.rank();
let digits: usize = self.digits();
let (mut tmp_pt, scratch1) = scratch.take_glwe_pt(module, basek, k);
let (mut tmp_pt, scratch1) = scratch.take_glwe_pt(self.n(), basek, k);
(0..self.rows()).for_each(|row_i| {
tmp_pt.data.zero();
@@ -82,11 +79,11 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
}
impl GGSWCiphertextCompressed<Vec<u8>> {
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize
pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> usize
where
Module<B>: GGSWEncryptSkFamily<B> + VecZnxAllocBytes,
Module<B>: GGSWEncryptSkFamily<B>,
{
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k, rank)
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k, rank)
}
}
@@ -102,16 +99,15 @@ impl<DataSelf: DataMut> GGSWCiphertextCompressed<DataSelf> {
scratch: &mut Scratch<B>,
) where
Module<B>: GGSWEncryptSkFamily<B> + VecZnxAddScalarInplace,
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
{
#[cfg(debug_assertions)]
{
use backend::hal::api::ZnxInfos;
assert_eq!(self.rank(), sk.rank());
assert_eq!(self.n(), module.n());
assert_eq!(pt.n(), module.n());
assert_eq!(sk.n(), module.n());
assert_eq!(self.n(), sk.n());
assert_eq!(pt.n(), sk.n());
}
let basek: usize = self.basek();
@@ -120,10 +116,12 @@ impl<DataSelf: DataMut> GGSWCiphertextCompressed<DataSelf> {
let cols: usize = rank + 1;
let digits: usize = self.digits();
let (mut tmp_pt, scratch_1) = scratch.take_glwe_pt(module, basek, k);
let (mut tmp_pt, scratch_1) = scratch.take_glwe_pt(self.n(), basek, k);
let mut source = Source::new(seed_xa);
self.seed = vec![[0u8; 32]; self.rows() * cols];
(0..self.rows()).for_each(|row_i| {
tmp_pt.data.zero();
@@ -137,7 +135,7 @@ impl<DataSelf: DataMut> GGSWCiphertextCompressed<DataSelf> {
let (seed, mut source_xa_tmp) = source.branch();
self.seed[row_i * cols + col_j] = seed;
encrypt_sk_internal(
module,
self.basek(),

View File

@@ -8,6 +8,7 @@ use crate::{GGSWCiphertext, GGSWCiphertextExec, GLWECiphertext, GLWEExternalProd
impl GGSWCiphertext<Vec<u8>> {
pub fn external_product_scratch_space<B: Backend>(
module: &Module<B>,
n: usize,
basek: usize,
k_out: usize,
k_in: usize,
@@ -18,11 +19,12 @@ impl GGSWCiphertext<Vec<u8>> {
where
Module<B>: GLWEExternalProductFamily<B>,
{
GLWECiphertext::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank)
GLWECiphertext::external_product_scratch_space(module, n, basek, k_out, k_in, k_ggsw, digits, rank)
}
pub fn external_product_inplace_scratch_space<B: Backend>(
module: &Module<B>,
n: usize,
basek: usize,
k_out: usize,
k_ggsw: usize,
@@ -32,7 +34,7 @@ impl GGSWCiphertext<Vec<u8>> {
where
Module<B>: GLWEExternalProductFamily<B>,
{
GLWECiphertext::external_product_inplace_scratch_space(module, basek, k_out, k_ggsw, digits, rank)
GLWECiphertext::external_product_inplace_scratch_space(module, n, basek, k_out, k_ggsw, digits, rank)
}
}
@@ -51,6 +53,9 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
{
use crate::{GGSWCiphertext, Infos};
assert_eq!(lhs.n(), self.n());
assert_eq!(rhs.n(), self.n());
assert_eq!(
self.rank(),
lhs.rank(),
@@ -70,6 +75,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
scratch.available()
>= GGSWCiphertext::external_product_scratch_space(
module,
self.n(),
self.basek(),
self.k(),
lhs.k(),
@@ -104,6 +110,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
{
#[cfg(debug_assertions)]
{
assert_eq!(rhs.n(), self.n());
assert_eq!(
self.rank(),
rhs.rank(),

View File

@@ -1,9 +1,9 @@
use backend::hal::{
api::{
ScratchAvailable, TakeVecZnxBig, TakeVecZnxDft, VecZnxAllocBytes, VecZnxBigAllocBytes, VecZnxDftAddInplace,
VecZnxDftCopy, VecZnxDftToVecZnxBigTmpA, VecZnxNormalizeTmpBytes, ZnxInfos,
ScratchAvailable, TakeVecZnxBig, TakeVecZnxDft, VecZnxBigAllocBytes, VecZnxDftAddInplace, VecZnxDftCopy,
VecZnxDftToVecZnxBigTmpA, VecZnxNormalizeTmpBytes, ZnxInfos,
},
layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnxDft, VmpPMat},
layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnx, VecZnxDft, VmpPMat},
};
use crate::{GGSWCiphertext, GLWECiphertext, GLWEKeyswitchFamily, GLWESwitchingKeyExec, GLWETensorKeyExec, Infos};
@@ -14,6 +14,7 @@ pub trait GGSWKeySwitchFamily<B> =
impl GGSWCiphertext<Vec<u8>> {
pub(crate) fn expand_row_scratch_space<B: Backend>(
module: &Module<B>,
n: usize,
basek: usize,
self_k: usize,
k_tsk: usize,
@@ -27,9 +28,10 @@ impl GGSWCiphertext<Vec<u8>> {
let self_size_out: usize = self_k.div_ceil(basek);
let self_size_in: usize = self_size_out.div_ceil(digits);
let tmp_dft_i: usize = module.vec_znx_dft_alloc_bytes(rank + 1, tsk_size);
let tmp_a: usize = module.vec_znx_dft_alloc_bytes(1, self_size_in);
let tmp_dft_i: usize = module.vec_znx_dft_alloc_bytes(n, rank + 1, tsk_size);
let tmp_a: usize = module.vec_znx_dft_alloc_bytes(n, 1, self_size_in);
let vmp: usize = module.vmp_apply_tmp_bytes(
n,
self_size_out,
self_size_in,
self_size_in,
@@ -37,13 +39,14 @@ impl GGSWCiphertext<Vec<u8>> {
rank,
tsk_size,
);
let tmp_idft: usize = module.vec_znx_big_alloc_bytes(1, tsk_size);
let tmp_idft: usize = module.vec_znx_big_alloc_bytes(n, 1, tsk_size);
let norm: usize = module.vec_znx_normalize_tmp_bytes(module.n());
tmp_dft_i + ((tmp_a + vmp) | (tmp_idft + norm))
}
pub fn keyswitch_scratch_space<B: Backend>(
module: &Module<B>,
n: usize,
basek: usize,
k_out: usize,
k_in: usize,
@@ -54,19 +57,20 @@ impl GGSWCiphertext<Vec<u8>> {
rank: usize,
) -> usize
where
Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxAllocBytes + VecZnxNormalizeTmpBytes,
Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
{
let out_size: usize = k_out.div_ceil(basek);
let res_znx: usize = module.vec_znx_alloc_bytes(rank + 1, out_size);
let ci_dft: usize = module.vec_znx_dft_alloc_bytes(rank + 1, out_size);
let ks: usize = GLWECiphertext::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits_ksk, rank, rank);
let expand_rows: usize = GGSWCiphertext::expand_row_scratch_space(module, basek, k_out, k_tsk, digits_tsk, rank);
let res_dft: usize = module.vec_znx_dft_alloc_bytes(rank + 1, out_size);
let res_znx: usize = VecZnx::alloc_bytes(n, rank + 1, out_size);
let ci_dft: usize = module.vec_znx_dft_alloc_bytes(n, rank + 1, out_size);
let ks: usize = GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_out, k_in, k_ksk, digits_ksk, rank, rank);
let expand_rows: usize = GGSWCiphertext::expand_row_scratch_space(module, n, basek, k_out, k_tsk, digits_tsk, rank);
let res_dft: usize = module.vec_znx_dft_alloc_bytes(n, rank + 1, out_size);
res_znx + ci_dft + (ks | expand_rows | res_dft)
}
pub fn keyswitch_inplace_scratch_space<B: Backend>(
module: &Module<B>,
n: usize,
basek: usize,
k_out: usize,
k_ksk: usize,
@@ -76,10 +80,10 @@ impl GGSWCiphertext<Vec<u8>> {
rank: usize,
) -> usize
where
Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxAllocBytes + VecZnxNormalizeTmpBytes,
Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
{
GGSWCiphertext::keyswitch_scratch_space(
module, basek, k_out, k_out, k_ksk, digits_ksk, k_tsk, digits_tsk, rank,
module, n, basek, k_out, k_out, k_ksk, digits_ksk, k_tsk, digits_tsk, rank,
)
}
}
@@ -99,10 +103,16 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
{
let cols: usize = self.rank() + 1;
#[cfg(debug_assertions)]
{
assert_eq!(self.n(), tsk.n());
}
assert!(
scratch.available()
>= GGSWCiphertext::expand_row_scratch_space(
module,
self.n(),
self.basek(),
self.k(),
tsk.k(),
@@ -131,10 +141,11 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
// col 2: (-(c0s0 + c1s1 + c2s2) , c0 , c1 + M[i], c2 )
// col 3: (-(d0s0 + d1s1 + d2s2) , d0 , d1 , d2 + M[i])
let n: usize = self.n();
let digits: usize = tsk.digits();
let (mut tmp_dft_i, scratch1) = scratch.take_vec_znx_dft(module, cols, tsk.size());
let (mut tmp_a, scratch2) = scratch1.take_vec_znx_dft(module, 1, ci_dft.size().div_ceil(digits));
let (mut tmp_dft_i, scratch1) = scratch.take_vec_znx_dft(n, cols, tsk.size());
let (mut tmp_a, scratch2) = scratch1.take_vec_znx_dft(n, 1, ci_dft.size().div_ceil(digits));
{
// Performs a key-switch for each combination of s[i]*s[j], i.e. for a0, a1, a2
@@ -184,7 +195,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
// =
// (-(x0s0 + x1s1 + x2s2), x0 + M[i], x1, x2)
module.vec_znx_dft_add_inplace(&mut tmp_dft_i, col_j, ci_dft, 0);
let (mut tmp_idft, scratch2) = scratch1.take_vec_znx_big(module, 1, tsk.size());
let (mut tmp_idft, scratch2) = scratch1.take_vec_znx_big(n, 1, tsk.size());
(0..cols).for_each(|i| {
module.vec_znx_dft_to_vec_znx_big_tmp_a(&mut tmp_idft, 0, &mut tmp_dft_i, i);
module.vec_znx_big_normalize(
@@ -209,6 +220,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
Scratch<B>: TakeVecZnxDft<B> + TakeVecZnxBig<B> + ScratchAvailable,
{
let n: usize = self.n();
let rank: usize = self.rank();
let cols: usize = rank + 1;
@@ -220,7 +232,7 @@ impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
.keyswitch(module, &lhs.at(row_i, 0), ksk, scratch);
// Pre-compute DFT of (a0, a1, a2)
let (mut ci_dft, scratch1) = scratch.take_vec_znx_dft(module, cols, self.size());
let (mut ci_dft, scratch1) = scratch.take_vec_znx_dft(n, cols, self.size());
(0..cols).for_each(|i| {
module.vec_znx_dft_from_vec_znx(1, 0, &mut ci_dft, i, &self.at(row_i, 0).data, i);
});

View File

@@ -1,13 +1,14 @@
use backend::hal::{
api::{MatZnxAlloc, MatZnxAllocBytes, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
api::{FillUniform, Reset, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
};
use std::fmt;
use crate::{GLWECiphertext, Infos};
pub trait GGSWLayoutFamily<B: Backend> = VmpPMatAlloc<B> + VmpPMatAllocBytes + VmpPMatPrepare<B>;
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone)]
pub struct GGSWCiphertext<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) basek: usize,
@@ -15,6 +16,37 @@ pub struct GGSWCiphertext<D: Data> {
pub(crate) digits: usize,
}
impl<D: DataRef> fmt::Debug for GGSWCiphertext<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"(GGSWCiphertext: basek={} k={} digits={}) {}",
self.basek, self.k, self.digits, self.data
)
}
}
impl<D: DataMut> Reset for GGSWCiphertext<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.digits = 0;
}
}
impl<D: DataMut> FillUniform for GGSWCiphertext<D>
where
MatZnx<D>: FillUniform,
{
fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
self.data.fill_uniform(source);
}
}
impl<D: DataRef> GGSWCiphertext<D> {
pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
GLWECiphertext {
@@ -36,10 +68,7 @@ impl<D: DataMut> GGSWCiphertext<D> {
}
impl GGSWCiphertext<Vec<u8>> {
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
where
Module<B>: MatZnxAlloc,
{
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
@@ -59,17 +88,14 @@ impl GGSWCiphertext<Vec<u8>> {
);
Self {
data: module.mat_znx_alloc(rows, rank + 1, rank + 1, k.div_ceil(basek)),
data: MatZnx::alloc(n, rows, rank + 1, rank + 1, k.div_ceil(basek)),
basek,
k: k,
digits,
}
}
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
where
Module<B>: MatZnxAllocBytes,
{
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
@@ -86,7 +112,7 @@ impl GGSWCiphertext<Vec<u8>> {
size
);
module.mat_znx_alloc_bytes(rows, rank + 1, rank + 1, size)
MatZnx::alloc_bytes(n, rows, rank + 1, rank + 1, size)
}
}

View File

@@ -1,11 +1,13 @@
use backend::hal::{
api::{MatZnxAlloc, MatZnxAllocBytes, VecZnxCopy, VecZnxFillUniform},
api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
};
use crate::{Decompress, GGSWCiphertext, GLWECiphertextCompressed, Infos};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone)]
pub struct GGSWCiphertextCompressed<D: Data> {
pub(crate) data: MatZnx<D>,
pub(crate) basek: usize,
@@ -15,11 +17,41 @@ pub struct GGSWCiphertextCompressed<D: Data> {
pub(crate) seed: Vec<[u8; 32]>,
}
impl<D: DataRef> fmt::Debug for GGSWCiphertextCompressed<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"(GGSWCiphertextCompressed: basek={} k={} digits={}) {}",
self.basek, self.k, self.digits, self.data
)
}
}
impl<D: DataMut> Reset for GGSWCiphertextCompressed<D>
where
MatZnx<D>: Reset,
{
fn reset(&mut self) {
self.data.reset();
self.basek = 0;
self.k = 0;
self.digits = 0;
self.rank = 0;
self.seed = Vec::new();
}
}
impl<D: DataMut> FillUniform for GGSWCiphertextCompressed<D>
where
MatZnx<D>: FillUniform,
{
fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
self.data.fill_uniform(source);
}
}
impl GGSWCiphertextCompressed<Vec<u8>> {
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
where
Module<B>: MatZnxAlloc,
{
pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
@@ -39,19 +71,16 @@ impl GGSWCiphertextCompressed<Vec<u8>> {
);
Self {
data: module.mat_znx_alloc(rows, rank + 1, 1, k.div_ceil(basek)),
data: MatZnx::alloc(n, rows, rank + 1, 1, k.div_ceil(basek)),
basek,
k: k,
digits,
rank,
seed: vec![[0u8; 32]; rows * (rank + 1)],
seed: Vec::new(),
}
}
pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
where
Module<B>: MatZnxAllocBytes,
{
pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
@@ -68,7 +97,7 @@ impl GGSWCiphertextCompressed<Vec<u8>> {
size
);
module.mat_znx_alloc_bytes(rows, rank + 1, 1, size)
MatZnx::alloc_bytes(n, rows, rank + 1, 1, size)
}
}
@@ -125,12 +154,29 @@ impl<D: Data> GGSWCiphertextCompressed<D> {
impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> {
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
self.k = reader.read_u64::<LittleEndian>()? as usize;
self.basek = reader.read_u64::<LittleEndian>()? as usize;
self.digits = reader.read_u64::<LittleEndian>()? as usize;
self.rank = reader.read_u64::<LittleEndian>()? as usize;
let seed_len = reader.read_u64::<LittleEndian>()? as usize;
self.seed = vec![[0u8; 32]; seed_len];
for s in &mut self.seed {
reader.read_exact(s)?;
}
self.data.read_from(reader)
}
}
impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> {
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u64::<LittleEndian>(self.k as u64)?;
writer.write_u64::<LittleEndian>(self.basek as u64)?;
writer.write_u64::<LittleEndian>(self.digits as u64)?;
writer.write_u64::<LittleEndian>(self.rank as u64)?;
writer.write_u64::<LittleEndian>(self.seed.len() as u64)?;
for s in &self.seed {
writer.write_all(s)?;
}
self.data.write_to(writer)
}
}

View File

@@ -14,7 +14,7 @@ pub struct GGSWCiphertextExec<D: Data, B: Backend> {
}
impl<B: Backend> GGSWCiphertextExec<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
pub fn alloc(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
where
Module<B>: GGSWLayoutFamily<B>,
{
@@ -37,14 +37,14 @@ impl<B: Backend> GGSWCiphertextExec<Vec<u8>, B> {
);
Self {
data: module.vmp_pmat_alloc(rows, rank + 1, rank + 1, k.div_ceil(basek)),
data: module.vmp_pmat_alloc(n, rows, rank + 1, rank + 1, k.div_ceil(basek)),
basek,
k: k,
digits,
}
}
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
pub fn bytes_of(module: &Module<B>, n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
where
Module<B>: GGSWLayoutFamily<B>,
{
@@ -64,7 +64,7 @@ impl<B: Backend> GGSWCiphertextExec<Vec<u8>, B> {
size
);
module.vmp_pmat_alloc_bytes(rows, rank + 1, rank + 1, size)
module.vmp_pmat_alloc_bytes(n, rows, rank + 1, rank + 1, size)
}
pub fn from<DataOther: DataRef>(
@@ -77,6 +77,7 @@ impl<B: Backend> GGSWCiphertextExec<Vec<u8>, B> {
{
let mut ggsw_exec: GGSWCiphertextExec<Vec<u8>, B> = Self::alloc(
module,
other.n(),
other.basek(),
other.k(),
other.rows(),

View File

@@ -1,6 +1,6 @@
use backend::hal::{
api::{
ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigNormalize,
ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxBigAlloc, VecZnxBigNormalize,
VecZnxBigNormalizeTmpBytes, VecZnxDftAlloc, VecZnxDftToVecZnxBigTmpA, VecZnxNormalizeTmpBytes, VecZnxStd,
VecZnxSubABInplace, ZnxZero,
},
@@ -27,7 +27,7 @@ impl<D: DataRef> GGSWCiphertext<D> {
) where
DataSk: DataRef,
DataScalar: DataRef,
Module<B>: GGSWAssertNoiseFamily<B> + VecZnxAlloc + VecZnxAddScalarInplace + VecZnxSubABInplace + VecZnxStd,
Module<B>: GGSWAssertNoiseFamily<B> + VecZnxAddScalarInplace + VecZnxSubABInplace + VecZnxStd,
B: TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
F: Fn(usize) -> f64,
{
@@ -35,13 +35,13 @@ impl<D: DataRef> GGSWCiphertext<D> {
let k: usize = self.k();
let digits: usize = self.digits();
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k);
let mut pt_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(1, self.size());
let mut pt_big: VecZnxBig<Vec<u8>, B> = module.vec_znx_big_alloc(1, self.size());
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self.n(), basek, k);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self.n(), basek, k);
let mut pt_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(self.n(), 1, self.size());
let mut pt_big: VecZnxBig<Vec<u8>, B> = module.vec_znx_big_alloc(self.n(), 1, self.size());
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GLWECiphertext::decrypt_scratch_space(module, basek, k) | module.vec_znx_normalize_tmp_bytes(module.n()),
GLWECiphertext::decrypt_scratch_space(module, self.n(), basek, k) | module.vec_znx_normalize_tmp_bytes(self.n()),
);
(0..self.rank() + 1).for_each(|col_j| {

View File

@@ -0,0 +1,15 @@
use backend::hal::tests::serialization::test_reader_writer_interface;
use crate::{GGSWCiphertext, GGSWCiphertextCompressed};
#[test]
fn ggsw_test_serialization() {
let original: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(1024, 12, 54, 3, 1, 2);
test_reader_writer_interface(original);
}
#[test]
fn ggsw_test_serialization_compressed() {
let original: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc(1024, 12, 54, 3, 1, 2);
test_reader_writer_interface(original);
}

View File

@@ -1,8 +1,7 @@
use backend::hal::{
api::{
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxCopy, VecZnxRotateInplace, VecZnxStd,
VecZnxSubABInplace, VecZnxSwithcDegree, ZnxViewMut,
ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxCopy,
VecZnxRotateInplace, VecZnxStd, VecZnxSubABInplace, VecZnxSwithcDegree, ZnxViewMut,
},
layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned},
oep::{
@@ -23,14 +22,9 @@ use crate::{
pub(crate) trait TestModuleFamily<B: Backend> = GLWESecretFamily<B>
+ GGSWEncryptSkFamily<B>
+ GGSWAssertNoiseFamily<B>
+ VecZnxAlloc
+ ScalarZnxAlloc
+ VecZnxAllocBytes
+ MatZnxAlloc
+ VecZnxAddScalarInplace
+ VecZnxSubABInplace
+ VecZnxStd
+ ScalarZnxAllocBytes
+ VecZnxCopy;
pub(crate) trait TestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
+ TakeVecZnxBigImpl<B>
@@ -49,23 +43,24 @@ where
Module<B>: TestModuleFamily<B>,
B: TestScratchFamily<B>,
{
let n: usize = module.n();
let rows: usize = (k - digits * basek) / (digits * basek);
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k, rows, digits, rank);
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k, rows, digits, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGSWCiphertext::encrypt_sk_scratch_space(
module, basek, k, rank,
module, n, basek, k, rank,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
sk_exec.prepare(module, &sk);
@@ -96,23 +91,23 @@ pub(crate) fn test_encrypt_sk_compressed<B: Backend>(
Module<B>: TestModuleFamily<B>,
B: TestScratchFamily<B>,
{
let n: usize = module.n();
let rows: usize = (k - digits * basek) / (digits * basek);
let mut ct_compressed: GGSWCiphertextCompressed<Vec<u8>> =
GGSWCiphertextCompressed::alloc(module, basek, k, rows, digits, rank);
let mut ct_compressed: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc(n, basek, k, rows, digits, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGSWCiphertextCompressed::encrypt_sk_scratch_space(
module, basek, k, rank,
module, n, basek, k, rank,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
sk_exec.prepare(module, &sk);
@@ -131,7 +126,7 @@ pub(crate) fn test_encrypt_sk_compressed<B: Backend>(
let noise_f = |_col_i: usize| -(k as f64) + sigma.log2() + 0.5;
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k, rows, digits, rank);
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k, rows, digits, rank);
ct.decompress(module, &ct_compressed);
ct.assert_noise(module, &sk_exec, &pt_scalar, &noise_f);
@@ -157,36 +152,37 @@ pub(crate) fn test_keyswitch<B: Backend>(
+ VecZnxSwithcDegree,
B: TestScratchFamily<B> + VecZnxDftAllocBytesImpl<B> + VecZnxBigAllocBytesImpl<B> + TakeSvpPPolImpl<B>,
{
let n: usize = module.n();
let rows: usize = k_in.div_ceil(digits * basek);
let digits_in: usize = 1;
let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_in, rows, digits_in, rank);
let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_out, rows, digits_in, rank);
let mut tsk: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(module, basek, k_ksk, rows, digits, rank);
let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(module, basek, k_ksk, rows, digits, rank, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_in, rows, digits_in, rank);
let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_out, rows, digits_in, rank);
let mut tsk: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(n, basek, k_ksk, rows, digits, rank);
let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(n, basek, k_ksk, rows, digits, rank, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_in, rank)
| GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k_in, rank)
| GLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k_ksk, rank, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, n, basek, k_tsk, rank)
| GGSWCiphertext::keyswitch_scratch_space(
module, basek, k_out, k_in, k_ksk, digits, k_tsk, digits, rank,
module, n, basek, k_out, k_in, k_ksk, digits, k_tsk, digits, rank,
),
);
let var_xs: f64 = 0.5;
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk_in.fill_ternary_prob(var_xs, &mut source_xs);
let sk_in_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_in);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk_out.fill_ternary_prob(var_xs, &mut source_xs);
let sk_out_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_out);
@@ -208,7 +204,7 @@ pub(crate) fn test_keyswitch<B: Backend>(
scratch.borrow(),
);
pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
ct_in.encrypt_sk(
module,
@@ -221,8 +217,8 @@ pub(crate) fn test_keyswitch<B: Backend>(
);
let mut ksk_exec: GLWESwitchingKeyExec<Vec<u8>, B> =
GLWESwitchingKeyExec::alloc(module, basek, k_ksk, rows, digits, rank, rank);
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, basek, k_ksk, rows, digits, rank);
GLWESwitchingKeyExec::alloc(module, n, basek, k_ksk, rows, digits, rank, rank);
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, n, basek, k_ksk, rows, digits, rank);
ksk_exec.prepare(module, &ksk, scratch.borrow());
tsk_exec.prepare(module, &tsk, scratch.borrow());
@@ -231,7 +227,7 @@ pub(crate) fn test_keyswitch<B: Backend>(
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
module.n() as f64,
n as f64,
basek * digits,
col_j,
var_xs,
@@ -267,33 +263,34 @@ pub(crate) fn test_keyswitch_inplace<B: Backend>(
+ VecZnxSwithcDegree,
B: TestScratchFamily<B>,
{
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(digits * basek);
let digits_in: usize = 1;
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_ct, rows, digits_in, rank);
let mut tsk: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(module, basek, k_tsk, rows, digits, rank);
let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(module, basek, k_ksk, rows, digits, rank, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ct, rows, digits_in, rank);
let mut tsk: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(n, basek, k_tsk, rows, digits, rank);
let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(n, basek, k_ksk, rows, digits, rank, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ct, rank)
| GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
| GGSWCiphertext::keyswitch_inplace_scratch_space(module, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k_ct, rank)
| GLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k_ksk, rank, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, n, basek, k_tsk, rank)
| GGSWCiphertext::keyswitch_inplace_scratch_space(module, n, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),
);
let var_xs: f64 = 0.5;
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk_in.fill_ternary_prob(var_xs, &mut source_xs);
let sk_in_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_in);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk_out.fill_ternary_prob(var_xs, &mut source_xs);
let sk_out_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_out);
@@ -315,7 +312,7 @@ pub(crate) fn test_keyswitch_inplace<B: Backend>(
scratch.borrow(),
);
pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
ct.encrypt_sk(
module,
@@ -328,8 +325,8 @@ pub(crate) fn test_keyswitch_inplace<B: Backend>(
);
let mut ksk_exec: GLWESwitchingKeyExec<Vec<u8>, B> =
GLWESwitchingKeyExec::alloc(module, basek, k_ksk, rows, digits, rank, rank);
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, basek, k_ksk, rows, digits, rank);
GLWESwitchingKeyExec::alloc(module, n, basek, k_ksk, rows, digits, rank, rank);
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, n, basek, k_ksk, rows, digits, rank);
ksk_exec.prepare(module, &ksk, scratch.borrow());
tsk_exec.prepare(module, &tsk, scratch.borrow());
@@ -338,7 +335,7 @@ pub(crate) fn test_keyswitch_inplace<B: Backend>(
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
module.n() as f64,
n as f64,
basek * digits,
col_j,
var_xs,
@@ -379,33 +376,34 @@ pub(crate) fn test_automorphism<B: Backend>(
+ VecZnxAutomorphism,
B: TestScratchFamily<B>,
{
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * digits);
let rows_in: usize = k_in.div_euclid(basek * digits);
let digits_in: usize = 1;
let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_in, rows_in, digits_in, rank);
let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_out, rows_in, digits_in, rank);
let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(module, basek, k_tsk, rows, digits, rank);
let mut auto_key: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_ksk, rows, digits, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_in, rows_in, digits_in, rank);
let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_out, rows_in, digits_in, rank);
let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(n, basek, k_tsk, rows, digits, rank);
let mut auto_key: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_in, rank)
| AutomorphismKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k_in, rank)
| AutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_ksk, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, n, basek, k_tsk, rank)
| GGSWCiphertext::automorphism_scratch_space(
module, basek, k_out, k_in, k_ksk, digits, k_tsk, digits, rank,
module, n, basek, k_out, k_in, k_ksk, digits, k_tsk, digits, rank,
),
);
let var_xs: f64 = 0.5;
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk.fill_ternary_prob(var_xs, &mut source_xs);
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
@@ -427,7 +425,7 @@ pub(crate) fn test_automorphism<B: Backend>(
scratch.borrow(),
);
pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
ct_in.encrypt_sk(
module,
@@ -439,10 +437,11 @@ pub(crate) fn test_automorphism<B: Backend>(
scratch.borrow(),
);
let mut auto_key_exec: AutomorphismKeyExec<Vec<u8>, B> = AutomorphismKeyExec::alloc(module, basek, k_ksk, rows, digits, rank);
let mut auto_key_exec: AutomorphismKeyExec<Vec<u8>, B> =
AutomorphismKeyExec::alloc(module, n, basek, k_ksk, rows, digits, rank);
auto_key_exec.prepare(module, &auto_key, scratch.borrow());
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, basek, k_tsk, rows, digits, rank);
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, n, basek, k_tsk, rows, digits, rank);
tsk_exec.prepare(module, &tensor_key, scratch.borrow());
ct_out.automorphism(module, &ct_in, &auto_key_exec, &tsk_exec, scratch.borrow());
@@ -451,7 +450,7 @@ pub(crate) fn test_automorphism<B: Backend>(
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
module.n() as f64,
n as f64,
basek * digits,
col_j,
var_xs,
@@ -491,29 +490,30 @@ pub(crate) fn test_automorphism_inplace<B: Backend>(
+ VecZnxAutomorphismInplace,
B: TestScratchFamily<B>,
{
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(digits * basek);
let rows_in: usize = k_ct.div_euclid(basek * digits);
let digits_in: usize = 1;
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_ct, rows_in, digits_in, rank);
let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(module, basek, k_tsk, rows, digits, rank);
let mut auto_key: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_ksk, rows, digits, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ct, rows_in, digits_in, rank);
let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(n, basek, k_tsk, rows, digits, rank);
let mut auto_key: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ct, rank)
| AutomorphismKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
| GGSWCiphertext::automorphism_inplace_scratch_space(module, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k_ct, rank)
| AutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_ksk, rank)
| GLWETensorKey::encrypt_sk_scratch_space(module, n, basek, k_tsk, rank)
| GGSWCiphertext::automorphism_inplace_scratch_space(module, n, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),
);
let var_xs: f64 = 0.5;
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk.fill_ternary_prob(var_xs, &mut source_xs);
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
@@ -535,7 +535,7 @@ pub(crate) fn test_automorphism_inplace<B: Backend>(
scratch.borrow(),
);
pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
ct.encrypt_sk(
module,
@@ -547,10 +547,11 @@ pub(crate) fn test_automorphism_inplace<B: Backend>(
scratch.borrow(),
);
let mut auto_key_exec: AutomorphismKeyExec<Vec<u8>, B> = AutomorphismKeyExec::alloc(module, basek, k_ksk, rows, digits, rank);
let mut auto_key_exec: AutomorphismKeyExec<Vec<u8>, B> =
AutomorphismKeyExec::alloc(module, n, basek, k_ksk, rows, digits, rank);
auto_key_exec.prepare(module, &auto_key, scratch.borrow());
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, basek, k_tsk, rows, digits, rank);
let mut tsk_exec: GLWETensorKeyExec<Vec<u8>, B> = GLWETensorKeyExec::alloc(module, n, basek, k_tsk, rows, digits, rank);
tsk_exec.prepare(module, &tensor_key, scratch.borrow());
ct.automorphism_inplace(module, &auto_key_exec, &tsk_exec, scratch.borrow());
@@ -559,7 +560,7 @@ pub(crate) fn test_automorphism_inplace<B: Backend>(
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
module.n() as f64,
n as f64,
basek * digits,
col_j,
var_xs,
@@ -595,15 +596,16 @@ pub(crate) fn test_external_product<B: Backend>(
+ VecZnxRotateInplace,
B: TestScratchFamily<B>,
{
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * digits);
let rows_in: usize = k_in.div_euclid(basek * digits);
let digits_in: usize = 1;
let mut ct_ggsw_lhs_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_in, rows_in, digits_in, rank);
let mut ct_ggsw_lhs_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_out, rows_in, digits_in, rank);
let mut ct_ggsw_rhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_ggsw, rows, digits, rank);
let mut pt_ggsw_lhs: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut pt_ggsw_rhs: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut ct_ggsw_lhs_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_in, rows_in, digits_in, rank);
let mut ct_ggsw_lhs_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_out, rows_in, digits_in, rank);
let mut ct_ggsw_rhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, digits, rank);
let mut pt_ggsw_lhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_ggsw_rhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
@@ -616,11 +618,11 @@ pub(crate) fn test_external_product<B: Backend>(
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ggsw, rank)
| GGSWCiphertext::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k_ggsw, rank)
| GGSWCiphertext::external_product_scratch_space(module, n, basek, k_out, k_in, k_ggsw, digits, rank),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
@@ -644,7 +646,7 @@ pub(crate) fn test_external_product<B: Backend>(
scratch.borrow(),
);
let mut ct_rhs_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::alloc(module, basek, k_ggsw, rows, digits, rank);
let mut ct_rhs_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::alloc(module, n, basek, k_ggsw, rows, digits, rank);
ct_rhs_exec.prepare(module, &ct_ggsw_rhs, scratch.borrow());
ct_ggsw_lhs_out.external_product(module, &ct_ggsw_lhs_in, &ct_rhs_exec, scratch.borrow());
@@ -654,13 +656,13 @@ pub(crate) fn test_external_product<B: Backend>(
let var_gct_err_lhs: f64 = sigma * sigma;
let var_gct_err_rhs: f64 = 0f64;
let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
let var_msg: f64 = 1f64 / n as f64; // X^{k}
let var_a0_err: f64 = sigma * sigma;
let var_a1_err: f64 = 1f64 / 12f64;
let max_noise = |_col_j: usize| -> f64 {
noise_ggsw_product(
module.n() as f64,
n as f64,
basek * digits,
0.5,
var_msg,
@@ -695,15 +697,16 @@ pub(crate) fn test_external_product_inplace<B: Backend>(
+ VecZnxRotateInplace,
B: TestScratchFamily<B>,
{
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(digits * basek);
let rows_in: usize = k_ct.div_euclid(basek * digits);
let digits_in: usize = 1;
let mut ct_ggsw_lhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_ct, rows_in, digits_in, rank);
let mut ct_ggsw_rhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_ggsw, rows, digits, rank);
let mut ct_ggsw_lhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ct, rows_in, digits_in, rank);
let mut ct_ggsw_rhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, digits, rank);
let mut pt_ggsw_lhs: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut pt_ggsw_rhs: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
let mut pt_ggsw_lhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_ggsw_rhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
@@ -716,11 +719,11 @@ pub(crate) fn test_external_product_inplace<B: Backend>(
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ggsw, rank)
| GGSWCiphertext::external_product_inplace_scratch_space(module, basek, k_ct, k_ggsw, digits, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k_ggsw, rank)
| GGSWCiphertext::external_product_inplace_scratch_space(module, n, basek, k_ct, k_ggsw, digits, rank),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
@@ -744,7 +747,7 @@ pub(crate) fn test_external_product_inplace<B: Backend>(
scratch.borrow(),
);
let mut ct_rhs_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::alloc(module, basek, k_ggsw, rows, digits, rank);
let mut ct_rhs_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::alloc(module, n, basek, k_ggsw, rows, digits, rank);
ct_rhs_exec.prepare(module, &ct_ggsw_rhs, scratch.borrow());
ct_ggsw_lhs.external_product_inplace(module, &ct_rhs_exec, scratch.borrow());
@@ -754,13 +757,13 @@ pub(crate) fn test_external_product_inplace<B: Backend>(
let var_gct_err_lhs: f64 = sigma * sigma;
let var_gct_err_rhs: f64 = 0f64;
let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
let var_msg: f64 = 1f64 / n as f64; // X^{k}
let var_a0_err: f64 = sigma * sigma;
let var_a1_err: f64 = 1f64 / 12f64;
let max_noise = |_col_j: usize| -> f64 {
noise_ggsw_product(
module.n() as f64,
n as f64,
basek * digits,
0.5,
var_msg,

View File

@@ -1,2 +1,3 @@
mod cpu_spqlios;
mod generic_serialization;
mod generic_tests;