From bb3ab6df146d02266e583acd70c6c8839f9e5ebd Mon Sep 17 00:00:00 2001 From: Jelle Vos Date: Wed, 7 Sep 2022 14:19:44 +0200 Subject: [PATCH] Implement decrypt_identity for all cryptosystems --- .../src/cryptosystems/curve_el_gamal.rs | 30 +++++++++++++++++++ .../src/cryptosystems/integer_el_gamal.rs | 25 ++++++++++++++++ scicrypt-he/src/cryptosystems/paillier.rs | 21 +++++++++++++ scicrypt-he/src/cryptosystems/rsa.rs | 21 +++++++++++++ scicrypt-traits/src/cryptosystems.rs | 11 +++++++ 5 files changed, 108 insertions(+) diff --git a/scicrypt-he/src/cryptosystems/curve_el_gamal.rs b/scicrypt-he/src/cryptosystems/curve_el_gamal.rs index eee81e7..dd10b5a 100644 --- a/scicrypt-he/src/cryptosystems/curve_el_gamal.rs +++ b/scicrypt-he/src/cryptosystems/curve_el_gamal.rs @@ -160,6 +160,14 @@ impl DecryptionKey for CurveElGamalSK { ) -> RistrettoPoint { self.decrypt_directly(ciphertext) } + + fn decrypt_identity_raw( + &self, + _public_key: &CurveElGamalPK, + ciphertext: &::Ciphertext, + ) -> bool { + ciphertext.c2 == self.key * ciphertext.c1 + } } impl DecryptionKey for CurveElGamalSK { @@ -170,6 +178,14 @@ impl DecryptionKey for CurveElGamalSK { ) -> RistrettoPoint { self.decrypt_directly(ciphertext) } + + fn decrypt_identity_raw( + &self, + _public_key: &PrecomputedCurveElGamalPK, + ciphertext: &::Ciphertext, + ) -> bool { + ciphertext.c2 == self.key * ciphertext.c1 + } } impl HomomorphicAddition for CurveElGamalPK { @@ -216,7 +232,9 @@ impl HomomorphicAddition for PrecomputedCurveElGamalPK { mod tests { use crate::cryptosystems::curve_el_gamal::CurveElGamal; use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; + use curve25519_dalek::ristretto::RistrettoPoint; use curve25519_dalek::scalar::Scalar; + use curve25519_dalek::traits::Identity; use rand_core::OsRng; use scicrypt_traits::cryptosystems::{AsymmetricCryptosystem, DecryptionKey, EncryptionKey}; use scicrypt_traits::randomness::GeneralRng; @@ -233,6 +251,18 @@ mod tests { assert_eq!(RISTRETTO_BASEPOINT_POINT, sk.decrypt(&ciphertext)); } + #[test] + fn test_encrypt_decrypt_identity() { + let mut rng = GeneralRng::new(OsRng); + + let el_gamal = CurveElGamal::setup(&Default::default()); + let (pk, sk) = el_gamal.generate_keys(&mut rng); + + let ciphertext = pk.encrypt(&RistrettoPoint::identity(), &mut rng); + + assert!(sk.decrypt_identity(&ciphertext)); + } + #[test] fn test_probabilistic_encryption() { let mut rng = GeneralRng::new(OsRng); diff --git a/scicrypt-he/src/cryptosystems/integer_el_gamal.rs b/scicrypt-he/src/cryptosystems/integer_el_gamal.rs index c96df33..38c1d42 100644 --- a/scicrypt-he/src/cryptosystems/integer_el_gamal.rs +++ b/scicrypt-he/src/cryptosystems/integer_el_gamal.rs @@ -175,6 +175,19 @@ impl DecryptionKey for IntegerElGamalSK { .unwrap()) .rem(&public_key.modulus) } + + fn decrypt_identity_raw( + &self, + public_key: &IntegerElGamalPK, + ciphertext: &::Ciphertext, + ) -> bool { + ciphertext.c2 + == Integer::from( + ciphertext + .c1 + .secure_pow_mod_ref(&self.key, &public_key.modulus), + ) + } } impl HomomorphicMultiplication for IntegerElGamalPK { @@ -217,6 +230,18 @@ mod tests { assert_eq!(19, sk.decrypt(&ciphertext)); } + #[test] + fn test_encrypt_decrypt_identity() { + let mut rng = GeneralRng::new(OsRng); + + let el_gamal = IntegerElGamal::setup(&Default::default()); + let (pk, sk) = el_gamal.generate_keys(&mut rng); + + let ciphertext = pk.encrypt(&Integer::from(1), &mut rng); + + assert!(sk.decrypt_identity(&ciphertext)); + } + #[test] fn test_homomorphic_mul() { let mut rng = GeneralRng::new(OsRng); diff --git a/scicrypt-he/src/cryptosystems/paillier.rs b/scicrypt-he/src/cryptosystems/paillier.rs index eace98f..3880d4b 100644 --- a/scicrypt-he/src/cryptosystems/paillier.rs +++ b/scicrypt-he/src/cryptosystems/paillier.rs @@ -131,6 +131,15 @@ impl DecryptionKey for PaillierSK { inner.rem(&public_key.n) } + + fn decrypt_identity_raw( + &self, + public_key: &PaillierPK, + ciphertext: &::Ciphertext, + ) -> bool { + // TODO: This can be optimized + self.decrypt_raw(public_key, ciphertext) == 0 + } } impl HomomorphicAddition for PaillierPK { @@ -175,6 +184,18 @@ mod tests { assert_eq!(15, sk.decrypt(&ciphertext)); } + #[test] + fn test_encrypt_decrypt_identity() { + let mut rng = GeneralRng::new(OsRng); + + let paillier = Paillier::setup(&BitsOfSecurity::ToyParameters); + let (pk, sk) = paillier.generate_keys(&mut rng); + + let ciphertext = pk.encrypt(&Integer::from(0), &mut rng); + + assert!(sk.decrypt_identity(&ciphertext)); + } + #[test] fn test_homomorphic_add() { let mut rng = GeneralRng::new(OsRng); diff --git a/scicrypt-he/src/cryptosystems/rsa.rs b/scicrypt-he/src/cryptosystems/rsa.rs index 4077144..718176a 100644 --- a/scicrypt-he/src/cryptosystems/rsa.rs +++ b/scicrypt-he/src/cryptosystems/rsa.rs @@ -79,6 +79,15 @@ impl DecryptionKey for RsaSK { fn decrypt_raw(&self, public_key: &RsaPK, ciphertext: &RsaCiphertext) -> Integer { Integer::from(ciphertext.c.secure_pow_mod_ref(&self.d, &public_key.n)) } + + fn decrypt_identity_raw( + &self, + public_key: &RsaPK, + ciphertext: &::Ciphertext, + ) -> bool { + // TODO: This can be optimized + self.decrypt_raw(public_key, ciphertext) == 1 + } } impl HomomorphicMultiplication for RsaPK { @@ -150,6 +159,18 @@ mod tests { assert_eq!(15, sk.decrypt(&ciphertext)); } + #[test] + fn test_encrypt_decrypt_identity() { + let mut rng = GeneralRng::new(OsRng); + + let rsa = Rsa::setup(&BitsOfSecurity::ToyParameters); + let (pk, sk) = rsa.generate_keys(&mut rng); + + let ciphertext = pk.encrypt(&Integer::from(1), &mut rng); + + assert!(sk.decrypt_identity(&ciphertext)); + } + #[test] fn test_homomorphic_mul() { let mut rng = GeneralRng::new(OsRng); diff --git a/scicrypt-traits/src/cryptosystems.rs b/scicrypt-traits/src/cryptosystems.rs index e64ad53..e5205d2 100644 --- a/scicrypt-traits/src/cryptosystems.rs +++ b/scicrypt-traits/src/cryptosystems.rs @@ -65,8 +65,19 @@ pub trait DecryptionKey { self.decrypt_raw(ciphertext.public_key, &ciphertext.ciphertext) } + /// Returns true if the associated ciphertext encrypts the identity. This is typically faster than a full decryption. + fn decrypt_identity<'pk>( + &self, + ciphertext: &AssociatedCiphertext<'pk, PK::Ciphertext, PK>, + ) -> bool { + self.decrypt_identity_raw(ciphertext.public_key, &ciphertext.ciphertext) + } + /// Decrypt the ciphertext using the secret key and its related public key. fn decrypt_raw(&self, public_key: &PK, ciphertext: &PK::Ciphertext) -> PK::Plaintext; + + /// Returns true if the encrypted value equals the identity. This is typically faster than a full decryption. + fn decrypt_identity_raw(&self, public_key: &PK, ciphertext: &PK::Ciphertext) -> bool; } #[derive(PartialEq, Eq, Debug)]