mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Expand boats' error types to give more detailed reasons for failures.
This code was significantly based off without boats' error types in
commit 6c1acaca7c, and also upon
conversation with them. Please target them with praise, and blame me
for whatever mistakes I might have made.
This commit is contained in:
parent
510a1f89c0
commit
c7b69c6562
3 changed files with 140 additions and 61 deletions
112
src/ed25519.rs
112
src/ed25519.rs
|
|
@ -10,7 +10,7 @@
|
|||
//! A Rust implementation of ed25519 EdDSA key generation, signing, and
|
||||
//! verification.
|
||||
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use core::fmt::{Debug};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use rand::Rng;
|
||||
|
|
@ -41,10 +41,13 @@ use curve25519_dalek::scalar::Scalar;
|
|||
|
||||
use subtle::slices_equal;
|
||||
|
||||
/// The length of an ed25519 EdDSA `Signature`, in bytes.
|
||||
use errors::DecodingError;
|
||||
use errors::InternalError;
|
||||
|
||||
/// The length of a curve25519 EdDSA `Signature`, in bytes.
|
||||
pub const SIGNATURE_LENGTH: usize = 64;
|
||||
|
||||
/// The length of an ed25519 EdDSA `SecretKey`, in bytes.
|
||||
/// The length of a curve25519 EdDSA `SecretKey`, in bytes.
|
||||
pub const SECRET_KEY_LENGTH: usize = 32;
|
||||
|
||||
/// The length of an ed25519 EdDSA `PublicKey`, in bytes.
|
||||
|
|
@ -53,6 +56,15 @@ pub const PUBLIC_KEY_LENGTH: usize = 32;
|
|||
/// The length of an ed25519 EdDSA `Keypair`, in bytes.
|
||||
pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH;
|
||||
|
||||
/// The length of the "key" portion of an "expanded" curve25519 EdDSA secret key, in bytes.
|
||||
const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32;
|
||||
|
||||
/// The length of the "nonce" portion of an "expanded" curve25519 EdDSA secret key, in bytes.
|
||||
const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32;
|
||||
|
||||
/// The length of an "expanded" curve25519 EdDSA key, `ExpandedSecretKey`, in bytes.
|
||||
pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH;
|
||||
|
||||
/// An EdDSA signature.
|
||||
///
|
||||
/// # Note
|
||||
|
|
@ -123,9 +135,11 @@ impl Signature {
|
|||
|
||||
/// Construct a `Signature` from a slice of bytes.
|
||||
#[inline]
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Signature, FromBytesError> {
|
||||
check_bytes_len(bytes, SIGNATURE_LENGTH)?;
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Signature, DecodingError> {
|
||||
if bytes.len() != SIGNATURE_LENGTH {
|
||||
return Err(DecodingError(InternalError::BytesLengthError{
|
||||
name: "Signature", length: SIGNATURE_LENGTH }));
|
||||
}
|
||||
let mut lower: [u8; 32] = [0u8; 32];
|
||||
let mut upper: [u8; 32] = [0u8; 32];
|
||||
|
||||
|
|
@ -133,7 +147,7 @@ impl Signature {
|
|||
upper.copy_from_slice(&bytes[32..]);
|
||||
|
||||
if upper[31] & 224 != 0 {
|
||||
return Err("High-bit of scalar 's' in signature must not be set.")
|
||||
return Err(DecodingError(InternalError::ScalarFormatError));
|
||||
}
|
||||
|
||||
Ok(Signature{ r: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) })
|
||||
|
|
@ -204,9 +218,9 @@ impl SecretKey {
|
|||
/// #
|
||||
/// use ed25519_dalek::SecretKey;
|
||||
/// use ed25519_dalek::SECRET_KEY_LENGTH;
|
||||
/// use ed25519_dalek::FromBytesError;
|
||||
/// use ed25519_dalek::DecodingError;
|
||||
///
|
||||
/// # fn doctest() -> Result<SecretKey, FromBytesError> {
|
||||
/// # fn doctest() -> Result<SecretKey, DecodingError> {
|
||||
/// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [
|
||||
/// 157, 097, 177, 157, 239, 253, 090, 096,
|
||||
/// 186, 132, 074, 244, 146, 236, 044, 196,
|
||||
|
|
@ -227,13 +241,14 @@ impl SecretKey {
|
|||
/// # Returns
|
||||
///
|
||||
/// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value
|
||||
/// is an `FromBytesError` describing the error that occurred.
|
||||
/// is an `DecodingError` wrapping the internal error that occurred.
|
||||
#[inline]
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<SecretKey, FromBytesError> {
|
||||
check_bytes_len(bytes, SECRET_KEY_LENGTH)?;
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<SecretKey, DecodingError> {
|
||||
if bytes.len() != SECRET_KEY_LENGTH {
|
||||
return Err(DecodingError(InternalError::BytesLengthError{
|
||||
name: "SecretKey", length: SECRET_KEY_LENGTH }));
|
||||
}
|
||||
let mut bits: [u8; 32] = [0u8; 32];
|
||||
|
||||
bits.copy_from_slice(&bytes[..32]);
|
||||
|
||||
Ok(SecretKey(bits))
|
||||
|
|
@ -437,7 +452,7 @@ impl ExpandedSecretKey {
|
|||
/// # fn main() { }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_bytes(&self) -> [u8; 64] {
|
||||
pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] {
|
||||
let mut bytes: [u8; 64] = [0u8; 64];
|
||||
|
||||
bytes[..32].copy_from_slice(self.key.as_bytes());
|
||||
|
|
@ -450,7 +465,7 @@ impl ExpandedSecretKey {
|
|||
/// # Returns
|
||||
///
|
||||
/// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose
|
||||
/// error value is an `FromBytesError` describing the error that occurred.
|
||||
/// error value is an `DecodingError` describing the error that occurred.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -461,10 +476,10 @@ impl ExpandedSecretKey {
|
|||
/// #
|
||||
/// use rand::{Rng, OsRng};
|
||||
/// use ed25519_dalek::{SecretKey, ExpandedSecretKey};
|
||||
/// use ed25519_dalek::FromBytesError;
|
||||
/// use ed25519_dalek::DecodingError;
|
||||
///
|
||||
/// # #[cfg(feature = "sha2")]
|
||||
/// # fn do_test() -> Result<ExpandedSecretKey, FromBytesError> {
|
||||
/// # fn do_test() -> Result<ExpandedSecretKey, DecodingError> {
|
||||
/// #
|
||||
/// let mut csprng: OsRng = OsRng::new().unwrap();
|
||||
/// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
|
||||
|
|
@ -485,9 +500,11 @@ impl ExpandedSecretKey {
|
|||
/// # fn main() {}
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<ExpandedSecretKey, FromBytesError> {
|
||||
check_bytes_len(bytes, 64)?;
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<ExpandedSecretKey, DecodingError> {
|
||||
if bytes.len() != EXPANDED_SECRET_KEY_LENGTH {
|
||||
return Err(DecodingError(InternalError::BytesLengthError{
|
||||
name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH }));
|
||||
}
|
||||
let mut lower: [u8; 32] = [0u8; 32];
|
||||
let mut upper: [u8; 32] = [0u8; 32];
|
||||
|
||||
|
|
@ -640,9 +657,9 @@ impl PublicKey {
|
|||
/// #
|
||||
/// use ed25519_dalek::PublicKey;
|
||||
/// use ed25519_dalek::PUBLIC_KEY_LENGTH;
|
||||
/// use ed25519_dalek::FromBytesError;
|
||||
/// use ed25519_dalek::DecodingError;
|
||||
///
|
||||
/// # fn doctest() -> Result<PublicKey, FromBytesError> {
|
||||
/// # fn doctest() -> Result<PublicKey, DecodingError> {
|
||||
/// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
|
||||
/// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58,
|
||||
/// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26];
|
||||
|
|
@ -660,13 +677,14 @@ impl PublicKey {
|
|||
/// # Returns
|
||||
///
|
||||
/// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value
|
||||
/// is an `FromBytesError` describing the error that occurred.
|
||||
/// is an `DecodingError` describing the error that occurred.
|
||||
#[inline]
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, FromBytesError> {
|
||||
check_bytes_len(bytes, PUBLIC_KEY_LENGTH)?;
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
|
||||
if bytes.len() != PUBLIC_KEY_LENGTH {
|
||||
return Err(DecodingError(InternalError::BytesLengthError{
|
||||
name: "PublicKey", length: PUBLIC_KEY_LENGTH }));
|
||||
}
|
||||
let mut bits: [u8; 32] = [0u8; 32];
|
||||
|
||||
bits.copy_from_slice(&bytes[..32]);
|
||||
|
||||
Ok(PublicKey(CompressedEdwardsY(bits)))
|
||||
|
|
@ -814,10 +832,12 @@ impl Keypair {
|
|||
/// # Returns
|
||||
///
|
||||
/// A `Result` whose okay value is an EdDSA `Keypair` or whose error value
|
||||
/// is an `FromBytesError` describing the error that occurred.
|
||||
pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result<Keypair, FromBytesError> {
|
||||
check_bytes_len(bytes, KEYPAIR_LENGTH)?;
|
||||
|
||||
/// is an `DecodingError` describing the error that occurred.
|
||||
pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result<Keypair, DecodingError> {
|
||||
if bytes.len() != KEYPAIR_LENGTH {
|
||||
return Err(DecodingError(InternalError::BytesLengthError{
|
||||
name: "Keypair", length: KEYPAIR_LENGTH}));
|
||||
}
|
||||
let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?;
|
||||
let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?;
|
||||
|
||||
|
|
@ -913,32 +933,6 @@ impl<'d> Deserialize<'d> for Keypair {
|
|||
}
|
||||
}
|
||||
|
||||
/// An error which occurred when using the `from_bytes` constructor.
|
||||
///
|
||||
/// This error will be returned if the byte slice given was not the correct
|
||||
/// length for constructing that kind of object.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct FromBytesError {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl Display for FromBytesError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "wrong length of bytes when constructing ed25519 object")
|
||||
}
|
||||
}
|
||||
|
||||
impl ::failure::Fail for FromBytesError { }
|
||||
|
||||
#[inline(always)]
|
||||
fn check_bytes_len(bytes: &[u8], len: usize) -> Result<(), FromBytesError> {
|
||||
if bytes.len() != len {
|
||||
Err(FromBytesError { _private: () })
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::io::BufReader;
|
||||
|
|
@ -1075,7 +1069,7 @@ mod test {
|
|||
#[test]
|
||||
fn public_key_from_bytes() {
|
||||
// Make another function so that we can test the ? operator.
|
||||
fn do_the_test() -> Result<PublicKey, FromBytesError> {
|
||||
fn do_the_test() -> Result<PublicKey, DecodingError> {
|
||||
let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
|
||||
215, 090, 152, 001, 130, 177, 010, 183,
|
||||
213, 075, 254, 211, 201, 100, 007, 058,
|
||||
|
|
|
|||
82
src/errors.rs
Normal file
82
src/errors.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of ed25519-dalek.
|
||||
// Copyright (c) 2017 Isis Lovecruft
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
|
||||
//! Errors which may occur when parsing keys and/or signatures to or from wire formats.
|
||||
|
||||
// rustc seems to think the typenames in match statements (e.g. in
|
||||
// Display) should be snake cased, for some reason.
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::fmt;
|
||||
use core::fmt::Display;
|
||||
|
||||
/// Internal errors. Most application-level developer will likely not
|
||||
/// need to pay any attention to these.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||
pub (crate) enum InternalError {
|
||||
PointDecompressionError,
|
||||
ScalarFormatError,
|
||||
/// 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::PointDecompressionError
|
||||
=> write!(f, "Cannot decompress extended twisted edwards point"),
|
||||
InternalError::ScalarFormatError
|
||||
=> write!(f, "Cannot use scalar with high-bit set"),
|
||||
InternalError::BytesLengthError{ name: n, length: l}
|
||||
=> write!(f, "{} must be {} bytes in length", n, l),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::failure::Fail for InternalError {}
|
||||
|
||||
/// Errors which may occur in the `from_bytes()` constructors of `PublicKey`,
|
||||
/// `SecretKey`, `ExpandedSecretKey`, `Keypair`, and `Signature`.
|
||||
///
|
||||
/// There was an internal problem due to parsing the `Signature`.
|
||||
///
|
||||
/// This error may arise due to:
|
||||
///
|
||||
/// * A problem decompressing `r`, a curve point, in the `Signature`, or the
|
||||
/// curve point for a `PublicKey`.
|
||||
/// * A problem with the format of `s`, a scalar, in the `Signature`. This
|
||||
/// is only raised if the high-bit of the scalar was set. (Scalars must
|
||||
/// only be constructed from 255-bit integers.)
|
||||
/// * Being given bytes with a length different to what was expected.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct DecodingError(pub (crate) InternalError);
|
||||
|
||||
impl Display for DecodingError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.0 {
|
||||
InternalError::PointDecompressionError => write!(f, "{}", self.0),
|
||||
InternalError::ScalarFormatError => write!(f, "{}", self.0),
|
||||
InternalError::BytesLengthError{ name: _, length: _ } => write!(f, "{}", self.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::failure::Fail for DecodingError {
|
||||
fn cause(&self) -> Option<&::failure::Fail> {
|
||||
match self.0 {
|
||||
InternalError::PointDecompressionError => Some(&self.0),
|
||||
InternalError::ScalarFormatError => Some(&self.0),
|
||||
InternalError::BytesLengthError{ name: _, length: _} => Some(&self.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -143,9 +143,9 @@
|
|||
//! # extern crate ed25519_dalek;
|
||||
//! # use rand::{Rng, OsRng};
|
||||
//! # use sha2::Sha512;
|
||||
//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, FromBytesError};
|
||||
//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, DecodingError};
|
||||
//! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
|
||||
//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), FromBytesError> {
|
||||
//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), DecodingError> {
|
||||
//! # let mut cspring: OsRng = OsRng::new().unwrap();
|
||||
//! # let keypair_orig: Keypair = Keypair::generate::<Sha512>(&mut cspring);
|
||||
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
|
||||
|
|
@ -287,5 +287,8 @@ extern crate bincode;
|
|||
|
||||
mod ed25519;
|
||||
|
||||
pub mod errors;
|
||||
|
||||
// Export everything public in ed25519.
|
||||
pub use ed25519::*;
|
||||
pub use errors::*;
|
||||
|
|
|
|||
Loading…
Reference in a new issue