From ffa12dc7a1c0d8c971df9b6e98eec80455977d04 Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Sun, 15 Jan 2023 17:26:58 -0800 Subject: [PATCH] Use Snafu to derive error methods --- umbral-pre/Cargo.toml | 1 + umbral-pre/src/capsule.rs | 18 ++++++------------ umbral-pre/src/capsule_frag.rs | 14 ++++---------- umbral-pre/src/dem.rs | 31 ++++++------------------------- umbral-pre/src/key_frag.rs | 22 ++++++++++------------ umbral-pre/src/pre.rs | 30 ++++++++++++++---------------- umbral-pre/src/traits.rs | 15 ++++----------- 7 files changed, 45 insertions(+), 86 deletions(-) diff --git a/umbral-pre/Cargo.toml b/umbral-pre/Cargo.toml index 04c1416..bb58610 100644 --- a/umbral-pre/Cargo.toml +++ b/umbral-pre/Cargo.toml @@ -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. diff --git a/umbral-pre/src/capsule.rs b/umbral-pre/src/capsule.rs index 426e5ec..35d4652 100644 --- a/umbral-pre/src/capsule.rs +++ b/umbral-pre/src/capsule.rs @@ -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}; @@ -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. diff --git a/umbral-pre/src/capsule_frag.rs b/umbral-pre/src/capsule_frag.rs index 44fb6ee..7e4addb 100644 --- a/umbral-pre/src/capsule_frag.rs +++ b/umbral-pre/src/capsule_frag.rs @@ -1,6 +1,7 @@ use core::fmt; use rand_core::{CryptoRng, RngCore}; +use snafu::Snafu; #[cfg(feature = "serde-support")] use serde::{Deserialize, Serialize}; @@ -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), diff --git a/umbral-pre/src/dem.rs b/umbral-pre/src/dem.rs index 9bc944a..1255631 100644 --- a/umbral-pre/src/dem.rs +++ b/umbral-pre/src/dem.rs @@ -1,5 +1,4 @@ use alloc::boxed::Box; -use core::fmt; use aead::{Aead, AeadCore, Payload}; use chacha20poly1305::{Key, KeyInit, KeySizeUser, XChaCha20Poly1305, XNonce}; @@ -7,53 +6,35 @@ 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>( seed: &[u8], salt: Option<&[u8]>, diff --git a/umbral-pre/src/key_frag.rs b/umbral-pre/src/key_frag.rs index a71ca66..531fc02 100644 --- a/umbral-pre/src/key_frag.rs +++ b/umbral-pre/src/key_frag.rs @@ -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")] @@ -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), diff --git a/umbral-pre/src/pre.rs b/umbral-pre/src/pre.rs index c5bac41..231714c 100644 --- a/umbral-pre/src/pre.rs +++ b/umbral-pre/src/pre.rs @@ -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; @@ -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, @@ -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)] diff --git a/umbral-pre/src/traits.rs b/umbral-pre/src/traits.rs index 62aaee9..e8f6327 100644 --- a/umbral-pre/src/traits.rs +++ b/umbral-pre/src/traits.rs @@ -3,11 +3,14 @@ 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, @@ -23,16 +26,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)