1use poulpy_hal::{
2 api::{ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxNormalizeInplace, VecZnxSubInplace},
3 layouts::{Backend, DataRef, Module, Scratch, ScratchOwned},
4};
5
6use crate::{
7 ScratchTakeCore,
8 decryption::GLWEDecrypt,
9 layouts::{GLWE, GLWEPlaintext, GLWEPlaintextToRef, GLWEToRef, LWEInfos, prepared::GLWESecretPreparedToRef},
10};
11
12impl<D: DataRef> GLWE<D> {
13 pub fn noise<M, S, P, BE: Backend>(&self, module: &M, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64
14 where
15 M: GLWENoise<BE>,
16 S: GLWESecretPreparedToRef<BE>,
17 P: GLWEPlaintextToRef,
18 {
19 module.glwe_noise(self, sk_prepared, pt_want, scratch)
20 }
21
22 pub fn assert_noise<M, BE: Backend, S, P>(&self, module: &M, sk_prepared: &S, pt_want: &P, max_noise: f64)
23 where
24 S: GLWESecretPreparedToRef<BE>,
25 P: GLWEPlaintextToRef,
26 M: GLWENoise<BE>,
27 {
28 module.glwe_assert_noise(self, sk_prepared, pt_want, max_noise);
29 }
30}
31
32pub trait GLWENoise<BE: Backend> {
33 fn glwe_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64
34 where
35 R: GLWEToRef,
36 S: GLWESecretPreparedToRef<BE>,
37 P: GLWEPlaintextToRef;
38
39 fn glwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64)
40 where
41 R: GLWEToRef,
42 S: GLWESecretPreparedToRef<BE>,
43 P: GLWEPlaintextToRef;
44}
45
46impl<BE: Backend> GLWENoise<BE> for Module<BE>
47where
48 Module<BE>: GLWEDecrypt<BE> + VecZnxSubInplace + VecZnxNormalizeInplace<BE>,
49 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
50 Scratch<BE>: ScratchTakeCore<BE>,
51{
52 fn glwe_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64
53 where
54 R: GLWEToRef,
55 S: GLWESecretPreparedToRef<BE>,
56 P: GLWEPlaintextToRef,
57 {
58 let res_ref: &GLWE<&[u8]> = &res.to_ref();
59
60 let pt_want: &GLWEPlaintext<&[u8]> = &pt_want.to_ref();
61
62 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(res_ref);
63 self.glwe_decrypt(res, &mut pt_have, sk_prepared, scratch);
64 self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0);
65 self.vec_znx_normalize_inplace(res_ref.base2k().into(), &mut pt_have.data, 0, scratch);
66 pt_have.data.std(res_ref.base2k().into(), 0).log2()
67 }
68
69 fn glwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64)
70 where
71 R: GLWEToRef,
72 S: GLWESecretPreparedToRef<BE>,
73 P: GLWEPlaintextToRef,
74 {
75 let res: &GLWE<&[u8]> = &res.to_ref();
76 let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res));
77 let noise_have: f64 = self.glwe_noise(res, sk_prepared, pt_want, scratch.borrow());
78 assert!(noise_have <= max_noise, "{noise_have} {max_noise}");
79 }
80}