arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-schemes/src/bin_fhe/blind_rotation/algorithms/mod.rs
poulpy-schemes/src/bin_fhe/blind_rotation/algorithms/mod.rsRaw
  1mod cggi;
  2
  3pub use cggi::*;
  4
  5use itertools::izip;
  6use poulpy_core::{
  7    ScratchTakeCore,
  8    layouts::{GGSWInfos, GLWE, GLWEInfos, LWE, LWEInfos},
  9};
 10use poulpy_hal::layouts::{Backend, DataMut, DataRef, Scratch, ZnxView};
 11
 12use crate::bin_fhe::blind_rotation::{
 13    BlindRotationKeyInfos, BlindRotationKeyPrepared, LookUpTableRotationDirection, LookupTable,
 14};
 15
 16pub trait BlindRotationAlgo: Sync {}
 17
 18pub trait BlindRotationExecute<BRA: BlindRotationAlgo, BE: Backend> {
 19    fn blind_rotation_execute_tmp_bytes<G, B>(
 20        &self,
 21        block_size: usize,
 22        extension_factor: usize,
 23        glwe_infos: &G,
 24        brk_infos: &B,
 25    ) -> usize
 26    where
 27        G: GLWEInfos,
 28        B: GGSWInfos;
 29
 30    fn blind_rotation_execute<DR, DL, DB>(
 31        &self,
 32        res: &mut GLWE<DR>,
 33        lwe: &LWE<DL>,
 34        lut: &LookupTable,
 35        brk: &BlindRotationKeyPrepared<DB, BRA, BE>,
 36        scratch: &mut Scratch<BE>,
 37    ) where
 38        DR: DataMut,
 39        DL: DataRef,
 40        DB: DataRef;
 41}
 42
 43impl<D: DataRef, BRA: BlindRotationAlgo, BE: Backend> BlindRotationKeyPrepared<D, BRA, BE>
 44where
 45    Scratch<BE>: ScratchTakeCore<BE>,
 46{
 47    pub fn execute<DR: DataMut, DI: DataRef, M>(
 48        &self,
 49        module: &M,
 50        res: &mut GLWE<DR>,
 51        lwe: &LWE<DI>,
 52        lut: &LookupTable,
 53        scratch: &mut Scratch<BE>,
 54    ) where
 55        M: BlindRotationExecute<BRA, BE>,
 56    {
 57        module.blind_rotation_execute(res, lwe, lut, self, scratch);
 58    }
 59}
 60
 61impl<BE: Backend, BRA: BlindRotationAlgo> BlindRotationKeyPrepared<Vec<u8>, BRA, BE> {
 62    pub fn execute_tmp_bytes<A, B, M>(
 63        module: &M,
 64        block_size: usize,
 65        extension_factor: usize,
 66        glwe_infos: &A,
 67        brk_infos: &B,
 68    ) -> usize
 69    where
 70        A: GLWEInfos,
 71        B: BlindRotationKeyInfos,
 72        M: BlindRotationExecute<BRA, BE>,
 73    {
 74        module.blind_rotation_execute_tmp_bytes(block_size, extension_factor, glwe_infos, brk_infos)
 75    }
 76}
 77
 78pub fn mod_switch_2n(n: usize, res: &mut [i64], lwe: &LWE<&[u8]>, rot_dir: LookUpTableRotationDirection) {
 79    let base2k: usize = lwe.base2k().into();
 80
 81    let log2n: usize = usize::BITS as usize - (n - 1).leading_zeros() as usize + 1;
 82
 83    res.copy_from_slice(lwe.data().at(0, 0));
 84
 85    match rot_dir {
 86        LookUpTableRotationDirection::Left => {
 87            res.iter_mut().for_each(|x| *x = -*x);
 88        }
 89        LookUpTableRotationDirection::Right => {}
 90    }
 91
 92    if base2k > log2n {
 93        let diff: usize = base2k - (log2n - 1); // additional -1 because we map to [-N/2, N/2) instead of [0, N)
 94        res.iter_mut().for_each(|x| {
 95            *x = div_round_by_pow2(x, diff);
 96        })
 97    } else {
 98        let rem: usize = base2k - (log2n % base2k);
 99        let size: usize = log2n.div_ceil(base2k);
100        (1..size).for_each(|i| {
101            if i == size - 1 && rem != base2k {
102                let k_rem: usize = base2k - rem;
103                izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| {
104                    *y = (*y << k_rem) + (x >> rem);
105                });
106            } else {
107                izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| {
108                    *y = (*y << base2k) + x;
109                });
110            }
111        })
112    }
113}
114
115#[inline(always)]
116fn div_round_by_pow2(x: &i64, k: usize) -> i64 {
117    (x + (1 << (k - 1))) >> k
118}