arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/encryption/gglwe_ct.rs
poulpy-core/src/encryption/gglwe_ct.rsRaw
  1use poulpy_hal::{
  2    api::{ModuleN, ScratchAvailable, VecZnxAddScalarInplace, VecZnxDftBytesOf, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes},
  3    layouts::{Backend, DataMut, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxInfos, ZnxZero},
  4    source::Source,
  5};
  6
  7use crate::{
  8    ScratchTakeCore,
  9    encryption::glwe_ct::GLWEEncryptSk,
 10    layouts::GLWEInfos,
 11    layouts::{
 12        GGLWE, GGLWEInfos, GGLWEToMut, GLWEPlaintext, LWEInfos,
 13        prepared::{GLWESecretPrepared, GLWESecretPreparedToRef},
 14    },
 15};
 16
 17impl GGLWE<Vec<u8>> {
 18    pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize
 19    where
 20        A: GGLWEInfos,
 21        M: GGLWEEncryptSk<BE>,
 22    {
 23        module.gglwe_encrypt_sk_tmp_bytes(infos)
 24    }
 25
 26    pub fn encrypt_pk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize
 27    where
 28        A: GGLWEInfos,
 29        M: GGLWEEncryptSk<BE>,
 30    {
 31        module.gglwe_encrypt_sk_tmp_bytes(infos)
 32    }
 33}
 34
 35impl<D: DataMut> GGLWE<D> {
 36    #[allow(clippy::too_many_arguments)]
 37    pub fn encrypt_sk<P, S, M, BE: Backend>(
 38        &mut self,
 39        module: &M,
 40        pt: &P,
 41        sk: &S,
 42        source_xa: &mut Source,
 43        source_xe: &mut Source,
 44        scratch: &mut Scratch<BE>,
 45    ) where
 46        P: ScalarZnxToRef,
 47        S: GLWESecretPreparedToRef<BE>,
 48        M: GGLWEEncryptSk<BE>,
 49        Scratch<BE>: ScratchTakeCore<BE>,
 50    {
 51        module.gglwe_encrypt_sk(self, pt, sk, source_xa, source_xe, scratch);
 52    }
 53}
 54
 55pub trait GGLWEEncryptSk<BE: Backend> {
 56    fn gglwe_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize
 57    where
 58        A: GGLWEInfos;
 59
 60    fn gglwe_encrypt_sk<R, P, S>(
 61        &self,
 62        res: &mut R,
 63        pt: &P,
 64        sk: &S,
 65        source_xa: &mut Source,
 66        source_xe: &mut Source,
 67        scratch: &mut Scratch<BE>,
 68    ) where
 69        R: GGLWEToMut,
 70        P: ScalarZnxToRef,
 71        S: GLWESecretPreparedToRef<BE>;
 72}
 73
 74impl<BE: Backend> GGLWEEncryptSk<BE> for Module<BE>
 75where
 76    Self: ModuleN
 77        + GLWEEncryptSk<BE>
 78        + VecZnxNormalizeTmpBytes
 79        + VecZnxDftBytesOf
 80        + VecZnxAddScalarInplace
 81        + VecZnxNormalizeInplace<BE>,
 82    Scratch<BE>: ScratchTakeCore<BE>,
 83{
 84    fn gglwe_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize
 85    where
 86        A: GGLWEInfos,
 87    {
 88        self.glwe_encrypt_sk_tmp_bytes(infos)
 89            + GLWEPlaintext::bytes_of_from_infos(self, infos).max(self.vec_znx_normalize_tmp_bytes())
 90    }
 91
 92    fn gglwe_encrypt_sk<R, P, S>(
 93        &self,
 94        res: &mut R,
 95        pt: &P,
 96        sk: &S,
 97        source_xa: &mut Source,
 98        source_xe: &mut Source,
 99        scratch: &mut Scratch<BE>,
100    ) where
101        R: GGLWEToMut,
102        P: ScalarZnxToRef,
103        S: GLWESecretPreparedToRef<BE>,
104    {
105        let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut();
106        let pt: &ScalarZnx<&[u8]> = &pt.to_ref();
107        let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref();
108
109        assert_eq!(
110            res.rank_in(),
111            pt.cols() as u32,
112            "res.rank_in(): {} != pt.cols(): {}",
113            res.rank_in(),
114            pt.cols()
115        );
116        assert_eq!(
117            res.rank_out(),
118            sk.rank(),
119            "res.rank_out(): {} != sk.rank(): {}",
120            res.rank_out(),
121            sk.rank()
122        );
123        assert_eq!(res.n(), sk.n());
124        assert_eq!(pt.n() as u32, sk.n());
125        assert!(
126            scratch.available() >= self.gglwe_encrypt_sk_tmp_bytes(res),
127            "scratch.available: {} < GGLWE::encrypt_sk_tmp_bytes(self, res.rank()={}, res.size()={}): {}",
128            scratch.available(),
129            res.rank_out(),
130            res.size(),
131            self.gglwe_encrypt_sk_tmp_bytes(res)
132        );
133        assert!(
134            res.dnum().0 * res.dsize().0 * res.base2k().0 <= res.k().0,
135            "res.dnum() : {} * res.dsize() : {} * res.base2k() : {} = {} >= res.k() = {}",
136            res.dnum(),
137            res.dsize(),
138            res.base2k(),
139            res.dnum().0 * res.dsize().0 * res.base2k().0,
140            res.k()
141        );
142
143        let dnum: usize = res.dnum().into();
144        let dsize: usize = res.dsize().into();
145        let base2k: usize = res.base2k().into();
146        let rank_in: usize = res.rank_in().into();
147
148        let (mut tmp_pt, scrach_1) = scratch.take_glwe_pt(self, &res.glwe_layout());
149        // For each input column (i.e. rank) produces a GGLWE of rank_out+1 columns
150        //
151        // Example for ksk rank 2 to rank 3:
152        //
153        // (-(a0*s0 + a1*s1 + a2*s2) + s0', a0, a1, a2)
154        // (-(b0*s0 + b1*s1 + b2*s2) + s0', b0, b1, b2)
155        //
156        // Example ksk rank 2 to rank 1
157        //
158        // (-(a*s) + s0, a)
159        // (-(b*s) + s1, b)
160
161        for col_i in 0..rank_in {
162            for row_i in 0..dnum {
163                // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
164                tmp_pt.data.zero(); // zeroes for next iteration
165                self.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, col_i);
166                self.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1);
167                self.glwe_encrypt_sk(
168                    &mut res.at_mut(row_i, col_i),
169                    &tmp_pt,
170                    sk,
171                    source_xa,
172                    source_xe,
173                    scrach_1,
174                );
175            }
176        }
177    }
178}