poulpy/core/src/gglwe_ciphertext.rs
core/src/gglwe_ciphertext.rsRaw
1use backend::{
2 Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, Module, ScalarZnx, Scratch, VecZnxAlloc, VecZnxDftAlloc, VecZnxOps,
3 ZnxInfos, ZnxZero,
4};
5use sampling::source::Source;
6
7use crate::{
8 elem::{GetRow, Infos, SetRow},
9 glwe_ciphertext::GLWECiphertext,
10 glwe_ciphertext_fourier::GLWECiphertextFourier,
11 glwe_plaintext::GLWEPlaintext,
12 keys::SecretKeyFourier,
13 utils::derive_size,
14};
15
16pub struct GGLWECiphertext<C, B: Backend> {
17 pub(crate) data: MatZnxDft<C, B>,
18 pub(crate) basek: usize,
19 pub(crate) k: usize,
20}
21
22impl<B: Backend> GGLWECiphertext<Vec<u8>, B> {
23 pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, rank_in: usize, rank_out: usize) -> Self {
24 Self {
25 data: module.new_mat_znx_dft(rows, rank_in, rank_out + 1, derive_size(basek, k)),
26 basek: basek,
27 k,
28 }
29 }
30}
31
32impl<T, B: Backend> Infos for GGLWECiphertext<T, B> {
33 type Inner = MatZnxDft<T, B>;
34
35 fn inner(&self) -> &Self::Inner {
36 &self.data
37 }
38
39 fn basek(&self) -> usize {
40 self.basek
41 }
42
43 fn k(&self) -> usize {
44 self.k
45 }
46}
47
48impl<T, B: Backend> GGLWECiphertext<T, B> {
49 pub fn rank(&self) -> usize {
50 self.data.cols_out() - 1
51 }
52
53 pub fn rank_in(&self) -> usize {
54 self.data.cols_in()
55 }
56
57 pub fn rank_out(&self) -> usize {
58 self.data.cols_out() - 1
59 }
60}
61
62impl GGLWECiphertext<Vec<u8>, FFT64> {
63 pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, rank: usize, size: usize) -> usize {
64 GLWECiphertext::encrypt_sk_scratch_space(module, size)
65 + module.bytes_of_vec_znx(rank + 1, size)
66 + module.bytes_of_vec_znx(1, size)
67 + module.bytes_of_vec_znx_dft(rank + 1, size)
68 }
69
70 pub fn generate_from_pk_scratch_space(_module: &Module<FFT64>, _rank: usize, _pk_size: usize) -> usize {
71 unimplemented!()
72 }
73}
74
75impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GGLWECiphertext<DataSelf, FFT64> {
76 pub fn encrypt_sk<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>(
77 &mut self,
78 module: &Module<FFT64>,
79 pt: &ScalarZnx<DataPt>,
80 sk_dft: &SecretKeyFourier<DataSk, FFT64>,
81 source_xa: &mut Source,
82 source_xe: &mut Source,
83 sigma: f64,
84 scratch: &mut Scratch,
85 ) {
86 #[cfg(debug_assertions)]
87 {
88 assert_eq!(self.rank_in(), pt.cols());
89 assert_eq!(self.rank_out(), sk_dft.rank());
90 assert_eq!(self.n(), module.n());
91 assert_eq!(sk_dft.n(), module.n());
92 assert_eq!(pt.n(), module.n());
93 assert!(
94 scratch.available() >= GGLWECiphertext::generate_from_sk_scratch_space(module, self.rank(), self.size()),
95 "scratch.available: {} < GGLWECiphertext::generate_from_sk_scratch_space(module, self.rank()={}, \
96 self.size()={}): {}",
97 scratch.available(),
98 self.rank(),
99 self.size(),
100 GGLWECiphertext::generate_from_sk_scratch_space(module, self.rank(), self.size())
101 )
102 }
103
104 let rows: usize = self.rows();
105 let size: usize = self.size();
106 let basek: usize = self.basek();
107 let k: usize = self.k();
108
109 let cols_in: usize = self.rank_in();
110 let cols_out: usize = self.rank_out() + 1;
111
112 let (tmp_znx_pt, scrach_1) = scratch.tmp_vec_znx(module, 1, size);
113 let (tmp_znx_ct, scrach_2) = scrach_1.tmp_vec_znx(module, cols_out, size);
114 let (tmp_znx_dft_ct, scratch_3) = scrach_2.tmp_vec_znx_dft(module, cols_out, size);
115
116 let mut vec_znx_pt: GLWEPlaintext<&mut [u8]> = GLWEPlaintext {
117 data: tmp_znx_pt,
118 basek,
119 k,
120 };
121
122 let mut vec_znx_ct: GLWECiphertext<&mut [u8]> = GLWECiphertext {
123 data: tmp_znx_ct,
124 basek,
125 k,
126 };
127
128 let mut vec_znx_ct_dft: GLWECiphertextFourier<&mut [u8], FFT64> = GLWECiphertextFourier {
129 data: tmp_znx_dft_ct,
130 basek,
131 k,
132 };
133
134 // For each input column (i.e. rank) produces a GGLWE ciphertext of rank_out+1 columns
135 //
136 // Example for ksk rank 2 to rank 3:
137 //
138 // (-(a0*s0 + a1*s1 + a2*s2) + s0', a0, a1, a2)
139 // (-(b0*s0 + b1*s1 + b2*s2) + s0', b0, b1, b2)
140 //
141 // Example ksk rank 2 to rank 1
142 //
143 // (-(a*s) + s0, a)
144 // (-(b*s) + s1, b)
145 (0..cols_in).for_each(|col_i| {
146 (0..rows).for_each(|row_i| {
147 // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
148 vec_znx_pt.data.zero(); // zeroes for next iteration
149 module.vec_znx_add_scalar_inplace(&mut vec_znx_pt.data, 0, row_i, pt, col_i); // Selects the i-th
150 module.vec_znx_normalize_inplace(basek, &mut vec_znx_pt.data, 0, scratch_3);
151
152 // rlwe encrypt of vec_znx_pt into vec_znx_ct
153 vec_znx_ct.encrypt_sk(
154 module,
155 &vec_znx_pt,
156 sk_dft,
157 source_xa,
158 source_xe,
159 sigma,
160 scratch_3,
161 );
162
163 // Switch vec_znx_ct into DFT domain
164 vec_znx_ct.dft(module, &mut vec_znx_ct_dft);
165
166 // Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
167 module.vmp_prepare_row(&mut self.data, row_i, col_i, &vec_znx_ct_dft.data);
168 });
169 });
170 }
171}
172
173impl<C: AsRef<[u8]>> GetRow<FFT64> for GGLWECiphertext<C, FFT64> {
174 fn get_row<R: AsMut<[u8]> + AsRef<[u8]>>(
175 &self,
176 module: &Module<FFT64>,
177 row_i: usize,
178 col_j: usize,
179 res: &mut GLWECiphertextFourier<R, FFT64>,
180 ) {
181 module.vmp_extract_row(&mut res.data, &self.data, row_i, col_j);
182 }
183}
184
185impl<C: AsMut<[u8]> + AsRef<[u8]>> SetRow<FFT64> for GGLWECiphertext<C, FFT64> {
186 fn set_row<R: AsRef<[u8]>>(
187 &mut self,
188 module: &Module<FFT64>,
189 row_i: usize,
190 col_j: usize,
191 a: &GLWECiphertextFourier<R, FFT64>,
192 ) {
193 module.vmp_prepare_row(&mut self.data, row_i, col_j, &a.data);
194 }
195}