arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/glwe_keys.rs
core/src/glwe_keys.rsRaw
  1use backend::{
  2    Backend, FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDft, ScalarZnxDftAlloc, ScalarZnxDftOps, ScratchOwned, VecZnxDft,
  3    ZnxInfos, ZnxZero,
  4};
  5use sampling::source::Source;
  6
  7use crate::{GLWECiphertextFourier, Infos};
  8
  9#[derive(Clone, Copy, Debug)]
 10pub(crate) enum SecretDistribution {
 11    TernaryFixed(usize), // Ternary with fixed Hamming weight
 12    TernaryProb(f64),    // Ternary with probabilistic Hamming weight
 13    ZERO,                // Debug mod
 14    NONE,
 15}
 16
 17pub struct GLWESecret<T, B: Backend> {
 18    pub(crate) data: ScalarZnx<T>,
 19    pub(crate) data_fourier: ScalarZnxDft<T, B>,
 20    pub(crate) dist: SecretDistribution,
 21}
 22
 23impl<B: Backend> GLWESecret<Vec<u8>, B> {
 24    pub fn alloc(module: &Module<B>, rank: usize) -> Self {
 25        Self {
 26            data: module.new_scalar_znx(rank),
 27            data_fourier: module.new_scalar_znx_dft(rank),
 28            dist: SecretDistribution::NONE,
 29        }
 30    }
 31
 32    pub fn bytes_of(module: &Module<B>, rank: usize) -> usize {
 33        module.bytes_of_scalar_znx(rank) + module.bytes_of_scalar_znx_dft(rank)
 34    }
 35}
 36
 37impl<DataSelf, B: Backend> GLWESecret<DataSelf, B> {
 38    pub fn n(&self) -> usize {
 39        self.data.n()
 40    }
 41
 42    pub fn log_n(&self) -> usize {
 43        self.data.log_n()
 44    }
 45
 46    pub fn rank(&self) -> usize {
 47        self.data.cols()
 48    }
 49}
 50
 51impl<S: AsMut<[u8]> + AsRef<[u8]>> GLWESecret<S, FFT64> {
 52    pub fn fill_ternary_prob(&mut self, module: &Module<FFT64>, prob: f64, source: &mut Source) {
 53        (0..self.rank()).for_each(|i| {
 54            self.data.fill_ternary_prob(i, prob, source);
 55        });
 56        self.prep_fourier(module);
 57        self.dist = SecretDistribution::TernaryProb(prob);
 58    }
 59
 60    pub fn fill_ternary_hw(&mut self, module: &Module<FFT64>, hw: usize, source: &mut Source) {
 61        (0..self.rank()).for_each(|i| {
 62            self.data.fill_ternary_hw(i, hw, source);
 63        });
 64        self.prep_fourier(module);
 65        self.dist = SecretDistribution::TernaryFixed(hw);
 66    }
 67
 68    pub fn fill_zero(&mut self) {
 69        self.data.zero();
 70        self.dist = SecretDistribution::ZERO;
 71    }
 72
 73    pub(crate) fn prep_fourier(&mut self, module: &Module<FFT64>) {
 74        (0..self.rank()).for_each(|i| {
 75            module.svp_prepare(&mut self.data_fourier, i, &self.data, i);
 76        });
 77    }
 78}
 79
 80pub struct GLWEPublicKey<D, B: Backend> {
 81    pub(crate) data: GLWECiphertextFourier<D, B>,
 82    pub(crate) dist: SecretDistribution,
 83}
 84
 85impl<B: Backend> GLWEPublicKey<Vec<u8>, B> {
 86    pub fn alloc(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self {
 87        Self {
 88            data: GLWECiphertextFourier::alloc(module, basek, k, rank),
 89            dist: SecretDistribution::NONE,
 90        }
 91    }
 92
 93    pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize {
 94        GLWECiphertextFourier::<Vec<u8>, B>::bytes_of(module, basek, k, rank)
 95    }
 96}
 97
 98impl<T, B: Backend> Infos for GLWEPublicKey<T, B> {
 99    type Inner = VecZnxDft<T, B>;
100
101    fn inner(&self) -> &Self::Inner {
102        &self.data.data
103    }
104
105    fn basek(&self) -> usize {
106        self.data.basek
107    }
108
109    fn k(&self) -> usize {
110        self.data.k
111    }
112}
113
114impl<T, B: Backend> GLWEPublicKey<T, B> {
115    pub fn rank(&self) -> usize {
116        self.cols() - 1
117    }
118}
119
120impl<C: AsRef<[u8]> + AsMut<[u8]>> GLWEPublicKey<C, FFT64> {
121    pub fn generate_from_sk<S: AsRef<[u8]>>(
122        &mut self,
123        module: &Module<FFT64>,
124        sk: &GLWESecret<S, FFT64>,
125        source_xa: &mut Source,
126        source_xe: &mut Source,
127        sigma: f64,
128    ) {
129        #[cfg(debug_assertions)]
130        {
131            match sk.dist {
132                SecretDistribution::NONE => panic!("invalid sk: SecretDistribution::NONE"),
133                _ => {}
134            }
135        }
136
137        // Its ok to allocate scratch space here since pk is usually generated only once.
138        let mut scratch: ScratchOwned = ScratchOwned::new(GLWECiphertextFourier::encrypt_sk_scratch_space(
139            module,
140            self.basek(),
141            self.k(),
142            self.rank(),
143        ));
144
145        self.data
146            .encrypt_zero_sk(module, sk, source_xa, source_xe, sigma, scratch.borrow());
147        self.dist = sk.dist;
148    }
149}