#![doc = include_str!("../README.md")]
#![forbid(missing_docs)]
mod decryption_key;
mod encryption_key;
pub mod utils;
#[cfg(feature = "serde")]
mod serde;
use std::fmt;
use rand_core::{CryptoRng, RngCore};
use rug::Integer;
pub type Ciphertext = Integer;
pub type Plaintext = Integer;
pub type Nonce = Integer;
pub use self::{decryption_key::DecryptionKey, encryption_key::EncryptionKey};
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct Error(#[from] Reason);
#[derive(Debug, thiserror::Error)]
enum Reason {
#[error("p,q are invalid")]
InvalidPQ,
#[error("encryption error")]
Encrypt,
#[error("decryption error")]
Decrypt,
#[error("homomorphic operation failed: invalid inputs")]
Ops,
#[error("could not precompute data for faster exponentiation")]
BuildFastExp,
#[error("bug occurred")]
Bug(#[source] Bug),
}
#[derive(Debug, thiserror::Error)]
enum Bug {
#[error("pow mod undefined")]
PowModUndef,
}
impl From<Bug> for Error {
fn from(err: Bug) -> Self {
Error(Reason::Bug(err))
}
}
mod sealed {
pub trait Sealed {}
impl Sealed for crate::EncryptionKey {}
impl Sealed for crate::DecryptionKey {}
}
pub trait AnyEncryptionKey: sealed::Sealed {
fn n(&self) -> &Integer;
fn nn(&self) -> &Integer;
fn half_n(&self) -> &Integer;
fn encrypt_with(&self, x: &Plaintext, nonce: &Nonce) -> Result<Ciphertext, Error>;
fn oadd(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error>;
fn osub(&self, c1: &Ciphertext, c2: &Ciphertext) -> Result<Ciphertext, Error>;
fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result<Ciphertext, Error>;
fn oneg(&self, ciphertext: &Ciphertext) -> Result<Ciphertext, Error>;
fn in_signed_group(&self, x: &Integer) -> bool;
}
pub trait AnyEncryptionKeyExt: AnyEncryptionKey {
fn encrypt_with_random(
&self,
rng: &mut (impl RngCore + CryptoRng),
x: &Plaintext,
) -> Result<(Ciphertext, Nonce), Error>;
}
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.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)
}
}
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()
}
}