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