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 assert!(
66 self.k() <= lhs.k(),
67 "output k={} cannot be greater than input k={}",
68 self.k(),
69 lhs.k()
70 )
71 }
72
73 let cols_out: usize = rhs.rank_out() + 1;
74
75 (0..self.rank_in()).for_each(|col_i| {
76 (0..self.rows()).for_each(|row_j| {
77 let (mut tmp_idft_data, scratct1) = scratch.tmp_vec_znx_big(module, cols_out, self.size());
78
79 {
80 let (mut tmp_dft, scratch2) = scratct1.tmp_fourier_glwe_ct(module, lhs.basek(), lhs.k(), lhs.rank());
81
82 // Extracts relevant row
83 lhs.get_row(module, row_j, col_i, &mut tmp_dft);
84
85 // Get a VecZnxBig from scratch space
86
87 // Switches input outside of DFT
88 (0..cols_out).for_each(|i| {
89 module.vec_znx_idft(&mut tmp_idft_data, i, &tmp_dft.data, i, scratch2);
90 });
91 }
92
93 // Consumes to small vec znx
94 let mut tmp_idft_small_data: VecZnx<&mut [u8]> = tmp_idft_data.to_vec_znx_small();
95
96 // Reverts the automorphis key from (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a)
97 (0..cols_out).for_each(|i| {
98 module.vec_znx_automorphism_inplace(lhs.p(), &mut tmp_idft_small_data, i);
99 });
100
101 // Wraps into ciphertext
102 let mut tmp_idft: GLWECiphertext<&mut [u8]> = GLWECiphertext::<&mut [u8]> {
103 data: tmp_idft_small_data,
104 basek: self.basek(),
105 k: self.k(),
106 };
107
108 // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a)
109 tmp_idft.keyswitch_inplace(module, &rhs.key, scratct1);
110
111 {
112 let (mut tmp_dft, _) = scratct1.tmp_fourier_glwe_ct(module, self.basek(), self.k(), self.rank());
113
114 // Applies back the automorphism X^{k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) -> (-pi^{-1}_{k'+k}(s)a + s, a)
115 // and switches back to DFT domain
116 (0..self.rank_out() + 1).for_each(|i| {
117 module.vec_znx_automorphism_inplace(lhs.p(), &mut tmp_idft.data, i);
118 module.vec_znx_dft(1, 0, &mut tmp_dft.data, i, &tmp_idft.data, i);
119 });
120
121 // Sets back the relevant row
122 self.set_row(module, row_j, col_i, &tmp_dft);
123 }
124 });
125 });
126
127 let (mut tmp_dft, _) = scratch.tmp_fourier_glwe_ct(module, self.basek(), self.k(), self.rank());
128 tmp_dft.data.zero();
129
130 (self.rows().min(lhs.rows())..self.rows()).for_each(|row_i| {
131 (0..self.rank_in()).for_each(|col_j| {
132 self.set_row(module, row_i, col_j, &tmp_dft);
133 });
134 });
135
136 self.p = (lhs.p * rhs.p) % (module.cyclotomic_order() as i64);
137 }
138
139 pub fn automorphism_inplace<DataRhs: AsRef<[u8]>>(
140 &mut self,
141 module: &Module<FFT64>,
142 rhs: &GLWEAutomorphismKey<DataRhs, FFT64>,
143 scratch: &mut Scratch,
144 ) {
145 unsafe {
146 let self_ptr: *mut GLWEAutomorphismKey<DataSelf, FFT64> = self as *mut GLWEAutomorphismKey<DataSelf, FFT64>;
147 self.automorphism(&module, &*self_ptr, rhs, scratch);
148 }
149 }
150}