diff --git a/Cargo.toml b/Cargo.toml index 864e7dfd6..c8b2cceea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ clear_on_drop = "=0.2.3" subtle = { version = "2", default-features = false } serde = { version = "1.0", default-features = false, optional = true } packed_simd = { version = "0.3.0", features = ["into_bits"], optional = true } +failure = { version = "0.1", optional = true } [build-dependencies] rand_core = { version = "0.3.0", default-features = false } @@ -60,6 +61,7 @@ clear_on_drop = "=0.2.3" subtle = { version = "2", default-features = false } serde = { version = "1.0", default-features = false, optional = true } packed_simd = { version = "0.3.0", features = ["into_bits"], optional = true } +failure = { version = "0.1", optional = true } [features] nightly = ["subtle/nightly", "clear_on_drop/nightly"] diff --git a/build.rs b/build.rs index 0ffa5fc78..d0913aa52 100644 --- a/build.rs +++ b/build.rs @@ -17,6 +17,9 @@ extern crate subtle; #[cfg(all(feature = "nightly", feature = "packed_simd"))] extern crate packed_simd; +#[cfg(feature = "failure")] +extern crate failure; + use std::env; use std::fs::File; use std::io::Write; @@ -41,6 +44,8 @@ mod macros; mod constants; #[path = "src/edwards.rs"] mod edwards; +#[path = "src/errors.rs"] +mod errors; #[path = "src/montgomery.rs"] mod montgomery; #[path = "src/ristretto.rs"] diff --git a/src/edwards.rs b/src/edwards.rs index 0c0af03e5..c665736b2 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -108,6 +108,8 @@ use subtle::ConstantTimeEq; use constants; +use errors::{CurveError, InternalError}; + use field::FieldElement; use scalar::Scalar; @@ -329,11 +331,12 @@ impl Default for CompressedEdwardsY { } impl TryFrom<&[u8]> for CompressedEdwardsY { - type Error = (); + type Error = CurveError; - fn try_from(bytes: &[u8]) -> Result { + fn try_from(bytes: &[u8]) -> Result { if bytes.len() != 32 { - return Err(()); + return Err(CurveError( + InternalError::BytesLengthError{name: "CompressedEdwardsY", length: 32})); } Ok(CompressedEdwardsY::from_slice(bytes)) diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 000000000..d6f64c671 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,66 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +//! Errors which may occur. +//! +//! Currently, these are only used in the implementations of `TryFrom`. +//! +//! This module optionally implements support for the types in the `failure` +//! crate. This can be enabled by building with `--features failure`. + +use core::fmt; +use core::fmt::Display; + +/// Internal errors. Most application-level developers will likely not +/// need to pay any attention to these. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub(crate) enum InternalError { + /// An error in the length of bytes handed to a constructor. + /// + /// To use this, pass a string specifying the `name` of the type which is + /// returning the error, and the `length` in bytes which its constructor + /// expects. + BytesLengthError { + name: &'static str, + length: usize, + }, +} + +impl Display for InternalError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + InternalError::BytesLengthError{ name: n, length: l} + => write!(f, "{} must be {} bytes in length", n, l), + } + } +} + +#[cfg(feature = "failure")] +impl ::failure::Fail for InternalError {} + +/// Errors which may occur. +/// +/// This error may arise due to: +/// +/// * Being given bytes with a length different to what was expected. +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub struct CurveError(pub(crate) InternalError); + +impl Display for CurveError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[cfg(feature = "failure")] +impl ::failure::Fail for CurveError { + fn cause(&self) -> Option<&dyn (::failure::Fail)> { + Some(&self.0) + } +} diff --git a/src/lib.rs b/src/lib.rs index f1ae938d9..4aa18f201 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,8 @@ extern crate packed_simd; extern crate byteorder; extern crate clear_on_drop; pub extern crate digest; +#[cfg(feature = "failure")] +extern crate failure; extern crate rand_core; #[cfg(all(test, feature = "stage2_build"))] extern crate rand_os; @@ -82,6 +84,9 @@ pub mod constants; // External (and internal) traits. pub mod traits; +// Errors which may occur. +pub mod errors; + //------------------------------------------------------------------------ // curve25519-dalek internal modules //------------------------------------------------------------------------ diff --git a/src/montgomery.rs b/src/montgomery.rs index 4e1da68e1..6c615c0a4 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -53,6 +53,7 @@ use core::ops::{Mul, MulAssign}; use constants::APLUS2_OVER_FOUR; use edwards::{CompressedEdwardsY, EdwardsPoint}; +use errors::{CurveError, InternalError}; use field::FieldElement; use scalar::Scalar; @@ -111,11 +112,12 @@ impl ValidityCheck for MontgomeryPoint { } impl TryFrom<&[u8]> for MontgomeryPoint { - type Error = (); + type Error = CurveError; - fn try_from(bytes: &[u8]) -> Result { + fn try_from(bytes: &[u8]) -> Result { if bytes.len() != 32 { - return Err(()); + return Err(CurveError( + InternalError::BytesLengthError{name: "MontgomeryPoint", length: 32})); } let mut array = [0u8; 32]; @@ -127,7 +129,8 @@ impl TryFrom<&[u8]> for MontgomeryPoint { return Ok(P); } - Err(()) + Err(CurveError( + InternalError::BytesLengthError{name: "MontgomeryPoint", length: 32})) } } diff --git a/src/ristretto.rs b/src/ristretto.rs index 804dc912d..ba9ac6601 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -181,6 +181,8 @@ use subtle::ConstantTimeEq; use edwards::EdwardsBasepointTable; use edwards::EdwardsPoint; +use errors::{CurveError, InternalError}; + #[allow(unused_imports)] use prelude::*; @@ -219,11 +221,12 @@ impl ConstantTimeEq for CompressedRistretto { } impl TryFrom<&[u8]> for CompressedRistretto { - type Error = (); + type Error = CurveError; - fn try_from(bytes: &[u8]) -> Result { + fn try_from(bytes: &[u8]) -> Result { if bytes.len() != 32 { - return Err(()); + return Err(CurveError( + InternalError::BytesLengthError{name: "CompressedRistretto", length: 32})); } Ok(CompressedRistretto::from_slice(bytes))