arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/rlwe/src/keys.rs
rlwe/src/keys.rsRaw
  1use base2k::{
  2    Backend, FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDft, ScalarZnxDftAlloc, ScalarZnxDftOps, ScalarZnxDftToMut,
  3    ScalarZnxDftToRef, ScalarZnxToMut, ScalarZnxToRef, ScratchOwned, VecZnxDft, VecZnxDftToMut, VecZnxDftToRef, ZnxInfos,
  4};
  5use sampling::source::Source;
  6
  7use crate::{elem::Infos, elem_rlwe::RLWECtDft};
  8
  9#[derive(Clone, Copy, Debug)]
 10pub enum SecretDistribution {
 11    TernaryFixed(usize), // Ternary with fixed Hamming weight
 12    TernaryProb(f64),    // Ternary with probabilistic Hamming weight
 13    NONE,
 14}
 15
 16pub struct SecretKey<T> {
 17    pub data: ScalarZnx<T>,
 18    pub dist: SecretDistribution,
 19}
 20
 21impl SecretKey<Vec<u8>> {
 22    pub fn new<B: Backend>(module: &Module<B>) -> Self {
 23        Self {
 24            data: module.new_scalar_znx(1),
 25            dist: SecretDistribution::NONE,
 26        }
 27    }
 28}
 29
 30impl<S> SecretKey<S>
 31where
 32    S: AsMut<[u8]> + AsRef<[u8]>,
 33{
 34    pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) {
 35        self.data.fill_ternary_prob(0, prob, source);
 36        self.dist = SecretDistribution::TernaryProb(prob);
 37    }
 38
 39    pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) {
 40        self.data.fill_ternary_hw(0, hw, source);
 41        self.dist = SecretDistribution::TernaryFixed(hw);
 42    }
 43}
 44
 45impl<C> ScalarZnxToMut for SecretKey<C>
 46where
 47    ScalarZnx<C>: ScalarZnxToMut,
 48{
 49    fn to_mut(&mut self) -> ScalarZnx<&mut [u8]> {
 50        self.data.to_mut()
 51    }
 52}
 53
 54impl<C> ScalarZnxToRef for SecretKey<C>
 55where
 56    ScalarZnx<C>: ScalarZnxToRef,
 57{
 58    fn to_ref(&self) -> ScalarZnx<&[u8]> {
 59        self.data.to_ref()
 60    }
 61}
 62
 63pub struct SecretKeyDft<T, B: Backend> {
 64    pub data: ScalarZnxDft<T, B>,
 65    pub dist: SecretDistribution,
 66}
 67
 68impl<B: Backend> SecretKeyDft<Vec<u8>, B> {
 69    pub fn new(module: &Module<B>) -> Self {
 70        Self {
 71            data: module.new_scalar_znx_dft(1),
 72            dist: SecretDistribution::NONE,
 73        }
 74    }
 75
 76    pub fn dft<S>(&mut self, module: &Module<FFT64>, sk: &SecretKey<S>)
 77    where
 78        SecretKeyDft<Vec<u8>, B>: ScalarZnxDftToMut<base2k::FFT64>,
 79        SecretKey<S>: ScalarZnxToRef,
 80    {
 81        #[cfg(debug_assertions)]
 82        {
 83            match sk.dist {
 84                SecretDistribution::NONE => panic!("invalid sk: SecretDistribution::NONE"),
 85                _ => {}
 86            }
 87        }
 88
 89        module.svp_prepare(self, 0, sk, 0);
 90        self.dist = sk.dist;
 91    }
 92}
 93
 94impl<C, B: Backend> ScalarZnxDftToMut<B> for SecretKeyDft<C, B>
 95where
 96    ScalarZnxDft<C, B>: ScalarZnxDftToMut<B>,
 97{
 98    fn to_mut(&mut self) -> ScalarZnxDft<&mut [u8], B> {
 99        self.data.to_mut()
100    }
101}
102
103impl<C, B: Backend> ScalarZnxDftToRef<B> for SecretKeyDft<C, B>
104where
105    ScalarZnxDft<C, B>: ScalarZnxDftToRef<B>,
106{
107    fn to_ref(&self) -> ScalarZnxDft<&[u8], B> {
108        self.data.to_ref()
109    }
110}
111
112pub struct PublicKey<D, B: Backend> {
113    pub data: RLWECtDft<D, B>,
114    pub dist: SecretDistribution,
115}
116
117impl<B: Backend> PublicKey<Vec<u8>, B> {
118    pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
119        Self {
120            data: RLWECtDft::new(module, log_base2k, log_k, 2),
121            dist: SecretDistribution::NONE,
122        }
123    }
124}
125
126impl<T, B: Backend> Infos for PublicKey<T, B> {
127    type Inner = VecZnxDft<T, B>;
128
129    fn inner(&self) -> &Self::Inner {
130        &self.data.data
131    }
132
133    fn log_base2k(&self) -> usize {
134        self.data.log_base2k
135    }
136
137    fn log_k(&self) -> usize {
138        self.data.log_k
139    }
140}
141
142impl<C, B: Backend> VecZnxDftToMut<B> for PublicKey<C, B>
143where
144    VecZnxDft<C, B>: VecZnxDftToMut<B>,
145{
146    fn to_mut(&mut self) -> VecZnxDft<&mut [u8], B> {
147        self.data.to_mut()
148    }
149}
150
151impl<C, B: Backend> VecZnxDftToRef<B> for PublicKey<C, B>
152where
153    VecZnxDft<C, B>: VecZnxDftToRef<B>,
154{
155    fn to_ref(&self) -> VecZnxDft<&[u8], B> {
156        self.data.to_ref()
157    }
158}
159
160impl<C> PublicKey<C, FFT64> {
161    pub fn generate<S>(
162        &mut self,
163        module: &Module<FFT64>,
164        sk_dft: &SecretKeyDft<S, FFT64>,
165        source_xa: &mut Source,
166        source_xe: &mut Source,
167        sigma: f64,
168        bound: f64,
169    ) where
170        VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
171        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64> + ZnxInfos,
172    {
173        #[cfg(debug_assertions)]
174        {
175            match sk_dft.dist {
176                SecretDistribution::NONE => panic!("invalid sk_dft: SecretDistribution::NONE"),
177                _ => {}
178            }
179        }
180
181        // Its ok to allocate scratch space here since pk is usually generated only once.
182        let mut scratch: ScratchOwned = ScratchOwned::new(RLWECtDft::encrypt_zero_sk_scratch_bytes(
183            module,
184            self.size(),
185        ));
186        self.data.encrypt_zero_sk(
187            module,
188            sk_dft,
189            source_xa,
190            source_xe,
191            sigma,
192            bound,
193            scratch.borrow(),
194        );
195        self.dist = sk_dft.dist;
196    }
197}