Skip to main content

gsw_rs/
lib.rs

1//! GSW (Gentry-Sahai-Waters) lattice-based Fully Homomorphic Encryption.
2//!
3//! This crate implements the GSW FHE scheme with:
4//! - LWE-based key generation
5//! - Homomorphic addition and multiplication
6//! - Bootstrapping (homomorphic evaluation of decryption)
7//!
8//! # Example
9//!
10//! ```ignore
11//! use gsw_rs::{gsw_keygen, encrypt, decrypt, homomorphic_add, homomorphic_mult};
12//! use gsw_rs::params::{Params, SecurityLevel};
13//! use rand::thread_rng;
14//!
15//! let params = Params::toy();
16//! let mut rng = thread_rng();
17//! let (sk, pk) = gsw_keygen(&mut rng, &params);
18//!
19//! let ct0 = encrypt(&mut rng, &pk, 0);
20//! let ct1 = encrypt(&mut rng, &pk, 1);
21//! assert_eq!(decrypt(&sk, &ct0), 0);
22//! assert_eq!(decrypt(&sk, &ct1), 1);
23//!
24//! let ct_and = homomorphic_mult(&params, &ct1, &ct1);
25//! assert_eq!(decrypt(&sk, &ct_and), 1);
26//! ```
27
28pub mod bootstrap;
29pub mod gadget;
30pub mod lwe;
31pub mod modular;
32pub mod params;
33
34pub use bootstrap::{bootstrap, decrypt_linear_part_clear, gen_evaluation_key, EvaluationKey};
35pub use gadget::{bit_decomp, bit_decomp_inverse, flatten, flatten_matrix, powers_of_2};
36pub use gsw::{
37    decrypt, encrypt, gsw_keygen, homomorphic_add, homomorphic_mult, homomorphic_nand,
38    Ciphertext, GswPublicKey, GswSecretKey,
39};
40pub use lwe::{keygen, PublicKey, SecretKey};
41pub use params::{Params, SecurityLevel};
42
43mod gsw;
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::bootstrap::{bootstrap, gen_evaluation_key};
49    use rand::SeedableRng;
50    use rand::thread_rng;
51    use rand_chacha::ChaCha20Rng;
52
53    #[test]
54    fn test_encrypt_decrypt() {
55        let params = Params::toy();
56        let mut rng = ChaCha20Rng::seed_from_u64(42);
57        let (sk, pk) = gsw_keygen(&mut rng, &params);
58        for bit in [0u8, 1u8] {
59            let ct = encrypt(&mut rng, &pk, bit);
60            assert_eq!(decrypt(&sk, &ct), bit);
61        }
62    }
63
64    #[test]
65    fn test_homomorphic_ops() {
66        let params = Params::toy();
67        let mut rng = ChaCha20Rng::seed_from_u64(42);
68        let (sk, pk) = gsw_keygen(&mut rng, &params);
69        let ct0 = encrypt(&mut rng, &pk, 0);
70        let ct1 = encrypt(&mut rng, &pk, 1);
71
72        assert_eq!(decrypt(&sk, &homomorphic_add(&params, &ct0, &ct0)), 0);
73        assert_eq!(decrypt(&sk, &homomorphic_add(&params, &ct0, &ct1)), 1);
74        assert_eq!(decrypt(&sk, &homomorphic_add(&params, &ct1, &ct1)), 0);
75        assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct0, &ct0)), 0);
76        assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct0, &ct1)), 0);
77        assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct1, &ct1)), 1);
78        assert_eq!(decrypt(&sk, &homomorphic_nand(&params, &ct1, &ct1)), 0);
79    }
80
81    #[test]
82    fn test_homomorphic_ops_deterministic() {
83        let params = Params::toy();
84        for seed in 0..100u64 {
85            let mut rng = ChaCha20Rng::seed_from_u64(seed);
86            let (sk, pk) = gsw_keygen(&mut rng, &params);
87            let ct0 = encrypt(&mut rng, &pk, 0);
88            let ct1 = encrypt(&mut rng, &pk, 1);
89
90            assert_eq!(decrypt(&sk, &homomorphic_add(&params, &ct0, &ct1)), 1, "seed {}: 0 XOR 1", seed);
91            assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct0, &ct1)), 0, "seed {}: 0 AND 1", seed);
92            assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct1, &ct1)), 1, "seed {}: 1 AND 1", seed);
93        }
94    }
95
96    #[test]
97    fn test_homomorphic_ops_nondeterministic() {
98        let params = Params::toy();
99        let mut rng = thread_rng();
100        for _ in 0..50 {
101            let (sk, pk) = gsw_keygen(&mut rng, &params);
102            let ct0 = encrypt(&mut rng, &pk, 0);
103            let ct1 = encrypt(&mut rng, &pk, 1);
104
105            assert_eq!(decrypt(&sk, &homomorphic_add(&params, &ct0, &ct0)), 0);
106            assert_eq!(decrypt(&sk, &homomorphic_add(&params, &ct0, &ct1)), 1);
107            assert_eq!(decrypt(&sk, &homomorphic_add(&params, &ct1, &ct1)), 0);
108            assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct0, &ct0)), 0);
109            assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct0, &ct1)), 0);
110            assert_eq!(decrypt(&sk, &homomorphic_mult(&params, &ct1, &ct1)), 1);
111            assert_eq!(decrypt(&sk, &homomorphic_nand(&params, &ct1, &ct1)), 0);
112        }
113    }
114
115    #[test]
116    fn test_bootstrap_nondeterministic() {
117        // Bootstrap adds N encryptions; verify it works with thread_rng() (non-deterministic).
118        let params = Params::toy();
119        let mut rng = thread_rng();
120        let mut passed = 0;
121        for _ in 0..50 {
122            let (sk, pk) = gsw_keygen(&mut rng, &params);
123            let ek = gen_evaluation_key(&mut rng, &sk, &pk);
124            let ct1 = encrypt(&mut rng, &pk, 1);
125            let ct_noisy = homomorphic_mult(&params, &ct1, &ct1);
126            let ct_bootstrapped = bootstrap(&params, &ct_noisy, &ek);
127            if decrypt(&sk, &ct_bootstrapped) == 1 {
128                passed += 1;
129            }
130        }
131        assert!(passed >= 10, "Bootstrap must succeed with non-deterministic RNG (got {}/50)", passed);
132    }
133
134    #[test]
135    fn test_bootstrap() {
136        let params = Params::toy();
137        let mut rng = ChaCha20Rng::seed_from_u64(42);
138        let (sk, pk) = gsw_keygen(&mut rng, &params);
139        let ek = gen_evaluation_key(&mut rng, &sk, &pk);
140        let ct1 = encrypt(&mut rng, &pk, 1);
141        let ct_noisy = homomorphic_mult(&params, &ct1, &ct1);
142        let ct_bootstrapped = bootstrap(&params, &ct_noisy, &ek);
143        assert_eq!(decrypt(&sk, &ct_bootstrapped), 1, "Bootstrap must produce correct output");
144    }
145}