poulpy/rlwe/src/trace.rs
rlwe/src/trace.rsRaw
1use crate::{automorphism::AutomorphismKey, ciphertext::Ciphertext, elem::ElemCommon, parameters::Parameters};
2use base2k::{
3 Module, VecZnx, VecZnxBig, VecZnxBigOps, VecZnxDft, VecZnxDftOps, VmpPMatOps,
4 assert_alignement,
5};
6use std::collections::HashMap;
7
8pub fn trace_galois_elements(module: &Module) -> Vec<i64>{
9 let mut gal_els: Vec<i64> = Vec::new();
10 (0..module.log_n()).for_each(|i|{
11 if i == 0 {
12 gal_els.push(-1);
13 } else {
14 gal_els.push(module.galois_element(1 << (i - 1)));
15 }
16 });
17 gal_els
18}
19
20impl Parameters{
21 pub fn trace_tmp_bytes(&self, res_logq: usize, in_logq: usize, gct_logq: usize) -> usize{
22 self.automorphism_tmp_bytes(res_logq, in_logq, gct_logq)
23 }
24}
25
26pub fn trace_tmp_bytes(
27 module: &Module,
28 c_cols: usize,
29 a_cols: usize,
30 b_rows: usize,
31 b_cols: usize,
32) -> usize {
33 return module.vmp_apply_dft_to_dft_tmp_bytes(c_cols, a_cols, b_rows, b_cols)
34 + 2 * module.bytes_of_vec_znx_dft(std::cmp::min(c_cols, a_cols));
35}
36
37pub fn trace_inplace(
38 module: &Module,
39 a: &mut Ciphertext<VecZnx>,
40 start: usize,
41 end: usize,
42 b: &HashMap<i64, AutomorphismKey>,
43 b_cols: usize,
44 tmp_bytes: &mut [u8],
45) {
46 let cols: usize = a.cols();
47
48 let b_rows: usize;
49
50 if let Some((_, key)) = b.iter().next() {
51 b_rows = key.value.rows();
52 #[cfg(debug_assertions)]{
53 println!("{} {}", b_cols, key.value.cols());
54 assert!(b_cols <= key.value.cols())
55 }
56 } else {
57 panic!("b: HashMap<i64, AutomorphismKey>, is empty")
58 }
59
60 #[cfg(debug_assertions)]
61 {
62 assert!(start <= end);
63 assert!(end <= module.n());
64 assert!(tmp_bytes.len() >= trace_tmp_bytes(module, cols, cols, b_rows, b_cols));
65 assert_alignement(tmp_bytes.as_ptr());
66 }
67
68 let cols: usize = std::cmp::min(b_cols, a.cols());
69
70 let (tmp_bytes_b1_dft, tmp_bytes) = tmp_bytes.split_at_mut(module.bytes_of_vec_znx_dft(cols));
71 let (tmp_bytes_res_dft, tmp_bytes) = tmp_bytes.split_at_mut(module.bytes_of_vec_znx_dft(b_cols));
72
73 let mut a1_dft: VecZnxDft = module.new_vec_znx_dft_from_bytes_borrow(cols, tmp_bytes_b1_dft);
74 let mut res_dft: VecZnxDft = module.new_vec_znx_dft_from_bytes_borrow(b_cols, tmp_bytes_res_dft);
75 let mut res_big: VecZnxBig = res_dft.as_vec_znx_big();
76
77 let log_base2k: usize = a.log_base2k();
78
79 (start..end).for_each(|i| {
80 a.at_mut(0).rsh(log_base2k, 1, tmp_bytes);
81 a.at_mut(1).rsh(log_base2k, 1, tmp_bytes);
82
83 let p: i64;
84 if i == 0 {
85 p = -1;
86 } else {
87 p = module.galois_element(1 << (i - 1));
88 }
89
90 if let Some(key) = b.get(&p) {
91 module.vec_znx_dft(&mut a1_dft, a.at(1));
92
93 // a[0] = NORMALIZE(a[0] + AUTO(a[0] + IDFT(<DFT(a[1]), key[0]>)))
94 module.vmp_apply_dft_to_dft(&mut res_dft, &a1_dft, key.value.at(0), tmp_bytes);
95 module.vec_znx_idft_tmp_a(&mut res_big, &mut res_dft);
96 module.vec_znx_big_add_small_inplace(&mut res_big, a.at(0));
97 module.vec_znx_big_automorphism_inplace(p, &mut res_big);
98 module.vec_znx_big_add_small_inplace(&mut res_big, a.at(0));
99 module.vec_znx_big_normalize(a.log_base2k(), a.at_mut(0), &mut res_big, tmp_bytes);
100
101 // a[1] = NORMALIZE(a[1] + AUTO(IDFT(<DFT(a[1]), key[1]>)))
102 module.vmp_apply_dft_to_dft(&mut res_dft, &a1_dft, key.value.at(1), tmp_bytes);
103 module.vec_znx_idft_tmp_a(&mut res_big, &mut res_dft);
104 module.vec_znx_big_automorphism_inplace(p, &mut res_big);
105 module.vec_znx_big_add_small_inplace(&mut res_big, a.at(1));
106 module.vec_znx_big_normalize(a.log_base2k(), a.at_mut(1), &mut res_big, tmp_bytes);
107 } else {
108 panic!("b[{}] is empty", p)
109 }
110 })
111}
112
113#[cfg(test)]
114mod test {
115 use crate::{
116 automorphism::AutomorphismKey, ciphertext::{new_gadget_ciphertext, Ciphertext}, decryptor::decrypt_rlwe, elem::{Elem, ElemCommon, ElemVecZnx}, encryptor::{encrypt_grlwe_sk, encrypt_rlwe_sk}, gadget_product::gadget_product_core, keys::SecretKey, parameters::{Parameters, ParametersLiteral, DEFAULTSIGMA}, plaintext::Plaintext
117 };
118 use base2k::{
119 BACKEND, Module, Infos, Sampling, SvpPPol, SvpPPolOps, VecZnx,
120 VecZnxDftOps, VecZnxOps, VmpPMat, alloc_aligned, Encoding,
121 };
122 use sampling::source::{Source, new_seed};
123 use std::collections::HashMap;
124 use super::{trace_galois_elements, trace_inplace};
125
126 #[test]
127 fn test_trace_inplace() {
128 let log_base2k: usize = 10;
129 let log_q: usize = 50;
130 let log_p: usize = 15;
131
132 // Basic parameters with enough limbs to test edge cases
133 let params_lit: ParametersLiteral = ParametersLiteral {
134 backend: BACKEND::FFT64,
135 log_n: 12,
136 log_q: log_q,
137 log_p: log_p,
138 log_base2k: log_base2k,
139 log_scale: 20,
140 xe: 3.2,
141 xs: 1 << 11,
142 };
143
144 let params: Parameters = Parameters::new(¶ms_lit);
145
146 let module: &Module = params.module();
147 let log_q: usize = params.log_q();
148 let log_qp: usize = params.log_qp();
149 let gct_rows: usize = params.cols_q();
150 let gct_cols: usize = params.cols_qp();
151
152 // scratch space
153 let mut tmp_bytes: Vec<u8> = alloc_aligned(
154 params.decrypt_rlwe_tmp_byte(log_q)
155 | params.encrypt_rlwe_sk_tmp_bytes(log_q)
156 | params.automorphism_key_new_tmp_bytes(gct_rows, log_qp)
157 | params.automorphism_tmp_bytes(log_q, log_q, log_qp),
158 );
159
160 // Samplers for public and private randomness
161 let mut source_xe: Source = Source::new(new_seed());
162 let mut source_xa: Source = Source::new(new_seed());
163 let mut source_xs: Source = Source::new(new_seed());
164
165 let mut sk: SecretKey = SecretKey::new(module);
166 sk.fill_ternary_hw(params.xs(), &mut source_xs);
167 let mut sk_svp_ppol: SvpPPol = module.new_svp_ppol();
168 module.svp_prepare(&mut sk_svp_ppol, &sk.0);
169
170 let gal_els: Vec<i64> = trace_galois_elements(module);
171
172 let auto_keys: HashMap<i64, AutomorphismKey> = AutomorphismKey::new_many(module, &gal_els, &sk, log_base2k, gct_rows, log_qp, &mut source_xa, &mut source_xe, DEFAULTSIGMA, &mut tmp_bytes);
173
174 let mut data: Vec<i64> = vec![0i64; params.n()];
175
176 data.iter_mut().enumerate().for_each(|(i, x)| *x = 1+i as i64);
177
178 let log_k: usize = 2 * log_base2k;
179
180 let mut ct: Ciphertext<VecZnx> = params.new_ciphertext(log_q);
181 let mut pt: Plaintext = params.new_plaintext(log_q);
182
183 pt.at_mut(0).encode_vec_i64(log_base2k, log_k, &data, 32);
184 pt.at_mut(0).normalize(log_base2k, &mut tmp_bytes);
185
186 pt.at(0).decode_vec_i64(log_base2k, log_k, &mut data);
187
188 pt.at(0).print(pt.cols(), 16);
189
190 encrypt_rlwe_sk(
191 module,
192 &mut ct.elem_mut(),
193 Some(pt.elem()),
194 &sk_svp_ppol,
195 &mut source_xa,
196 &mut source_xe,
197 params.xe(),
198 &mut tmp_bytes,
199 );
200
201 trace_inplace(module, &mut ct, module.log_n()-2, module.log_n(), &auto_keys, gct_cols, & mut tmp_bytes);
202
203 // pt = dec(auto(ct)) - auto(pt)
204 decrypt_rlwe(
205 module,
206 pt.elem_mut(),
207 ct.elem(),
208 &sk_svp_ppol,
209 &mut tmp_bytes,
210 );
211
212 pt.at(0).print(pt.cols(), 16);
213
214 pt.at(0).decode_vec_i64(log_base2k, log_k, &mut data);
215
216 println!("trace: {:?}", &data[..16]);
217
218 }
219}