poulpy/poulpy-core/src/encryption/compressed/gglwe_ct.rs
poulpy-core/src/encryption/compressed/gglwe_ct.rsRaw
1use poulpy_hal::{
2 api::{
3 ScratchAvailable, VecZnxAddScalarInplace, VecZnxDftBytesOf, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes,
4 ZnNormalizeInplace,
5 },
6 layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxZero},
7 source::Source,
8};
9
10use crate::{
11 TakeGLWEPlaintext,
12 encryption::{SIGMA, glwe_ct::GLWEEncryptSkInternal},
13 layouts::{
14 GGLWE, GGLWEInfos, LWEInfos,
15 compressed::{GGLWECompressed, GGLWECompressedToMut},
16 prepared::{GLWESecretPrepared, GLWESecretPreparedToRef},
17 },
18};
19
20impl<D: DataMut> GGLWECompressed<D> {
21 #[allow(clippy::too_many_arguments)]
22 pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>(
23 &mut self,
24 module: &Module<B>,
25 pt: &ScalarZnx<DataPt>,
26 sk: &GLWESecretPrepared<DataSk, B>,
27 seed: [u8; 32],
28 source_xe: &mut Source,
29 scratch: &mut Scratch<B>,
30 ) where
31 Module<B>: GGLWECompressedEncryptSk<B>,
32 {
33 module.gglwe_compressed_encrypt_sk(self, pt, sk, seed, source_xe, scratch);
34 }
35}
36
37impl GGLWECompressed<Vec<u8>> {
38 pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize
39 where
40 A: GGLWEInfos,
41 Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftBytesOf + VecZnxNormalizeTmpBytes,
42 {
43 GGLWE::encrypt_sk_scratch_space(module, infos)
44 }
45}
46
47pub trait GGLWECompressedEncryptSk<B: Backend> {
48 fn gglwe_compressed_encrypt_sk<R, P, S>(
49 &self,
50 res: &mut R,
51 pt: &P,
52 sk: &S,
53 seed: [u8; 32],
54 source_xe: &mut Source,
55 scratch: &mut Scratch<B>,
56 ) where
57 R: GGLWECompressedToMut,
58 P: ScalarZnxToRef,
59 S: GLWESecretPreparedToRef<B>;
60}
61
62impl<B: Backend> GGLWECompressedEncryptSk<B> for Module<B>
63where
64 Module<B>: GLWEEncryptSkInternal<B>
65 + VecZnxNormalizeInplace<B>
66 + VecZnxNormalizeTmpBytes
67 + VecZnxDftBytesOf
68 + VecZnxAddScalarInplace
69 + ZnNormalizeInplace<B>,
70 Scratch<B>: TakeGLWEPlaintext<B> + ScratchAvailable,
71{
72 fn gglwe_compressed_encrypt_sk<R, P, S>(
73 &self,
74 res: &mut R,
75 pt: &P,
76 sk: &S,
77 seed: [u8; 32],
78 source_xe: &mut Source,
79 scratch: &mut Scratch<B>,
80 ) where
81 R: GGLWECompressedToMut,
82 P: ScalarZnxToRef,
83 S: GLWESecretPreparedToRef<B>,
84 {
85 let res: &mut GGLWECompressed<&mut [u8]> = &mut res.to_mut();
86 let pt: &ScalarZnx<&[u8]> = &pt.to_ref();
87
88 #[cfg(debug_assertions)]
89 {
90 use poulpy_hal::layouts::ZnxInfos;
91 let sk = &sk.to_ref();
92
93 assert_eq!(
94 res.rank_in(),
95 pt.cols() as u32,
96 "res.rank_in(): {} != pt.cols(): {}",
97 res.rank_in(),
98 pt.cols()
99 );
100 assert_eq!(
101 res.rank_out(),
102 sk.rank(),
103 "res.rank_out(): {} != sk.rank(): {}",
104 res.rank_out(),
105 sk.rank()
106 );
107 assert_eq!(res.n(), sk.n());
108 assert_eq!(pt.n() as u32, sk.n());
109 assert!(
110 scratch.available() >= GGLWECompressed::encrypt_sk_scratch_space(self, res),
111 "scratch.available: {} < GGLWECiphertext::encrypt_sk_scratch_space: {}",
112 scratch.available(),
113 GGLWECompressed::encrypt_sk_scratch_space(self, res)
114 );
115 assert!(
116 res.dnum().0 * res.dsize().0 * res.base2k().0 <= res.k().0,
117 "res.dnum() : {} * res.dsize() : {} * res.base2k() : {} = {} >= res.k() = {}",
118 res.dnum(),
119 res.dsize(),
120 res.base2k(),
121 res.dnum().0 * res.dsize().0 * res.base2k().0,
122 res.k()
123 );
124 }
125
126 let dnum: usize = res.dnum().into();
127 let dsize: usize = res.dsize().into();
128 let base2k: usize = res.base2k().into();
129 let rank_in: usize = res.rank_in().into();
130 let cols: usize = (res.rank_out() + 1).into();
131
132 let mut source_xa = Source::new(seed);
133
134 let (mut tmp_pt, scrach_1) = scratch.take_glwe_pt(res);
135 (0..rank_in).for_each(|col_i| {
136 (0..dnum).for_each(|d_i| {
137 // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
138 tmp_pt.data.zero(); // zeroes for next iteration
139 self.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + d_i * dsize, pt, col_i);
140 self.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1);
141
142 let (seed, mut source_xa_tmp) = source_xa.branch();
143 res.seed[col_i * dnum + d_i] = seed;
144
145 self.glwe_encrypt_sk_internal(
146 res.base2k().into(),
147 res.k().into(),
148 &mut res.at_mut(d_i, col_i).data,
149 cols,
150 true,
151 Some((&tmp_pt, 0)),
152 sk,
153 &mut source_xa_tmp,
154 source_xe,
155 SIGMA,
156 scrach_1,
157 );
158 });
159 });
160 }
161}