mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 13:16:44 +01:00
wip rlwe + some bug fixes in base2k
This commit is contained in:
77
rlwe/examples/encryption.rs
Normal file
77
rlwe/examples/encryption.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use base2k::{Encoding, FFT64, SvpPPolOps};
|
||||
use rlwe::{
|
||||
ciphertext::Ciphertext,
|
||||
decryptor::{Decryptor, decrypt_rlwe_thread_safe_tmp_byte},
|
||||
encryptor::{EncryptorSk, encrypt_rlwe_sk_tmp_bytes},
|
||||
keys::SecretKey,
|
||||
parameters::{Parameters, ParametersLiteral},
|
||||
plaintext::Plaintext,
|
||||
};
|
||||
use sampling::source::{Source, new_seed};
|
||||
|
||||
fn main() {
|
||||
let params_lit: ParametersLiteral = ParametersLiteral {
|
||||
log_n: 10,
|
||||
log_q: 54,
|
||||
log_p: 0,
|
||||
log_base2k: 17,
|
||||
log_scale: 20,
|
||||
xe: 3.2,
|
||||
xs: 128,
|
||||
};
|
||||
|
||||
let params: Parameters = Parameters::new::<FFT64>(¶ms_lit);
|
||||
|
||||
let mut tmp_bytes: Vec<u8> = vec![
|
||||
0u8;
|
||||
params.decrypt_rlwe_thread_safe_tmp_byte(params.log_q())
|
||||
| params.encrypt_rlwe_sk_tmp_bytes(params.log_q())
|
||||
];
|
||||
|
||||
let sk: SecretKey = SecretKey::new(params.module());
|
||||
|
||||
let mut want = vec![i64::default(); params.n()];
|
||||
|
||||
want.iter_mut().enumerate().for_each(|(i, x)| *x = i as i64);
|
||||
|
||||
let mut pt: Plaintext = params.new_plaintext(params.log_q() - 20);
|
||||
|
||||
let log_base2k = pt.log_base2k();
|
||||
|
||||
let log_k: usize = 17;
|
||||
|
||||
pt.0.value[0].encode_vec_i64(log_base2k, log_k, &want, 32);
|
||||
pt.0.value[0].normalize(log_base2k, &mut tmp_bytes);
|
||||
|
||||
println!("log_k: {}", log_k);
|
||||
pt.0.value[0].print_limbs(pt.limbs(), 16);
|
||||
|
||||
let mut ct: Ciphertext = params.new_ciphertext(params.log_q());
|
||||
|
||||
let mut source_xe: Source = Source::new(new_seed());
|
||||
let mut source_xa: Source = Source::new(new_seed());
|
||||
|
||||
let mut sk_svp_ppol: base2k::SvpPPol = params.module().svp_new_ppol();
|
||||
params.module().svp_prepare(&mut sk_svp_ppol, &sk.0);
|
||||
|
||||
params.encrypt_rlwe_sk_thread_safe(
|
||||
&mut ct,
|
||||
Some(&pt),
|
||||
&sk_svp_ppol,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
&mut tmp_bytes,
|
||||
);
|
||||
|
||||
params.decrypt_rlwe_thread_safe(&mut pt, &ct, &sk_svp_ppol, &mut tmp_bytes);
|
||||
|
||||
pt.0.value[0].print_limbs(pt.limbs(), 16);
|
||||
|
||||
let mut have = vec![i64::default(); params.n()];
|
||||
|
||||
println!("pt: {}", log_k);
|
||||
pt.0.value[0].decode_vec_i64(pt.log_base2k(), log_k, &mut have);
|
||||
|
||||
println!("want: {:?}", &want[..16]);
|
||||
println!("have: {:?}", &have[..16]);
|
||||
}
|
||||
@@ -1,20 +1,19 @@
|
||||
use crate::elem::Elem;
|
||||
use crate::parameters::Parameters;
|
||||
use crate::plaintext::Plaintext;
|
||||
use base2k::VecZnx;
|
||||
use base2k::{Module, VecZnx, VmpPMat, VmpPMatOps};
|
||||
|
||||
pub struct Ciphertext(pub Elem);
|
||||
|
||||
/*
|
||||
impl Parameters {
|
||||
pub fn new_ciphertext(&self, degree: usize, log_base2k: usize, log_q: usize) -> Ciphertext {
|
||||
Ciphertext(self.new_elem(degree, log_base2k, log_q))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Ciphertext {
|
||||
pub fn new(n: usize, log_base2k: usize, log_q: usize, degree: usize) -> Self {
|
||||
Self(Elem::new(n, log_base2k, log_q, degree))
|
||||
pub fn new(
|
||||
module: &Module,
|
||||
log_base2k: usize,
|
||||
log_q: usize,
|
||||
degree: usize,
|
||||
log_scale: usize,
|
||||
) -> Self {
|
||||
Self(Elem::new(module, log_base2k, log_q, degree, log_scale))
|
||||
}
|
||||
|
||||
pub fn n(&self) -> usize {
|
||||
@@ -45,7 +44,75 @@ impl Ciphertext {
|
||||
self.0.log_base2k()
|
||||
}
|
||||
|
||||
pub fn log_scale(&self) -> usize {
|
||||
self.0.log_scale
|
||||
}
|
||||
|
||||
pub fn as_plaintext(&self) -> Plaintext {
|
||||
unsafe { Plaintext(std::ptr::read(&self.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub fn new_ciphertext(&self, log_q: usize) -> Ciphertext {
|
||||
Ciphertext::new(self.module(), self.log_base2k(), log_q, self.log_scale(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GadgetCiphertext {
|
||||
pub value: Vec<VmpPMat>,
|
||||
pub log_base2k: usize,
|
||||
pub log_q: usize,
|
||||
pub log_scale: usize,
|
||||
}
|
||||
|
||||
impl GadgetCiphertext {
|
||||
pub fn new(
|
||||
module: &Module,
|
||||
log_base2k: usize,
|
||||
rows: usize,
|
||||
log_q: usize,
|
||||
log_scale: usize,
|
||||
) -> Self {
|
||||
let cols: usize = (log_q + log_base2k - 1) / log_base2k;
|
||||
let mut value: Vec<VmpPMat> = Vec::new();
|
||||
(0..rows).for_each(|_| value.push(module.new_vmp_pmat(rows, cols)));
|
||||
Self {
|
||||
value,
|
||||
log_base2k,
|
||||
log_q,
|
||||
log_scale,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn n(&self) -> usize {
|
||||
self.value[0].n
|
||||
}
|
||||
|
||||
pub fn rows(&self) -> usize {
|
||||
self.value[0].rows
|
||||
}
|
||||
|
||||
pub fn cols(&self) -> usize {
|
||||
self.value[0].cols
|
||||
}
|
||||
|
||||
pub fn degree(&self) -> usize {
|
||||
self.value.len() - 1
|
||||
}
|
||||
|
||||
pub fn log_q(&self) -> usize {
|
||||
self.log_q
|
||||
}
|
||||
|
||||
pub fn log_base2k(&self) -> usize {
|
||||
self.log_base2k
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RGSWCiphertext {
|
||||
pub value: [GadgetCiphertext; 2],
|
||||
pub log_base2k: usize,
|
||||
pub log_q: usize,
|
||||
pub log_p: usize,
|
||||
}
|
||||
|
||||
80
rlwe/src/decryptor.rs
Normal file
80
rlwe/src/decryptor.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use crate::{
|
||||
ciphertext::Ciphertext, keys::SecretKey, parameters::Parameters, plaintext::Plaintext,
|
||||
};
|
||||
use base2k::{Module, SvpPPol, SvpPPolOps, VecZnxDft};
|
||||
use std::cmp::min;
|
||||
|
||||
pub struct Decryptor {
|
||||
sk: SvpPPol,
|
||||
}
|
||||
|
||||
impl Decryptor {
|
||||
pub fn new(params: &Parameters, sk: &SecretKey) -> Self {
|
||||
let mut sk_svp_ppol: SvpPPol = params.module().svp_new_ppol();
|
||||
sk.prepare(params.module(), &mut sk_svp_ppol);
|
||||
Self { sk: sk_svp_ppol }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt_rlwe_thread_safe_tmp_byte(module: &Module, limbs: usize) -> usize {
|
||||
module.bytes_of_vec_znx_dft(limbs) + module.vec_znx_big_normalize_tmp_bytes()
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub fn decrypt_rlwe_thread_safe_tmp_byte(&self, log_q: usize) -> usize {
|
||||
decrypt_rlwe_thread_safe_tmp_byte(
|
||||
self.module(),
|
||||
(log_q + self.log_base2k() - 1) / self.log_base2k(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn decrypt_rlwe_thread_safe(
|
||||
&self,
|
||||
res: &mut Plaintext,
|
||||
ct: &Ciphertext,
|
||||
sk: &SvpPPol,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
decrypt_rlwe_thread_safe(self.module(), res, ct, sk, tmp_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt_rlwe_thread_safe(
|
||||
module: &Module,
|
||||
res: &mut Plaintext,
|
||||
ct: &Ciphertext,
|
||||
sk: &SvpPPol,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
let limbs: usize = min(res.limbs(), ct.limbs());
|
||||
|
||||
assert!(
|
||||
tmp_bytes.len() >= decrypt_rlwe_thread_safe_tmp_byte(module, limbs),
|
||||
"invalid tmp_bytes: tmp_bytes.len()={} < decrypt_rlwe_thread_safe_tmp_byte={}",
|
||||
tmp_bytes.len(),
|
||||
decrypt_rlwe_thread_safe_tmp_byte(module, limbs)
|
||||
);
|
||||
|
||||
let res_dft_bytes: usize = module.bytes_of_vec_znx_dft(limbs);
|
||||
|
||||
let mut res_dft: VecZnxDft = VecZnxDft::from_bytes(limbs, tmp_bytes);
|
||||
let mut res_big: base2k::VecZnxBig = res_dft.as_vec_znx_big();
|
||||
|
||||
// res_dft <- DFT(ct[1]) * DFT(sk)
|
||||
module.svp_apply_dft(&mut res_dft, sk, &ct.0.value[1], limbs);
|
||||
// res_big <- ct[1] x sk
|
||||
module.vec_znx_idft_tmp_a(&mut res_big, &mut res_dft, limbs);
|
||||
// res_big <- ct[1] x sk + ct[0]
|
||||
module.vec_znx_big_add_small_inplace(&mut res_big, &ct.0.value[0], limbs);
|
||||
// res <- normalize(ct[1] x sk + ct[0])
|
||||
module.vec_znx_big_normalize(
|
||||
ct.log_base2k(),
|
||||
res.at_mut(0),
|
||||
&res_big,
|
||||
&mut tmp_bytes[res_dft_bytes..],
|
||||
);
|
||||
|
||||
res.0.log_base2k = ct.log_base2k();
|
||||
res.0.log_q = min(res.log_q(), ct.log_q());
|
||||
res.0.log_scale = ct.log_scale();
|
||||
}
|
||||
@@ -1,21 +1,59 @@
|
||||
use crate::parameters::Parameters;
|
||||
use base2k::{Infos, VecZnx};
|
||||
use base2k::{Infos, Module, VecZnx, VecZnxOps};
|
||||
|
||||
pub struct Elem {
|
||||
pub value: Vec<VecZnx>,
|
||||
pub log_base2k: usize,
|
||||
pub log_q: usize,
|
||||
pub log_scale: usize,
|
||||
}
|
||||
|
||||
impl Elem {
|
||||
pub fn new(n: usize, log_base2k: usize, log_q: usize, degree: usize) -> Self {
|
||||
pub fn new(
|
||||
module: &Module,
|
||||
log_base2k: usize,
|
||||
log_q: usize,
|
||||
degree: usize,
|
||||
log_scale: usize,
|
||||
) -> Self {
|
||||
let limbs: usize = (log_q + log_base2k - 1) / log_base2k;
|
||||
let mut value: Vec<VecZnx> = Vec::new();
|
||||
(0..degree + 1).for_each(|_| value.push(VecZnx::new(n, limbs)));
|
||||
(0..degree + 1).for_each(|_| value.push(module.new_vec_znx(limbs)));
|
||||
Self {
|
||||
value,
|
||||
log_base2k,
|
||||
log_q,
|
||||
log_base2k,
|
||||
log_scale: log_scale,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes_of(module: &Module, log_base2k: usize, log_q: usize, degree: usize) -> usize {
|
||||
let cols = (log_q + log_base2k - 1) / log_base2k;
|
||||
module.n() * cols * (degree + 1) * 8
|
||||
}
|
||||
|
||||
pub fn from_bytes(
|
||||
module: &Module,
|
||||
log_base2k: usize,
|
||||
log_q: usize,
|
||||
degree: usize,
|
||||
bytes: &mut [u8],
|
||||
) -> Self {
|
||||
let n: usize = module.n();
|
||||
assert!(bytes.len() >= Self::bytes_of(module, log_base2k, log_q, degree));
|
||||
let mut value: Vec<VecZnx> = Vec::new();
|
||||
let limbs: usize = (log_q + log_base2k - 1) / log_base2k;
|
||||
let size = VecZnx::bytes(n, limbs);
|
||||
let mut ptr: usize = 0;
|
||||
(0..degree + 1).for_each(|_| {
|
||||
value.push(VecZnx::from_bytes(n, limbs, &mut bytes[ptr..]));
|
||||
ptr += size
|
||||
});
|
||||
Self {
|
||||
value,
|
||||
log_q,
|
||||
log_base2k,
|
||||
log_scale: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +73,10 @@ impl Elem {
|
||||
self.log_base2k
|
||||
}
|
||||
|
||||
pub fn log_scale(&self) -> usize {
|
||||
self.log_scale
|
||||
}
|
||||
|
||||
pub fn log_q(&self) -> usize {
|
||||
self.log_q
|
||||
}
|
||||
@@ -49,3 +91,13 @@ impl Elem {
|
||||
&mut self.value[i]
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub fn bytes_of_elem(&self, log_q: usize, degree: usize) -> usize {
|
||||
Elem::bytes_of(self.module(), self.log_base2k(), log_q, degree)
|
||||
}
|
||||
|
||||
pub fn elem_from_bytes(&self, log_q: usize, degree: usize, bytes: &mut [u8]) -> Elem {
|
||||
Elem::from_bytes(self.module(), self.log_base2k(), log_q, degree, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +1,141 @@
|
||||
use crate::ciphertext::Ciphertext;
|
||||
use crate::ciphertext::{Ciphertext, GadgetCiphertext};
|
||||
use crate::elem::Elem;
|
||||
use crate::keys::SecretKey;
|
||||
use crate::parameters::Parameters;
|
||||
use crate::plaintext::Plaintext;
|
||||
use base2k::ffi::znx::znx_zero_i64_ref;
|
||||
use base2k::sampling::Sampling;
|
||||
use base2k::{Module, SvpPPol, SvpPPolOps, VecZnx, VecZnxBig, VecZnxDft};
|
||||
use sampling::source::Source;
|
||||
use base2k::{
|
||||
Module, Scalar, SvpPPol, SvpPPolOps, VecZnx, VecZnxBig, VecZnxDft, VecZnxOps, VmpPMatOps,
|
||||
};
|
||||
use sampling::source::{Source, new_seed};
|
||||
|
||||
pub struct EncryptorSk {
|
||||
pub sk: SvpPPol,
|
||||
sk: SvpPPol,
|
||||
source_xa: Source,
|
||||
source_xe: Source,
|
||||
initialized: bool,
|
||||
tmp_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl EncryptorSk {
|
||||
pub fn new(params: &Parameters, sk: &SecretKey) -> Self {
|
||||
pub fn new(params: &Parameters, sk: Option<&SecretKey>) -> Self {
|
||||
let mut sk_svp_ppol: SvpPPol = params.module().svp_new_ppol();
|
||||
params.module().svp_prepare(&mut sk_svp_ppol, &sk.0);
|
||||
Self { sk: sk_svp_ppol }
|
||||
let mut initialized: bool = false;
|
||||
if let Some(sk) = sk {
|
||||
sk.prepare(params.module(), &mut sk_svp_ppol);
|
||||
initialized = true;
|
||||
}
|
||||
Self {
|
||||
sk: sk_svp_ppol,
|
||||
initialized,
|
||||
source_xa: Source::new(new_seed()),
|
||||
source_xe: Source::new(new_seed()),
|
||||
tmp_bytes: vec![0u8; params.encrypt_rlwe_sk_tmp_bytes(params.limbs_qp())],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_sk(&mut self, module: &Module, sk: &SecretKey) {
|
||||
sk.prepare(module, &mut self.sk);
|
||||
self.initialized = true;
|
||||
}
|
||||
|
||||
pub fn seed_source_xa(&mut self, seed: [u8; 32]) {
|
||||
self.source_xa = Source::new(seed)
|
||||
}
|
||||
|
||||
pub fn seed_source_xe(&mut self, seed: [u8; 32]) {
|
||||
self.source_xe = Source::new(seed)
|
||||
}
|
||||
|
||||
pub fn encrypt_rlwe_sk(
|
||||
&mut self,
|
||||
params: &Parameters,
|
||||
ct: &mut Ciphertext,
|
||||
pt: Option<&Plaintext>,
|
||||
) {
|
||||
assert!(
|
||||
self.initialized == true,
|
||||
"invalid call to [EncryptorSk.encrypt_rlwe_sk]: [EncryptorSk] has not been initialized with a [SecretKey]"
|
||||
);
|
||||
params.encrypt_rlwe_sk_thread_safe(
|
||||
ct,
|
||||
pt,
|
||||
&self.sk,
|
||||
&mut self.source_xa,
|
||||
&mut self.source_xe,
|
||||
&mut self.tmp_bytes,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn encrypt_rlwe_sk_thread_safe(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
ct: &mut Ciphertext,
|
||||
pt: Option<&Plaintext>,
|
||||
xa_source: &mut Source,
|
||||
xe_source: &mut Source,
|
||||
source_xa: &mut Source,
|
||||
source_xe: &mut Source,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
params.encrypt_rlwe_sk(ct, pt, &self.sk, xa_source, xe_source, tmp_bytes);
|
||||
assert!(
|
||||
self.initialized == true,
|
||||
"invalid call to [EncryptorSk.encrypt_rlwe_sk_thread_safe]: [EncryptorSk] has not been initialized with a [SecretKey]"
|
||||
);
|
||||
params.encrypt_rlwe_sk_thread_safe(ct, pt, &self.sk, source_xa, source_xe, tmp_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub fn encrypt_rlwe_sk_tmp_bytes(&self, limbs: usize) -> usize {
|
||||
encrypt_rlwe_sk_tmp_bytes(self.module(), limbs)
|
||||
pub fn encrypt_rlwe_sk_tmp_bytes(&self, log_q: usize) -> usize {
|
||||
encrypt_rlwe_sk_tmp_bytes(self.module(), self.log_base2k(), log_q)
|
||||
}
|
||||
|
||||
pub fn encrypt_rlwe_sk(
|
||||
pub fn encrypt_rlwe_sk_thread_safe(
|
||||
&self,
|
||||
ct: &mut Ciphertext,
|
||||
pt: Option<&Plaintext>,
|
||||
sk: &SvpPPol,
|
||||
xa_source: &mut Source,
|
||||
xe_source: &mut Source,
|
||||
source_xa: &mut Source,
|
||||
source_xe: &mut Source,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
encrypt_rlwe_sk(
|
||||
encrypt_rlwe_sk_thread_safe(
|
||||
self.module(),
|
||||
&mut ct.0,
|
||||
pt.map(|pt| &pt.0),
|
||||
sk,
|
||||
xa_source,
|
||||
xe_source,
|
||||
source_xa,
|
||||
source_xe,
|
||||
self.xe(),
|
||||
tmp_bytes,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encrypt_rlwe_sk_tmp_bytes(module: &Module, limbs: usize) -> usize {
|
||||
module.bytes_of_vec_znx_dft(limbs) + module.vec_znx_big_normalize_tmp_bytes()
|
||||
pub fn encrypt_rlwe_sk_tmp_bytes(module: &Module, log_base2k: usize, log_q: usize) -> usize {
|
||||
module.bytes_of_vec_znx_dft((log_q + log_base2k - 1) / log_base2k)
|
||||
+ module.vec_znx_big_normalize_tmp_bytes()
|
||||
}
|
||||
|
||||
pub fn encrypt_rlwe_sk(
|
||||
pub fn encrypt_rlwe_sk_thread_safe(
|
||||
module: &Module,
|
||||
ct: &mut Elem,
|
||||
pt: Option<&Elem>,
|
||||
sk: &SvpPPol,
|
||||
xa_source: &mut Source,
|
||||
xe_source: &mut Source,
|
||||
source_xa: &mut Source,
|
||||
source_xe: &mut Source,
|
||||
sigma: f64,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
let limbs: usize = ct.limbs();
|
||||
let log_base2k: usize = ct.log_base2k();
|
||||
let log_q: usize = ct.log_q();
|
||||
|
||||
assert!(
|
||||
tmp_bytes.len() >= encrypt_rlwe_sk_tmp_bytes(module, limbs),
|
||||
tmp_bytes.len() >= encrypt_rlwe_sk_tmp_bytes(module, log_base2k, log_q),
|
||||
"invalid tmp_bytes: tmp_bytes={} < encrypt_rlwe_sk_tmp_bytes={}",
|
||||
tmp_bytes.len(),
|
||||
encrypt_rlwe_sk_tmp_bytes(module, limbs)
|
||||
encrypt_rlwe_sk_tmp_bytes(module, log_base2k, log_q)
|
||||
);
|
||||
|
||||
let log_q: usize = ct.log_q();
|
||||
@@ -86,7 +143,7 @@ pub fn encrypt_rlwe_sk(
|
||||
let c1: &mut VecZnx = ct.at_mut(1);
|
||||
|
||||
// c1 <- Z_{2^prec}[X]/(X^{N}+1)
|
||||
c1.fill_uniform(limbs, log_base2k, xa_source);
|
||||
c1.fill_uniform(log_base2k, limbs, source_xa);
|
||||
|
||||
let bytes_of_vec_znx_dft = module.bytes_of_vec_znx_dft(limbs);
|
||||
|
||||
@@ -95,7 +152,7 @@ pub fn encrypt_rlwe_sk(
|
||||
VecZnxDft::from_bytes(limbs, &mut tmp_bytes[..bytes_of_vec_znx_dft]);
|
||||
|
||||
// Applies buf_dft <- s * c1
|
||||
module.svp_apply_dft(&mut buf_dft, sk, c1);
|
||||
module.svp_apply_dft(&mut buf_dft, sk, c1, limbs);
|
||||
|
||||
// Alias scratch space
|
||||
let mut buf_big: VecZnxBig = buf_dft.as_vec_znx_big();
|
||||
@@ -110,5 +167,90 @@ pub fn encrypt_rlwe_sk(
|
||||
// c0 <- normalize(buf_big) + e
|
||||
let c0: &mut VecZnx = ct.at_mut(0);
|
||||
module.vec_znx_big_normalize(log_base2k, c0, &buf_big, carry);
|
||||
c0.add_normal(log_base2k, log_q, xe_source, sigma, (sigma * 6.0).ceil());
|
||||
c0.add_normal(log_base2k, log_q, source_xe, sigma, (sigma * 6.0).ceil());
|
||||
}
|
||||
|
||||
pub fn encrypt_grlwe_sk_tmp_bytes(
|
||||
module: &Module,
|
||||
log_base2k: usize,
|
||||
rows: usize,
|
||||
log_q: usize,
|
||||
) -> usize {
|
||||
let cols = (log_q + log_base2k - 1) / log_base2k;
|
||||
Elem::bytes_of(module, log_base2k, log_q, 1)
|
||||
+ Plaintext::bytes_of(module, log_base2k, log_q)
|
||||
+ encrypt_rlwe_sk_tmp_bytes(module, log_base2k, log_q)
|
||||
+ module.vmp_prepare_tmp_bytes(rows, cols)
|
||||
}
|
||||
|
||||
pub fn encrypt_grlwe_sk_thread_safe(
|
||||
module: &Module,
|
||||
ct: &mut GadgetCiphertext,
|
||||
m: &Scalar,
|
||||
sk: &SvpPPol,
|
||||
source_xa: &mut Source,
|
||||
source_xe: &mut Source,
|
||||
sigma: f64,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
let rows: usize = ct.rows();
|
||||
let log_q: usize = ct.log_q();
|
||||
let log_base2k: usize = ct.log_base2k();
|
||||
|
||||
let min_tmp_bytes_len = encrypt_grlwe_sk_tmp_bytes(module, log_base2k, rows, log_q);
|
||||
|
||||
assert!(
|
||||
tmp_bytes.len() >= min_tmp_bytes_len,
|
||||
"invalid tmp_bytes: tmp_bytes.len()={} < encrypt_grlwe_sk_tmp_bytes={}",
|
||||
tmp_bytes.len(),
|
||||
min_tmp_bytes_len
|
||||
);
|
||||
|
||||
let mut ptr: usize = 0;
|
||||
let mut tmp_elem: Elem = Elem::from_bytes(module, log_base2k, ct.log_q(), 1, tmp_bytes);
|
||||
let bytes_of_elem: usize = Elem::bytes_of(module, log_base2k, log_q, 1);
|
||||
ptr += bytes_of_elem;
|
||||
|
||||
let mut tmp_pt: Plaintext =
|
||||
Plaintext::from_bytes(module, log_base2k, log_q, &mut tmp_bytes[ptr..]);
|
||||
ptr += Plaintext::bytes_of(module, log_base2k, log_q);
|
||||
|
||||
let (tmp_bytes_encrypt_sk, tmp_bytes_vmp_prepare_row) =
|
||||
tmp_bytes[ptr..].split_at_mut(encrypt_rlwe_sk_tmp_bytes(module, log_base2k, log_q));
|
||||
|
||||
(0..rows).for_each(|row_i| {
|
||||
// Sets the i-th row of the RLWE sample to m (i.e. m * 2^{-log_base2k*i})
|
||||
tmp_pt.0.value[0].at_mut(row_i).copy_from_slice(&m.0);
|
||||
|
||||
// Encrypts RLWE(m * 2^{-log_base2k*i})
|
||||
encrypt_rlwe_sk_thread_safe(
|
||||
module,
|
||||
&mut tmp_elem,
|
||||
Some(&tmp_pt.0),
|
||||
sk,
|
||||
source_xa,
|
||||
source_xe,
|
||||
sigma,
|
||||
tmp_bytes_encrypt_sk,
|
||||
);
|
||||
|
||||
// Zeroes the ith-row of tmp_pt
|
||||
tmp_pt.0.value[0].at_mut(row_i).fill(0);
|
||||
|
||||
// GRLWE[row_i][0] = -as + m * 2^{-i*log_base2k} + e*2^{-log_q}
|
||||
module.vmp_prepare_row(
|
||||
&mut ct.value[0],
|
||||
tmp_elem.at(0),
|
||||
row_i,
|
||||
tmp_bytes_vmp_prepare_row,
|
||||
);
|
||||
|
||||
// GRLWE[row_i][1] = a
|
||||
module.vmp_prepare_row(
|
||||
&mut ct.value[1],
|
||||
tmp_elem.at(1),
|
||||
row_i,
|
||||
tmp_bytes_vmp_prepare_row,
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
82
rlwe/src/evaluator.rs
Normal file
82
rlwe/src/evaluator.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
use crate::ciphertext::{Ciphertext, GadgetCiphertext};
|
||||
use base2k::{Module, VecZnxBig, VecZnxDft, VmpPMatOps};
|
||||
|
||||
pub fn gadget_product_tmp_bytes(
|
||||
module: &Module,
|
||||
log_base2k: usize,
|
||||
out_log_q: usize,
|
||||
in_log_q: usize,
|
||||
gct_rows: usize,
|
||||
gct_log_q: usize,
|
||||
) -> usize {
|
||||
let gct_cols: usize = (gct_log_q + log_base2k - 1) / log_base2k;
|
||||
let in_limbs: usize = (in_log_q + log_base2k - 1) / log_base2k;
|
||||
let out_limbs: usize = (out_log_q + log_base2k - 1) / log_base2k;
|
||||
module.vmp_apply_dft_to_dft_tmp_bytes(out_limbs, in_limbs, gct_rows, gct_cols)
|
||||
+ 2 * module.bytes_of_vec_znx_dft(gct_cols)
|
||||
}
|
||||
|
||||
pub fn gadget_product_inplace(
|
||||
module: &Module,
|
||||
a: &mut Ciphertext,
|
||||
b: &GadgetCiphertext,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
// This is safe to do because the relevant values of a are copied to a buffer before being
|
||||
// overwritten.
|
||||
unsafe {
|
||||
let a_ptr: *mut Ciphertext = a;
|
||||
gadget_product(module, a, &*a_ptr, b, tmp_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gadget_product(
|
||||
module: &Module,
|
||||
res: &mut Ciphertext,
|
||||
a: &Ciphertext,
|
||||
b: &GadgetCiphertext,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
assert!(
|
||||
a.log_base2k() == b.log_base2k(),
|
||||
"invalid inputs: a.log_base2k={} != b.log_base2k={}",
|
||||
a.log_base2k(),
|
||||
b.log_base2k()
|
||||
);
|
||||
|
||||
let log_base2k: usize = b.log_base2k();
|
||||
let cols: usize = b.cols();
|
||||
|
||||
let (tmp_bytes_vmp_apply_dft, tmp_bytes) =
|
||||
tmp_bytes.split_at_mut(module.bytes_of_vec_znx_dft(cols));
|
||||
|
||||
let (tmp_bytes_c1_dft, tmp_bytes_res_dft) = tmp_bytes.split_at_mut(tmp_bytes.len() >> 1);
|
||||
|
||||
let mut c1_dft: VecZnxDft = module.new_vec_znx_from_bytes(cols, tmp_bytes_c1_dft);
|
||||
let mut res_dft: VecZnxDft = module.new_vec_znx_from_bytes(cols, tmp_bytes_res_dft);
|
||||
let mut res_big: VecZnxBig = res_dft.as_vec_znx_big();
|
||||
|
||||
// c1_dft <- DFT(b[1])
|
||||
module.vec_znx_dft(&mut c1_dft, a.at(1), a.limbs());
|
||||
|
||||
// res_dft <- DFT(c1) x GadgetCiphertext[0]
|
||||
module.vmp_apply_dft_to_dft(&mut res_dft, &c1_dft, &b.value[0], tmp_bytes_vmp_apply_dft);
|
||||
|
||||
// res_big <- IDFT(DFT(c1) x GadgetCiphertext[0])
|
||||
module.vec_znx_idft_tmp_a(&mut res_big, &mut res_dft, cols);
|
||||
|
||||
// res_big <- c0 + c1_dft x GadgetCiphertext[0]
|
||||
module.vec_znx_big_add_small_inplace(&mut res_big, a.at(0), cols);
|
||||
|
||||
// res[0] = normalize(c0 + c1_dft x GadgetCiphertext[0])
|
||||
module.vec_znx_big_normalize(log_base2k, res.at_mut(0), &res_big, tmp_bytes_vmp_apply_dft);
|
||||
|
||||
// res_dft <- DFT(c1) x GadgetCiphertext[1]
|
||||
module.vmp_apply_dft_to_dft(&mut res_dft, &c1_dft, &b.value[1], tmp_bytes_vmp_apply_dft);
|
||||
|
||||
// res_big <- IDFT(DFT(c1) x GadgetCiphertext[1])
|
||||
module.vec_znx_idft_tmp_a(&mut res_big, &mut res_dft, cols);
|
||||
|
||||
// res[1] = normalize(c1_dft x GadgetCiphertext[1])
|
||||
module.vec_znx_big_normalize(log_base2k, res.at_mut(1), &res_big, tmp_bytes_vmp_apply_dft);
|
||||
}
|
||||
@@ -1 +1,53 @@
|
||||
use crate::keys::{PublicKey, SecretKey, SwitchingKey};
|
||||
use crate::parameters::Parameters;
|
||||
use base2k::SvpPPol;
|
||||
use sampling::source::Source;
|
||||
|
||||
pub struct KeyGenerator {}
|
||||
|
||||
impl KeyGenerator {
|
||||
pub fn gen_secret_key_thread_safe(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
source: &mut Source,
|
||||
) -> SecretKey {
|
||||
let mut sk: SecretKey = SecretKey::new(params.module());
|
||||
sk.fill_ternary_hw(params.xs(), source);
|
||||
sk
|
||||
}
|
||||
|
||||
pub fn gen_public_key_thread_safe(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
sk_ppol: &SvpPPol,
|
||||
source: &mut Source,
|
||||
tmp_bytes: &mut [u8],
|
||||
) -> PublicKey {
|
||||
let mut xa_source: Source = source.branch();
|
||||
let mut xe_source: Source = source.branch();
|
||||
let mut pk: PublicKey =
|
||||
PublicKey::new(params.module(), params.log_base2k(), params.log_qp());
|
||||
pk.gen_thread_safe(
|
||||
params.module(),
|
||||
sk_ppol,
|
||||
params.xe(),
|
||||
&mut xa_source,
|
||||
&mut xe_source,
|
||||
tmp_bytes,
|
||||
);
|
||||
pk
|
||||
}
|
||||
|
||||
pub fn gen_switching_key(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
sk_in: &SecretKey,
|
||||
sk_out: &SecretKey,
|
||||
rows: usize,
|
||||
log_q: usize,
|
||||
) -> SwitchingKey {
|
||||
let swk = SwitchingKey::new(params.module(), params.log_base2k(), rows, log_q, 0);
|
||||
|
||||
swk
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,86 @@
|
||||
use crate::ciphertext::GadgetCiphertext;
|
||||
use crate::elem::Elem;
|
||||
use crate::encryptor::{encrypt_rlwe_sk, encrypt_rlwe_sk_tmp_bytes};
|
||||
use crate::encryptor::{encrypt_rlwe_sk_thread_safe, encrypt_rlwe_sk_tmp_bytes};
|
||||
use crate::parameters::Parameters;
|
||||
use base2k::{Module, Sampling, Scalar, SvpPPol, SvpPPolOps, VecZnx};
|
||||
use base2k::{Module, Scalar, SvpPPol, SvpPPolOps, VmpPMat, VmpPMatOps};
|
||||
use sampling::source::Source;
|
||||
|
||||
pub struct SecretKey(pub Scalar);
|
||||
|
||||
impl SecretKey {
|
||||
pub fn new_ternary_prob(module: &Module, limbs: usize, prob: f64, source: &mut Source) -> Self {
|
||||
let mut sk: Scalar = Scalar::new(module.n());
|
||||
sk.fill_ternary_prob(prob, source);
|
||||
SecretKey(sk)
|
||||
pub fn new(params: &Module) -> Self {
|
||||
SecretKey(Scalar::new(params.n()))
|
||||
}
|
||||
|
||||
pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) {
|
||||
self.0.fill_ternary_prob(prob, source);
|
||||
}
|
||||
|
||||
pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) {
|
||||
self.0.fill_ternary_hw(hw, source);
|
||||
}
|
||||
|
||||
pub fn prepare(&self, module: &Module, sk_ppol: &mut SvpPPol) {
|
||||
module.svp_prepare(sk_ppol, &self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PublicKey(pub Elem);
|
||||
|
||||
impl PublicKey {
|
||||
pub fn new(
|
||||
params: &Parameters,
|
||||
pub fn new(module: &Module, log_base2k: usize, log_q: usize) -> PublicKey {
|
||||
PublicKey(Elem::new(module, log_base2k, log_q, 1, 0))
|
||||
}
|
||||
|
||||
pub fn gen_thread_safe(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
sk: &SvpPPol,
|
||||
xe: f64,
|
||||
xa_source: &mut Source,
|
||||
xe_source: &mut Source,
|
||||
tmp_bytes: &mut [u8],
|
||||
) -> Self {
|
||||
let mut pk: Elem = Elem::new(params.n(), params.log_base2k(), params.log_qp(), 1);
|
||||
encrypt_rlwe_sk(
|
||||
params.module(),
|
||||
&mut pk,
|
||||
) {
|
||||
encrypt_rlwe_sk_thread_safe(
|
||||
module,
|
||||
&mut self.0,
|
||||
None,
|
||||
sk,
|
||||
xa_source,
|
||||
xe_source,
|
||||
params.xe(),
|
||||
xe,
|
||||
tmp_bytes,
|
||||
);
|
||||
PublicKey(pk)
|
||||
}
|
||||
|
||||
pub fn new_tmp_bytes(params: &Parameters) -> usize {
|
||||
encrypt_rlwe_sk_tmp_bytes(params.module(), params.limbs_qp())
|
||||
pub fn gen_thread_safe_tmp_bytes(module: &Module, log_base2k: usize, log_q: usize) -> usize {
|
||||
encrypt_rlwe_sk_tmp_bytes(module, log_base2k, log_q)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SwitchingKey(GadgetCiphertext);
|
||||
|
||||
impl SwitchingKey {
|
||||
pub fn new(
|
||||
module: &Module,
|
||||
log_base2k: usize,
|
||||
rows: usize,
|
||||
log_q: usize,
|
||||
log_scale: usize,
|
||||
) -> SwitchingKey {
|
||||
SwitchingKey(GadgetCiphertext::new(
|
||||
module, log_base2k, rows, log_q, log_scale,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn gen_thread_safe(
|
||||
&mut self,
|
||||
params: &mut Parameters,
|
||||
sk_in: &SvpPPol,
|
||||
sk_out: &SvpPPol,
|
||||
xa_source: &mut Source,
|
||||
xe_source: &mut Source,
|
||||
tmp_bytes: &mut [u8],
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pub mod ciphertext;
|
||||
pub mod decryptor;
|
||||
pub mod elem;
|
||||
pub mod encryptor;
|
||||
pub mod evaluator;
|
||||
pub mod key_generator;
|
||||
pub mod keys;
|
||||
pub mod parameters;
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
use crate::ciphertext::Ciphertext;
|
||||
use crate::elem::Elem;
|
||||
use base2k::VecZnx;
|
||||
use crate::parameters::Parameters;
|
||||
use base2k::{Module, VecZnx};
|
||||
|
||||
pub struct Plaintext(pub Elem);
|
||||
|
||||
/*
|
||||
impl Parameters {
|
||||
pub fn new_plaintext(&self, log_q: usize) -> Plaintext {
|
||||
Plaintext(self.new_elem(0, log_q))
|
||||
Plaintext::new(self.module(), self.log_base2k(), log_q, self.log_scale())
|
||||
}
|
||||
|
||||
pub fn bytes_of_plaintext(&self, log_q: usize) -> usize {
|
||||
Elem::bytes_of(self.module(), self.log_base2k(), log_q, 0)
|
||||
}
|
||||
|
||||
pub fn plaintext_from_bytes(&self, log_q: usize, bytes: &mut [u8]) -> Plaintext {
|
||||
Plaintext(self.elem_from_bytes(log_q, 0, bytes))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Plaintext {
|
||||
pub fn new(n: usize, log_base2k: usize, log_q: usize) -> Self {
|
||||
Self(Elem::new(n, log_base2k, log_q, 0))
|
||||
pub fn new(module: &Module, log_base2k: usize, log_q: usize, log_scale: usize) -> Self {
|
||||
Self(Elem::new(module, log_base2k, log_q, 0, log_scale))
|
||||
}
|
||||
|
||||
pub fn bytes_of(module: &Module, log_base2k: usize, log_q: usize) -> usize {
|
||||
Elem::bytes_of(module, log_base2k, log_q, 0)
|
||||
}
|
||||
|
||||
pub fn from_bytes(module: &Module, log_base2k: usize, log_q: usize, bytes: &mut [u8]) -> Self {
|
||||
Self(Elem::from_bytes(module, log_base2k, log_q, 0, bytes))
|
||||
}
|
||||
|
||||
pub fn n(&self) -> usize {
|
||||
@@ -45,6 +60,10 @@ impl Plaintext {
|
||||
self.0.log_base2k()
|
||||
}
|
||||
|
||||
pub fn log_scale(&self) -> usize {
|
||||
self.0.log_scale()
|
||||
}
|
||||
|
||||
pub fn as_ciphertext(&self) -> Ciphertext {
|
||||
unsafe { Ciphertext(std::ptr::read(&self.0)) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user