arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/shortint/enc_dec.rs
src/shortint/enc_dec.rsRaw
  1use itertools::Itertools;
  2
  3use crate::{
  4    bool::BoolEvaluator,
  5    random::{DefaultSecureRng, RandomFillUniformInModulus},
  6    utils::WithLocal,
  7    Decryptor, Encryptor, KeySwitchWithId, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor,
  8    RowMut, SampleExtractor,
  9};
 10
 11/// Fhe UInt8 type
 12///
 13/// - Stores encryptions of bits in little endian (i.e least signficant bit
 14///   stored at 0th index and most signficant bit stores at 7th index)
 15#[derive(Clone)]
 16pub struct FheUint8<C> {
 17    pub(super) data: Vec<C>,
 18}
 19
 20impl<C> FheUint8<C> {
 21    pub(super) fn data(&self) -> &[C] {
 22        &self.data
 23    }
 24
 25    pub(super) fn data_mut(&mut self) -> &mut [C] {
 26        &mut self.data
 27    }
 28}
 29
 30/// Stored a batch of Fhe Uint8 ciphertext as collection of RLWE ciphertexts
 31///
 32/// To extract Fhe Uint8 ciphertext at `index` call `self.extract(index)`
 33pub struct BatchedFheUint8<C> {
 34    /// Vector of RLWE ciphertexts `C`
 35    data: Vec<C>,
 36    /// Count of FheUint8s packed in vector of RLWE ciphertexts
 37    count: usize,
 38}
 39
 40impl<C, R> SampleExtractor<FheUint8<R>> for BatchedFheUint8<C>
 41where
 42    C: SampleExtractor<R>,
 43{
 44    /// Extract Fhe Uint8 ciphertext at `index`
 45    ///
 46    /// `Self` stores batch of Fhe uint8 ciphertext as vector of RLWE
 47    /// ciphertexts. Since Fhe uint8 ciphertext is collection of 8 bool
 48    /// ciphertexts, Fhe uint8 ciphertext at index `i` is stored in coefficients
 49    /// `i*8...(i+1)*8`. To extract Fhe uint8 at index `i`, sample extract bool
 50    /// ciphertext at indices `[i*8, ..., (i+1)*8)`
 51    fn extract_at(&self, index: usize) -> FheUint8<R> {
 52        assert!(index < self.count);
 53        BoolEvaluator::with_local(|e| {
 54            let ring_size = e.parameters().rlwe_n().0;
 55
 56            let start_index = index * 8;
 57            let end_index = (index + 1) * 8;
 58            let data = (start_index..end_index)
 59                .map(|i| {
 60                    let rlwe_index = i / ring_size;
 61                    let coeff_index = i % ring_size;
 62                    self.data[rlwe_index].extract_at(coeff_index)
 63                })
 64                .collect_vec();
 65            FheUint8 { data }
 66        })
 67    }
 68
 69    /// Extracts all FheUint8s packed in vector of RLWE ciphertexts of `Self`
 70    fn extract_all(&self) -> Vec<FheUint8<R>> {
 71        (0..self.count)
 72            .map(|index| self.extract_at(index))
 73            .collect_vec()
 74    }
 75
 76    /// Extracts first `how_many` FheUint8s packed in vector of RLWE
 77    /// ciphertexts of `Self`
 78    fn extract_many(&self, how_many: usize) -> Vec<FheUint8<R>> {
 79        (0..how_many)
 80            .map(|index| self.extract_at(index))
 81            .collect_vec()
 82    }
 83}
 84
 85impl<M: MatrixEntity + MatrixMut<MatElement = u64>> From<&SeededBatchedFheUint8<M::R, [u8; 32]>>
 86    for BatchedFheUint8<M>
 87where
 88    <M as Matrix>::R: RowMut,
 89{
 90    /// Unseeds collection of seeded RLWE ciphertext in SeededBatchedFheUint8
 91    /// and returns as `Self`
 92    fn from(value: &SeededBatchedFheUint8<M::R, [u8; 32]>) -> Self {
 93        BoolEvaluator::with_local(|e| {
 94            let parameters = e.parameters();
 95            let ring_size = parameters.rlwe_n().0;
 96            let rlwe_q = parameters.rlwe_q();
 97
 98            let mut prng = DefaultSecureRng::new_seeded(value.seed);
 99            let rlwes = value
100                .data
101                .iter()
102                .map(|partb| {
103                    let mut rlwe = M::zeros(2, ring_size);
104
105                    // sample A
106                    RandomFillUniformInModulus::random_fill(&mut prng, rlwe_q, rlwe.get_row_mut(0));
107
108                    // Copy over B
109                    rlwe.get_row_mut(1).copy_from_slice(partb.as_ref());
110
111                    rlwe
112                })
113                .collect_vec();
114            Self {
115                data: rlwes,
116                count: value.count,
117            }
118        })
119    }
120}
121
122pub struct SeededBatchedFheUint8<C, S> {
123    /// Vector of Seeded RLWE ciphertexts `C`.
124    ///
125    /// If RLWE(m) = [a, b] s.t. m + e = b - as, `a` can be seeded and seeded
126    /// RLWE ciphertext only contains `b` polynomial
127    data: Vec<C>,
128    /// Seed for the ciphertexts
129    seed: S,
130    /// Count of FheUint8s packed in vector of RLWE ciphertexts
131    count: usize,
132}
133
134impl<C, S> SeededBatchedFheUint8<C, S> {
135    pub fn unseed<M>(&self) -> BatchedFheUint8<M>
136    where
137        BatchedFheUint8<M>: for<'a> From<&'a SeededBatchedFheUint8<C, S>>,
138        M: Matrix<R = C>,
139    {
140        BatchedFheUint8::from(self)
141    }
142}
143
144impl<K, C, S> Encryptor<[u8], SeededBatchedFheUint8<C, S>> for K
145where
146    K: Encryptor<[bool], (Vec<C>, S)>,
147{
148    /// Encrypt a slice of u8s of arbitray length as `SeededBatchedFheUint8`
149    fn encrypt(&self, m: &[u8]) -> SeededBatchedFheUint8<C, S> {
150        // convert vector of u8s to vector bools
151        let bool_m = m
152            .iter()
153            .flat_map(|v| (0..8).into_iter().map(|i| (((*v) >> i) & 1) == 1))
154            .collect_vec();
155        let (cts, seed) = K::encrypt(&self, &bool_m);
156        SeededBatchedFheUint8 {
157            data: cts,
158            seed,
159            count: m.len(),
160        }
161    }
162}
163
164impl<K, C> Encryptor<[u8], BatchedFheUint8<C>> for K
165where
166    K: Encryptor<[bool], Vec<C>>,
167{
168    fn encrypt(&self, m: &[u8]) -> BatchedFheUint8<C> {
169        let bool_m = m
170            .iter()
171            .flat_map(|v| {
172                (0..8)
173                    .into_iter()
174                    .map(|i| ((*v >> i) & 1) == 1)
175                    .collect_vec()
176            })
177            .collect_vec();
178        let cts = K::encrypt(&self, &bool_m);
179        BatchedFheUint8 {
180            data: cts,
181            count: m.len(),
182        }
183    }
184}
185
186impl<C> KeySwitchWithId<BatchedFheUint8<C>> for BatchedFheUint8<C>
187where
188    C: KeySwitchWithId<C>,
189{
190    /// Key switching collection of RLWE ciphertexts in `BatchedFheUint8` from
191    /// user j's RLWE secret u_j to ideal RLWE secret key `s` of the protocol.
192    ///
193    /// - user_id: user id of user j
194    fn key_switch(&self, user_id: usize) -> BatchedFheUint8<C> {
195        let data = self
196            .data
197            .iter()
198            .map(|c| c.key_switch(user_id))
199            .collect_vec();
200        BatchedFheUint8 {
201            data,
202            count: self.count,
203        }
204    }
205}
206
207impl<C, K> MultiPartyDecryptor<u8, FheUint8<C>> for K
208where
209    K: MultiPartyDecryptor<bool, C>,
210    <Self as MultiPartyDecryptor<bool, C>>::DecryptionShare: Clone,
211{
212    type DecryptionShare = Vec<<Self as MultiPartyDecryptor<bool, C>>::DecryptionShare>;
213    fn gen_decryption_share(&self, c: &FheUint8<C>) -> Self::DecryptionShare {
214        assert!(c.data().len() == 8);
215        c.data()
216            .iter()
217            .map(|bit_c| {
218                let decryption_share =
219                    MultiPartyDecryptor::<bool, C>::gen_decryption_share(self, bit_c);
220                decryption_share
221            })
222            .collect_vec()
223    }
224
225    fn aggregate_decryption_shares(&self, c: &FheUint8<C>, shares: &[Self::DecryptionShare]) -> u8 {
226        let mut out = 0u8;
227
228        (0..8).into_iter().for_each(|i| {
229            // Collect bit i^th decryption share of each party
230            let bit_i_decryption_shares = shares.iter().map(|s| s[i].clone()).collect_vec();
231            let bit_i = MultiPartyDecryptor::<bool, C>::aggregate_decryption_shares(
232                self,
233                &c.data()[i],
234                &bit_i_decryption_shares,
235            );
236
237            if bit_i {
238                out += 1 << i;
239            }
240        });
241
242        out
243    }
244}
245
246impl<C, K> Encryptor<u8, FheUint8<C>> for K
247where
248    K: Encryptor<bool, C>,
249{
250    fn encrypt(&self, m: &u8) -> FheUint8<C> {
251        let cts = (0..8)
252            .into_iter()
253            .map(|i| {
254                let bit = ((m >> i) & 1) == 1;
255                K::encrypt(self, &bit)
256            })
257            .collect_vec();
258        FheUint8 { data: cts }
259    }
260}
261
262impl<K, C> Decryptor<u8, FheUint8<C>> for K
263where
264    K: Decryptor<bool, C>,
265{
266    fn decrypt(&self, c: &FheUint8<C>) -> u8 {
267        assert!(c.data.len() == 8);
268        let mut out = 0u8;
269        c.data().iter().enumerate().for_each(|(index, bit_c)| {
270            let bool = K::decrypt(self, bit_c);
271            if bool {
272                out += 1 << index;
273            }
274        });
275        out
276    }
277}