poulpy/core/src/ggsw/automorphism.rs
core/src/ggsw/automorphism.rsRaw
1use backend::hal::{
2 api::{ScratchAvailable, TakeVecZnxBig, TakeVecZnxDft, VecZnxAutomorphismInplace, VecZnxNormalizeTmpBytes},
3 layouts::{Backend, DataMut, DataRef, Module, Scratch},
4};
5
6use crate::{
7 AutomorphismKeyExec, GGSWCiphertext, GGSWKeySwitchFamily, GLWECiphertext, GLWEKeyswitchFamily, GLWETensorKeyExec, Infos,
8};
9
10impl GGSWCiphertext<Vec<u8>> {
11 pub fn automorphism_scratch_space<B: Backend>(
12 module: &Module<B>,
13 n: usize,
14 basek: usize,
15 k_out: usize,
16 k_in: usize,
17 k_ksk: usize,
18 digits_ksk: usize,
19 k_tsk: usize,
20 digits_tsk: usize,
21 rank: usize,
22 ) -> usize
23 where
24 Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
25 {
26 let out_size: usize = k_out.div_ceil(basek);
27 let ci_dft: usize = module.vec_znx_dft_alloc_bytes(n, rank + 1, out_size);
28 let ks_internal: usize =
29 GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_out, k_in, k_ksk, digits_ksk, rank, rank);
30 let expand: usize = GGSWCiphertext::expand_row_scratch_space(module, n, basek, k_out, k_tsk, digits_tsk, rank);
31 ci_dft + (ks_internal | expand)
32 }
33
34 pub fn automorphism_inplace_scratch_space<B: Backend>(
35 module: &Module<B>,
36 n: usize,
37 basek: usize,
38 k_out: usize,
39 k_ksk: usize,
40 digits_ksk: usize,
41 k_tsk: usize,
42 digits_tsk: usize,
43 rank: usize,
44 ) -> usize
45 where
46 Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
47 {
48 GGSWCiphertext::automorphism_scratch_space(
49 module, n, basek, k_out, k_out, k_ksk, digits_ksk, k_tsk, digits_tsk, rank,
50 )
51 }
52}
53
54impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
55 pub fn automorphism<DataLhs: DataRef, DataAk: DataRef, DataTsk: DataRef, B: Backend>(
56 &mut self,
57 module: &Module<B>,
58 lhs: &GGSWCiphertext<DataLhs>,
59 auto_key: &AutomorphismKeyExec<DataAk, B>,
60 tensor_key: &GLWETensorKeyExec<DataTsk, B>,
61 scratch: &mut Scratch<B>,
62 ) where
63 Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxAutomorphismInplace + VecZnxNormalizeTmpBytes,
64 Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B>,
65 {
66 #[cfg(debug_assertions)]
67 {
68 use crate::Infos;
69
70 assert_eq!(self.n(), auto_key.n());
71 assert_eq!(lhs.n(), auto_key.n());
72
73 assert_eq!(
74 self.rank(),
75 lhs.rank(),
76 "ggsw_out rank: {} != ggsw_in rank: {}",
77 self.rank(),
78 lhs.rank()
79 );
80 assert_eq!(
81 self.rank(),
82 auto_key.rank(),
83 "ggsw_in rank: {} != auto_key rank: {}",
84 self.rank(),
85 auto_key.rank()
86 );
87 assert_eq!(
88 self.rank(),
89 tensor_key.rank(),
90 "ggsw_in rank: {} != tensor_key rank: {}",
91 self.rank(),
92 tensor_key.rank()
93 );
94 assert!(
95 scratch.available()
96 >= GGSWCiphertext::automorphism_scratch_space(
97 module,
98 self.n(),
99 self.basek(),
100 self.k(),
101 lhs.k(),
102 auto_key.k(),
103 auto_key.digits(),
104 tensor_key.k(),
105 tensor_key.digits(),
106 self.rank(),
107 )
108 )
109 };
110
111 let n: usize = auto_key.n();
112 let rank: usize = self.rank();
113 let cols: usize = rank + 1;
114
115 // Keyswitch the j-th row of the col 0
116 (0..lhs.rows()).for_each(|row_i| {
117 // Key-switch column 0, i.e.
118 // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0pi^-1(s0) + a1pi^-1(s1) + a2pi^-1(s2)) + M[i], a0, a1, a2)
119 self.at_mut(row_i, 0)
120 .automorphism(module, &lhs.at(row_i, 0), auto_key, scratch);
121
122 // Isolates DFT(AUTO(a[i]))
123 let (mut ci_dft, scratch1) = scratch.take_vec_znx_dft(n, cols, self.size());
124 (0..cols).for_each(|i| {
125 module.vec_znx_dft_from_vec_znx(1, 0, &mut ci_dft, i, &self.at(row_i, 0).data, i);
126 });
127
128 // Generates
129 //
130 // col 1: (-(b0s0 + b1s1 + b2s2) , b0 + pi(M[i]), b1 , b2 )
131 // col 2: (-(c0s0 + c1s1 + c2s2) , c0 , c1 + pi(M[i]), c2 )
132 // col 3: (-(d0s0 + d1s1 + d2s2) , d0 , d1 , d2 + pi(M[i]))
133 (1..cols).for_each(|col_j| {
134 self.expand_row(module, row_i, col_j, &ci_dft, tensor_key, scratch1);
135 });
136 })
137 }
138
139 pub fn automorphism_inplace<DataKsk: DataRef, DataTsk: DataRef, B: Backend>(
140 &mut self,
141 module: &Module<B>,
142 auto_key: &AutomorphismKeyExec<DataKsk, B>,
143 tensor_key: &GLWETensorKeyExec<DataTsk, B>,
144 scratch: &mut Scratch<B>,
145 ) where
146 Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxAutomorphismInplace + VecZnxNormalizeTmpBytes,
147 Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B>,
148 {
149 unsafe {
150 let self_ptr: *mut GGSWCiphertext<DataSelf> = self as *mut GGSWCiphertext<DataSelf>;
151 self.automorphism(module, &*self_ptr, auto_key, tensor_key, scratch);
152 }
153 }
154}