poulpy/core/src/gglwe/automorphism.rs
core/src/gglwe/automorphism.rsRaw
1use backend::{FFT64, Module, Scratch, VecZnx, VecZnxDftOps, VecZnxOps, ZnxZero};
2
3use crate::{FourierGLWECiphertext, GLWEAutomorphismKey, GLWECiphertext, GetRow, Infos, ScratchCore, SetRow};
4
5impl GLWEAutomorphismKey<Vec<u8>, FFT64> {
6 pub fn automorphism_scratch_space(
7 module: &Module<FFT64>,
8 basek: usize,
9 k_out: usize,
10 k_in: usize,
11 k_ksk: usize,
12 digits: usize,
13 rank: usize,
14 ) -> usize {
15 let tmp_dft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank);
16 let tmp_idft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank);
17 let idft: usize = module.vec_znx_idft_tmp_bytes();
18 let keyswitch: usize = GLWECiphertext::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank);
19 tmp_dft + tmp_idft + idft + keyswitch
20 }
21
22 pub fn automorphism_inplace_scratch_space(
23 module: &Module<FFT64>,
24 basek: usize,
25 k_out: usize,
26 k_ksk: usize,
27 digits: usize,
28 rank: usize,
29 ) -> usize {
30 GLWEAutomorphismKey::automorphism_scratch_space(module, basek, k_out, k_out, k_ksk, digits, rank)
31 }
32}
33
34impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWEAutomorphismKey<DataSelf, FFT64> {
35 pub fn automorphism<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>(
36 &mut self,
37 module: &Module<FFT64>,
38 lhs: &GLWEAutomorphismKey<DataLhs, FFT64>,
39 rhs: &GLWEAutomorphismKey<DataRhs, FFT64>,
40 scratch: &mut Scratch,
41 ) {
42 #[cfg(debug_assertions)]
43 {
44 assert_eq!(
45 self.rank_in(),
46 lhs.rank_in(),
47 "ksk_out input rank: {} != ksk_in input rank: {}",
48 self.rank_in(),
49 lhs.rank_in()
50 );
51 assert_eq!(
52 lhs.rank_out(),
53 rhs.rank_in(),
54 "ksk_in output rank: {} != ksk_apply input rank: {}",
55 self.rank_out(),
56 rhs.rank_in()
57 );
58 assert_eq!(
59 self.rank_out(),
60 rhs.rank_out(),
61 "ksk_out output rank: {} != ksk_apply output rank: {}",
62 self.rank_out(),
63 rhs.rank_out()
64 );
65 }
66
67 let cols_out: usize = rhs.rank_out() + 1;
68
69 let (mut tmp_dft, scratch1) = scratch.tmp_glwe_fourier(module, lhs.basek(), lhs.k(), lhs.rank());
70
71 (0..self.rank_in()).for_each(|col_i| {
72 (0..self.rows()).for_each(|row_j| {
73 // Extracts relevant row
74 lhs.get_row(module, row_j, col_i, &mut tmp_dft);
75
76 // Get a VecZnxBig from scratch space
77 let (mut tmp_idft_data, scratch2) = scratch1.tmp_vec_znx_big(module, cols_out, self.size());
78
79 // Switches input outside of DFT
80 (0..cols_out).for_each(|i| {
81 module.vec_znx_idft(&mut tmp_idft_data, i, &tmp_dft.data, i, scratch2);
82 });
83
84 // Consumes to small vec znx
85 let mut tmp_idft_small_data: VecZnx<&mut [u8]> = tmp_idft_data.to_vec_znx_small();
86
87 // Reverts the automorphis key from (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a)
88 (0..cols_out).for_each(|i| {
89 module.vec_znx_automorphism_inplace(lhs.p(), &mut tmp_idft_small_data, i);
90 });
91
92 // Wraps into ciphertext
93 let mut tmp_idft: GLWECiphertext<&mut [u8]> = GLWECiphertext::<&mut [u8]> {
94 data: tmp_idft_small_data,
95 basek: self.basek(),
96 k: self.k(),
97 };
98
99 // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a)
100 tmp_idft.keyswitch_inplace(module, &rhs.key, scratch2);
101
102 // Applies back the automorphism X^{k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) -> (-pi^{-1}_{k'+k}(s)a + s, a)
103 // and switches back to DFT domain
104 (0..self.rank_out() + 1).for_each(|i| {
105 module.vec_znx_automorphism_inplace(lhs.p(), &mut tmp_idft.data, i);
106 module.vec_znx_dft(1, 0, &mut tmp_dft.data, i, &tmp_idft.data, i);
107 });
108
109 // Sets back the relevant row
110 self.set_row(module, row_j, col_i, &tmp_dft);
111 });
112 });
113
114 tmp_dft.data.zero();
115
116 (self.rows().min(lhs.rows())..self.rows()).for_each(|row_i| {
117 (0..self.rank_in()).for_each(|col_j| {
118 self.set_row(module, row_i, col_j, &tmp_dft);
119 });
120 });
121
122 self.p = (lhs.p * rhs.p) % (module.cyclotomic_order() as i64);
123 }
124
125 pub fn automorphism_inplace<DataRhs: AsRef<[u8]>>(
126 &mut self,
127 module: &Module<FFT64>,
128 rhs: &GLWEAutomorphismKey<DataRhs, FFT64>,
129 scratch: &mut Scratch,
130 ) {
131 unsafe {
132 let self_ptr: *mut GLWEAutomorphismKey<DataSelf, FFT64> = self as *mut GLWEAutomorphismKey<DataSelf, FFT64>;
133 self.automorphism(&module, &*self_ptr, rhs, scratch);
134 }
135 }
136}