arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/blind_rotation/tests/key.rs
core/src/blind_rotation/tests/key.rsRaw
  1use backend::hal::{
  2    api::{ScratchAvailable, SvpPPolAlloc, SvpPrepare, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, ZnxView, ZnxViewMut},
  3    layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, ScalarZnx, ScalarZnxToRef, Scratch, SvpPPol, WriterTo},
  4};
  5use sampling::source::Source;
  6
  7use crate::{
  8    Distribution, GGSWCiphertext, GGSWCiphertextExec, GGSWEncryptSkFamily, GGSWLayoutFamily, GLWESecretExec, Infos, LWESecret,
  9};
 10
 11pub struct BlindRotationKeyCGGI<D: Data> {
 12    pub(crate) keys: Vec<GGSWCiphertext<D>>,
 13    pub(crate) dist: Distribution,
 14}
 15
 16impl<D: Data> PartialEq for BlindRotationKeyCGGI<D> {
 17    fn eq(&self, other: &Self) -> bool {
 18        if self.keys.len() != other.keys.len() {
 19            return false;
 20        }
 21        for (a, b) in self.keys.iter().zip(other.keys.iter()) {
 22            if a != b {
 23                return false;
 24            }
 25        }
 26        self.dist == other.dist
 27    }
 28}
 29
 30impl<D: Data> Eq for BlindRotationKeyCGGI<D> {}
 31
 32use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 33
 34impl<D: DataMut> ReaderFrom for BlindRotationKeyCGGI<D> {
 35    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
 36        match Distribution::read_from(reader) {
 37            Ok(dist) => self.dist = dist,
 38            Err(e) => return Err(e),
 39        }
 40        let len: usize = reader.read_u64::<LittleEndian>()? as usize;
 41        if self.keys.len() != len {
 42            return Err(std::io::Error::new(
 43                std::io::ErrorKind::InvalidData,
 44                format!("self.keys.len()={} != read len={}", self.keys.len(), len),
 45            ));
 46        }
 47        for key in &mut self.keys {
 48            key.read_from(reader)?;
 49        }
 50        Ok(())
 51    }
 52}
 53
 54impl<D: DataRef> WriterTo for BlindRotationKeyCGGI<D> {
 55    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
 56        match self.dist.write_to(writer) {
 57            Ok(()) => {}
 58            Err(e) => return Err(e),
 59        }
 60        writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
 61        for key in &self.keys {
 62            key.write_to(writer)?;
 63        }
 64        Ok(())
 65    }
 66}
 67
 68impl BlindRotationKeyCGGI<Vec<u8>> {
 69    pub fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
 70        let mut data: Vec<GGSWCiphertext<Vec<u8>>> = Vec::with_capacity(n_lwe);
 71        (0..n_lwe).for_each(|_| data.push(GGSWCiphertext::alloc(n_gglwe, basek, k, rows, 1, rank)));
 72        Self {
 73            keys: data,
 74            dist: Distribution::NONE,
 75        }
 76    }
 77
 78    pub fn generate_from_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> usize
 79    where
 80        Module<B>: GGSWEncryptSkFamily<B>,
 81    {
 82        GGSWCiphertext::encrypt_sk_scratch_space(module, n, basek, k, rank)
 83    }
 84}
 85
 86impl<D: DataRef> BlindRotationKeyCGGI<D> {
 87    #[allow(dead_code)]
 88    pub(crate) fn n(&self) -> usize {
 89        self.keys[0].n()
 90    }
 91
 92    #[allow(dead_code)]
 93    pub(crate) fn rows(&self) -> usize {
 94        self.keys[0].rows()
 95    }
 96
 97    #[allow(dead_code)]
 98    pub(crate) fn k(&self) -> usize {
 99        self.keys[0].k()
100    }
101
102    #[allow(dead_code)]
103    pub(crate) fn size(&self) -> usize {
104        self.keys[0].size()
105    }
106
107    #[allow(dead_code)]
108    pub(crate) fn rank(&self) -> usize {
109        self.keys[0].rank()
110    }
111
112    pub(crate) fn basek(&self) -> usize {
113        self.keys[0].basek()
114    }
115
116    #[allow(dead_code)]
117    pub(crate) fn block_size(&self) -> usize {
118        match self.dist {
119            Distribution::BinaryBlock(value) => value,
120            _ => 1,
121        }
122    }
123}
124
125impl<D: DataMut> BlindRotationKeyCGGI<D> {
126    pub fn generate_from_sk<DataSkGLWE, DataSkLWE, B: Backend>(
127        &mut self,
128        module: &Module<B>,
129        sk_glwe: &GLWESecretExec<DataSkGLWE, B>,
130        sk_lwe: &LWESecret<DataSkLWE>,
131        source_xa: &mut Source,
132        source_xe: &mut Source,
133        sigma: f64,
134        scratch: &mut Scratch<B>,
135    ) where
136        DataSkGLWE: DataRef,
137        DataSkLWE: DataRef,
138        Module<B>: GGSWEncryptSkFamily<B> + VecZnxAddScalarInplace,
139        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
140    {
141        #[cfg(debug_assertions)]
142        {
143            assert_eq!(self.keys.len(), sk_lwe.n());
144            assert!(sk_glwe.n() <= TakeScalarZnx);
145            assert_eq!(sk_glwe.rank(), self.keys[0].rank());
146            match sk_lwe.dist {
147                Distribution::BinaryBlock(_)
148                | Distribution::BinaryFixed(_)
149                | Distribution::BinaryProb(_)
150                | Distribution::ZERO => {}
151                _ => panic!(
152                    "invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)"
153                ),
154            }
155        }
156
157        self.dist = sk_lwe.dist;
158
159        let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n(), 1);
160        let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data.to_ref();
161
162        self.keys.iter_mut().enumerate().for_each(|(i, ggsw)| {
163            pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i];
164            ggsw.encrypt_sk(module, &pt, sk_glwe, source_xa, source_xe, sigma, scratch);
165        });
166    }
167}
168
169#[derive(PartialEq, Eq)]
170pub struct BlindRotationKeyCGGIExec<D: Data, B: Backend> {
171    pub(crate) data: Vec<GGSWCiphertextExec<D, B>>,
172    pub(crate) dist: Distribution,
173    pub(crate) x_pow_a: Option<Vec<SvpPPol<Vec<u8>, B>>>,
174}
175
176impl<D: Data, B: Backend> BlindRotationKeyCGGIExec<D, B> {
177    #[allow(dead_code)]
178    pub(crate) fn n(&self) -> usize {
179        self.data[0].n()
180    }
181
182    #[allow(dead_code)]
183    pub(crate) fn rows(&self) -> usize {
184        self.data[0].rows()
185    }
186
187    #[allow(dead_code)]
188    pub(crate) fn k(&self) -> usize {
189        self.data[0].k()
190    }
191
192    #[allow(dead_code)]
193    pub(crate) fn size(&self) -> usize {
194        self.data[0].size()
195    }
196
197    #[allow(dead_code)]
198    pub(crate) fn rank(&self) -> usize {
199        self.data[0].rank()
200    }
201
202    pub(crate) fn basek(&self) -> usize {
203        self.data[0].basek()
204    }
205
206    pub(crate) fn block_size(&self) -> usize {
207        match self.dist {
208            Distribution::BinaryBlock(value) => value,
209            _ => 1,
210        }
211    }
212}
213
214pub trait BlindRotationKeyCGGIExecLayoutFamily<B: Backend> = GGSWLayoutFamily<B> + SvpPPolAlloc<B> + SvpPrepare<B>;
215
216impl<B: Backend> BlindRotationKeyCGGIExec<Vec<u8>, B> {
217    pub fn alloc(module: &Module<B>, n_glwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self
218    where
219        Module<B>: BlindRotationKeyCGGIExecLayoutFamily<B>,
220    {
221        let mut data: Vec<GGSWCiphertextExec<Vec<u8>, B>> = Vec::with_capacity(n_lwe);
222        (0..n_lwe).for_each(|_| {
223            data.push(GGSWCiphertextExec::alloc(
224                module, n_glwe, basek, k, rows, 1, rank,
225            ))
226        });
227        Self {
228            data,
229            dist: Distribution::NONE,
230            x_pow_a: None,
231        }
232    }
233
234    pub fn from<DataOther>(module: &Module<B>, other: &BlindRotationKeyCGGI<DataOther>, scratch: &mut Scratch<B>) -> Self
235    where
236        DataOther: DataRef,
237        Module<B>: BlindRotationKeyCGGIExecLayoutFamily<B>,
238    {
239        let mut brk: BlindRotationKeyCGGIExec<Vec<u8>, B> = Self::alloc(
240            module,
241            other.n(),
242            other.keys.len(),
243            other.basek(),
244            other.k(),
245            other.rows(),
246            other.rank(),
247        );
248        brk.prepare(module, other, scratch);
249        brk
250    }
251}
252
253impl<D: DataMut, B: Backend> BlindRotationKeyCGGIExec<D, B> {
254    pub fn prepare<DataOther>(&mut self, module: &Module<B>, other: &BlindRotationKeyCGGI<DataOther>, scratch: &mut Scratch<B>)
255    where
256        DataOther: DataRef,
257        Module<B>: BlindRotationKeyCGGIExecLayoutFamily<B>,
258    {
259        #[cfg(debug_assertions)]
260        {
261            assert_eq!(self.data.len(), other.keys.len());
262        }
263
264        let n: usize = other.n();
265
266        self.data
267            .iter_mut()
268            .zip(other.keys.iter())
269            .for_each(|(ggsw_exec, other)| {
270                ggsw_exec.prepare(module, other, scratch);
271            });
272
273        self.dist = other.dist;
274
275        match other.dist {
276            Distribution::BinaryBlock(_) => {
277                let mut x_pow_a: Vec<SvpPPol<Vec<u8>, B>> = Vec::with_capacity(n << 1);
278                let mut buf: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
279                (0..n << 1).for_each(|i| {
280                    let mut res: SvpPPol<Vec<u8>, B> = module.svp_ppol_alloc(n, 1);
281                    set_xai_plus_y(module, i, 0, &mut res, &mut buf);
282                    x_pow_a.push(res);
283                });
284                self.x_pow_a = Some(x_pow_a);
285            }
286            _ => {}
287        }
288    }
289}
290
291pub fn set_xai_plus_y<A, C, B: Backend>(module: &Module<B>, ai: usize, y: i64, res: &mut SvpPPol<A, B>, buf: &mut ScalarZnx<C>)
292where
293    A: DataMut,
294    C: DataMut,
295    Module<B>: SvpPrepare<B>,
296{
297    let n: usize = res.n();
298
299    {
300        let raw: &mut [i64] = buf.at_mut(0, 0);
301        if ai < n {
302            raw[ai] = 1;
303        } else {
304            raw[(ai - n) & (n - 1)] = -1;
305        }
306        raw[0] += y;
307    }
308
309    module.svp_prepare(res, 0, buf, 0);
310
311    {
312        let raw: &mut [i64] = buf.at_mut(0, 0);
313
314        if ai < n {
315            raw[ai] = 0;
316        } else {
317            raw[(ai - n) & (n - 1)] = 0;
318        }
319        raw[0] = 0;
320    }
321}