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