Merge branch 'release/0.9.1'

This commit is contained in:
Isis Lovecruft 2017-06-26 20:41:39 +00:00
commit 010e1f8dec
Failed to extract signature
8 changed files with 111 additions and 248 deletions

View file

@ -37,6 +37,8 @@ matrix:
env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES=''
- rust: beta
env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES=''
- rust: nightly
env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='alloc'
script:
- cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS

View file

@ -1,6 +1,6 @@
[package]
name = "curve25519-dalek"
version = "0.9.0"
version = "0.9.1"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
@ -30,14 +30,17 @@ optional = true
version = "0.3"
[dependencies.digest]
version = "0.4"
version = "0.6"
[dependencies.subtle]
version = "^0.1"
[dependencies.generic-array]
# same version that digest depends on
version = "^0.6"
version = "^0.8"
[dev-dependencies.sha2]
version = "0.4"
version = "0.6"
[dev-dependencies.serde_cbor]
version = "0.6"
@ -46,6 +49,7 @@ version = "0.6"
nightly = ["radix_51"]
default = ["std"]
std = ["rand"]
alloc = []
yolocrypto = []
bench = []
# Radix-51 arithmetic using u128

View file

@ -77,8 +77,8 @@
// affine and projective cakes and eat both of them too.
#![allow(non_snake_case)]
#[cfg(not(feature = "std"))]
use collections::Vec;
#[cfg(feature = "alloc")]
use alloc::Vec;
use core::fmt::Debug;
use core::iter::Iterator;
@ -91,7 +91,7 @@ use constants;
use field::FieldElement;
use scalar::Scalar;
use subtle::arrays_equal;
use subtle::bytes_equal_ct;
use subtle::bytes_equal;
use subtle::CTAssignable;
use subtle::CTEq;
use subtle::CTNegatable;
@ -318,7 +318,8 @@ impl<'de> Deserialize<'de> for ExtendedPoint {
{
if v.len() == 32 {
let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8]
CompressedEdwardsY(*arr32).decompress()
CompressedEdwardsY(*arr32)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
@ -1006,7 +1007,7 @@ impl EdwardsBasepointTable {
// XXX can we skip the initialization without too much unsafety?
// stick 30K on the stack and call it a day.
let mut table = EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]);
let mut P = basepoint.clone();
let mut P = *basepoint;
for i in 0..32 {
// P = (16^2)^i * B
let mut jP = P.to_affine_niels();
@ -1081,7 +1082,7 @@ fn select_precomputed_point<T>(x: i8, points: &[T; 8]) -> T
for j in 1..9 {
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
t.conditional_assign(&points[j-1],
bytes_equal_ct(xabs as u8, j as u8));
bytes_equal(xabs as u8, j as u8));
}
// Now t == |x| * P.
@ -1181,22 +1182,22 @@ pub mod vartime {
impl Index<usize> for OddMultiples {
type Output = ProjectiveNielsPoint;
fn index<'a>(&'a self, _index: usize) -> &'a ProjectiveNielsPoint {
fn index(&self, _index: usize) -> &ProjectiveNielsPoint {
&(self.0[_index])
}
}
/// Given a vector of public scalars and a vector of (possibly secret)
/// points, compute
///
/// c_1 P_1 + ... + c_n P_n.
/// points, compute `c_1 P_1 + ... + c_n P_n`.
///
/// # Input
///
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
/// error to call this function with two vectors of different lengths.
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn k_fold_scalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
where I: IntoIterator<Item=&'a Scalar>, J: IntoIterator<Item=&'b ExtendedPoint>
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b ExtendedPoint>
{
//assert_eq!(scalars.len(), points.len());
@ -1669,7 +1670,7 @@ mod bench {
use test::Bencher;
use constants;
use super::*;
use super::test::{A_SCALAR};
use super::test::A_SCALAR;
#[bench]
fn edwards_decompress(b: &mut Bencher) {

View file

@ -166,7 +166,8 @@ impl<'de> Deserialize<'de> for DecafPoint {
{
if v.len() == 32 {
let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8]
CompressedDecaf(*arr32).decompress()
CompressedDecaf(*arr32)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
@ -209,7 +210,7 @@ impl DecafPoint {
// Its inverse is x -> -ix.
// let untwisted_X = &self.X * &constants::MSQRT_M1;
// etc.
//
// Step 0: pre-rotation, needed for Decaf with E[8] = Z/8.
//
// We want to select a point (x,y) in the coset P + E[4] with
@ -467,7 +468,8 @@ impl DecafPoint {
/// ```
///
pub fn hash_from_bytes<D>(input: &[u8]) -> DecafPoint
where D: Digest<OutputSize=U32> + Default {
where D: Digest<OutputSize = U32> + Default
{
let mut hash = D::default();
hash.input(input);
DecafPoint::from_hash(hash)
@ -479,7 +481,8 @@ impl DecafPoint {
/// to stream data into the `Digest` than to pass a single byte
/// slice.
pub fn from_hash<D>(hash: D) -> DecafPoint
where D: Digest<OutputSize=U32> + Default {
where D: Digest<OutputSize = U32> + Default
{
// XXX this seems clumsy
let mut output = [0u8; 32];
output.copy_from_slice(hash.result().as_slice());
@ -617,10 +620,15 @@ impl CTAssignable for DecafPoint {
/// # Example
///
/// ```
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// #
/// # use subtle::CTAssignable;
/// #
/// # use curve25519_dalek::curve::Identity;
/// # use curve25519_dalek::decaf::DecafPoint;
/// # use curve25519_dalek::subtle::CTAssignable;
/// # use curve25519_dalek::constants;
/// # fn main() {
/// let A = DecafPoint::identity();
/// let B = constants::DECAF_ED25519_BASEPOINT;
///
@ -630,6 +638,7 @@ impl CTAssignable for DecafPoint {
/// assert!(P == A);
/// P.conditional_assign(&B, 1u8);
/// assert!(P == B);
/// # }
/// ```
fn conditional_assign(&mut self, other: &DecafPoint, choice: u8) {
self.0.X.conditional_assign(&other.0.X, choice);
@ -675,7 +684,8 @@ pub mod vartime {
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
/// error to call this function with two vectors of different lengths.
pub fn k_fold_scalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> DecafPoint
where I: IntoIterator<Item=&'a Scalar>, J: IntoIterator<Item=&'b DecafPoint>
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b DecafPoint>
{
let extended_points = points.into_iter().map(|P| &P.0);
DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, extended_points))
@ -836,4 +846,3 @@ mod bench {
b.iter(|| P.compress());
}
}

View file

@ -340,25 +340,33 @@ impl CTAssignable for FieldElement {
/// If `choice == 0`, replace `self` with `self`:
///
/// ```
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::field::FieldElement;
/// # use curve25519_dalek::subtle::CTAssignable;
/// # use subtle::CTAssignable;
/// # fn main() {
/// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 0);
/// assert!(h == f);
/// # }
/// ```
///
/// If `choice == 1`, replace `self` with `f`:
///
/// ```
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::field::FieldElement;
/// # use curve25519_dalek::subtle::CTAssignable;
/// # use subtle::CTAssignable;
/// # fn main() {
/// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// # let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 1);
/// assert!(h == g);
/// # }
/// ```
///
/// # Preconditions
@ -826,7 +834,7 @@ impl FieldElement {
debug_assert!((s[31] & 0b1000_0000u8) == 0u8);
s[31] &= 127u8;
return s
s
}
/// Determine if this `FieldElement` is negative, in the sense

View file

@ -10,9 +10,10 @@
// - Henry de Valence <hdevalence@hdevalence.ca>
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(collections))]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "nightly", feature(i128_type))]
#![cfg_attr(feature = "bench", feature(test))]
#![cfg_attr(all(feature = "nightly", feature = "std"), feature(zero_one))]
#![allow(unused_features)]
#![deny(missing_docs)] // refuse to compile if documentation is missing
@ -46,6 +47,7 @@ extern crate arrayref;
extern crate generic_array;
extern crate digest;
extern crate subtle;
#[cfg(feature = "serde")]
extern crate serde;
@ -58,8 +60,8 @@ extern crate core;
#[cfg(feature = "std")]
extern crate rand;
#[cfg(not(feature = "std"))]
extern crate collections;
#[cfg(feature = "alloc")]
extern crate alloc;
// Modules for low-level operations directly on field elements and curve points.
@ -71,9 +73,8 @@ pub mod curve;
#[cfg(feature = "yolocrypto")]
pub mod decaf;
// Constant-time functions and other miscelaneous utilities.
// Other miscelaneous utilities.
pub mod subtle;
pub mod utils;
// Low-level curve and point constants, as well as pre-computed curve group elements.

View file

@ -158,8 +158,11 @@ impl CTAssignable for Scalar {
/// Conditionally assign another Scalar to this one.
///
/// ```
/// # extern crate curve25519_dalek;
/// # extern crate subtle;
/// # use curve25519_dalek::scalar::Scalar;
/// # use curve25519_dalek::subtle::CTAssignable;
/// # use subtle::CTAssignable;
/// # fn main() {
/// let a = Scalar([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
/// let b = Scalar([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@ -169,6 +172,7 @@ impl CTAssignable for Scalar {
/// assert!(t[0] == a[0]);
/// t.conditional_assign(&b, 1u8);
/// assert!(t[0] == b[0]);
/// # }
/// ```
///
/// # Preconditions
@ -270,7 +274,8 @@ impl Scalar {
/// ```
///
pub fn hash_from_bytes<D>(input: &[u8]) -> Scalar
where D: Digest<OutputSize = U64> + Default {
where D: Digest<OutputSize = U64> + Default
{
let mut hash = D::default();
hash.input(input);
Scalar::from_hash(hash)
@ -282,7 +287,8 @@ impl Scalar {
/// to stream data into the `Digest` than to pass a single byte
/// slice.
pub fn from_hash<D>(hash: D) -> Scalar
where D: Digest<OutputSize=U64> + Default {
where D: Digest<OutputSize = U64> + Default
{
// XXX this seems clumsy
let mut output = [0u8; 64];
output.copy_from_slice(hash.result().as_slice());
@ -717,7 +723,6 @@ impl UnpackedScalar {
UnpackedScalar(*array_ref!(limbs, 0, 12))
}
}
#[cfg(test)]

View file

@ -1,167 +0,0 @@
// -*- mode: rust; -*-
//
// To the extent possible under law, the authors have waived all copyright and
// related or neighboring rights to curve25519-dalek, using the Creative
// Commons "CC0" public domain dedication. See
// <http://creativecommons.org/publicdomain/zero/.0/> for full details.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Constant-time traits and utility functions.
use core::ops::Neg;
/// Trait for items which can be conditionally assigned in constant time.
pub trait CTAssignable {
/// If `choice == 1u8`, assign `other` to `self`.
/// Otherwise, leave `self` unchanged.
/// Executes in constant time.
fn conditional_assign(&mut self, other: &Self, choice: u8);
}
/// Trait for items whose equality to another item may be tested in constant time.
pub trait CTEq {
/// Determine if two items are equal in constant time.
///
/// # Returns
///
/// `1u8` if the two items are equal, and `0u8` otherwise.
fn ct_eq(&self, other: &Self) -> u8;
}
/// Trait for items which can be conditionally negated in constant time.
///
/// Note: it is not necessary to implement this trait, as a generic
/// implementation is provided.
pub trait CTNegatable
{
/// Conditionally negate an element if `choice == 1u8`.
fn conditional_negate(&mut self, choice: u8);
}
impl<T> CTNegatable for T
where T: CTAssignable, for<'a> &'a T: Neg<Output=T>
{
fn conditional_negate(&mut self, choice: u8) {
// Need to cast to eliminate mutability
let self_neg: T = -(self as &T);
self.conditional_assign(&self_neg, choice);
}
}
/// Check equality of two bytes in constant time.
///
/// # Return
///
/// Returns `1u8` if `a == b` and `0u8` otherwise.
#[inline(always)]
pub fn bytes_equal_ct(a: u8, b: u8) -> u8 {
let mut x: u8;
x = !(a ^ b);
x &= x >> 4;
x &= x >> 2;
x &= x >> 1;
x
}
/// Test if a byte is non-zero in constant time.
///
/// ```
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::subtle::byte_is_nonzero;
/// # fn main() {
/// let mut x: u8;
/// x = 0;
/// assert!(byte_is_nonzero(x) == 0);
/// x = 3;
/// assert!(byte_is_nonzero(x) == 1);
/// # }
/// ```
///
/// # Return
///
/// * If b != 0, returns 1u8.
/// * If b == 0, returns 0u8.
#[inline(always)]
pub fn byte_is_nonzero(b: u8) -> u8 {
let mut x = b;
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
(x & 1)
}
/// Check equality of two arrays, `a` and `b`, in constant time.
///
/// There is a `debug_assert!` that the two arrays are of equal length. For
/// example, the following code will panic:
///
/// ```rust,ignore
/// let a: [u8; 3] = [0, 0, 0];
/// let b: [u8; 4] = [0, 0, 0, 0];
///
/// assert!(arrays_equal(&a, &b) == 1);
/// ```
///
/// However, if the arrays are equal length, but their contents do *not* match,
/// `0u8` will be returned:
///
/// ```
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::subtle::arrays_equal;
/// # fn main() {
/// let a: [u8; 3] = [0, 1, 2];
/// let b: [u8; 3] = [1, 2, 3];
///
/// assert!(arrays_equal(&a, &b) == 0);
/// # }
/// ```
///
/// And finally, if the contents *do* match, `1u8` is returned:
///
/// ```
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::subtle::arrays_equal;
/// # fn main() {
/// let a: [u8; 3] = [0, 1, 2];
/// let b: [u8; 3] = [0, 1, 2];
///
/// assert!(arrays_equal(&a, &b) == 1);
/// # }
/// ```
///
/// This function is commonly used in various cryptographic applications, such
/// as [signature verification](https://github.com/isislovecruft/ed25519-dalek/blob/0.3.2/src/ed25519.rs#L280),
/// among many other applications.
///
/// # Return
///
/// Returns `1u8` if `a == b` and `0u8` otherwise.
#[inline(always)]
pub fn arrays_equal(a: &[u8], b: &[u8]) -> u8 {
debug_assert!(a.len() == b.len());
let mut x: u8 = 0;
for i in 0 .. a.len() {
x |= a[i] ^ b[i];
}
bytes_equal_ct(x, 0)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[should_panic]
fn arrays_equal_different_lengths() {
let a: [u8; 3] = [0, 0, 0];
let b: [u8; 4] = [0, 0, 0, 0];
assert!(arrays_equal(&a, &b) == 1);
}
}