From 7f2ee8cda13210aae187293607f9837624f4af9c Mon Sep 17 00:00:00 2001 From: Denis Varlakov Date: Thu, 21 Sep 2023 11:46:40 +0000 Subject: [PATCH 1/2] Add `AnyEncryptioKey` trait --- src/decryption_key.rs | 4 +- src/lib.rs | 173 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 2 deletions(-) diff --git a/src/decryption_key.rs b/src/decryption_key.rs index f14ceaf..2462250 100644 --- a/src/decryption_key.rs +++ b/src/decryption_key.rs @@ -131,8 +131,8 @@ impl DecryptionKey { } /// Returns a (public) encryption key corresponding to the (secret) decryption key - pub fn encryption_key(&self) -> EncryptionKey { - self.ek.clone() + pub fn encryption_key(&self) -> &EncryptionKey { + &self.ek } /// The Paillier modulus diff --git a/src/lib.rs b/src/lib.rs index d328b28..1f76d0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub mod utils; #[cfg(feature = "serde")] mod serde; +use rand_core::{CryptoRng, RngCore}; use rug::Integer; pub type Ciphertext = Integer; @@ -44,3 +45,175 @@ impl From for Error { Error(Reason::Bug(err)) } } + +mod sealed { + pub trait Sealed {} + impl Sealed for crate::EncryptionKey {} + impl Sealed for crate::DecryptionKey {} +} + +/// Any key capable of encryption +/// +/// Both encryption and decryption keys can be used to carry out encryption. Moreover, encryption +/// using decryption key is faster. +/// +/// ## Example +/// This trait can be used, for instance, to accept an encryption key as an argument to the function +/// and benefit from faster encryption if decryption key is provided. +/// +/// ```rust +/// use fast_paillier::{AnyEncryptionKey, Error}; +/// use rug::Integer; +/// +/// // This function accepts both encryption and decryption key. If decryption key is provided, +/// // it'll be more efficient +/// fn some_function(ek: &dyn AnyEncryptionKey) -> Result { +/// // ... +/// # let x = Integer::from(123); let r = Integer::from(321); +/// let ciphertext = ek.encrypt_with(&x, &r)?; +/// Ok(ciphertext) +/// } +/// ``` +pub trait AnyEncryptionKey: sealed::Sealed { + /// Returns `N` + fn n(&self) -> &Integer; + /// Returns `N^2` + fn nn(&self) -> &Integer; + /// Returns `N/2` + fn half_n(&self) -> &Integer; + + /// Encrypts the plaintext `x` in `{-N/2, .., N_2}` with `nonce` in `Z*_n` + /// + /// Returns error if inputs are not in specified range + fn encrypt_with(&self, x: &Plaintext, nonce: &Nonce) -> Result; + + /// Homomorphic addition of two ciphertexts + /// + /// ```text + /// oadd(Enc(a1), Enc(a2)) = Enc(a1 + a2) + /// ``` + fn oadd(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result; + /// Homomorphic subtraction of two ciphertexts + /// + /// ```text + /// osub(Enc(a1), Enc(a2)) = Enc(a1 - a2) + /// ``` + fn osub(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result; + /// Homomorphic multiplication of scalar at ciphertext + /// + /// ```text + /// omul(a, Enc(c)) = Enc(a * c) + /// ``` + fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result; + /// Homomorphic negation of a ciphertext + /// + /// ```text + /// oneg(Enc(a)) = Enc(-a) + /// ``` + fn oneg(&self, ciphertext: &Ciphertext) -> Result; + + /// Checks whether `x` is `{-N/2, .., N/2}` + fn in_signed_group(&self, x: &Integer) -> bool; +} + +/// Additional functionality implemented for [AnyEncryptionKey] +pub trait AnyEncryptionKeyExt: AnyEncryptionKey { + /// Encrypts the plaintext `x` in `{-N/2, .., N_2}` + /// + /// Nonce is sampled randomly using `rng`. + /// + /// Returns error if plaintext is not in specified range + fn encrypt_with_random( + &self, + rng: &mut (impl RngCore + CryptoRng), + x: &Plaintext, + ) -> Result<(Ciphertext, Nonce), Error>; +} + +impl AnyEncryptionKeyExt for E { + fn encrypt_with_random( + &self, + rng: &mut (impl RngCore + CryptoRng), + x: &Plaintext, + ) -> Result<(Ciphertext, Nonce), Error> { + let nonce = utils::sample_in_mult_group(rng, self.n()); + let ciphertext = self.encrypt_with(x, &nonce)?; + Ok((ciphertext, nonce)) + } +} + +impl AnyEncryptionKey for EncryptionKey { + fn n(&self) -> &Integer { + self.n() + } + + fn nn(&self) -> &Integer { + self.nn() + } + + fn half_n(&self) -> &Integer { + self.half_n() + } + + fn encrypt_with(&self, x: &Plaintext, nonce: &Nonce) -> Result { + self.encrypt_with(x, nonce) + } + + fn oadd(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result { + self.oadd(c1, c2) + } + + fn osub(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result { + self.osub(c1, c2) + } + + fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result { + self.omul(scalar, ciphertext) + } + + fn oneg(&self, ciphertext: &Ciphertext) -> Result { + self.oneg(ciphertext) + } + + fn in_signed_group(&self, x: &Integer) -> bool { + self.in_signed_group(x) + } +} + +impl AnyEncryptionKey for DecryptionKey { + fn n(&self) -> &Integer { + self.encryption_key().n() + } + + fn nn(&self) -> &Integer { + self.encryption_key().nn() + } + + fn half_n(&self) -> &Integer { + self.encryption_key().half_n() + } + + fn encrypt_with(&self, x: &Plaintext, nonce: &Nonce) -> Result { + self.encrypt_with(x, nonce) + } + + fn oadd(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result { + self.encryption_key().oadd(c1, c2) + } + + fn osub(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result { + self.encryption_key().osub(c1, c2) + } + + fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result { + self.encryption_key().omul(scalar, ciphertext) + } + + fn oneg(&self, ciphertext: &Ciphertext) -> Result { + self.encryption_key().oneg(ciphertext) + } + + fn in_signed_group(&self, x: &Integer) -> bool { + self.encryption_key().in_signed_group(x) + } +} From 72b2fc654e4f9af3172204ca0ae9a3e0bcd5f66e Mon Sep 17 00:00:00 2001 From: Denis Varlakov Date: Thu, 21 Sep 2023 11:53:10 +0000 Subject: [PATCH 2/2] Impl Debug for AnyEncryptionKey --- src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1f76d0b..a9f3fbe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ pub mod utils; #[cfg(feature = "serde")] mod serde; +use std::fmt; + use rand_core::{CryptoRng, RngCore}; use rug::Integer; @@ -217,3 +219,11 @@ impl AnyEncryptionKey for DecryptionKey { self.encryption_key().in_signed_group(x) } } + +impl<'a> fmt::Debug for dyn AnyEncryptionKey + 'a { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PaillierEncKey") + .field("N", self.n()) + .finish_non_exhaustive() + } +}