mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 13:16:44 +01:00
core refactoring (#69)
This commit is contained in:
committed by
GitHub
parent
6303346eef
commit
8d9897b88b
39
bin_fhe/blind_rotation/tests/cpu_spqlios/fft64.rs
Normal file
39
bin_fhe/blind_rotation/tests/cpu_spqlios/fft64.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use backend::{
|
||||
hal::{api::ModuleNew, layouts::Module},
|
||||
implementation::cpu_spqlios::FFT64,
|
||||
};
|
||||
|
||||
use crate::blind_rotation::tests::{
|
||||
generic_cggi::blind_rotatio_test,
|
||||
generic_lut::{test_lut_extended, test_lut_standard},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn lut_standard() {
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(32);
|
||||
test_lut_standard(&module);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lut_extended() {
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(32);
|
||||
test_lut_extended(&module);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn standard() {
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(512);
|
||||
blind_rotatio_test(&module, 224, 1, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_binary() {
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(512);
|
||||
blind_rotatio_test(&module, 224, 7, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_binary_extended() {
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(512);
|
||||
blind_rotatio_test(&module, 224, 7, 2);
|
||||
}
|
||||
1
bin_fhe/blind_rotation/tests/cpu_spqlios/mod.rs
Normal file
1
bin_fhe/blind_rotation/tests/cpu_spqlios/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
mod fft64;
|
||||
163
bin_fhe/blind_rotation/tests/generic_cggi.rs
Normal file
163
bin_fhe/blind_rotation/tests/generic_cggi.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use backend::hal::{
|
||||
api::{
|
||||
ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxEncodeCoeffsi64, VecZnxFillUniform,
|
||||
VecZnxRotateInplace, VecZnxSub, VecZnxSwithcDegree, VmpPMatAlloc, VmpPMatPrepare, ZnxView,
|
||||
},
|
||||
layouts::{Backend, Module, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl,
|
||||
TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
BlindRotationKeyCGGI, BlindRotationKeyCGGIExec, BlindRotationKeyCGGIExecLayoutFamily, CCGIBlindRotationFamily, Infos,
|
||||
LookUpTable, cggi_blind_rotate, cggi_blind_rotate_scratch_space,
|
||||
layouts::{
|
||||
GLWECiphertext, GLWEPlaintext, GLWESecret, LWECiphertext, LWECiphertextToRef, LWEPlaintext, LWESecret,
|
||||
prepared::GLWESecretExec,
|
||||
},
|
||||
mod_switch_2n,
|
||||
};
|
||||
|
||||
use crate::trait_families::{GLWEDecryptFamily, GLWESecretExecModuleFamily};
|
||||
|
||||
pub(crate) trait CGGITestModuleFamily<B: Backend> = CCGIBlindRotationFamily<B>
|
||||
+ GLWESecretExecModuleFamily<B>
|
||||
+ GLWEDecryptFamily<B>
|
||||
+ BlindRotationKeyCGGIExecLayoutFamily<B>
|
||||
+ VecZnxFillUniform
|
||||
+ VecZnxAddNormal
|
||||
+ VecZnxAddScalarInplace
|
||||
+ VecZnxEncodeCoeffsi64
|
||||
+ VecZnxRotateInplace
|
||||
+ VecZnxSwithcDegree
|
||||
+ VecZnxSub
|
||||
+ VmpPMatAlloc<B>
|
||||
+ VmpPMatPrepare<B>;
|
||||
pub(crate) trait CGGITestScratchFamily<B: Backend> = VecZnxDftAllocBytesImpl<B>
|
||||
+ VecZnxBigAllocBytesImpl<B>
|
||||
+ ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>
|
||||
+ TakeVecZnxDftSliceImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeVecZnxImpl<B>
|
||||
+ TakeVecZnxSliceImpl<B>;
|
||||
|
||||
pub(crate) fn blind_rotatio_test<B: Backend>(module: &Module<B>, n_lwe: usize, block_size: usize, extension_factor: usize)
|
||||
where
|
||||
Module<B>: CGGITestModuleFamily<B>,
|
||||
B: CGGITestScratchFamily<B>,
|
||||
{
|
||||
let n: usize = module.n();
|
||||
let basek: usize = 19;
|
||||
let k_lwe: usize = 24;
|
||||
let k_brk: usize = 3 * basek;
|
||||
let rows_brk: usize = 2; // Ensures first limb is noise-free.
|
||||
let k_lut: usize = 1 * basek;
|
||||
let k_res: usize = 2 * basek;
|
||||
let rank: usize = 1;
|
||||
|
||||
let message_modulus: usize = 1 << 4;
|
||||
|
||||
let mut source_xs: Source = Source::new([2u8; 32]);
|
||||
let mut source_xe: Source = Source::new([2u8; 32]);
|
||||
let mut source_xa: Source = Source::new([1u8; 32]);
|
||||
|
||||
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
|
||||
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_glwe_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_glwe);
|
||||
|
||||
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
|
||||
sk_lwe.fill_binary_block(block_size, &mut source_xs);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::<B>::alloc(BlindRotationKeyCGGI::generate_from_sk_scratch_space(
|
||||
module, n, basek, k_brk, rank,
|
||||
));
|
||||
|
||||
let mut scratch_br: ScratchOwned<B> = ScratchOwned::<B>::alloc(cggi_blind_rotate_scratch_space(
|
||||
module,
|
||||
n,
|
||||
block_size,
|
||||
extension_factor,
|
||||
basek,
|
||||
k_res,
|
||||
k_brk,
|
||||
rows_brk,
|
||||
rank,
|
||||
));
|
||||
|
||||
let mut brk: BlindRotationKeyCGGI<Vec<u8>> = BlindRotationKeyCGGI::alloc(n, n_lwe, basek, k_brk, rows_brk, rank);
|
||||
|
||||
brk.generate_from_sk(
|
||||
module,
|
||||
&sk_glwe_dft,
|
||||
&sk_lwe,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
3.2,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe);
|
||||
|
||||
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe);
|
||||
|
||||
let x: i64 = 2;
|
||||
let bits: usize = 8;
|
||||
|
||||
module.encode_coeff_i64(basek, &mut pt_lwe.data, 0, bits, 0, x, bits);
|
||||
|
||||
lwe.encrypt_sk(
|
||||
module,
|
||||
&pt_lwe,
|
||||
&sk_lwe,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
3.2,
|
||||
);
|
||||
|
||||
let mut f: Vec<i64> = vec![0i64; message_modulus];
|
||||
f.iter_mut()
|
||||
.enumerate()
|
||||
.for_each(|(i, x)| *x = 2 * (i as i64) + 1);
|
||||
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(n, basek, k_lut, extension_factor);
|
||||
lut.set(module, &f, message_modulus);
|
||||
|
||||
let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_res, rank);
|
||||
|
||||
let brk_exec: BlindRotationKeyCGGIExec<Vec<u8>, B> = BlindRotationKeyCGGIExec::from(module, &brk, scratch_br.borrow());
|
||||
|
||||
cggi_blind_rotate(module, &mut res, &lwe, &lut, &brk_exec, scratch_br.borrow());
|
||||
|
||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_res);
|
||||
|
||||
res.decrypt(module, &mut pt_have, &sk_glwe_dft, scratch.borrow());
|
||||
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; lwe.n() + 1]; // TODO: from scratch space
|
||||
|
||||
mod_switch_2n(
|
||||
2 * lut.domain_size(),
|
||||
&mut lwe_2n,
|
||||
&lwe.to_ref(),
|
||||
lut.rotation_direction(),
|
||||
);
|
||||
|
||||
let pt_want: i64 = (lwe_2n[0]
|
||||
+ lwe_2n[1..]
|
||||
.iter()
|
||||
.zip(sk_lwe.data.at(0, 0))
|
||||
.map(|(x, y)| x * y)
|
||||
.sum::<i64>())
|
||||
& (2 * lut.domain_size() - 1) as i64;
|
||||
|
||||
lut.rotate(module, pt_want);
|
||||
|
||||
// First limb should be exactly equal (test are parameterized such that the noise does not reach
|
||||
// the first limb)
|
||||
assert_eq!(pt_have.data.at(0, 0), lut.data[0].at(0, 0));
|
||||
}
|
||||
95
bin_fhe/blind_rotation/tests/generic_lut.rs
Normal file
95
bin_fhe/blind_rotation/tests/generic_lut.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use std::vec;
|
||||
|
||||
use backend::hal::{
|
||||
api::{
|
||||
VecZnxCopy, VecZnxDecodeVeci64, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSwithcDegree,
|
||||
},
|
||||
layouts::{Backend, Module},
|
||||
oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl},
|
||||
};
|
||||
|
||||
use crate::{DivRound, LookUpTable};
|
||||
|
||||
pub(crate) fn test_lut_standard<B: Backend>(module: &Module<B>)
|
||||
where
|
||||
Module<B>: VecZnxRotateInplace
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
+ VecZnxSwithcDegree
|
||||
+ VecZnxCopy
|
||||
+ VecZnxDecodeVeci64,
|
||||
B: ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
|
||||
{
|
||||
let n: usize = module.n();
|
||||
let basek: usize = 20;
|
||||
let k_lut: usize = 40;
|
||||
let message_modulus: usize = 16;
|
||||
let extension_factor: usize = 1;
|
||||
|
||||
let log_scale: usize = basek + 1;
|
||||
|
||||
let mut f: Vec<i64> = vec![0i64; message_modulus];
|
||||
f.iter_mut()
|
||||
.enumerate()
|
||||
.for_each(|(i, x)| *x = (i as i64) - 8);
|
||||
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(n, basek, k_lut, extension_factor);
|
||||
lut.set(module, &f, log_scale);
|
||||
|
||||
let half_step: i64 = lut.domain_size().div_round(message_modulus << 1) as i64;
|
||||
lut.rotate(module, half_step);
|
||||
|
||||
let step: usize = lut.domain_size().div_round(message_modulus);
|
||||
|
||||
let mut lut_dec: Vec<i64> = vec![0i64; module.n()];
|
||||
module.decode_vec_i64(basek, &lut.data[0], 0, log_scale, &mut lut_dec);
|
||||
|
||||
(0..lut.domain_size()).step_by(step).for_each(|i| {
|
||||
(0..step).for_each(|_| {
|
||||
assert_eq!(f[i / step] % message_modulus as i64, lut_dec[i]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn test_lut_extended<B: Backend>(module: &Module<B>)
|
||||
where
|
||||
Module<B>: VecZnxRotateInplace
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
+ VecZnxSwithcDegree
|
||||
+ VecZnxCopy
|
||||
+ VecZnxDecodeVeci64,
|
||||
B: ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
|
||||
{
|
||||
let n: usize = module.n();
|
||||
let basek: usize = 20;
|
||||
let k_lut: usize = 40;
|
||||
let message_modulus: usize = 16;
|
||||
let extension_factor: usize = 4;
|
||||
|
||||
let log_scale: usize = basek + 1;
|
||||
|
||||
let mut f: Vec<i64> = vec![0i64; message_modulus];
|
||||
f.iter_mut()
|
||||
.enumerate()
|
||||
.for_each(|(i, x)| *x = (i as i64) - 8);
|
||||
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(n, basek, k_lut, extension_factor);
|
||||
lut.set(&module, &f, log_scale);
|
||||
|
||||
let half_step: i64 = lut.domain_size().div_round(message_modulus << 1) as i64;
|
||||
lut.rotate(&module, half_step);
|
||||
|
||||
let step: usize = module.n().div_round(message_modulus);
|
||||
|
||||
let mut lut_dec: Vec<i64> = vec![0i64; module.n()];
|
||||
|
||||
(0..extension_factor).for_each(|ext| {
|
||||
module.decode_vec_i64(basek, &lut.data[ext], 0, log_scale, &mut lut_dec);
|
||||
(0..module.n()).step_by(step).for_each(|i| {
|
||||
(0..step).for_each(|_| {
|
||||
assert_eq!(f[i / step] % message_modulus as i64, lut_dec[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
15
bin_fhe/blind_rotation/tests/generic_serialization.rs
Normal file
15
bin_fhe/blind_rotation/tests/generic_serialization.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use backend::hal::tests::serialization::test_reader_writer_interface;
|
||||
|
||||
use crate::{BlindRotationKeyCGGI, BlindRotationKeyCGGICompressed};
|
||||
|
||||
#[test]
|
||||
fn test_cggi_blind_rotation_key_serialization() {
|
||||
let original: BlindRotationKeyCGGI<Vec<u8>> = BlindRotationKeyCGGI::alloc(256, 64, 12, 54, 2, 2);
|
||||
test_reader_writer_interface(original);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cggi_blind_rotation_key_compressed_serialization() {
|
||||
let original: BlindRotationKeyCGGICompressed<Vec<u8>> = BlindRotationKeyCGGICompressed::alloc(256, 64, 12, 54, 2, 2);
|
||||
test_reader_writer_interface(original);
|
||||
}
|
||||
396
bin_fhe/blind_rotation/tests/generics_automorphism_key.rs
Normal file
396
bin_fhe/blind_rotation/tests/generics_automorphism_key.rs
Normal file
@@ -0,0 +1,396 @@
|
||||
use backend::hal::{
|
||||
api::{
|
||||
ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxCopy,
|
||||
VecZnxStd, VecZnxSubScalarInplace, VecZnxSwithcDegree,
|
||||
},
|
||||
layouts::{Backend, Module, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
AutomorphismKey, AutomorphismKeyCompressed, AutomorphismKeyEncryptSkFamily, AutomorphismKeyExec, GGLWEExecLayoutFamily,
|
||||
GLWEDecryptFamily, GLWEKeyswitchFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, Infos,
|
||||
noise::log2_std_noise_gglwe_product,
|
||||
};
|
||||
|
||||
pub(crate) trait AutomorphismTestModuleFamily<B: Backend> = AutomorphismKeyEncryptSkFamily<B>
|
||||
+ GLWEKeyswitchFamily<B>
|
||||
+ VecZnxAutomorphism
|
||||
+ GGLWEExecLayoutFamily<B>
|
||||
+ VecZnxSwithcDegree
|
||||
+ VecZnxAddScalarInplace
|
||||
+ VecZnxAutomorphism
|
||||
+ VecZnxAutomorphismInplace
|
||||
+ GLWEDecryptFamily<B>
|
||||
+ VecZnxSubScalarInplace
|
||||
+ VecZnxStd
|
||||
+ VecZnxCopy;
|
||||
pub(crate) trait AutomorphismTestScratchFamily<B: Backend> = ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeScalarZnxImpl<B>
|
||||
+ TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxImpl<B>
|
||||
+ TakeSvpPPolImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>;
|
||||
|
||||
pub(crate) fn test_automorphisk_key_encrypt_sk<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k_ksk: usize,
|
||||
digits: usize,
|
||||
rank: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||
B: AutomorphismTestScratchFamily<B>,
|
||||
{
|
||||
let n: usize = TakeScalarZnx;
|
||||
let rows: usize = (k_ksk - digits * basek) / (digits * basek);
|
||||
|
||||
let mut atk: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
|
||||
|
||||
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(AutomorphismKey::encrypt_sk_scratch_space(
|
||||
module, n, basek, k_ksk, rank,
|
||||
));
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
|
||||
let p = -5;
|
||||
|
||||
atk.encrypt_sk(
|
||||
module,
|
||||
p,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut sk_out: GLWESecret<Vec<u8>> = sk.clone();
|
||||
(0..atk.rank()).for_each(|i| {
|
||||
module.vec_znx_automorphism(
|
||||
module.galois_element_inv(p),
|
||||
&mut sk_out.data.as_vec_znx_mut(),
|
||||
i,
|
||||
&sk.data.as_vec_znx(),
|
||||
i,
|
||||
);
|
||||
});
|
||||
let sk_out_exec = GLWESecretExec::from(module, &sk_out);
|
||||
|
||||
atk.key
|
||||
.key
|
||||
.assert_noise(module, &sk_out_exec, &sk.data, sigma);
|
||||
}
|
||||
|
||||
pub(crate) fn test_automorphisk_key_encrypt_sk_compressed<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k_ksk: usize,
|
||||
digits: usize,
|
||||
rank: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||
B: AutomorphismTestScratchFamily<B>,
|
||||
{
|
||||
let n: usize = TakeScalarZnx;
|
||||
let rows: usize = (k_ksk - digits * basek) / (digits * basek);
|
||||
|
||||
let mut atk_compressed: AutomorphismKeyCompressed<Vec<u8>> =
|
||||
AutomorphismKeyCompressed::alloc(n, basek, k_ksk, rows, digits, rank);
|
||||
|
||||
let mut source_xs: Source = Source::new([0u8; 32]);
|
||||
let mut source_xe: Source = Source::new([0u8; 32]);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(AutomorphismKey::encrypt_sk_scratch_space(
|
||||
module, n, basek, k_ksk, rank,
|
||||
));
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
|
||||
let p = -5;
|
||||
|
||||
let seed_xa: [u8; 32] = [1u8; 32];
|
||||
|
||||
atk_compressed.encrypt_sk(
|
||||
module,
|
||||
p,
|
||||
&sk,
|
||||
seed_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut sk_out: GLWESecret<Vec<u8>> = sk.clone();
|
||||
(0..atk_compressed.rank()).for_each(|i| {
|
||||
module.vec_znx_automorphism(
|
||||
module.galois_element_inv(p),
|
||||
&mut sk_out.data.as_vec_znx_mut(),
|
||||
i,
|
||||
&sk.data.as_vec_znx(),
|
||||
i,
|
||||
);
|
||||
});
|
||||
let sk_out_exec = GLWESecretExec::from(module, &sk_out);
|
||||
|
||||
let mut atk: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
|
||||
atk.decompress(module, &atk_compressed);
|
||||
|
||||
atk.key
|
||||
.key
|
||||
.assert_noise(module, &sk_out_exec, &sk.data, sigma);
|
||||
}
|
||||
|
||||
pub(crate) fn test_gglwe_automorphism<B: Backend>(
|
||||
module: &Module<B>,
|
||||
p0: i64,
|
||||
p1: i64,
|
||||
basek: usize,
|
||||
digits: usize,
|
||||
k_in: usize,
|
||||
k_out: usize,
|
||||
k_apply: usize,
|
||||
sigma: f64,
|
||||
rank: usize,
|
||||
) where
|
||||
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||
B: AutomorphismTestScratchFamily<B>,
|
||||
{
|
||||
let n: usize = TakeScalarZnx;
|
||||
let digits_in: usize = 1;
|
||||
|
||||
let rows_in: usize = k_in / (basek * digits);
|
||||
let rows_apply: usize = k_in.div_ceil(basek * digits);
|
||||
|
||||
let mut auto_key_in: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_in, rows_in, digits_in, rank);
|
||||
let mut auto_key_out: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_out, rows_in, digits_in, rank);
|
||||
let mut auto_key_apply: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_apply, rows_apply, digits, rank);
|
||||
|
||||
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(
|
||||
AutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_apply, rank)
|
||||
| AutomorphismKey::automorphism_scratch_space(module, n, basek, k_out, k_in, k_apply, digits, rank),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(TakeScalarZnx, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
|
||||
// gglwe_{s1}(s0) = s0 -> s1
|
||||
auto_key_in.encrypt_sk(
|
||||
module,
|
||||
p0,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
// gglwe_{s2}(s1) -> s1 -> s2
|
||||
auto_key_apply.encrypt_sk(
|
||||
module,
|
||||
p1,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut auto_key_apply_exec: AutomorphismKeyExec<Vec<u8>, B> =
|
||||
AutomorphismKeyExec::alloc(module, n, basek, k_apply, rows_apply, digits, rank);
|
||||
|
||||
auto_key_apply_exec.prepare(module, &auto_key_apply, scratch.borrow());
|
||||
|
||||
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
||||
auto_key_out.automorphism(module, &auto_key_in, &auto_key_apply_exec, scratch.borrow());
|
||||
|
||||
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(TakeScalarZnx, basek, k_out);
|
||||
|
||||
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(TakeScalarZnx, rank);
|
||||
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
|
||||
(0..rank).for_each(|i| {
|
||||
module.vec_znx_automorphism(
|
||||
module.galois_element_inv(p0 * p1),
|
||||
&mut sk_auto.data.as_vec_znx_mut(),
|
||||
i,
|
||||
&sk.data.as_vec_znx(),
|
||||
i,
|
||||
);
|
||||
});
|
||||
|
||||
let sk_auto_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_auto);
|
||||
|
||||
(0..auto_key_out.rank_in()).for_each(|col_i| {
|
||||
(0..auto_key_out.rows()).for_each(|row_i| {
|
||||
auto_key_out
|
||||
.at(row_i, col_i)
|
||||
.decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());
|
||||
|
||||
module.vec_znx_sub_scalar_inplace(
|
||||
&mut pt.data,
|
||||
0,
|
||||
(digits_in - 1) + row_i * digits_in,
|
||||
&sk.data,
|
||||
col_i,
|
||||
);
|
||||
|
||||
let noise_have: f64 = module.vec_znx_std(basek, &pt.data, 0).log2();
|
||||
let noise_want: f64 = log2_std_noise_gglwe_product(
|
||||
TakeScalarZnx as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
0.5,
|
||||
0f64,
|
||||
sigma * sigma,
|
||||
0f64,
|
||||
rank as f64,
|
||||
k_out,
|
||||
k_apply,
|
||||
);
|
||||
|
||||
assert!(
|
||||
noise_have < noise_want + 0.5,
|
||||
"{} {}",
|
||||
noise_have,
|
||||
noise_want
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn test_gglwe_automorphism_inplace<B: Backend>(
|
||||
module: &Module<B>,
|
||||
p0: i64,
|
||||
p1: i64,
|
||||
basek: usize,
|
||||
digits: usize,
|
||||
k_in: usize,
|
||||
k_apply: usize,
|
||||
sigma: f64,
|
||||
rank: usize,
|
||||
) where
|
||||
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||
B: AutomorphismTestScratchFamily<B>,
|
||||
{
|
||||
let n: usize = TakeScalarZnx;
|
||||
let digits_in: usize = 1;
|
||||
|
||||
let rows_in: usize = k_in / (basek * digits);
|
||||
let rows_apply: usize = k_in.div_ceil(basek * digits);
|
||||
|
||||
let mut auto_key: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_in, rows_in, digits_in, rank);
|
||||
let mut auto_key_apply: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(n, basek, k_apply, rows_apply, digits, rank);
|
||||
|
||||
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(
|
||||
AutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_apply, rank)
|
||||
| AutomorphismKey::automorphism_inplace_scratch_space(module, n, basek, k_in, k_apply, digits, rank),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(TakeScalarZnx, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
|
||||
// gglwe_{s1}(s0) = s0 -> s1
|
||||
auto_key.encrypt_sk(
|
||||
module,
|
||||
p0,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
// gglwe_{s2}(s1) -> s1 -> s2
|
||||
auto_key_apply.encrypt_sk(
|
||||
module,
|
||||
p1,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut auto_key_apply_exec: AutomorphismKeyExec<Vec<u8>, B> =
|
||||
AutomorphismKeyExec::alloc(module, n, basek, k_apply, rows_apply, digits, rank);
|
||||
|
||||
auto_key_apply_exec.prepare(module, &auto_key_apply, scratch.borrow());
|
||||
|
||||
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
||||
auto_key.automorphism_inplace(module, &auto_key_apply_exec, scratch.borrow());
|
||||
|
||||
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(TakeScalarZnx, basek, k_in);
|
||||
|
||||
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(TakeScalarZnx, rank);
|
||||
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
|
||||
|
||||
(0..rank).for_each(|i| {
|
||||
module.vec_znx_automorphism(
|
||||
module.galois_element_inv(p0 * p1),
|
||||
&mut sk_auto.data.as_vec_znx_mut(),
|
||||
i,
|
||||
&sk.data.as_vec_znx(),
|
||||
i,
|
||||
);
|
||||
});
|
||||
|
||||
let sk_auto_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_auto);
|
||||
|
||||
(0..auto_key.rank_in()).for_each(|col_i| {
|
||||
(0..auto_key.rows()).for_each(|row_i| {
|
||||
auto_key
|
||||
.at(row_i, col_i)
|
||||
.decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());
|
||||
module.vec_znx_sub_scalar_inplace(
|
||||
&mut pt.data,
|
||||
0,
|
||||
(digits_in - 1) + row_i * digits_in,
|
||||
&sk.data,
|
||||
col_i,
|
||||
);
|
||||
|
||||
let noise_have: f64 = module.vec_znx_std(basek, &pt.data, 0).log2();
|
||||
let noise_want: f64 = log2_std_noise_gglwe_product(
|
||||
TakeScalarZnx as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
0.5,
|
||||
0f64,
|
||||
sigma * sigma,
|
||||
0f64,
|
||||
rank as f64,
|
||||
k_in,
|
||||
k_apply,
|
||||
);
|
||||
|
||||
assert!(
|
||||
noise_have < noise_want + 0.5,
|
||||
"{} {}",
|
||||
noise_have,
|
||||
noise_want
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
321
bin_fhe/blind_rotation/tests/key.rs
Normal file
321
bin_fhe/blind_rotation/tests/key.rs
Normal file
@@ -0,0 +1,321 @@
|
||||
use backend::hal::{
|
||||
api::{ScratchAvailable, SvpPPolAlloc, SvpPrepare, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, ZnxView, ZnxViewMut},
|
||||
layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, ScalarZnx, ScalarZnxToRef, Scratch, SvpPPol, WriterTo},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
Distribution, GGSWCiphertext, GGSWCiphertextExec, GGSWEncryptSkFamily, GGSWLayoutFamily, GLWESecretExec, Infos, LWESecret,
|
||||
};
|
||||
|
||||
pub struct BlindRotationKeyCGGI<D: Data> {
|
||||
pub(crate) keys: Vec<GGSWCiphertext<D>>,
|
||||
pub(crate) dist: Distribution,
|
||||
}
|
||||
|
||||
impl<D: Data> PartialEq for BlindRotationKeyCGGI<D> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.keys.len() != other.keys.len() {
|
||||
return false;
|
||||
}
|
||||
for (a, b) in self.keys.iter().zip(other.keys.iter()) {
|
||||
if a != b {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.dist == other.dist
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data> Eq for BlindRotationKeyCGGI<D> {}
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
impl<D: DataMut> ReaderFrom for BlindRotationKeyCGGI<D> {
|
||||
fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
|
||||
match Distribution::read_from(reader) {
|
||||
Ok(dist) => self.dist = dist,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
let len: usize = reader.read_u64::<LittleEndian>()? as usize;
|
||||
if self.keys.len() != len {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
format!("self.keys.len()={} != read len={}", self.keys.len(), len),
|
||||
));
|
||||
}
|
||||
for key in &mut self.keys {
|
||||
key.read_from(reader)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> WriterTo for BlindRotationKeyCGGI<D> {
|
||||
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
match self.dist.write_to(writer) {
|
||||
Ok(()) => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
|
||||
for key in &self.keys {
|
||||
key.write_to(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl BlindRotationKeyCGGI<Vec<u8>> {
|
||||
pub fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
|
||||
let mut data: Vec<GGSWCiphertext<Vec<u8>>> = Vec::with_capacity(n_lwe);
|
||||
(0..n_lwe).for_each(|_| data.push(GGSWCiphertext::alloc(n_gglwe, basek, k, rows, 1, rank)));
|
||||
Self {
|
||||
keys: data,
|
||||
dist: Distribution::NONE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_from_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> usize
|
||||
where
|
||||
Module<B>: GGSWEncryptSkFamily<B>,
|
||||
{
|
||||
GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k, rank)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef> BlindRotationKeyCGGI<D> {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn n(&self) -> usize {
|
||||
self.keys[0].n()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rows(&self) -> usize {
|
||||
self.keys[0].rows()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn k(&self) -> usize {
|
||||
self.keys[0].k()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
self.keys[0].size()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rank(&self) -> usize {
|
||||
self.keys[0].rank()
|
||||
}
|
||||
|
||||
pub(crate) fn basek(&self) -> usize {
|
||||
self.keys[0].basek()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn block_size(&self) -> usize {
|
||||
match self.dist {
|
||||
Distribution::BinaryBlock(value) => value,
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut> BlindRotationKeyCGGI<D> {
|
||||
pub fn generate_from_sk<DataSkGLWE, DataSkLWE, B: Backend>(
|
||||
&mut self,
|
||||
module: &Module<B>,
|
||||
sk_glwe: &GLWESecretExec<DataSkGLWE, B>,
|
||||
sk_lwe: &LWESecret<DataSkLWE>,
|
||||
source_xa: &mut Source,
|
||||
source_xe: &mut Source,
|
||||
sigma: f64,
|
||||
scratch: &mut Scratch<B>,
|
||||
) where
|
||||
DataSkGLWE: DataRef,
|
||||
DataSkLWE: DataRef,
|
||||
Module<B>: GGSWEncryptSkFamily<B> + VecZnxAddScalarInplace,
|
||||
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert_eq!(self.keys.len(), sk_lwe.n());
|
||||
assert!(sk_glwe.n() <= TakeScalarZnx);
|
||||
assert_eq!(sk_glwe.rank(), self.keys[0].rank());
|
||||
match sk_lwe.dist {
|
||||
Distribution::BinaryBlock(_)
|
||||
| Distribution::BinaryFixed(_)
|
||||
| Distribution::BinaryProb(_)
|
||||
| Distribution::ZERO => {}
|
||||
_ => panic!(
|
||||
"invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
self.dist = sk_lwe.dist;
|
||||
|
||||
let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n(), 1);
|
||||
let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data.to_ref();
|
||||
|
||||
self.keys.iter_mut().enumerate().for_each(|(i, ggsw)| {
|
||||
pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i];
|
||||
ggsw.encrypt_sk(module, &pt, sk_glwe, source_xa, source_xe, sigma, scratch);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct BlindRotationKeyCGGIExec<D: Data, B: Backend> {
|
||||
pub(crate) data: Vec<GGSWCiphertextExec<D, B>>,
|
||||
pub(crate) dist: Distribution,
|
||||
pub(crate) x_pow_a: Option<Vec<SvpPPol<Vec<u8>, B>>>,
|
||||
}
|
||||
|
||||
impl<D: Data, B: Backend> BlindRotationKeyCGGIExec<D, B> {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn n(&self) -> usize {
|
||||
self.data[0].n()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rows(&self) -> usize {
|
||||
self.data[0].rows()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn k(&self) -> usize {
|
||||
self.data[0].k()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
self.data[0].size()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rank(&self) -> usize {
|
||||
self.data[0].rank()
|
||||
}
|
||||
|
||||
pub(crate) fn basek(&self) -> usize {
|
||||
self.data[0].basek()
|
||||
}
|
||||
|
||||
pub(crate) fn block_size(&self) -> usize {
|
||||
match self.dist {
|
||||
Distribution::BinaryBlock(value) => value,
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BlindRotationKeyCGGIExecLayoutFamily<B: Backend> = GGSWLayoutFamily<B> + SvpPPolAlloc<B> + SvpPrepare<B>;
|
||||
|
||||
impl<B: Backend> BlindRotationKeyCGGIExec<Vec<u8>, B> {
|
||||
pub fn alloc(module: &Module<B>, n_glwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self
|
||||
where
|
||||
Module<B>: BlindRotationKeyCGGIExecLayoutFamily<B>,
|
||||
{
|
||||
let mut data: Vec<GGSWCiphertextExec<Vec<u8>, B>> = Vec::with_capacity(n_lwe);
|
||||
(0..n_lwe).for_each(|_| {
|
||||
data.push(GGSWCiphertextExec::alloc(
|
||||
module, n_glwe, basek, k, rows, 1, rank,
|
||||
))
|
||||
});
|
||||
Self {
|
||||
data,
|
||||
dist: Distribution::NONE,
|
||||
x_pow_a: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from<DataOther>(module: &Module<B>, other: &BlindRotationKeyCGGI<DataOther>, scratch: &mut Scratch<B>) -> Self
|
||||
where
|
||||
DataOther: DataRef,
|
||||
Module<B>: BlindRotationKeyCGGIExecLayoutFamily<B>,
|
||||
{
|
||||
let mut brk: BlindRotationKeyCGGIExec<Vec<u8>, B> = Self::alloc(
|
||||
module,
|
||||
other.n(),
|
||||
other.keys.len(),
|
||||
other.basek(),
|
||||
other.k(),
|
||||
other.rows(),
|
||||
other.rank(),
|
||||
);
|
||||
brk.prepare(module, other, scratch);
|
||||
brk
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut, B: Backend> BlindRotationKeyCGGIExec<D, B> {
|
||||
pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &BlindRotationKeyCGGI<DataOther>, scratch: &mut Scratch<B>)
|
||||
where
|
||||
DataOther: DataRef,
|
||||
Module<B>: BlindRotationKeyCGGIExecLayoutFamily<B>,
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert_eq!(self.data.len(), other.keys.len());
|
||||
}
|
||||
|
||||
let n: usize = other.n();
|
||||
|
||||
self.data
|
||||
.iter_mut()
|
||||
.zip(other.keys.iter())
|
||||
.for_each(|(ggsw_exec, other)| {
|
||||
ggsw_exec.prepare(module, other, scratch);
|
||||
});
|
||||
|
||||
self.dist = other.dist;
|
||||
|
||||
match other.dist {
|
||||
Distribution::BinaryBlock(_) => {
|
||||
let mut x_pow_a: Vec<SvpPPol<Vec<u8>, B>> = Vec::with_capacity(n << 1);
|
||||
let mut buf: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
|
||||
(0..n << 1).for_each(|i| {
|
||||
let mut res: SvpPPol<Vec<u8>, B> = module.svp_ppol_alloc(n, 1);
|
||||
set_xai_plus_y(module, i, 0, &mut res, &mut buf);
|
||||
x_pow_a.push(res);
|
||||
});
|
||||
self.x_pow_a = Some(x_pow_a);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_xai_plus_y<A, C, B: Backend>(module: &Module<B>, ai: usize, y: i64, res: &mut SvpPPol<A, B>, buf: &mut ScalarZnx<C>)
|
||||
where
|
||||
A: DataMut,
|
||||
C: DataMut,
|
||||
Module<B>: SvpPrepare<B>,
|
||||
{
|
||||
let n: usize = res.n();
|
||||
|
||||
{
|
||||
let raw: &mut [i64] = buf.at_mut(0, 0);
|
||||
if ai < n {
|
||||
raw[ai] = 1;
|
||||
} else {
|
||||
raw[(ai - n) & (n - 1)] = -1;
|
||||
}
|
||||
raw[0] += y;
|
||||
}
|
||||
|
||||
module.svp_prepare(res, 0, buf, 0);
|
||||
|
||||
{
|
||||
let raw: &mut [i64] = buf.at_mut(0, 0);
|
||||
|
||||
if ai < n {
|
||||
raw[ai] = 0;
|
||||
} else {
|
||||
raw[(ai - n) & (n - 1)] = 0;
|
||||
}
|
||||
raw[0] = 0;
|
||||
}
|
||||
}
|
||||
4
bin_fhe/blind_rotation/tests/mod.rs
Normal file
4
bin_fhe/blind_rotation/tests/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod cpu_spqlios;
|
||||
mod generic_cggi;
|
||||
mod generic_lut;
|
||||
mod generic_serialization;
|
||||
Reference in New Issue
Block a user