arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/bin_fhe/blind_rotation/key_compressed.rs
bin_fhe/blind_rotation/key_compressed.rsRaw
  1use backend::hal::{
  2    api::{FillUniform, Reset, ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, ZnxView, ZnxViewMut},
  3    layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, ScalarZnx, ScalarZnxToRef, Scratch, WriterTo},
  4};
  5use sampling::source::Source;
  6
  7use crate::{
  8    Distribution, Infos,
  9    layouts::{LWESecret, compressed::GGSWCiphertextCompressed, prepared::GLWESecretExec},
 10};
 11use std::fmt;
 12
 13use crate::trait_families::GGSWEncryptSkFamily;
 14
 15#[derive(Clone)]
 16pub struct BlindRotationKeyCGGICompressed<D: Data> {
 17    pub(crate) keys: Vec<GGSWCiphertextCompressed<D>>,
 18    pub(crate) dist: Distribution,
 19}
 20
 21impl<D: DataRef> fmt::Debug for BlindRotationKeyCGGICompressed<D> {
 22    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 23        write!(f, "{}", self)
 24    }
 25}
 26
 27impl<D: Data> PartialEq for BlindRotationKeyCGGICompressed<D> {
 28    fn eq(&self, other: &Self) -> bool {
 29        if self.keys.len() != other.keys.len() {
 30            return false;
 31        }
 32        for (a, b) in self.keys.iter().zip(other.keys.iter()) {
 33            if a != b {
 34                return false;
 35            }
 36        }
 37        self.dist == other.dist
 38    }
 39}
 40
 41impl<D: Data> Eq for BlindRotationKeyCGGICompressed<D> {}
 42
 43impl<D: DataRef> fmt::Display for BlindRotationKeyCGGICompressed<D> {
 44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 45        for (i, key) in self.keys.iter().enumerate() {
 46            write!(f, "key[{}]: {}", i, key)?;
 47        }
 48        writeln!(f, "{:?}", self.dist)
 49    }
 50}
 51
 52impl<D: DataMut> Reset for BlindRotationKeyCGGICompressed<D> {
 53    fn reset(&mut self) {
 54        self.keys.iter_mut().for_each(|key| key.reset());
 55        self.dist = Distribution::NONE;
 56    }
 57}
 58
 59impl<D: DataMut> FillUniform for BlindRotationKeyCGGICompressed<D> {
 60    fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
 61        self.keys
 62            .iter_mut()
 63            .for_each(|key| key.fill_uniform(source));
 64    }
 65}
 66
 67use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 68
 69impl<D: DataMut> ReaderFrom for BlindRotationKeyCGGICompressed<D> {
 70    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
 71        match Distribution::read_from(reader) {
 72            Ok(dist) => self.dist = dist,
 73            Err(e) => return Err(e),
 74        }
 75        let len: usize = reader.read_u64::<LittleEndian>()? as usize;
 76        if self.keys.len() != len {
 77            return Err(std::io::Error::new(
 78                std::io::ErrorKind::InvalidData,
 79                format!("self.keys.len()={} != read len={}", self.keys.len(), len),
 80            ));
 81        }
 82        for key in &mut self.keys {
 83            key.read_from(reader)?;
 84        }
 85        Ok(())
 86    }
 87}
 88
 89impl<D: DataRef> WriterTo for BlindRotationKeyCGGICompressed<D> {
 90    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
 91        match self.dist.write_to(writer) {
 92            Ok(()) => {}
 93            Err(e) => return Err(e),
 94        }
 95        writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
 96        for key in &self.keys {
 97            key.write_to(writer)?;
 98        }
 99        Ok(())
100    }
101}
102
103impl BlindRotationKeyCGGICompressed<Vec<u8>> {
104    pub fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
105        let mut data: Vec<GGSWCiphertextCompressed<Vec<u8>>> = Vec::with_capacity(n_lwe);
106        (0..n_lwe).for_each(|_| {
107            data.push(GGSWCiphertextCompressed::alloc(
108                n_gglwe, basek, k, rows, 1, rank,
109            ))
110        });
111        Self {
112            keys: data,
113            dist: Distribution::NONE,
114        }
115    }
116
117    pub fn generate_from_sk_scratch_space<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> usize
118    where
119        Module<B>: GGSWEncryptSkFamily<B>,
120    {
121        GGSWCiphertextCompressed::encrypt_sk_scratch_space(module, n, basek, k, rank)
122    }
123}
124
125impl<D: DataRef> BlindRotationKeyCGGICompressed<D> {
126    #[allow(dead_code)]
127    pub(crate) fn n(&self) -> usize {
128        self.keys[0].n()
129    }
130
131    #[allow(dead_code)]
132    pub(crate) fn rows(&self) -> usize {
133        self.keys[0].rows()
134    }
135
136    #[allow(dead_code)]
137    pub(crate) fn k(&self) -> usize {
138        self.keys[0].k()
139    }
140
141    #[allow(dead_code)]
142    pub(crate) fn size(&self) -> usize {
143        self.keys[0].size()
144    }
145
146    #[allow(dead_code)]
147    pub(crate) fn rank(&self) -> usize {
148        self.keys[0].rank()
149    }
150
151    #[allow(dead_code)]
152    pub(crate) fn basek(&self) -> usize {
153        self.keys[0].basek()
154    }
155
156    #[allow(dead_code)]
157    pub(crate) fn block_size(&self) -> usize {
158        match self.dist {
159            Distribution::BinaryBlock(value) => value,
160            _ => 1,
161        }
162    }
163}
164
165impl<D: DataMut> BlindRotationKeyCGGICompressed<D> {
166    pub fn generate_from_sk<DataSkGLWE, DataSkLWE, B: Backend>(
167        &mut self,
168        module: &Module<B>,
169        sk_glwe: &GLWESecretExec<DataSkGLWE, B>,
170        sk_lwe: &LWESecret<DataSkLWE>,
171        seed_xa: [u8; 32],
172        source_xe: &mut Source,
173        sigma: f64,
174        scratch: &mut Scratch<B>,
175    ) where
176        DataSkGLWE: DataRef,
177        DataSkLWE: DataRef,
178        Module<B>: GGSWEncryptSkFamily<B> + VecZnxAddScalarInplace,
179        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
180    {
181        #[cfg(debug_assertions)]
182        {
183            assert_eq!(self.keys.len(), sk_lwe.n());
184            assert!(sk_glwe.n() <= module.n());
185            assert_eq!(sk_glwe.rank(), self.keys[0].rank());
186            match sk_lwe.dist {
187                Distribution::BinaryBlock(_)
188                | Distribution::BinaryFixed(_)
189                | Distribution::BinaryProb(_)
190                | Distribution::ZERO => {}
191                _ => panic!(
192                    "invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)"
193                ),
194            }
195        }
196
197        self.dist = sk_lwe.dist;
198
199        let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n(), 1);
200        let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data.to_ref();
201
202        let mut source_xa: Source = Source::new(seed_xa);
203
204        self.keys.iter_mut().enumerate().for_each(|(i, ggsw)| {
205            pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i];
206            ggsw.encrypt_sk(
207                module,
208                &pt,
209                sk_glwe,
210                source_xa.new_seed(),
211                source_xe,
212                sigma,
213                scratch,
214            );
215        });
216    }
217}