scicrypt_he/cryptosystems/
rsa.rs

1use scicrypt_bigint::UnsignedInteger;
2use scicrypt_numbertheory::gen_rsa_modulus;
3use scicrypt_traits::cryptosystems::{
4    Associable, AsymmetricCryptosystem, DecryptionKey, EncryptionKey, SigningKey, VerificationKey,
5};
6use scicrypt_traits::homomorphic::HomomorphicMultiplication;
7use scicrypt_traits::randomness::GeneralRng;
8use scicrypt_traits::randomness::SecureRng;
9use scicrypt_traits::security::BitsOfSecurity;
10use serde::{Deserialize, Serialize};
11
12/// The RSA cryptosystem.
13#[derive(Copy, Clone)]
14pub struct Rsa {
15    modulus_size: u32,
16}
17
18/// Public key for the RSA cryptosystem.
19#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
20pub struct RsaPK {
21    /// Public modulus
22    pub n: UnsignedInteger,
23    /// Public exponentation factor
24    pub e: UnsignedInteger,
25}
26
27/// Decryption key for RSA
28pub struct RsaSK {
29    d: UnsignedInteger,
30}
31
32/// Ciphertext of the RSA cryptosystem, which is multiplicatively homomorphic.
33#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
34pub struct RsaCiphertext {
35    /// Ciphertext as an Integer
36    pub c: UnsignedInteger,
37}
38
39impl Associable<RsaPK> for RsaCiphertext {}
40
41impl AsymmetricCryptosystem for Rsa {
42    type PublicKey = RsaPK;
43    type SecretKey = RsaSK;
44
45    fn setup(security_param: &BitsOfSecurity) -> Self {
46        Rsa {
47            modulus_size: security_param.to_public_key_bit_length(),
48        }
49    }
50
51    fn generate_keys<R: SecureRng>(&self, rng: &mut GeneralRng<R>) -> (RsaPK, RsaSK) {
52        let (n, lambda) = gen_rsa_modulus(self.modulus_size, rng);
53
54        let e = UnsignedInteger::new(65537, 17);
55        let d = e
56            .clone()
57            .invert_leaky(&lambda)
58            .expect("e should always be invertible mod lambda.");
59
60        (RsaPK { n, e }, RsaSK { d })
61    }
62}
63
64impl EncryptionKey for RsaPK {
65    type Input = UnsignedInteger;
66    type Plaintext = UnsignedInteger;
67    type Ciphertext = RsaCiphertext;
68    type Randomness = UnsignedInteger;
69
70    fn encrypt_raw<R: SecureRng>(
71        &self,
72        plaintext: &UnsignedInteger,
73        _rng: &mut GeneralRng<R>,
74    ) -> Self::Ciphertext {
75        self.encrypt_without_randomness(plaintext)
76    }
77
78    fn encrypt_without_randomness(&self, plaintext: &Self::Plaintext) -> Self::Ciphertext {
79        RsaCiphertext {
80            c: plaintext.pow_mod(&self.e, &self.n),
81        }
82    }
83
84    fn randomize<R: SecureRng>(
85        &self,
86        _ciphertext: Self::Ciphertext,
87        _rng: &mut GeneralRng<R>,
88    ) -> Self::Ciphertext {
89        panic!("Not possible to randomize Rsa ciphertext")
90    }
91
92    fn randomize_with(
93        &self,
94        _ciphertext: Self::Ciphertext,
95        _randomness: &Self::Randomness,
96    ) -> Self::Ciphertext {
97        panic!("Not possible to randomize Rsa ciphertext")
98    }
99}
100
101impl DecryptionKey<RsaPK> for RsaSK {
102    fn decrypt_raw(&self, public_key: &RsaPK, ciphertext: &RsaCiphertext) -> UnsignedInteger {
103        ciphertext.c.pow_mod(&self.d, &public_key.n)
104    }
105
106    fn decrypt_identity_raw(
107        &self,
108        public_key: &RsaPK,
109        ciphertext: &<RsaPK as EncryptionKey>::Ciphertext,
110    ) -> bool {
111        // TODO: This can be optimized
112        self.decrypt_raw(public_key, ciphertext) == UnsignedInteger::from(1u64)
113    }
114}
115
116impl HomomorphicMultiplication for RsaPK {
117    fn mul(
118        &self,
119        ciphertext_a: &Self::Ciphertext,
120        ciphertext_b: &Self::Ciphertext,
121    ) -> Self::Ciphertext {
122        RsaCiphertext {
123            c: (&ciphertext_a.c * &ciphertext_b.c) % &self.n,
124        }
125    }
126
127    fn pow(&self, ciphertext: &Self::Ciphertext, input: &Self::Input) -> Self::Ciphertext {
128        RsaCiphertext {
129            c: ciphertext.c.pow_mod(input, &self.n),
130        }
131    }
132}
133/// Signature of the RSA cryptosystem
134#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
135pub struct RsaSignature {
136    /// Signature as an Integer
137    pub s: UnsignedInteger,
138}
139
140impl VerificationKey for RsaPK {
141    type Plaintext = UnsignedInteger;
142    type Signature = RsaSignature;
143
144    fn verify(&self, signature: &Self::Signature, plaintext: &Self::Plaintext) -> bool {
145        signature.s.pow_mod(&self.e, &self.n) == *plaintext
146    }
147}
148
149impl SigningKey<RsaPK> for RsaSK {
150    fn sign<R: SecureRng>(
151        &self,
152        plaintext: &<RsaPK as VerificationKey>::Plaintext,
153        public_key: &RsaPK,
154        _rng: &mut GeneralRng<R>,
155    ) -> RsaSignature {
156        RsaSignature {
157            s: plaintext.pow_mod(&self.d, &public_key.n),
158        }
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use crate::cryptosystems::rsa::Rsa;
165    use rand_core::OsRng;
166    use scicrypt_bigint::UnsignedInteger;
167    use scicrypt_traits::cryptosystems::{
168        AsymmetricCryptosystem, DecryptionKey, EncryptionKey, SigningKey, VerificationKey,
169    };
170    use scicrypt_traits::randomness::GeneralRng;
171    use scicrypt_traits::security::BitsOfSecurity;
172
173    #[test]
174    fn test_encrypt_decrypt_generator() {
175        let mut rng = GeneralRng::new(OsRng);
176
177        let rsa = Rsa::setup(&BitsOfSecurity::ToyParameters);
178        let (pk, sk) = rsa.generate_keys(&mut rng);
179
180        let ciphertext = pk.encrypt(&UnsignedInteger::from(15u64), &mut rng);
181
182        assert_eq!(UnsignedInteger::from(15u64), sk.decrypt(&ciphertext));
183    }
184
185    #[test]
186    fn test_encrypt_decrypt_identity() {
187        let mut rng = GeneralRng::new(OsRng);
188
189        let rsa = Rsa::setup(&BitsOfSecurity::ToyParameters);
190        let (pk, sk) = rsa.generate_keys(&mut rng);
191
192        let ciphertext = pk.encrypt(&UnsignedInteger::from(1), &mut rng);
193
194        assert!(sk.decrypt_identity(&ciphertext));
195    }
196
197    #[test]
198    fn test_homomorphic_mul() {
199        let mut rng = GeneralRng::new(OsRng);
200
201        let rsa = Rsa::setup(&BitsOfSecurity::ToyParameters);
202        let (pk, sk) = rsa.generate_keys(&mut rng);
203
204        let ciphertext_a = pk.encrypt(&UnsignedInteger::from(7u64), &mut rng);
205        let ciphertext_b = pk.encrypt(&UnsignedInteger::from(7u64), &mut rng);
206        let ciphertext_twice = &ciphertext_a * &ciphertext_b;
207
208        assert_eq!(UnsignedInteger::from(49u64), sk.decrypt(&ciphertext_twice));
209    }
210
211    #[test]
212    fn test_homomorphic_scalar_pow() {
213        let mut rng = GeneralRng::new(OsRng);
214
215        let rsa = Rsa::setup(&BitsOfSecurity::ToyParameters);
216        let (pk, sk) = rsa.generate_keys(&mut rng);
217
218        let ciphertext = pk.encrypt(&UnsignedInteger::from(9u64), &mut rng);
219        let ciphertext_twice = ciphertext.pow(&UnsignedInteger::from(4u64));
220
221        assert_eq!(
222            UnsignedInteger::from(6561u64),
223            sk.decrypt(&ciphertext_twice)
224        );
225    }
226
227    #[test]
228    fn test_signature_verification() {
229        let mut rng = GeneralRng::new(OsRng);
230
231        let rsa = Rsa::setup(&BitsOfSecurity::ToyParameters);
232        let (pk, sk) = rsa.generate_keys(&mut rng);
233        let plaintext = UnsignedInteger::from(10u64);
234
235        let signature = sk.sign(&plaintext, &pk, &mut rng);
236
237        assert!(pk.verify(&signature, &plaintext));
238    }
239
240    #[test]
241    fn test_signature_verification_incorrect() {
242        let mut rng = GeneralRng::new(OsRng);
243
244        let rsa = Rsa::setup(&BitsOfSecurity::ToyParameters);
245        let (pk, sk) = rsa.generate_keys(&mut rng);
246        let plaintext = UnsignedInteger::from(10u64);
247
248        let signature = sk.sign(&plaintext, &pk, &mut rng);
249
250        assert!(!pk.verify(&signature, &UnsignedInteger::from(11u64)));
251    }
252}