Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/compressed try from #1

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,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"]
Expand Down
26 changes: 25 additions & 1 deletion src/edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -107,6 +108,8 @@ use subtle::ConstantTimeEq;

use constants;

use errors::{CurveError, InternalError};

use field::FieldElement;
use scalar::Scalar;

Expand Down Expand Up @@ -327,12 +330,33 @@ impl Default for CompressedEdwardsY {
}
}

impl From<[u8; 32]> for CompressedEdwardsY {
fn from(bytes: [u8; 32]) -> Self {
CompressedEdwardsY(bytes)
}
}

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
///
/// 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];

Expand Down
69 changes: 69 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// -*- 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)
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ pub mod constants;
// External (and internal) traits.
pub mod traits;

// Errors which may occur.
pub mod errors;

//------------------------------------------------------------------------
// curve25519-dalek internal modules
//------------------------------------------------------------------------
Expand Down
50 changes: 50 additions & 0 deletions src/montgomery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@
// 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;

use traits::Identity;
use traits::ValidityCheck;

use subtle::Choice;
use subtle::ConditionallySelectable;
Expand Down Expand Up @@ -90,6 +93,53 @@ 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 From<[u8; 32]> for MontgomeryPoint {
fn from(bytes: [u8; 32]) -> Self {
MontgomeryPoint(bytes)
}
}

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] {
Expand Down
26 changes: 25 additions & 1 deletion src/ristretto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -180,6 +181,8 @@ use subtle::ConstantTimeEq;
use edwards::EdwardsBasepointTable;
use edwards::EdwardsPoint;

use errors::{CurveError, InternalError};

#[allow(unused_imports)]
use prelude::*;

Expand Down Expand Up @@ -217,6 +220,25 @@ 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 From<[u8; 32]> for CompressedRistretto {
fn from(bytes: [u8; 32]) -> Self {
CompressedRistretto(bytes)
}
}

impl CompressedRistretto {
/// Copy the bytes of this `CompressedRistretto`.
pub fn to_bytes(&self) -> [u8; 32] {
Expand All @@ -232,7 +254,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];

Expand Down
36 changes: 31 additions & 5 deletions src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@

use core::borrow::Borrow;
use core::cmp::{Eq, PartialEq};
use core::convert::TryFrom;
use core::fmt::Debug;
use core::iter::{Product, Sum};
use core::ops::Index;
Expand All @@ -148,6 +149,8 @@ use core::ops::{Add, AddAssign};
use core::ops::{Mul, MulAssign};
use core::ops::{Sub, SubAssign};

use errors::{CurveError, InternalError};

#[allow(unused_imports)]
use prelude::*;

Expand Down Expand Up @@ -242,11 +245,7 @@ impl Scalar {
/// require specific bit-patterns when performing scalar
/// multiplication.
pub fn from_bits(bytes: [u8; 32]) -> Scalar {
let mut s = Scalar{bytes: bytes};
// Ensure that s < 2^255 by masking the high bit
s.bytes[31] &= 0b0111_1111;

s
Scalar::from(bytes)
}
}

Expand Down Expand Up @@ -459,6 +458,33 @@ impl Default for Scalar {
}
}

impl TryFrom<&[u8]> for Scalar {
type Error = CurveError;

fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != 32 {
return Err(CurveError(
InternalError::BytesLengthError{name: "Scalar", length: 32}));
}

let mut s_bytes = [0x00u8; 32];
s_bytes.copy_from_slice(bytes);

Ok(Scalar::from(s_bytes))
}
}

impl From<[u8; 32]> for Scalar {
fn from(bytes: [u8; 32]) -> Self {
let mut s = Scalar{bytes: bytes};

// Ensure that s < 2^255 by masking the high bit
s.bytes[31] &= 0b0111_1111;

s
}
}

impl From<u8> for Scalar {
fn from(x: u8) -> Scalar {
let mut s_bytes = [0u8; 32];
Expand Down