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