mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 21:26:41 +01:00
Dev serialization (#64)
* Added compressed serialization for GLWECiphertext + Ciphertext decompression * Added compressed serialization for GGLWECiphertext & GLWESwitchingkey * generalized automorphism test * Removed ops on scalar_znx, replaced by as_vec_znx/as_vec_znx_mut and then call op on vec_znx * Added tests for automorphism key encryption * Added tensorkey compressed * added ggsw compressed
This commit is contained in:
committed by
GitHub
parent
4c59733566
commit
9aa4b1f1e2
191
core/src/glwe/tests/cpu_spqlios/fft64.rs
Normal file
191
core/src/glwe/tests/cpu_spqlios/fft64.rs
Normal file
@@ -0,0 +1,191 @@
|
||||
use backend::{
|
||||
hal::{api::ModuleNew, layouts::Module},
|
||||
implementation::cpu_spqlios::FFT64,
|
||||
};
|
||||
|
||||
use crate::glwe::tests::{
|
||||
generic_automorphism::{test_automorphism, test_automorphism_inplace},
|
||||
generic_encryption::{test_encrypt_pk, test_encrypt_sk, test_encrypt_sk_compressed, test_encrypt_zero_sk},
|
||||
generic_external_product::{test_external_product, test_external_product_inplace},
|
||||
generic_keyswitch::{test_keyswitch, test_keyswitch_inplace},
|
||||
generic_serialization::{test_serialization, test_serialization_compressed},
|
||||
packing::test_packing,
|
||||
trace::test_trace_inplace,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn encrypt_sk() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
(1..4).for_each(|rank| {
|
||||
println!("test encrypt_sk rank: {}", rank);
|
||||
test_encrypt_sk(&module, 8, 54, 30, 3.2, rank);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_sk_compressed() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
(1..4).for_each(|rank| {
|
||||
println!("test encrypt_sk rank: {}", rank);
|
||||
test_encrypt_sk_compressed(&module, 8, 54, 30, 3.2, rank);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_zero_sk() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
(1..4).for_each(|rank| {
|
||||
println!("test encrypt_zero_sk rank: {}", rank);
|
||||
test_encrypt_zero_sk(&module, 8, 64, 3.2, rank);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_pk() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
(1..4).for_each(|rank| {
|
||||
println!("test encrypt_pk rank: {}", rank);
|
||||
test_encrypt_pk(&module, 8, 64, 64, 3.2, rank)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
let basek: usize = 12;
|
||||
let k_in: usize = 45;
|
||||
let digits: usize = k_in.div_ceil(basek);
|
||||
(1..4).for_each(|rank_in| {
|
||||
(1..4).for_each(|rank_out| {
|
||||
(1..digits + 1).for_each(|di| {
|
||||
let k_ksk: usize = k_in + basek * di;
|
||||
let k_out: usize = k_ksk; // better capture noise
|
||||
println!(
|
||||
"test keyswitch digits: {} rank_in: {} rank_out: {}",
|
||||
di, rank_in, rank_out
|
||||
);
|
||||
test_keyswitch(
|
||||
&module, basek, k_out, k_in, k_ksk, di, rank_in, rank_out, 3.2,
|
||||
);
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_inplace() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
let basek: usize = 12;
|
||||
let k_ct: usize = 45;
|
||||
let digits: usize = k_ct.div_ceil(basek);
|
||||
(1..4).for_each(|rank| {
|
||||
(1..digits + 1).for_each(|di| {
|
||||
let k_ksk: usize = k_ct + basek * di;
|
||||
println!("test keyswitch_inplace digits: {} rank: {}", di, rank);
|
||||
test_keyswitch_inplace(&module, basek, k_ct, k_ksk, di, rank, 3.2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn automorphism_inplace() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
let basek: usize = 12;
|
||||
let k_ct: usize = 60;
|
||||
let digits: usize = k_ct.div_ceil(basek);
|
||||
(1..4).for_each(|rank| {
|
||||
(1..digits + 1).for_each(|di| {
|
||||
let k_ksk: usize = k_ct + basek * di;
|
||||
println!("test automorphism_inplace digits: {} rank: {}", di, rank);
|
||||
test_automorphism_inplace(&module, basek, -5, k_ct, k_ksk, di, rank, 3.2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn automorphism() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
let basek: usize = 12;
|
||||
let k_in: usize = 60;
|
||||
let digits: usize = k_in.div_ceil(basek);
|
||||
(1..4).for_each(|rank| {
|
||||
(1..digits + 1).for_each(|di| {
|
||||
let k_ksk: usize = k_in + basek * di;
|
||||
let k_out: usize = k_ksk; // Better capture noise.
|
||||
println!("test automorphism digits: {} rank: {}", di, rank);
|
||||
test_automorphism(&module, basek, -5, k_out, k_in, k_ksk, di, rank, 3.2);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_product() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
let basek: usize = 12;
|
||||
let k_in: usize = 45;
|
||||
let digits: usize = k_in.div_ceil(basek);
|
||||
(1..4).for_each(|rank| {
|
||||
(1..digits + 1).for_each(|di| {
|
||||
let k_ggsw: usize = k_in + basek * di;
|
||||
let k_out: usize = k_ggsw; // Better capture noise
|
||||
println!("test external_product digits: {} rank: {}", di, rank);
|
||||
test_external_product(&module, basek, k_out, k_in, k_ggsw, di, rank, 3.2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_product_inplace() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
let basek: usize = 12;
|
||||
let k_ct: usize = 60;
|
||||
let digits: usize = k_ct.div_ceil(basek);
|
||||
(1..4).for_each(|rank| {
|
||||
(1..digits + 1).for_each(|di| {
|
||||
let k_ggsw: usize = k_ct + basek * di;
|
||||
println!("test external_product digits: {} rank: {}", di, rank);
|
||||
test_external_product_inplace(&module, basek, k_ct, k_ggsw, di, rank, 3.2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_inplace() {
|
||||
let log_n: usize = 8;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
(1..4).for_each(|rank| {
|
||||
println!("test trace_inplace rank: {}", rank);
|
||||
test_trace_inplace(&module, 8, 54, 3.2, rank);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn packing() {
|
||||
let log_n: usize = 5;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
test_packing(&module);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialization() {
|
||||
let log_n: usize = 5;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
test_serialization(&module);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialization_compressed() {
|
||||
let log_n: usize = 5;
|
||||
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
|
||||
test_serialization_compressed(&module);
|
||||
}
|
||||
1
core/src/glwe/tests/cpu_spqlios/mod.rs
Normal file
1
core/src/glwe/tests/cpu_spqlios/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
mod fft64;
|
||||
210
core/src/glwe/tests/generic_automorphism.rs
Normal file
210
core/src/glwe/tests/generic_automorphism.rs
Normal file
@@ -0,0 +1,210 @@
|
||||
use backend::hal::{
|
||||
api::{
|
||||
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxFillUniform, VecZnxStd,
|
||||
VecZnxSwithcDegree,
|
||||
},
|
||||
layouts::{Backend, Module, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
AutomorphismKey, AutomorphismKeyEncryptSkFamily, AutomorphismKeyExec, GGLWEExecLayoutFamily, GLWECiphertext,
|
||||
GLWEDecryptFamily, GLWEKeyswitchFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, Infos,
|
||||
noise::log2_std_noise_gglwe_product,
|
||||
};
|
||||
|
||||
pub(crate) trait AutomorphismTestModuleFamily<B: Backend> = AutomorphismKeyEncryptSkFamily<B>
|
||||
+ GLWEDecryptFamily<B>
|
||||
+ GGLWEExecLayoutFamily<B>
|
||||
+ GLWEKeyswitchFamily<B>
|
||||
+ MatZnxAlloc
|
||||
+ VecZnxAlloc
|
||||
+ ScalarZnxAllocBytes
|
||||
+ VecZnxAllocBytes
|
||||
+ VecZnxAutomorphism
|
||||
+ VecZnxSwithcDegree
|
||||
+ ScalarZnxAlloc
|
||||
+ VecZnxAddScalarInplace
|
||||
+ VecZnxAutomorphismInplace
|
||||
+ VecZnxStd;
|
||||
pub(crate) trait AutomorphismTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>
|
||||
+ TakeSvpPPolImpl<B>
|
||||
+ ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeScalarZnxImpl<B>
|
||||
+ TakeVecZnxImpl<B>;
|
||||
|
||||
pub(crate) fn test_automorphism<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
p: i64,
|
||||
k_out: usize,
|
||||
k_in: usize,
|
||||
k_ksk: usize,
|
||||
digits: usize,
|
||||
rank: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||
B: AutomorphismTestScratchFamily<B>,
|
||||
{
|
||||
let rows: usize = k_in.div_ceil(basek * digits);
|
||||
|
||||
let mut autokey: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||
let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_in, rank);
|
||||
let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_out, rank);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_in);
|
||||
|
||||
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]);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_in, &mut source_xa);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
AutomorphismKey::encrypt_sk_scratch_space(module, basek, autokey.k(), rank)
|
||||
| GLWECiphertext::decrypt_scratch_space(module, basek, ct_out.k())
|
||||
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_in.k())
|
||||
| GLWECiphertext::automorphism_scratch_space(
|
||||
module,
|
||||
basek,
|
||||
ct_out.k(),
|
||||
ct_in.k(),
|
||||
autokey.k(),
|
||||
digits,
|
||||
rank,
|
||||
),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
autokey.encrypt_sk(
|
||||
module,
|
||||
p,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct_in.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut autokey_exec: AutomorphismKeyExec<Vec<u8>, B> = AutomorphismKeyExec::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||
autokey_exec.prepare(module, &autokey, scratch.borrow());
|
||||
|
||||
ct_out.automorphism(module, &ct_in, &autokey_exec, scratch.borrow());
|
||||
|
||||
let max_noise: f64 = log2_std_noise_gglwe_product(
|
||||
module.n() as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
0.5,
|
||||
0f64,
|
||||
sigma * sigma,
|
||||
0f64,
|
||||
rank as f64,
|
||||
k_in,
|
||||
k_ksk,
|
||||
);
|
||||
|
||||
module.vec_znx_automorphism_inplace(p, &mut pt_want.data, 0);
|
||||
|
||||
ct_out.assert_noise(module, &sk_exec, &pt_want, max_noise + 1.0);
|
||||
}
|
||||
|
||||
pub(crate) fn test_automorphism_inplace<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
p: i64,
|
||||
k_ct: usize,
|
||||
k_ksk: usize,
|
||||
digits: usize,
|
||||
rank: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: AutomorphismTestModuleFamily<B>,
|
||||
B: AutomorphismTestScratchFamily<B>,
|
||||
{
|
||||
let rows: usize = k_ct.div_ceil(basek * digits);
|
||||
|
||||
let mut autokey: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
|
||||
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]);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
AutomorphismKey::encrypt_sk_scratch_space(module, basek, autokey.k(), rank)
|
||||
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
|
||||
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
|
||||
| GLWECiphertext::automorphism_inplace_scratch_space(module, basek, ct.k(), autokey.k(), digits, rank),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
autokey.encrypt_sk(
|
||||
module,
|
||||
p,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut autokey_exec: AutomorphismKeyExec<Vec<u8>, B> = AutomorphismKeyExec::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||
autokey_exec.prepare(module, &autokey, scratch.borrow());
|
||||
|
||||
ct.automorphism_inplace(module, &autokey_exec, scratch.borrow());
|
||||
|
||||
let max_noise: f64 = log2_std_noise_gglwe_product(
|
||||
module.n() as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
0.5,
|
||||
0f64,
|
||||
sigma * sigma,
|
||||
0f64,
|
||||
rank as f64,
|
||||
k_ct,
|
||||
k_ksk,
|
||||
);
|
||||
|
||||
module.vec_znx_automorphism_inplace(p, &mut pt_want.data, 0);
|
||||
|
||||
ct.assert_noise(module, &sk_exec, &pt_want, max_noise + 1.0);
|
||||
}
|
||||
225
core/src/glwe/tests/generic_encryption.rs
Normal file
225
core/src/glwe/tests/generic_encryption.rs
Normal file
@@ -0,0 +1,225 @@
|
||||
use backend::hal::{
|
||||
api::{
|
||||
ScalarZnxAlloc, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAlloc, VecZnxCopy, VecZnxDftAlloc, VecZnxFillUniform,
|
||||
VecZnxStd, VecZnxSubABInplace,
|
||||
},
|
||||
layouts::{Backend, Module, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
GLWECiphertext, GLWECiphertextCompressed, GLWEDecryptFamily, GLWEEncryptPkFamily, GLWEEncryptSkFamily, GLWEOps,
|
||||
GLWEPlaintext, GLWEPublicKey, GLWEPublicKeyExec, GLWESecret, GLWESecretExec, GLWESecretFamily, Infos,
|
||||
};
|
||||
|
||||
pub(crate) trait EncryptionTestModuleFamily<B: Backend> =
|
||||
GLWEDecryptFamily<B> + GLWESecretFamily<B> + VecZnxAlloc + ScalarZnxAlloc + VecZnxStd;
|
||||
|
||||
pub(crate) trait EncryptionTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>
|
||||
+ TakeSvpPPolImpl<B>
|
||||
+ ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeScalarZnxImpl<B>
|
||||
+ TakeVecZnxImpl<B>;
|
||||
|
||||
pub(crate) fn test_encrypt_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pt: usize, sigma: f64, rank: usize)
|
||||
where
|
||||
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
|
||||
B: EncryptionTestScratchFamily<B>,
|
||||
{
|
||||
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_pt);
|
||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_pt);
|
||||
|
||||
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(
|
||||
GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
|
||||
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k()),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_pt, &mut source_xa);
|
||||
|
||||
ct.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct.decrypt(module, &mut pt_have, &sk_exec, scratch.borrow());
|
||||
|
||||
pt_want.sub_inplace_ab(module, &pt_have);
|
||||
|
||||
let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0) * (ct.k() as f64).exp2();
|
||||
let noise_want: f64 = sigma;
|
||||
|
||||
assert!(noise_have <= noise_want + 0.2);
|
||||
}
|
||||
|
||||
pub(crate) fn test_encrypt_sk_compressed<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k_ct: usize,
|
||||
k_pt: usize,
|
||||
sigma: f64,
|
||||
rank: usize,
|
||||
) where
|
||||
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B> + VecZnxCopy,
|
||||
B: EncryptionTestScratchFamily<B>,
|
||||
{
|
||||
let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(module, basek, k_ct, rank);
|
||||
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_pt);
|
||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_pt);
|
||||
|
||||
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(
|
||||
GLWECiphertextCompressed::encrypt_sk_scratch_space(module, basek, k_ct)
|
||||
| GLWECiphertext::decrypt_scratch_space(module, basek, k_ct),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_pt, &mut source_xa);
|
||||
|
||||
let seed_xa: [u8; 32] = [1u8; 32];
|
||||
|
||||
ct_compressed.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_exec,
|
||||
seed_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
ct.decompress(module, &ct_compressed);
|
||||
|
||||
ct.decrypt(module, &mut pt_have, &sk_exec, scratch.borrow());
|
||||
|
||||
pt_want.sub_inplace_ab(module, &pt_have);
|
||||
|
||||
let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0) * (ct.k() as f64).exp2();
|
||||
let noise_want: f64 = sigma;
|
||||
|
||||
assert!(noise_have <= noise_want + 0.2);
|
||||
}
|
||||
|
||||
pub(crate) fn test_encrypt_zero_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, sigma: f64, rank: usize)
|
||||
where
|
||||
Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
|
||||
B: EncryptionTestScratchFamily<B>,
|
||||
{
|
||||
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
|
||||
let mut source_xs: Source = Source::new([0u8; 32]);
|
||||
let mut source_xe: Source = Source::new([1u8; 32]);
|
||||
let mut source_xa: Source = Source::new([0u8; 32]);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
GLWECiphertext::decrypt_scratch_space(module, basek, k_ct)
|
||||
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, k_ct),
|
||||
);
|
||||
|
||||
ct.encrypt_zero_sk(
|
||||
module,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
ct.decrypt(module, &mut pt, &sk_exec, scratch.borrow());
|
||||
|
||||
assert!((sigma - module.vec_znx_std(basek, &pt.data, 0) * (k_ct as f64).exp2()) <= 0.2);
|
||||
}
|
||||
|
||||
pub(crate) fn test_encrypt_pk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pk: usize, sigma: f64, rank: usize)
|
||||
where
|
||||
Module<B>: EncryptionTestModuleFamily<B>
|
||||
+ GLWEEncryptPkFamily<B>
|
||||
+ GLWEEncryptSkFamily<B>
|
||||
+ VecZnxDftAlloc<B>
|
||||
+ VecZnxFillUniform
|
||||
+ VecZnxSubABInplace,
|
||||
B: EncryptionTestScratchFamily<B>,
|
||||
{
|
||||
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
|
||||
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 source_xu: Source = Source::new([0u8; 32]);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc(module, basek, k_pk, rank);
|
||||
pk.generate_from_sk(module, &sk_exec, &mut source_xa, &mut source_xe, sigma);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
|
||||
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
|
||||
| GLWECiphertext::encrypt_pk_scratch_space(module, basek, pk.k()),
|
||||
);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
|
||||
|
||||
let pk_exec: GLWEPublicKeyExec<Vec<u8>, B> = GLWEPublicKeyExec::from(module, &pk, scratch.borrow());
|
||||
|
||||
ct.encrypt_pk(
|
||||
module,
|
||||
&pt_want,
|
||||
&pk_exec,
|
||||
&mut source_xu,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct.decrypt(module, &mut pt_have, &sk_exec, scratch.borrow());
|
||||
|
||||
pt_want.sub_inplace_ab(module, &pt_have);
|
||||
|
||||
let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0).log2();
|
||||
let noise_want: f64 = ((((rank as f64) + 1.0) * module.n() as f64 * 0.5 * sigma * sigma).sqrt()).log2() - (k_ct as f64);
|
||||
|
||||
assert!(
|
||||
noise_have <= noise_want + 0.2,
|
||||
"{} {}",
|
||||
noise_have,
|
||||
noise_want
|
||||
);
|
||||
}
|
||||
233
core/src/glwe/tests/generic_external_product.rs
Normal file
233
core/src/glwe/tests/generic_external_product.rs
Normal file
@@ -0,0 +1,233 @@
|
||||
use backend::hal::{
|
||||
api::{
|
||||
MatZnxAlloc, ScalarZnxAlloc, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAlloc,
|
||||
VecZnxAllocBytes, VecZnxFillUniform, VecZnxRotateInplace, VecZnxStd, ZnxViewMut,
|
||||
},
|
||||
layouts::{Backend, Module, ScalarZnx, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
GGSWCiphertext, GGSWCiphertextExec, GGSWLayoutFamily, GLWECiphertext, GLWEDecryptFamily, GLWEEncryptSkFamily,
|
||||
GLWEExternalProductFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, Infos, noise::noise_ggsw_product,
|
||||
};
|
||||
|
||||
pub(crate) trait ExternalProductTestModuleFamily<B: Backend> = GLWEEncryptSkFamily<B>
|
||||
+ GLWEDecryptFamily<B>
|
||||
+ GLWESecretFamily<B>
|
||||
+ GLWEExternalProductFamily<B>
|
||||
+ GGSWLayoutFamily<B>
|
||||
+ MatZnxAlloc
|
||||
+ VecZnxAlloc
|
||||
+ ScalarZnxAlloc
|
||||
+ VecZnxAllocBytes
|
||||
+ VecZnxAddScalarInplace
|
||||
+ VecZnxRotateInplace
|
||||
+ VecZnxStd;
|
||||
|
||||
pub(crate) trait ExternalProductTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>
|
||||
+ TakeSvpPPolImpl<B>
|
||||
+ ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeScalarZnxImpl<B>
|
||||
+ TakeVecZnxImpl<B>;
|
||||
|
||||
pub(crate) fn test_external_product<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k_out: usize,
|
||||
k_in: usize,
|
||||
k_ggsw: usize,
|
||||
digits: usize,
|
||||
rank: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: ExternalProductTestModuleFamily<B>,
|
||||
B: ExternalProductTestScratchFamily<B>,
|
||||
{
|
||||
let rows: usize = k_in.div_ceil(basek * digits);
|
||||
|
||||
let mut ct_ggsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_ggsw, rows, digits, rank);
|
||||
let mut ct_glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_in, rank);
|
||||
let mut ct_glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_out, rank);
|
||||
let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_in);
|
||||
|
||||
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]);
|
||||
|
||||
// Random input plaintext
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_in, &mut source_xa);
|
||||
|
||||
pt_want.data.at_mut(0, 0)[1] = 1;
|
||||
|
||||
let k: usize = 1;
|
||||
|
||||
pt_rgsw.raw_mut()[k] = 1; // X^{k}
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, ct_ggsw.k(), rank)
|
||||
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_glwe_in.k())
|
||||
| GLWECiphertext::external_product_scratch_space(
|
||||
module,
|
||||
basek,
|
||||
ct_glwe_out.k(),
|
||||
ct_glwe_in.k(),
|
||||
ct_ggsw.k(),
|
||||
digits,
|
||||
rank,
|
||||
),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
ct_ggsw.encrypt_sk(
|
||||
module,
|
||||
&pt_rgsw,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct_glwe_in.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let ct_ggsw_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::from(module, &ct_ggsw, scratch.borrow());
|
||||
|
||||
ct_glwe_out.external_product(module, &ct_glwe_in, &ct_ggsw_exec, scratch.borrow());
|
||||
|
||||
module.vec_znx_rotate_inplace(k as i64, &mut pt_want.data, 0);
|
||||
|
||||
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_a0_err: f64 = sigma * sigma;
|
||||
let var_a1_err: f64 = 1f64 / 12f64;
|
||||
|
||||
let max_noise: f64 = noise_ggsw_product(
|
||||
module.n() as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
var_msg,
|
||||
var_a0_err,
|
||||
var_a1_err,
|
||||
var_gct_err_lhs,
|
||||
var_gct_err_rhs,
|
||||
rank as f64,
|
||||
k_in,
|
||||
k_ggsw,
|
||||
);
|
||||
|
||||
ct_glwe_out.assert_noise(module, &sk_exec, &pt_want, max_noise + 0.5);
|
||||
}
|
||||
|
||||
pub(crate) fn test_external_product_inplace<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k_ct: usize,
|
||||
k_ggsw: usize,
|
||||
digits: usize,
|
||||
rank: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: ExternalProductTestModuleFamily<B>,
|
||||
B: ExternalProductTestScratchFamily<B>,
|
||||
{
|
||||
let rows: usize = k_ct.div_ceil(basek * digits);
|
||||
|
||||
let mut ct_ggsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(module, basek, k_ggsw, rows, digits, rank);
|
||||
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.scalar_znx_alloc(1);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
|
||||
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]);
|
||||
|
||||
// Random input plaintext
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
|
||||
|
||||
pt_want.data.at_mut(0, 0)[1] = 1;
|
||||
|
||||
let k: usize = 1;
|
||||
|
||||
pt_rgsw.raw_mut()[k] = 1; // X^{k}
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, ct_ggsw.k(), rank)
|
||||
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_glwe.k())
|
||||
| GLWECiphertext::external_product_inplace_scratch_space(module, basek, ct_glwe.k(), ct_ggsw.k(), digits, rank),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
ct_ggsw.encrypt_sk(
|
||||
module,
|
||||
&pt_rgsw,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct_glwe.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let ct_ggsw_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::from(module, &ct_ggsw, scratch.borrow());
|
||||
|
||||
ct_glwe.external_product_inplace(module, &ct_ggsw_exec, scratch.borrow());
|
||||
|
||||
module.vec_znx_rotate_inplace(k as i64, &mut pt_want.data, 0);
|
||||
|
||||
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_a0_err: f64 = sigma * sigma;
|
||||
let var_a1_err: f64 = 1f64 / 12f64;
|
||||
|
||||
let max_noise: f64 = noise_ggsw_product(
|
||||
module.n() as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
var_msg,
|
||||
var_a0_err,
|
||||
var_a1_err,
|
||||
var_gct_err_lhs,
|
||||
var_gct_err_rhs,
|
||||
rank as f64,
|
||||
k_ct,
|
||||
k_ggsw,
|
||||
);
|
||||
|
||||
ct_glwe.assert_noise(module, &sk_exec, &pt_want, max_noise + 0.5);
|
||||
}
|
||||
209
core/src/glwe/tests/generic_keyswitch.rs
Normal file
209
core/src/glwe/tests/generic_keyswitch.rs
Normal file
@@ -0,0 +1,209 @@
|
||||
use backend::hal::{
|
||||
api::{
|
||||
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||
VecZnxAlloc, VecZnxAllocBytes, VecZnxFillUniform, VecZnxStd, VecZnxSwithcDegree,
|
||||
},
|
||||
layouts::{Backend, Module, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
GGLWEExecLayoutFamily, GLWECiphertext, GLWEDecryptFamily, GLWEKeyswitchFamily, GLWEPlaintext, GLWESecret, GLWESecretExec,
|
||||
GLWESecretFamily, GLWESwitchingKey, GLWESwitchingKeyEncryptSkFamily, GLWESwitchingKeyExec, Infos,
|
||||
noise::log2_std_noise_gglwe_product,
|
||||
};
|
||||
|
||||
pub(crate) trait KeySwitchTestModuleFamily<B: Backend> = GLWESecretFamily<B>
|
||||
+ GLWESwitchingKeyEncryptSkFamily<B>
|
||||
+ GLWEKeyswitchFamily<B>
|
||||
+ GLWEDecryptFamily<B>
|
||||
+ GGLWEExecLayoutFamily<B>
|
||||
+ MatZnxAlloc
|
||||
+ VecZnxAlloc
|
||||
+ ScalarZnxAlloc
|
||||
+ ScalarZnxAllocBytes
|
||||
+ VecZnxAllocBytes
|
||||
+ VecZnxStd
|
||||
+ VecZnxSwithcDegree
|
||||
+ VecZnxAddScalarInplace;
|
||||
|
||||
pub(crate) trait KeySwitchTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>
|
||||
+ TakeSvpPPolImpl<B>
|
||||
+ ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeScalarZnxImpl<B>
|
||||
+ TakeVecZnxImpl<B>;
|
||||
|
||||
pub(crate) fn test_keyswitch<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k_out: usize,
|
||||
k_in: usize,
|
||||
k_ksk: usize,
|
||||
digits: usize,
|
||||
rank_in: usize,
|
||||
rank_out: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: KeySwitchTestModuleFamily<B>,
|
||||
B: KeySwitchTestScratchFamily<B>,
|
||||
{
|
||||
let rows: usize = k_in.div_ceil(basek * digits);
|
||||
|
||||
let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(module, basek, k_ksk, rows, digits, rank_in, rank_out);
|
||||
let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_in, rank_in);
|
||||
let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_out, rank_out);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_in);
|
||||
|
||||
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]);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_in, &mut source_xa);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, ksk.k(), rank_in, rank_out)
|
||||
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_in.k())
|
||||
| GLWECiphertext::keyswitch_scratch_space(
|
||||
module,
|
||||
basek,
|
||||
ct_out.k(),
|
||||
ct_in.k(),
|
||||
ksk.k(),
|
||||
digits,
|
||||
rank_in,
|
||||
rank_out,
|
||||
),
|
||||
);
|
||||
|
||||
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank_in);
|
||||
sk_in.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_in_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_in);
|
||||
|
||||
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank_out);
|
||||
sk_out.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_out_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_out);
|
||||
|
||||
ksk.encrypt_sk(
|
||||
module,
|
||||
&sk_in,
|
||||
&sk_out,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct_in.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_in_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let ksk_exec: GLWESwitchingKeyExec<Vec<u8>, B> = GLWESwitchingKeyExec::from(module, &ksk, scratch.borrow());
|
||||
|
||||
ct_out.keyswitch(module, &ct_in, &ksk_exec, scratch.borrow());
|
||||
|
||||
let max_noise: f64 = log2_std_noise_gglwe_product(
|
||||
module.n() as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
0.5,
|
||||
0f64,
|
||||
sigma * sigma,
|
||||
0f64,
|
||||
rank_in as f64,
|
||||
k_in,
|
||||
k_ksk,
|
||||
);
|
||||
|
||||
ct_out.assert_noise(module, &sk_out_exec, &pt_want, max_noise + 0.5);
|
||||
}
|
||||
|
||||
pub(crate) fn test_keyswitch_inplace<B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k_ct: usize,
|
||||
k_ksk: usize,
|
||||
digits: usize,
|
||||
rank: usize,
|
||||
sigma: f64,
|
||||
) where
|
||||
Module<B>: KeySwitchTestModuleFamily<B>,
|
||||
B: KeySwitchTestScratchFamily<B>,
|
||||
{
|
||||
let rows: usize = k_ct.div_ceil(basek * digits);
|
||||
|
||||
let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(module, basek, k_ksk, rows, digits, rank, rank);
|
||||
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
|
||||
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]);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, ksk.k(), rank, rank)
|
||||
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_glwe.k())
|
||||
| GLWECiphertext::keyswitch_inplace_scratch_space(module, basek, ct_glwe.k(), ksk.k(), digits, rank),
|
||||
);
|
||||
|
||||
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk_in.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_in_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_in);
|
||||
|
||||
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk_out.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_out_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_out);
|
||||
|
||||
ksk.encrypt_sk(
|
||||
module,
|
||||
&sk_in,
|
||||
&sk_out,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
ct_glwe.encrypt_sk(
|
||||
module,
|
||||
&pt_want,
|
||||
&sk_in_exec,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let ksk_exec: GLWESwitchingKeyExec<Vec<u8>, B> = GLWESwitchingKeyExec::from(module, &ksk, scratch.borrow());
|
||||
|
||||
ct_glwe.keyswitch_inplace(module, &ksk_exec, scratch.borrow());
|
||||
|
||||
let max_noise: f64 = log2_std_noise_gglwe_product(
|
||||
module.n() as f64,
|
||||
basek * digits,
|
||||
0.5,
|
||||
0.5,
|
||||
0f64,
|
||||
sigma * sigma,
|
||||
0f64,
|
||||
rank as f64,
|
||||
k_ct,
|
||||
k_ksk,
|
||||
);
|
||||
|
||||
ct_glwe.assert_noise(module, &sk_out_exec, &pt_want, max_noise + 0.5);
|
||||
}
|
||||
23
core/src/glwe/tests/generic_serialization.rs
Normal file
23
core/src/glwe/tests/generic_serialization.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use backend::hal::{
|
||||
api::VecZnxAlloc,
|
||||
layouts::{Backend, Module},
|
||||
tests::serialization::test_reader_writer_interface,
|
||||
};
|
||||
|
||||
use crate::{GLWECiphertext, GLWECiphertextCompressed};
|
||||
|
||||
pub(crate) fn test_serialization<B: Backend>(module: &Module<B>)
|
||||
where
|
||||
Module<B>: VecZnxAlloc,
|
||||
{
|
||||
let original: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, 12, 54, 3);
|
||||
test_reader_writer_interface(original);
|
||||
}
|
||||
|
||||
pub(crate) fn test_serialization_compressed<B: Backend>(module: &Module<B>)
|
||||
where
|
||||
Module<B>: VecZnxAlloc,
|
||||
{
|
||||
let original: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(module, 12, 54, 3);
|
||||
test_reader_writer_interface(original);
|
||||
}
|
||||
8
core/src/glwe/tests/mod.rs
Normal file
8
core/src/glwe/tests/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
mod cpu_spqlios;
|
||||
mod generic_automorphism;
|
||||
mod generic_encryption;
|
||||
mod generic_external_product;
|
||||
mod generic_keyswitch;
|
||||
mod generic_serialization;
|
||||
mod packing;
|
||||
mod trace;
|
||||
177
core/src/glwe/tests/packing.rs
Normal file
177
core/src/glwe/tests/packing.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use backend::hal::{
|
||||
api::{
|
||||
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxBigSubSmallBInplace, VecZnxEncodeVeci64, VecZnxRotateInplace,
|
||||
VecZnxStd, VecZnxSwithcDegree,
|
||||
},
|
||||
layouts::{Backend, Module, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
AutomorphismKey, AutomorphismKeyExec, GGLWEExecLayoutFamily, GLWECiphertext, GLWEDecryptFamily, GLWEKeyswitchFamily, GLWEOps,
|
||||
GLWEPacker, GLWEPackingFamily, GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, GLWESwitchingKeyEncryptSkFamily,
|
||||
};
|
||||
|
||||
pub(crate) trait PackingTestModuleFamily<B: Backend> = GLWEPackingFamily<B>
|
||||
+ GLWESecretFamily<B>
|
||||
+ GLWESwitchingKeyEncryptSkFamily<B>
|
||||
+ GLWEKeyswitchFamily<B>
|
||||
+ GLWEDecryptFamily<B>
|
||||
+ GGLWEExecLayoutFamily<B>
|
||||
+ MatZnxAlloc
|
||||
+ VecZnxAlloc
|
||||
+ ScalarZnxAlloc
|
||||
+ ScalarZnxAllocBytes
|
||||
+ VecZnxAllocBytes
|
||||
+ VecZnxStd
|
||||
+ VecZnxSwithcDegree
|
||||
+ VecZnxAddScalarInplace
|
||||
+ VecZnxEncodeVeci64
|
||||
+ VecZnxRotateInplace
|
||||
+ VecZnxAutomorphism
|
||||
+ VecZnxBigSubSmallBInplace<B>;
|
||||
|
||||
pub(crate) trait PackingTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>
|
||||
+ TakeSvpPPolImpl<B>
|
||||
+ ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeScalarZnxImpl<B>
|
||||
+ TakeVecZnxImpl<B>;
|
||||
|
||||
pub(crate) fn test_packing<B: Backend>(module: &Module<B>)
|
||||
where
|
||||
Module<B>: PackingTestModuleFamily<B>,
|
||||
B: PackingTestScratchFamily<B>,
|
||||
{
|
||||
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 basek: usize = 18;
|
||||
let k_ct: usize = 36;
|
||||
let pt_k: usize = 18;
|
||||
let rank: usize = 3;
|
||||
let sigma: f64 = 3.2;
|
||||
let digits: usize = 1;
|
||||
let k_ksk: usize = k_ct + basek * digits;
|
||||
|
||||
let rows: usize = k_ct.div_ceil(basek * digits);
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
|
||||
GLWECiphertext::encrypt_sk_scratch_space(module, basek, k_ct)
|
||||
| AutomorphismKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
|
||||
| GLWEPacker::scratch_space(module, basek, k_ct, k_ksk, digits, rank),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
let mut data: Vec<i64> = vec![0i64; module.n()];
|
||||
data.iter_mut().enumerate().for_each(|(i, x)| {
|
||||
*x = i as i64;
|
||||
});
|
||||
|
||||
module.encode_vec_i64(basek, &mut pt.data, 0, pt_k, &data, 32);
|
||||
|
||||
let gal_els: Vec<i64> = GLWEPacker::galois_elements(module);
|
||||
|
||||
let mut auto_keys: HashMap<i64, AutomorphismKeyExec<Vec<u8>, B>> = HashMap::new();
|
||||
let mut tmp: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_ksk, rows, digits, rank);
|
||||
gal_els.iter().for_each(|gal_el| {
|
||||
tmp.encrypt_sk(
|
||||
module,
|
||||
*gal_el,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
let atk_exec: AutomorphismKeyExec<Vec<u8>, B> = AutomorphismKeyExec::from(module, &tmp, scratch.borrow());
|
||||
auto_keys.insert(*gal_el, atk_exec);
|
||||
});
|
||||
|
||||
let log_batch: usize = 0;
|
||||
|
||||
let mut packer: GLWEPacker = GLWEPacker::new(module, log_batch, basek, k_ct, rank);
|
||||
|
||||
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
|
||||
ct.encrypt_sk(
|
||||
module,
|
||||
&pt,
|
||||
&sk_dft,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let log_n: usize = module.log_n();
|
||||
|
||||
(0..module.n() >> log_batch).for_each(|i| {
|
||||
ct.encrypt_sk(
|
||||
module,
|
||||
&pt,
|
||||
&sk_dft,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
pt.rotate_inplace(module, -(1 << log_batch)); // X^-batch * pt
|
||||
|
||||
if reverse_bits_msb(i, log_n as u32) % 5 == 0 {
|
||||
packer.add(module, Some(&ct), &auto_keys, scratch.borrow());
|
||||
} else {
|
||||
packer.add(
|
||||
module,
|
||||
None::<&GLWECiphertext<Vec<u8>>>,
|
||||
&auto_keys,
|
||||
scratch.borrow(),
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
let mut res = GLWECiphertext::alloc(module, basek, k_ct, rank);
|
||||
packer.flush(module, &mut res);
|
||||
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k_ct);
|
||||
let mut data: Vec<i64> = vec![0i64; module.n()];
|
||||
data.iter_mut().enumerate().for_each(|(i, x)| {
|
||||
if i % 5 == 0 {
|
||||
*x = reverse_bits_msb(i, log_n as u32) as i64;
|
||||
}
|
||||
});
|
||||
|
||||
module.encode_vec_i64(basek, &mut pt_want.data, 0, pt_k, &data, 32);
|
||||
|
||||
res.decrypt(module, &mut pt, &sk_dft, scratch.borrow());
|
||||
|
||||
pt.sub_inplace_ab(module, &pt_want);
|
||||
|
||||
let noise_have: f64 = module.vec_znx_std(basek, &pt.data, 0).log2();
|
||||
// println!("noise_have: {}", noise_have);
|
||||
assert!(
|
||||
noise_have < -((k_ct - basek) as f64),
|
||||
"noise: {}",
|
||||
noise_have
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn reverse_bits_msb(x: usize, n: u32) -> usize {
|
||||
x.reverse_bits() >> (usize::BITS - n)
|
||||
}
|
||||
152
core/src/glwe/tests/trace.rs
Normal file
152
core/src/glwe/tests/trace.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use backend::hal::{
|
||||
api::{
|
||||
MatZnxAlloc, ScalarZnxAlloc, ScalarZnxAllocBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace,
|
||||
VecZnxAlloc, VecZnxAllocBytes, VecZnxAutomorphism, VecZnxBigAutomorphismInplace, VecZnxBigSubSmallBInplace, VecZnxCopy,
|
||||
VecZnxEncodeVeci64, VecZnxFillUniform, VecZnxNormalizeInplace, VecZnxRotateInplace, VecZnxRshInplace, VecZnxStd,
|
||||
VecZnxSubABInplace, VecZnxSwithcDegree, ZnxView, ZnxViewMut,
|
||||
},
|
||||
layouts::{Backend, Module, ScratchOwned},
|
||||
oep::{
|
||||
ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
|
||||
TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
|
||||
},
|
||||
};
|
||||
use sampling::source::Source;
|
||||
|
||||
use crate::{
|
||||
AutomorphismKey, AutomorphismKeyExec, GGLWEExecLayoutFamily, GLWECiphertext, GLWEDecryptFamily, GLWEKeyswitchFamily,
|
||||
GLWEPlaintext, GLWESecret, GLWESecretExec, GLWESecretFamily, GLWESwitchingKeyEncryptSkFamily, Infos,
|
||||
noise::var_noise_gglwe_product,
|
||||
};
|
||||
|
||||
pub(crate) trait TraceTestModuleFamily<B: Backend> = GLWESecretFamily<B>
|
||||
+ GLWESwitchingKeyEncryptSkFamily<B>
|
||||
+ GLWEKeyswitchFamily<B>
|
||||
+ GLWEDecryptFamily<B>
|
||||
+ GGLWEExecLayoutFamily<B>
|
||||
+ MatZnxAlloc
|
||||
+ VecZnxAlloc
|
||||
+ ScalarZnxAlloc
|
||||
+ ScalarZnxAllocBytes
|
||||
+ VecZnxAllocBytes
|
||||
+ VecZnxStd
|
||||
+ VecZnxSwithcDegree
|
||||
+ VecZnxAddScalarInplace
|
||||
+ VecZnxEncodeVeci64
|
||||
+ VecZnxRotateInplace
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxBigAutomorphismInplace<B>
|
||||
+ VecZnxCopy
|
||||
+ VecZnxAutomorphism
|
||||
+ VecZnxRshInplace;
|
||||
|
||||
pub(crate) trait TraceTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
|
||||
+ TakeVecZnxBigImpl<B>
|
||||
+ TakeSvpPPolImpl<B>
|
||||
+ ScratchOwnedAllocImpl<B>
|
||||
+ ScratchOwnedBorrowImpl<B>
|
||||
+ ScratchAvailableImpl<B>
|
||||
+ TakeScalarZnxImpl<B>
|
||||
+ TakeVecZnxImpl<B>;
|
||||
|
||||
pub(crate) fn test_trace_inplace<B: Backend>(module: &Module<B>, basek: usize, k: usize, sigma: f64, rank: usize)
|
||||
where
|
||||
Module<B>: TraceTestModuleFamily<B>,
|
||||
B: TraceTestScratchFamily<B>,
|
||||
{
|
||||
let k_autokey: usize = k + basek;
|
||||
|
||||
let digits: usize = 1;
|
||||
let rows: usize = k.div_ceil(basek * digits);
|
||||
|
||||
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(module, basek, k, rank);
|
||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k);
|
||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(module, basek, k);
|
||||
|
||||
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(
|
||||
GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
|
||||
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
|
||||
| AutomorphismKey::encrypt_sk_scratch_space(module, basek, k_autokey, rank)
|
||||
| GLWECiphertext::trace_inplace_scratch_space(module, basek, ct.k(), k_autokey, digits, rank),
|
||||
);
|
||||
|
||||
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module, rank);
|
||||
sk.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
|
||||
|
||||
let mut data_want: Vec<i64> = vec![0i64; module.n()];
|
||||
|
||||
data_want
|
||||
.iter_mut()
|
||||
.for_each(|x| *x = source_xa.next_i64() & 0xFF);
|
||||
|
||||
module.vec_znx_fill_uniform(basek, &mut pt_have.data, 0, k, &mut source_xa);
|
||||
|
||||
ct.encrypt_sk(
|
||||
module,
|
||||
&pt_have,
|
||||
&sk_dft,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut auto_keys: HashMap<i64, AutomorphismKeyExec<Vec<u8>, B>> = HashMap::new();
|
||||
let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module);
|
||||
let mut tmp: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc(module, basek, k_autokey, rows, digits, rank);
|
||||
gal_els.iter().for_each(|gal_el| {
|
||||
tmp.encrypt_sk(
|
||||
module,
|
||||
*gal_el,
|
||||
&sk,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
sigma,
|
||||
scratch.borrow(),
|
||||
);
|
||||
let atk_exec: AutomorphismKeyExec<Vec<u8>, B> = AutomorphismKeyExec::from(module, &tmp, scratch.borrow());
|
||||
auto_keys.insert(*gal_el, atk_exec);
|
||||
});
|
||||
|
||||
ct.trace_inplace(module, 0, 5, &auto_keys, scratch.borrow());
|
||||
ct.trace_inplace(module, 5, module.log_n(), &auto_keys, scratch.borrow());
|
||||
|
||||
(0..pt_want.size()).for_each(|i| pt_want.data.at_mut(0, i)[0] = pt_have.data.at(0, i)[0]);
|
||||
|
||||
ct.decrypt(module, &mut pt_have, &sk_dft, scratch.borrow());
|
||||
|
||||
module.vec_znx_sub_ab_inplace(&mut pt_want.data, 0, &pt_have.data, 0);
|
||||
module.vec_znx_normalize_inplace(basek, &mut pt_want.data, 0, scratch.borrow());
|
||||
|
||||
let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0).log2();
|
||||
|
||||
let mut noise_want: f64 = var_noise_gglwe_product(
|
||||
module.n() as f64,
|
||||
basek,
|
||||
0.5,
|
||||
0.5,
|
||||
1.0 / 12.0,
|
||||
sigma * sigma,
|
||||
0.0,
|
||||
rank as f64,
|
||||
k,
|
||||
k_autokey,
|
||||
);
|
||||
noise_want += sigma * sigma * (-2.0 * (k) as f64).exp2();
|
||||
noise_want += module.n() as f64 * 1.0 / 12.0 * 0.5 * rank as f64 * (-2.0 * (k) as f64).exp2();
|
||||
noise_want = noise_want.sqrt().log2();
|
||||
|
||||
assert!(
|
||||
(noise_have - noise_want).abs() < 1.0,
|
||||
"{} > {}",
|
||||
noise_have,
|
||||
noise_want
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user