Skip to content

Commit

Permalink
use results and errors now
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Lodder <[email protected]>
  • Loading branch information
mikelodder7 committed Aug 21, 2024
1 parent af50481 commit 626bcdb
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 41 deletions.
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license = "Apache-2.0"
name = "libpaillier"
readme = "README.md"
repository = "https://github.com/mikelodder7/paillier-rs"
version = "0.6.0"
version = "0.7.0"

[features]
default = ["crypto"]
Expand All @@ -24,12 +24,13 @@ wasm = ["getrandom", "rand", "wasm-bindgen", "serde-wasm-bindgen"]
digest = "0.10"
getrandom = { version = "0.2", features = ["js"], optional = true }
rand = { version = "0.8", optional = true }
postcard = { version = "1.0.9", features = ["use-std"] }
serde = { version = "1.0", features = ["serde_derive"] }
serde_bare = "0.5"
serde-wasm-bindgen = { version = "0.6", optional = true }
unknown_order = { version = "0.8", default-features = false }
thiserror = "1.0"
unknown_order = { version = "0.10", default-features = false }
wasm-bindgen = { version = "0.2", default-features = false, features = ["serde-serialize"], optional = true }
zeroize = { version = "1.5", features = ["zeroize_derive"] }
zeroize = { version = "1.8", features = ["zeroize_derive"] }

