From a7f317a2b8db95ac415e26e18865a871d0291757 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 18 Oct 2019 19:12:57 +0000 Subject: [PATCH 01/11] Impl TryFrom<&[u8]> for all compressed point types. This reduces copy-pasta in downstream users to check the length of the slice beforehand. --- src/edwards.rs | 17 ++++++++++++++++- src/ristretto.rs | 17 ++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 998af8d..f0ddaa4 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -93,6 +93,7 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::convert::TryFrom; use core::fmt::Debug; use core::iter::Iterator; use core::iter::Sum; @@ -335,12 +336,26 @@ impl Default for CompressedEdwardsY { } } +impl TryFrom<&[u8]> for CompressedEdwardsY { + type Error = (); + + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() != 32 { + return Err(()); + } + + Ok(CompressedEdwardsY::from_slice(bytes)) + } +} + impl CompressedEdwardsY { /// Construct a `CompressedEdwardsY` from a slice of bytes. /// /// # Panics /// - /// If the input `bytes` slice does not have a length of 32. + /// 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 { let mut tmp = [0u8; 32]; diff --git a/src/ristretto.rs b/src/ristretto.rs index 6d53e89..59ca562 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -158,6 +158,7 @@ //! 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}; @@ -217,6 +218,18 @@ impl ConstantTimeEq for CompressedRistretto { } } +impl TryFrom<&[u8]> for CompressedRistretto { + type Error = (); + + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() != 32 { + return Err(()); + } + + Ok(CompressedRistretto::from_slice(bytes)) + } +} + impl CompressedRistretto { /// Copy the bytes of this `CompressedRistretto`. pub fn to_bytes(&self) -> [u8; 32] { @@ -232,7 +245,9 @@ impl CompressedRistretto { /// /// # Panics /// - /// If the input `bytes` slice does not have a length of 32. + /// 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 { let mut tmp = [0u8; 32]; From db3d26f4b9df7b58a319ffc6029682b24b8f42d7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 23 Oct 2019 16:34:07 +0000 Subject: [PATCH 02/11] Fix typo in TryFrom docstring. --- src/edwards.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edwards.rs b/src/edwards.rs index f0ddaa4..d29ca2f 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -355,7 +355,7 @@ impl CompressedEdwardsY { /// /// 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]`. + /// `TryFrom<&[u8]>`. pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY { let mut tmp = [0u8; 32]; From 1fa0048262d416f00aaa0d255609f127592d4efb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 23 Oct 2019 18:59:58 +0000 Subject: [PATCH 03/11] Implement TryFrom<&[u8]> and ValidityCheck for MontgomeryPoint. --- src/montgomery.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/montgomery.rs b/src/montgomery.rs index a89de22..c85397d 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -48,6 +48,7 @@ // 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; @@ -56,6 +57,7 @@ use field::FieldElement; use scalar::Scalar; use traits::Identity; +use traits::ValidityCheck; use subtle::Choice; use subtle::ConditionallySelectable; @@ -91,6 +93,45 @@ impl PartialEq for MontgomeryPoint { impl Eq for MontgomeryPoint {} +impl ValidityCheck for MontgomeryPoint { + /// Decode the \\(u\\)-coordinate field element and re-encode it + /// to its canonical form to check whether the original was valid. + /// + /// There are no other required checks for the Mongomery form of the curve, + /// as every element in \\( \mathbb{F}\_{q} \\) lies either on the curve or + /// its quadratic twist. (cf. §5.2 of "Montgomery Curves and Their + /// Arithmetic" by [Costello and Smith][costello-smith].) + /// + /// [costello-smith]: https://eprint.iacr.org/2017/212.pdf + fn is_valid(&self) -> bool { + let maybe_u: FieldElement = FieldElement::from_bytes(&self.0); + let u: [u8; 32] = maybe_u.to_bytes(); + + u.ct_eq(&self.0).into() + } +} + +impl TryFrom<&[u8]> for MontgomeryPoint { + type Error = (); + + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() != 32 { + return Err(()); + } + + let mut array = [0u8; 32]; + array.copy_from_slice(&bytes[..32]); + + let P = MontgomeryPoint(array); + + if P.is_valid() { + return Ok(P); + } + + Err(()) + } +} + impl MontgomeryPoint { /// View this `MontgomeryPoint` as an array of bytes. pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { From 1d8b3995c958c181e4b8254e43d211140b04940c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 23 Oct 2019 19:29:02 +0000 Subject: [PATCH 04/11] Add custom error types, currently only used in TryFrom impls. --- src/edwards.rs | 9 ++++--- src/errors.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 ++++ src/montgomery.rs | 11 +++++--- src/ristretto.rs | 9 ++++--- 5 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 src/errors.rs diff --git a/src/edwards.rs b/src/edwards.rs index d29ca2f..5c90195 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; @@ -337,11 +339,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 0000000..d6f64c6 --- /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 0216628..5359b16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,8 @@ extern crate packed_simd; extern crate byteorder; pub extern crate digest; +#[cfg(feature = "failure")] +extern crate failure; extern crate rand_core; #[cfg(test)] 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 c85397d..7a4f841 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; @@ -112,11 +113,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]; @@ -128,7 +130,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 59ca562..46c1c2d 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)) From c21224170a584a7a08b00f56e7b25f85a28a35c9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 23 Oct 2019 21:32:27 +0000 Subject: [PATCH 05/11] Remove optional failure dependency and impl std::error::Error. --- src/errors.rs | 17 ++++++++++------- src/lib.rs | 2 -- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index d6f64c6..13a7638 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -11,12 +11,15 @@ //! //! 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`. +//! 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)] @@ -41,8 +44,8 @@ impl Display for InternalError { } } -#[cfg(feature = "failure")] -impl ::failure::Fail for InternalError {} +#[cfg(feature = "std")] +impl Error for InternalError { } /// Errors which may occur. /// @@ -58,9 +61,9 @@ impl Display for CurveError { } } -#[cfg(feature = "failure")] -impl ::failure::Fail for CurveError { - fn cause(&self) -> Option<&dyn (::failure::Fail)> { +#[cfg(feature = "std")] +impl Error for CurveError { + fn source(&self) -> Option<&(dyn Error + 'static)> { Some(&self.0) } } diff --git a/src/lib.rs b/src/lib.rs index 5359b16..f9bb55d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,8 +43,6 @@ extern crate packed_simd; extern crate byteorder; pub extern crate digest; -#[cfg(feature = "failure")] -extern crate failure; extern crate rand_core; #[cfg(test)] extern crate rand_os; From 9ae2e3b4822caad8e958a6bd743fe647bcd0c7a3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 28 Oct 2019 17:24:02 +0000 Subject: [PATCH 06/11] Change all from_slice() constructors to return Options. 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` types for better error handling with less boilerplate. Note that this is a breaking API change. --- src/edwards.rs | 31 +++++++-------------- src/errors.rs | 69 ----------------------------------------------- src/lib.rs | 3 --- src/montgomery.rs | 48 ++++++++++++++++----------------- src/ristretto.rs | 31 +++++++-------------- 5 files changed, 41 insertions(+), 141 deletions(-) delete mode 100644 src/errors.rs diff --git a/src/edwards.rs b/src/edwards.rs index 5c90195..d72ec28 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -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 { - 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` which is `None` if the input `bytes` + /// slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> Option { + if bytes.len() != 32 { + return None; + } + let mut tmp = [0u8; 32]; tmp.copy_from_slice(bytes); - CompressedEdwardsY(tmp) + Some(CompressedEdwardsY(tmp)) } } diff --git a/src/errors.rs b/src/errors.rs deleted file mode 100644 index 13a7638..0000000 --- a/src/errors.rs +++ /dev/null @@ -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 - -//! 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) - } -} diff --git a/src/lib.rs b/src/lib.rs index f9bb55d..0216628 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 //------------------------------------------------------------------------ diff --git a/src/montgomery.rs b/src/montgomery.rs index 7a4f841..66b4670 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -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 { - 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` 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 { + 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`. /// diff --git a/src/ristretto.rs b/src/ristretto.rs index 46c1c2d..b730938 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -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 { - 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` which is `None` if the input `bytes` + /// slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> Option { + 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`. From 6a44f317026da8bb402279e6c6aaded91e3bdc3f Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 10 Dec 2019 14:16:24 -0800 Subject: [PATCH 07/11] Revert "Merge pull request #296 from isislovecruft/feature/compressed-try-from" This reverts commit 46f56f91ee94732e0dffc625579617760ac554a4, reversing changes made to a9b1d50c5a9acd8623e632a33d6cfe31af7b57c7. These changes are not semver-compatible with the 2.0.0 release. --- src/edwards.rs | 13 ++++--------- src/montgomery.rs | 42 ------------------------------------------ src/ristretto.rs | 13 ++++--------- 3 files changed, 8 insertions(+), 60 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index d72ec28..998af8d 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -338,20 +338,15 @@ impl Default for CompressedEdwardsY { impl CompressedEdwardsY { /// Construct a `CompressedEdwardsY` from a slice of bytes. /// - /// # Returns + /// # Panics /// - /// An `Option` which is `None` if the input `bytes` - /// slice does not have a length of 32. - pub fn from_slice(bytes: &[u8]) -> Option { - if bytes.len() != 32 { - return None; - } - + /// If the input `bytes` slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY { let mut tmp = [0u8; 32]; tmp.copy_from_slice(bytes); - Some(CompressedEdwardsY(tmp)) + CompressedEdwardsY(tmp) } } diff --git a/src/montgomery.rs b/src/montgomery.rs index 14957d1..4768451 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -56,7 +56,6 @@ use field::FieldElement; use scalar::Scalar; use traits::Identity; -use traits::ValidityCheck; use subtle::Choice; use subtle::ConditionallySelectable; @@ -94,24 +93,6 @@ impl PartialEq for MontgomeryPoint { impl Eq for MontgomeryPoint {} -impl ValidityCheck for MontgomeryPoint { - /// Decode the \\(u\\)-coordinate field element and re-encode it - /// to its canonical form to check whether the original was valid. - /// - /// There are no other required checks for the Mongomery form of the curve, - /// as every element in \\( \mathbb{F}\_{q} \\) lies either on the curve or - /// its quadratic twist. (cf. §5.2 of "Montgomery Curves and Their - /// Arithmetic" by [Costello and Smith][costello-smith].) - /// - /// [costello-smith]: https://eprint.iacr.org/2017/212.pdf - fn is_valid(&self) -> bool { - let maybe_u: FieldElement = FieldElement::from_bytes(&self.0); - let u: [u8; 32] = maybe_u.to_bytes(); - - u.ct_eq(&self.0).into() - } -} - impl Zeroize for MontgomeryPoint { fn zeroize(&mut self) { self.0.zeroize(); @@ -129,29 +110,6 @@ impl MontgomeryPoint { self.0 } - /// Attempt to create a `MontgomeryPoint` from a slice of bytes. - /// - /// # Returns - /// - /// An `Option` 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 { - 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`. /// diff --git a/src/ristretto.rs b/src/ristretto.rs index 485c01f..c4b6170 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -230,20 +230,15 @@ impl CompressedRistretto { /// Construct a `CompressedRistretto` from a slice of bytes. /// - /// # Returns + /// # Panics /// - /// An `Option` which is `None` if the input `bytes` - /// slice does not have a length of 32. - pub fn from_slice(bytes: &[u8]) -> Option { - if bytes.len() != 32 { - return None; - } - + /// If the input `bytes` slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> CompressedRistretto { let mut tmp = [0u8; 32]; tmp.copy_from_slice(bytes); - Some(CompressedRistretto(tmp)) + CompressedRistretto(tmp) } /// Attempt to decompress to an `RistrettoPoint`. From 7b1363a964dbaaf4fce84decdbb2107934aab836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 24 Feb 2020 14:24:49 -0500 Subject: [PATCH 08/11] Bump criterion version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 87d35e8..7c4e238 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "mast [dev-dependencies] sha2 = { version = "0.8", default-features = false } bincode = "1" -criterion = "0.2" +criterion = "0.3.0" rand = "0.7" [[bench]] From d57fb6caebb03bb37da9980be689430969027009 Mon Sep 17 00:00:00 2001 From: Rui Morais Date: Tue, 25 Feb 2020 18:16:06 +0000 Subject: [PATCH 09/11] Derive of Hash trait to CompressedRistretto --- src/ristretto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ristretto.rs b/src/ristretto.rs index c4b6170..977f52f 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -208,7 +208,7 @@ use backend::vector::scalar_mul; /// /// The Ristretto encoding is canonical, so two points are equal if and /// only if their encodings are equal. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct CompressedRistretto(pub [u8; 32]); impl ConstantTimeEq for CompressedRistretto { From 6a8e46606375a393332a2ceb2d3d4c2f17d3ce23 Mon Sep 17 00:00:00 2001 From: Rui Morais Date: Tue, 25 Feb 2020 22:39:19 +0000 Subject: [PATCH 10/11] add derive Hash to Scalar, MontgomeryPoint and CompressedEdwardsY --- src/edwards.rs | 2 +- src/montgomery.rs | 2 +- src/scalar.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 998af8d..810bc20 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -150,7 +150,7 @@ use backend::vector::scalar_mul; /// /// The first 255 bits of a `CompressedEdwardsY` represent the /// \\(y\\)-coordinate. The high bit of the 32nd byte gives the sign of \\(x\\). -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct CompressedEdwardsY(pub [u8; 32]); impl ConstantTimeEq for CompressedEdwardsY { diff --git a/src/montgomery.rs b/src/montgomery.rs index 4768451..c3676c2 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -65,7 +65,7 @@ use zeroize::Zeroize; /// Holds the \\(u\\)-coordinate of a point on the Montgomery form of /// Curve25519 or its twist. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct MontgomeryPoint(pub [u8; 32]); diff --git a/src/scalar.rs b/src/scalar.rs index d365d25..54da07a 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -182,7 +182,7 @@ type UnpackedScalar = backend::serial::u32::scalar::Scalar29; /// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which /// represents an element of \\(\mathbb Z / \ell\\). -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Hash)] pub struct Scalar { /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the /// group order. From 3fc47ef8675c6c14d26b366bbe4b35767cfceffa Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 29 May 2020 12:39:39 -0700 Subject: [PATCH 11/11] Bump version to 2.1.0 --- CHANGELOG.md | 4 ++++ Cargo.toml | 6 +++++- src/lib.rs | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a46b2ff..a84de2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Entries are listed in reverse chronological order. +## 2.1.0 + +* Make `Scalar::from_bits` a `const fn`, allowing its use in `const` contexts. + ## 2.0.0 * Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin diff --git a/Cargo.toml b/Cargo.toml index 7c4e238..d73a932 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,10 @@ [package] name = "curve25519-dalek" -version = "2.0.0" +# Before incrementing: +# - update CHANGELOG +# - update html_root_url +# - update README if required by semver +version = "2.1.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/src/lib.rs b/src/lib.rs index de30492..e1409a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/2.1.0")] //! Note that docs will only build on nightly Rust until //! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732).