arnaucube
arnaucube/fhe-studyPublic Self-hosted repository
fhe-study/gfhe/src/glev.rs
gfhe/src/glev.rsRaw
 1use anyhow::Result;
 2use rand::Rng;
 3use rand_distr::{Normal, Uniform};
 4use std::ops::{Add, Mul};
 5
 6use arith::{Ring, TR};
 7
 8use crate::glwe::{PublicKey, SecretKey, GLWE};
 9
10const ERR_SIGMA: f64 = 3.2;
11
12// l GLWEs
13#[derive(Clone, Debug)]
14pub struct GLev<R: Ring, const K: usize>(pub(crate) Vec<GLWE<R, K>>);
15
16impl<R: Ring, const K: usize> GLev<R, K> {
17    pub fn encrypt(
18        mut rng: impl Rng,
19        beta: u32,
20        l: u32,
21        pk: &PublicKey<R, K>,
22        m: &R,
23    ) -> Result<Self> {
24        let glev: Vec<GLWE<R, K>> = (0..l)
25            .map(|i| {
26                GLWE::<R, K>::encrypt(&mut rng, pk, &(*m * (R::Q / beta.pow(i as u32) as u64)))
27            })
28            .collect::<Result<Vec<_>>>()?;
29
30        Ok(Self(glev))
31    }
32    pub fn encrypt_s(
33        mut rng: impl Rng,
34        beta: u32,
35        l: u32,
36        sk: &SecretKey<R, K>,
37        m: &R,
38        // delta: u64,
39    ) -> Result<Self> {
40        let glev: Vec<GLWE<R, K>> = (1..l + 1)
41            .map(|i| {
42                GLWE::<R, K>::encrypt_s(&mut rng, sk, &(*m * (R::Q / beta.pow(i as u32) as u64)))
43            })
44            .collect::<Result<Vec<_>>>()?;
45
46        Ok(Self(glev))
47    }
48
49    pub fn decrypt<const T: u64>(&self, sk: &SecretKey<R, K>, beta: u32) -> R {
50        let pt = self.0[1].decrypt(sk);
51        pt.mul_div_round(beta as u64, R::Q)
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use anyhow::Result;
58    use rand::distributions::Uniform;
59
60    use super::*;
61    use arith::Rq;
62
63    #[test]
64    fn test_encrypt_decrypt() -> Result<()> {
65        const Q: u64 = 2u64.pow(16) + 1;
66        const N: usize = 128;
67        const T: u64 = 2; // plaintext modulus
68        const K: usize = 16;
69        type S = GLev<Rq<Q, N>, K>;
70
71        let beta: u32 = 2;
72        let l: u32 = 16;
73
74        // let delta: u64 = Q / T; // floored
75        let mut rng = rand::thread_rng();
76        let msg_dist = Uniform::new(0_u64, T);
77
78        for _ in 0..200 {
79            let (sk, pk) = GLWE::<Rq<Q, N>, K>::new_key(&mut rng)?;
80
81            let m = Rq::<T, N>::rand_u64(&mut rng, msg_dist)?;
82            let m: Rq<Q, N> = m.remodule::<Q>();
83
84            let c = S::encrypt(&mut rng, beta, l, &pk, &m)?;
85            let m_recovered = c.decrypt::<T>(&sk, beta);
86
87            assert_eq!(m.remodule::<T>(), m_recovered.remodule::<T>());
88        }
89
90        Ok(())
91    }
92}