poulpy/poulpy-schemes/src/tfhe/bdd_arithmetic/bdd_rotation.rs
poulpy-schemes/src/tfhe/bdd_arithmetic/bdd_rotation.rsRaw
1use poulpy_core::{
2 GLWECopy, GLWERotate, ScratchTakeCore,
3 layouts::{GGSW, GGSWInfos, GGSWToMut, GGSWToRef, GLWE, GLWEInfos, GLWEToMut, GLWEToRef},
4};
5use poulpy_hal::layouts::{Backend, Module, Scratch};
6
7use crate::tfhe::bdd_arithmetic::{Cmux, GetGGSWBit, UnsignedInteger};
8
9impl<T: UnsignedInteger, BE: Backend> GGSWBlindRotation<T, BE> for Module<BE>
10where
11 Self: GLWEBlindRotation<T, BE>,
12 Scratch<BE>: ScratchTakeCore<BE>,
13{
14}
15
16pub trait GGSWBlindRotation<T: UnsignedInteger, BE: Backend>
17where
18 Self: GLWEBlindRotation<T, BE>,
19 Scratch<BE>: ScratchTakeCore<BE>,
20{
21 fn ggsw_blind_rotation_tmp_bytes<R, K>(&self, res_infos: &R, k_infos: &K) -> usize
22 where
23 R: GLWEInfos,
24 K: GGSWInfos,
25 {
26 self.glwe_blind_rotation_tmp_bytes(res_infos, k_infos)
27 }
28
29 fn ggsw_blind_rotation<R, G, K>(
30 &self,
31 res: &mut R,
32 test_ggsw: &G,
33 k: &K,
34 bit_start: usize,
35 bit_size: usize,
36 bit_step: usize,
37 scratch: &mut Scratch<BE>,
38 ) where
39 R: GGSWToMut,
40 G: GGSWToRef,
41 K: GetGGSWBit<T, BE>,
42 Scratch<BE>: ScratchTakeCore<BE>,
43 {
44 let res: &mut GGSW<&mut [u8]> = &mut res.to_mut();
45 let test_ggsw: &GGSW<&[u8]> = &test_ggsw.to_ref();
46
47 for row in 0..res.dnum().into() {
48 for col in 0..(res.rank() + 1).into() {
49 self.glwe_blind_rotation(
50 &mut res.at_mut(row, col),
51 &test_ggsw.at(row, col),
52 k,
53 bit_start,
54 bit_size,
55 bit_step,
56 scratch,
57 );
58 }
59 }
60 }
61}
62
63impl<T: UnsignedInteger, BE: Backend> GLWEBlindRotation<T, BE> for Module<BE>
64where
65 Self: GLWECopy + GLWERotate<BE> + Cmux<BE>,
66 Scratch<BE>: ScratchTakeCore<BE>,
67{
68}
69
70pub trait GLWEBlindRotation<T: UnsignedInteger, BE: Backend>
71where
72 Self: GLWECopy + GLWERotate<BE> + Cmux<BE>,
73 Scratch<BE>: ScratchTakeCore<BE>,
74{
75 fn glwe_blind_rotation_tmp_bytes<R, K>(&self, res_infos: &R, k_infos: &K) -> usize
76 where
77 R: GLWEInfos,
78 K: GGSWInfos,
79 {
80 self.cmux_tmp_bytes(res_infos, res_infos, k_infos) + GLWE::bytes_of_from_infos(res_infos)
81 }
82
83 /// Homomorphic multiplication of res by X^{k[bit_start..bit_start + bit_size] * bit_step}.
84 fn glwe_blind_rotation<R, G, K>(
85 &self,
86 res: &mut R,
87 test_glwe: &G,
88 k: &K,
89 bit_start: usize,
90 bit_size: usize,
91 bit_step: usize,
92 scratch: &mut Scratch<BE>,
93 ) where
94 R: GLWEToMut,
95 G: GLWEToRef,
96 K: GetGGSWBit<T, BE>,
97 Scratch<BE>: ScratchTakeCore<BE>,
98 {
99 assert!(bit_start + bit_size <= T::WORD_SIZE);
100
101 let mut res: GLWE<&mut [u8]> = res.to_mut();
102
103 let (mut tmp_res, scratch_1) = scratch.take_glwe(&res);
104
105 // res <- test_glwe
106 self.glwe_copy(&mut res, test_glwe);
107
108 // a_is_res = true => (a, b) = (&mut res, &mut tmp_res)
109 // a_is_res = false => (a, b) = (&mut tmp_res, &mut res)
110 let mut a_is_res: bool = true;
111
112 for i in 0..bit_size {
113 let (a, b) = if a_is_res {
114 (&mut res, &mut tmp_res)
115 } else {
116 (&mut tmp_res, &mut res)
117 };
118
119 // a <- a ; b <- a * X^{-2^{i + bit_step}}
120 self.glwe_rotate(-1 << (i + bit_step), b, a);
121
122 // b <- (b - a) * GGSW(b[i]) + a
123 self.cmux_inplace(b, a, &k.get_bit(i + bit_start), scratch_1);
124
125 // ping-pong roles for next iter
126 a_is_res = !a_is_res;
127 }
128
129 // Ensure the final value ends up in `res`
130 if !a_is_res {
131 self.glwe_copy(&mut res, &tmp_res);
132 }
133 }
134}