Skip to content

Commit

Permalink
Use Snafu to derive error methods
Browse files Browse the repository at this point in the history
  • Loading branch information
fjarri committed Jan 16, 2023
1 parent 50a7a6e commit 0763d32
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 86 deletions.
1 change: 1 addition & 0 deletions umbral-pre/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ js-sys = { version = "0.3", optional = true }
wasm-bindgen = { version = "0.2.74", optional = true }
derive_more = { version = "0.99", optional = true, default_features = false, features = ["as_ref", "from", "into"] }
wasm-bindgen-derive = { version = "0.1", optional = true }
snafu = { version = "0.7", default-features = false }

# These packages are among the dependencies of the packages above.
# Their versions should be updated when the main packages above are updated.
Expand Down
18 changes: 6 additions & 12 deletions umbral-pre/src/capsule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use core::fmt;

use generic_array::GenericArray;
use rand_core::{CryptoRng, RngCore};
use snafu::Snafu;

#[cfg(feature = "serde-support")]
use serde::{Deserialize, Serialize};
Expand All @@ -23,32 +24,25 @@ use crate::traits::fmt_public;
use crate::{DefaultDeserialize, DefaultSerialize};

/// Errors that can happen when opening a `Capsule` using reencrypted `CapsuleFrag` objects.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Snafu)]
pub enum OpenReencryptedError {
/// An empty capsule fragment list is given.
#[snafu(display("Empty CapsuleFrag sequence"))]
NoCapsuleFrags,
/// Capsule fragments are mismatched (originated from [`KeyFrag`](crate::KeyFrag) objects
/// generated by different [`generate_kfrags`](crate::generate_kfrags) calls).
#[snafu(display("CapsuleFrags are not pairwise consistent"))]
MismatchedCapsuleFrags,
/// Some of the given capsule fragments are repeated.
#[snafu(display("Some of the CapsuleFrags are repeated"))]
RepeatingCapsuleFrags,
/// Internal validation of the result has failed.
/// Can be caused by an incorrect (possibly modified) capsule
/// or some of the capsule fragments.
#[snafu(display("Internal validation failed"))]
ValidationFailed,
}

impl fmt::Display for OpenReencryptedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NoCapsuleFrags => write!(f, "Empty CapsuleFrag sequence"),
Self::MismatchedCapsuleFrags => write!(f, "CapsuleFrags are not pairwise consistent"),
Self::RepeatingCapsuleFrags => write!(f, "Some of the CapsuleFrags are repeated"),
Self::ValidationFailed => write!(f, "Internal validation failed"),
}
}
}

/// A helper struct:
/// - allows us not to serialize `params`
/// - allows us to verify the capsule on deserialization.
Expand Down
14 changes: 4 additions & 10 deletions umbral-pre/src/capsule_frag.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::fmt;

use rand_core::{CryptoRng, RngCore};
use snafu::Snafu;

#[cfg(feature = "serde-support")]
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -91,23 +92,16 @@ impl fmt::Display for CapsuleFrag {
}

/// Possible errors that can be returned by [`CapsuleFrag::verify`].
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Snafu)]
pub enum CapsuleFragVerificationError {
/// Inconsistent internal state leading to signature verification failure.
#[snafu(display("Invalid CapsuleFrag signature"))]
IncorrectKeyFragSignature,
/// Inconsistent internal state leading to commitment verification failure.
#[snafu(display("Failed to verify reencryption proof"))]
IncorrectReencryption,
}

impl fmt::Display for CapsuleFragVerificationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::IncorrectKeyFragSignature => write!(f, "Invalid CapsuleFrag signature"),
Self::IncorrectReencryption => write!(f, "Failed to verify reencryption proof"),
}
}
}

impl CapsuleFrag {
fn reencrypted(
rng: &mut (impl CryptoRng + RngCore),
Expand Down
31 changes: 6 additions & 25 deletions umbral-pre/src/dem.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,40 @@
use alloc::boxed::Box;
use core::fmt;

use aead::{Aead, AeadCore, Payload};
use chacha20poly1305::{Key, KeyInit, KeySizeUser, XChaCha20Poly1305, XNonce};
use generic_array::{ArrayLength, GenericArray};
use hkdf::Hkdf;
use rand_core::{CryptoRng, RngCore};
use sha2::Sha256;
use snafu::Snafu;
use typenum::Unsigned;
use zeroize::ZeroizeOnDrop;

use crate::secret_box::SecretBox;

/// Errors that can happen during symmetric encryption.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Snafu)]
pub enum EncryptionError {
/// Given plaintext is too large for the backend to handle.
#[snafu(display("Plaintext is too large to encrypt"))]
PlaintextTooLarge,
}

impl fmt::Display for EncryptionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::PlaintextTooLarge => write!(f, "Plaintext is too large to encrypt"),
}
}
}

/// Errors that can happend during symmetric decryption.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Snafu)]
pub enum DecryptionError {
/// Ciphertext (which should be prepended by the nonce) is shorter than the nonce length.
#[snafu(display("The ciphertext must include the nonce"))]
CiphertextTooShort,
/// The ciphertext and the attached authentication data are inconsistent.
/// This can happen if:
/// - an incorrect key is used,
/// - the ciphertext is modified or cut short,
/// - an incorrect authentication data is provided on decryption.
#[snafu(display("Decryption of ciphertext failed."))]
AuthenticationFailed,
}

