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