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