Change all from_slice() constructors to return Option<T>s.

We due this in lieu of implementing `TryFrom` to allow for API
consumers to use the `?` operator to convert potential `None`s into
their own `Result<T, CustomError>` types for better error handling
with less boilerplate.

Note that this is a breaking API change.
This commit is contained in:
Isis Lovecruft 2019-10-28 17:24:02 +00:00
parent c21224170a
commit 9ae2e3b482
No known key found for this signature in database
GPG key ID: AB41313533E8E812
5 changed files with 41 additions and 141 deletions

View file

@ -93,7 +93,6 @@
#![allow(non_snake_case)]
use core::borrow::Borrow;
use core::convert::TryFrom;
use core::fmt::Debug;
use core::iter::Iterator;
use core::iter::Sum;
@ -108,8 +107,6 @@ use subtle::ConstantTimeEq;
use constants;
use errors::{CurveError, InternalError};
use field::FieldElement;
use scalar::Scalar;
@ -338,33 +335,23 @@ impl Default for CompressedEdwardsY {
}
}
impl TryFrom<&[u8]> for CompressedEdwardsY {
type Error = CurveError;
fn try_from(bytes: &[u8]) -> Result<CompressedEdwardsY, CurveError> {
if bytes.len() != 32 {
return Err(CurveError(
InternalError::BytesLengthError{name: "CompressedEdwardsY", length: 32}));
}
Ok(CompressedEdwardsY::from_slice(bytes))
}
}
impl CompressedEdwardsY {
/// Construct a `CompressedEdwardsY` from a slice of bytes.
///
/// # Panics
/// # Returns
///
/// If the input `bytes` slice does not have a length of 32. For
/// a panic-safe version of this API, see the implementation of
/// `TryFrom<&[u8]>`.
pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY {
/// An `Option<CompressedEdwardsY>` which is `None` if the input `bytes`
/// slice does not have a length of 32.
pub fn from_slice(bytes: &[u8]) -> Option<CompressedEdwardsY> {
if bytes.len() != 32 {
return None;
}
let mut tmp = [0u8; 32];
tmp.copy_from_slice(bytes);
CompressedEdwardsY(tmp)
Some(CompressedEdwardsY(tmp))
}
}

View file

@ -1,69 +0,0 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2019 Isis Lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
//! Errors which may occur.
//!
//! Currently, these are only used in the implementations of `TryFrom`.
//!
//! If used with `std` support, this public types in this module implement the
//! `std::error::Error` trait.
use core::fmt;
use core::fmt::Display;
#[cfg(feature = "std")]
use std::error::Error;
/// 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 = "std")]
impl Error 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 = "std")]
impl Error for CurveError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.0)
}
}

View file

@ -82,9 +82,6 @@ pub mod constants;
// External (and internal) traits.
pub mod traits;
// Errors which may occur.
pub mod errors;
//------------------------------------------------------------------------
// curve25519-dalek internal modules
//------------------------------------------------------------------------

View file

@ -48,12 +48,10 @@
// affine and projective cakes and eat both of them too.
#![allow(non_snake_case)]
use core::convert::TryFrom;
use core::ops::{Mul, MulAssign};
use constants::APLUS2_OVER_FOUR;
use edwards::{CompressedEdwardsY, EdwardsPoint};
use errors::{CurveError, InternalError};
use field::FieldElement;
use scalar::Scalar;
@ -112,29 +110,6 @@ impl ValidityCheck for MontgomeryPoint {
}
}
impl TryFrom<&[u8]> for MontgomeryPoint {
type Error = CurveError;
fn try_from(bytes: &[u8]) -> Result<MontgomeryPoint, CurveError> {
if bytes.len() != 32 {
return Err(CurveError(
InternalError::BytesLengthError{name: "MontgomeryPoint", length: 32}));
}
let mut array = [0u8; 32];
array.copy_from_slice(&bytes[..32]);
let P = MontgomeryPoint(array);
if P.is_valid() {
return Ok(P);
}
Err(CurveError(
InternalError::BytesLengthError{name: "MontgomeryPoint", length: 32}))
}
}
impl MontgomeryPoint {
/// View this `MontgomeryPoint` as an array of bytes.
pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] {
@ -146,6 +121,29 @@ impl MontgomeryPoint {
self.0
}
/// Attempt to create a `MontgomeryPoint` from a slice of bytes.
///
/// # Returns
///
/// An `Option<MontgomeryPoint>` which is `None` if the length of the slice
/// of bytes is not 32, or if the bytes did not represent a canonical
/// `FieldElement`.
pub fn from_slice(bytes: &[u8]) -> Option<MontgomeryPoint> {
if bytes.len() != 32 {
return None;
}
let mut array = [0u8; 32];
array.copy_from_slice(&bytes[..32]);
let P = MontgomeryPoint(array);
if P.is_valid() {
return Some(P);
}
None
}
/// Attempt to convert to an `EdwardsPoint`, using the supplied
/// choice of sign for the `EdwardsPoint`.
///

View file

@ -158,7 +158,6 @@
//! https://ristretto.group/
use core::borrow::Borrow;
use core::convert::TryFrom;
use core::fmt::Debug;
use core::iter::Sum;
use core::ops::{Add, Neg, Sub};
@ -181,8 +180,6 @@ use subtle::ConstantTimeEq;
use edwards::EdwardsBasepointTable;
use edwards::EdwardsPoint;
use errors::{CurveError, InternalError};
#[allow(unused_imports)]
use prelude::*;
@ -220,19 +217,6 @@ impl ConstantTimeEq for CompressedRistretto {
}
}
impl TryFrom<&[u8]> for CompressedRistretto {
type Error = CurveError;
fn try_from(bytes: &[u8]) -> Result<CompressedRistretto, CurveError> {
if bytes.len() != 32 {
return Err(CurveError(
InternalError::BytesLengthError{name: "CompressedRistretto", length: 32}));
}
Ok(CompressedRistretto::from_slice(bytes))
}
}
impl CompressedRistretto {
/// Copy the bytes of this `CompressedRistretto`.
pub fn to_bytes(&self) -> [u8; 32] {
@ -246,17 +230,20 @@ impl CompressedRistretto {
/// Construct a `CompressedRistretto` from a slice of bytes.
///
/// # Panics
/// # Returns
///
/// If the input `bytes` slice does not have a length of 32. For a
/// panic-safe version of this API, see the implementation of
/// `TryFrom<&[u8]>`.
pub fn from_slice(bytes: &[u8]) -> CompressedRistretto {
/// An `Option<CompressedRistretto>` which is `None` if the input `bytes`
/// slice does not have a length of 32.
pub fn from_slice(bytes: &[u8]) -> Option<CompressedRistretto> {
if bytes.len() != 32 {
return None;
}
let mut tmp = [0u8; 32];
tmp.copy_from_slice(bytes);
CompressedRistretto(tmp)
Some(CompressedRistretto(tmp))
}
/// Attempt to decompress to an `RistrettoPoint`.