Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AnyEncryptioKey trait #7

Merged
merged 2 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/decryption_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ impl<FastExp: utils::FactorizedExp> DecryptionKey<FastExp> {
}

/// 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
Expand Down
183 changes: 183 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ pub mod utils;
#[cfg(feature = "serde")]
mod serde;

use std::fmt;

use rand_core::{CryptoRng, RngCore};
use rug::Integer;

pub type Ciphertext = Integer;
Expand Down Expand Up @@ -44,3 +47,183 @@ impl From<Bug> 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<Integer, Error> {
/// // ...
/// # 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<Ciphertext, Error>;

/// Homomorphic addition of two ciphertexts
///
/// ```text
/// oadd(Enc(a1), Enc(a2)) = Enc(a1 + a2)
/// ```
fn oadd(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error>;
/// Homomorphic subtraction of two ciphertexts
///
/// ```text
/// osub(Enc(a1), Enc(a2)) = Enc(a1 - a2)
/// ```
fn osub(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error>;
/// Homomorphic multiplication of scalar at ciphertext
///
/// ```text
/// omul(a, Enc(c)) = Enc(a * c)
/// ```
fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result<Ciphertext, Error>;
/// Homomorphic negation of a ciphertext
///
/// ```text
/// oneg(Enc(a)) = Enc(-a)
/// ```
fn oneg(&self, ciphertext: &Ciphertext) -> Result<Ciphertext, Error>;

/// 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>;
}
maurges marked this conversation as resolved.
Show resolved Hide resolved

impl<E: AnyEncryptionKey> 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<Ciphertext, Error> {
self.encrypt_with(x, nonce)
}

fn oadd(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error> {
self.oadd(c1, c2)
}

fn osub(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error> {
self.osub(c1, c2)
}

fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result<Ciphertext, Error> {
self.omul(scalar, ciphertext)
}

fn oneg(&self, ciphertext: &Ciphertext) -> Result<Ciphertext, Error> {
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<Ciphertext, Error> {
self.encrypt_with(x, nonce)
}

fn oadd(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error> {
self.encryption_key().oadd(c1, c2)
}

fn osub(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error> {
self.encryption_key().osub(c1, c2)
}

fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result<Ciphertext, Error> {
self.encryption_key().omul(scalar, ciphertext)
}

fn oneg(&self, ciphertext: &Ciphertext) -> Result<Ciphertext, Error> {
self.encryption_key().oneg(ciphertext)
}

fn in_signed_group(&self, x: &Integer) -> bool {
self.encryption_key().in_signed_group(x)
}
}
maurges marked this conversation as resolved.
Show resolved Hide resolved

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()
}
}