impl fmt::Display for DecryptionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CiphertextTooShort => write!(f, "The ciphertext must include the nonce"),
Self::AuthenticationFailed => write!(
f,
"Decryption of ciphertext failed: \
either someone tampered with the ciphertext or \
you are using an incorrect decryption key."
),
}
}
}

pub(crate) fn kdf<S: ArrayLength<u8>>(
seed: &[u8],
salt: Option<&[u8]>,
Expand Down
22 changes: 10 additions & 12 deletions umbral-pre/src/key_frag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use core::fmt;

use generic_array::GenericArray;
use rand_core::{CryptoRng, RngCore};
use snafu::Snafu;
use typenum::U32;

#[cfg(feature = "serde-support")]
Expand Down Expand Up @@ -163,31 +164,28 @@ impl fmt::Display for KeyFrag {
}

/// Possible errors that can be returned by [`KeyFrag::verify`].
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Snafu)]
pub enum KeyFragVerificationError {
/// Inconsistent internal state leading to commitment verification failure.
#[snafu(display("Invalid kfrag commitment"))]
IncorrectCommitment,
/// A delegating key was included in the signature when [`KeyFrag`] was created,
/// but no delegating key was provided during verification.
#[snafu(display(
"A signature of a delegating key was included in this kfrag but the key is not provided"
))]
DelegatingKeyNotProvided,
/// A receiving key was included in the signature when [`KeyFrag`] was created,
/// but no receiving key was provided during verification.
#[snafu(display(
"A signature of a receiving key was included in this kfrag, but the key is not provided"
))]
ReceivingKeyNotProvided,
/// Inconsistent internal state leading to signature verification failure.
#[snafu(display("Failed to verify the kfrag signature"))]
IncorrectSignature,
}

impl fmt::Display for KeyFragVerificationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::IncorrectCommitment => write!(f, "Invalid kfrag commitment"),
Self::DelegatingKeyNotProvided => write!(f, "A signature of a delegating key was included in this kfrag but the key is not provided"),
Self::ReceivingKeyNotProvided => write!(f, "A signature of a receiving key was included in this kfrag, but the key is not provided"),
Self::IncorrectSignature => write!(f, "Failed to verify the kfrag signature"),
}
}
}

impl KeyFrag {
fn from_base(
rng: &mut (impl CryptoRng + RngCore),
Expand Down
30 changes: 14 additions & 16 deletions umbral-pre/src/pre.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! The high-level functional reencryption API.
use core::fmt;

use rand_core::{CryptoRng, RngCore};
use snafu::{ResultExt, Snafu};

#[cfg(feature = "default-rng")]
use rand_core::OsRng;
Expand All @@ -17,21 +16,20 @@ use alloc::boxed::Box;
use alloc::vec::Vec;

/// Errors that can happen when decrypting a reencrypted ciphertext.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Snafu)]
pub enum ReencryptionError {
/// An error when opening a capsule. See [`OpenReencryptedError`] for the options.
OnOpen(OpenReencryptedError),
#[snafu(display("Re-encryption error on open: {source}"))]
OnOpen {
/// The underlying error.
source: OpenReencryptedError,
},
/// An error when decrypting the ciphertext. See [`DecryptionError`] for the options.
OnDecryption(DecryptionError),
}

impl fmt::Display for ReencryptionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnOpen(err) => write!(f, "Re-encryption error on open: {}", err),
Self::OnDecryption(err) => write!(f, "Re-encryption error on decryption: {}", err),
}
}
#[snafu(display("Re-encryption error on decryption: {source}"))]
OnDecryption {
/// The underlying error.
source: DecryptionError,
},
}

/// Encrypts the given plaintext message using a DEM scheme,
Expand Down Expand Up @@ -182,10 +180,10 @@ pub fn decrypt_reencrypted(
.collect();
let key_seed = capsule
.open_reencrypted(receiving_sk, delegating_pk, &cfrags)
.map_err(ReencryptionError::OnOpen)?;
.context(OnOpenSnafu)?;
let dem = DEM::new(key_seed.as_secret());
dem.decrypt(&ciphertext, &capsule.to_associated_data_bytes())
.map_err(ReencryptionError::OnDecryption)
.context(OnDecryptionSnafu)
}

#[cfg(test)]
Expand Down
19 changes: 8 additions & 11 deletions umbral-pre/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ use alloc::boxed::Box;

use core::fmt;

use snafu::Snafu;

#[cfg(feature = "default-serialization")]
use serde::{Deserialize, Serialize};

/// The provided bytestring is of an incorrect size.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Snafu)]
#[snafu(display(
"Bytestring size mismatch: expected {} bytes, got {}",
expected_size,
received_size
))]
pub struct SizeMismatchError {
pub(crate) received_size: usize,
pub(crate) expected_size: usize,
Expand All @@ -23,16 +30,6 @@ impl SizeMismatchError {
}
}

impl fmt::Display for SizeMismatchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Bytestring size mismatch: expected {} bytes, got {}",
self.expected_size, self.received_size
)
}
}

/// A `fmt` implementation for types with secret data.
pub(crate) fn fmt_secret(type_name: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:...", type_name)
Expand Down

0 comments on commit 0763d32

Please sign in to comment.