[dev-dependencies]
elliptic-curve = "0.13"
Expand Down
16 changes: 8 additions & 8 deletions src/decryptionkey.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{mod_in, Ciphertext, EncryptionKey};
use crate::{mod_in, Ciphertext, EncryptionKey, error::*};
use serde::{Deserialize, Serialize};
use unknown_order::BigNumber;
use zeroize::Zeroize;
Expand Down Expand Up @@ -62,7 +62,7 @@ impl DecryptionKey {
let tt = t.modpow(&lambda, pk.nn());

// L((N+1)^lambda mod N^2)^-1 mod N
let uu = pk.l(&tt).map(|uu| uu.invert(pk.n()));
let uu = pk.l(&tt).map(|uu| uu.invert(pk.n())).ok();
match uu {
None => None,
Some(u_inv) => u_inv.map(|u| DecryptionKey {
Expand All @@ -75,9 +75,9 @@ impl DecryptionKey {
}

/// Reverse ciphertext to plaintext
pub fn decrypt(&self, c: &Ciphertext) -> Option<Vec<u8>> {
if !mod_in(&c, &self.pk.nn) {
return None;
pub fn decrypt(&self, c: &Ciphertext) -> PaillierResult<Vec<u8>> {
if !mod_in(c, &self.pk.nn) {
return Err(PaillierError::InvalidCiphertext);
}

// a = c^\lambda mod n^2
Expand All @@ -101,14 +101,14 @@ impl DecryptionKey {
totient: self.totient.to_bytes(),
u: self.u.to_bytes(),
};
serde_bare::to_vec(&bytes).unwrap()
postcard::to_stdvec(&bytes).unwrap()
}

/// Convert a byte representation to a decryption key
pub fn from_bytes<B: AsRef<[u8]>>(data: B) -> Result<Self, String> {
pub fn from_bytes<B: AsRef<[u8]>>(data: B) -> PaillierResult<Self> {
let data = data.as_ref();
let bytes =
serde_bare::from_slice::<DecryptionKeyBytes>(data).map_err(|e| e.to_string())?;
postcard::from_bytes::<DecryptionKeyBytes>(data)?;
let pk = EncryptionKey::from_bytes(bytes.n.as_slice())?;
Ok(Self {
pk,
Expand Down
46 changes: 23 additions & 23 deletions src/encryptionkey.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{mod_in, Ciphertext, DecryptionKey, Nonce};
use crate::{mod_in, Ciphertext, DecryptionKey, Nonce, PaillierError, PaillierResult};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use unknown_order::BigNumber;
use zeroize::Zeroize;
Expand Down Expand Up @@ -42,72 +42,72 @@ impl EncryptionKey {
/// l computes a residuosity class of N^2: (x - 1) / n
/// where it is the quotient x - 1 divided by N not modular multiplication of x - 1 times
/// the modular multiplication inverse of N. The function comes from Paillier's 99 paper.
pub(crate) fn l(&self, x: &BigNumber) -> Option<BigNumber> {
pub(crate) fn l(&self, x: &BigNumber) -> PaillierResult<BigNumber> {
let one = BigNumber::one();
// Ensure x = 1 mod N
if x % &self.n != one {
return None;
if !(x % &self.n).is_one() {
return Err(PaillierError::InvalidEncryptionKey);
}

// Ensure x \in [1..N^2]
if !mod_in(&x, &self.nn) {
return None;
if !mod_in(x, &self.nn) {
return Err(PaillierError::InvalidEncryptionKey);
}

//(x - 1) / N
Some((x - &one) / &self.n)
Ok((x - &one) / &self.n)
}

/// Encrypt a given message with the encryption key and optionally use a random value
/// x must be less than N
#[allow(clippy::many_single_char_names)]
pub fn encrypt<M>(&self, x: M, r: Option<Nonce>) -> Option<(Ciphertext, Nonce)>
pub fn encrypt<M>(&self, x: M, r: Option<Nonce>) -> PaillierResult<(Ciphertext, Nonce)>
where
M: AsRef<[u8]>,
{
let xx = BigNumber::from_slice(x);
if !mod_in(&xx, &self.n) {
return None;
return Err(PaillierError::InvalidEncryptionInputs);
}

let r = r.unwrap_or_else(|| Nonce::random(&self.n));

if !mod_in(&r, &self.n) {
return None;
return Err(PaillierError::InvalidEncryptionInputs);
}

// a = (N+1)^m mod N^2
let a = (&self.n + BigNumber::one()).modpow(&xx, &self.nn);
// b = r^N mod N^2
let b = &r.modpow(&self.n, &self.nn);

let c = a.modmul(&b, &self.nn);
Some((c, r))
let c = a.modmul(b, &self.nn);
Ok((c, r))
}

/// Combines two Paillier ciphertexts
/// commonly denoted in text as c1 \bigoplus c2
pub fn add(&self, c1: &Ciphertext, c2: &Ciphertext) -> Option<Ciphertext> {
pub fn add(&self, c1: &Ciphertext, c2: &Ciphertext) -> PaillierResult<Ciphertext> {
// constant time check
let c1_check = mod_in(&c1, &self.nn);
let c2_check = mod_in(&c2, &self.nn);
let c1_check = mod_in(c1, &self.nn);
let c2_check = mod_in(c2, &self.nn);
if !c1_check | !c2_check {
return None;
return Err(PaillierError::InvalidCipherTextAddInputs);
}

Some(c1.modmul(c2, &self.nn))
Ok(c1.modmul(c2, &self.nn))
}

/// Equivalent to adding two Paillier exponents
pub fn mul(&self, c: &Ciphertext, a: &BigNumber) -> Option<Ciphertext> {
pub fn mul(&self, c: &Ciphertext, a: &BigNumber) -> PaillierResult<Ciphertext> {
// constant time check
let c1_check = mod_in(&c, &self.nn);
let c2_check = mod_in(&a, &self.n);
let c1_check = mod_in(c, &self.nn);
let c2_check = mod_in(a, &self.n);
if !c1_check | !c2_check {
return None;
return Err(PaillierError::InvalidCipherTextMulInputs);
}

Some(c.modpow(a, &self.nn))
Ok(c.modpow(a, &self.nn))
}

/// Get this key's byte representation
Expand All @@ -116,7 +116,7 @@ impl EncryptionKey {
}

/// Convert a byte representation to a encryption key
pub fn from_bytes<B: AsRef<[u8]>>(data: B) -> Result<Self, String> {
pub fn from_bytes<B: AsRef<[u8]>>(data: B) -> PaillierResult<Self> {
let data = data.as_ref();
let n = BigNumber::from_slice(data);
Ok(Self::from_n(n))
Expand Down
30 changes: 30 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use thiserror::Error;

/// Errors produced by the Paillier scheme
#[derive(Debug, Error)]
pub enum PaillierError {
/// Postcard deserialization error
#[error("Invalid serialized bytes: {0}")]
PostcardError(#[from] postcard::Error),
/// Invalid proof size
#[error("Invalid proof size: {0}")]
InvalidProofSize(usize),
/// Invalid encryption key
#[error("Invalid encryption key")]
InvalidEncryptionKey,
/// Invalid encryption inputs
#[error("Invalid encryption inputs")]
InvalidEncryptionInputs,
/// Invalid ciphertext add inputs
#[error("Invalid ciphertext add inputs")]
InvalidCipherTextAddInputs,
/// Invalid ciphertext multiply inputs
#[error("Invalid ciphertext multiply inputs")]
InvalidCipherTextMulInputs,
/// Invalid ciphertext
#[error("Invalid ciphertext, unable to decrypt")]
InvalidCiphertext,
}

/// Paillier results
pub type PaillierResult<T> = Result<T, PaillierError>;
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
mod macros;
mod decryptionkey;
mod encryptionkey;
mod error;
mod proof_psf;

pub use error::*;
pub use unknown_order;

use unknown_order::BigNumber;
Expand Down
12 changes: 6 additions & 6 deletions src/proof_psf.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{mod_in, DecryptionKey, EncryptionKey};
use crate::{mod_in, DecryptionKey, EncryptionKey, error::*};
use digest::{
generic_array::{typenum::Unsigned, GenericArray},
Digest,
Expand Down Expand Up @@ -59,14 +59,14 @@ impl ProofSquareFree {

/// Get this proof's byte representation
pub fn to_bytes(&self) -> Vec<u8> {
serde_bare::to_vec(&self.0).unwrap()
postcard::to_stdvec(&self.0).unwrap()
}

/// Convert a byte representation to a proof
pub fn from_bytes<B: AsRef<[u8]>>(data: B) -> Result<Self, String> {
pub fn from_bytes<B: AsRef<[u8]>>(data: B) -> PaillierResult<Self> {
let data = data.as_ref();
let messages = serde_bare::from_slice::<Vec<BigNumber>>(data).map_err(|e| e.to_string())?;
Ok(Self(messages))
let out = postcard::from_bytes::<Vec<BigNumber>>(data).map(Self)?;
Ok(out)
}
}

Expand Down Expand Up @@ -119,7 +119,7 @@ fn hash_pieces<D: Digest>(data: &[&[u8]]) -> GenericArray<u8, D::OutputSize> {
// hash each piece individually to avoid potential padding attacks
// then hash all the outputs together
let mut hasher = D::new();
data.iter().map(|datum| D::digest(&datum)).for_each(|d| {
data.iter().map(|datum| D::digest(datum)).for_each(|d| {
hasher.update(d.as_slice());
});
hasher.finalize()
Expand Down

0 comments on commit 626bcdb

Please sign in to comment.