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='' env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES=''
- rust: beta - rust: beta
env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='' env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES=''
- rust: nightly
env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='alloc'
script: script:
- cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS

View file

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

View file

@ -77,8 +77,8 @@
// affine and projective cakes and eat both of them too. // affine and projective cakes and eat both of them too.
#![allow(non_snake_case)] #![allow(non_snake_case)]
#[cfg(not(feature = "std"))] #[cfg(feature = "alloc")]
use collections::Vec; use alloc::Vec;
use core::fmt::Debug; use core::fmt::Debug;
use core::iter::Iterator; use core::iter::Iterator;
@ -91,7 +91,7 @@ use constants;
use field::FieldElement; use field::FieldElement;
use scalar::Scalar; use scalar::Scalar;
use subtle::arrays_equal; use subtle::arrays_equal;
use subtle::bytes_equal_ct; use subtle::bytes_equal;
use subtle::CTAssignable; use subtle::CTAssignable;
use subtle::CTEq; use subtle::CTEq;
use subtle::CTNegatable; use subtle::CTNegatable;
@ -193,7 +193,7 @@ impl CompressedMontgomeryU {
// //
// XXX any other exceptional points for the birational map? // XXX any other exceptional points for the birational map?
pub fn decompress(&self) -> Option<ExtendedPoint> { pub fn decompress(&self) -> Option<ExtendedPoint> {
let u: FieldElement = FieldElement::from_bytes(&self.0); let u: FieldElement = FieldElement::from_bytes(&self.0);
// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660. // If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
// But 486660 is nonsquare mod p, so this is not a curve point. // But 486660 is nonsquare mod p, so this is not a curve point.
@ -317,8 +317,9 @@ impl<'de> Deserialize<'de> for ExtendedPoint {
where E: serde::de::Error where E: serde::de::Error
{ {
if v.len() == 32 { if v.len() == 32 {
let arr32 = array_ref!(v,0,32); // &[u8;32] from &[u8] 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")) .ok_or(serde::de::Error::custom("decompression failed"))
} else { } else {
Err(serde::de::Error::invalid_length(v.len(), &self)) Err(serde::de::Error::invalid_length(v.len(), &self))
@ -518,8 +519,8 @@ impl CTAssignable for ExtendedPoint {
impl CTEq for ExtendedPoint { impl CTEq for ExtendedPoint {
fn ct_eq(&self, other: &ExtendedPoint) -> u8 { fn ct_eq(&self, other: &ExtendedPoint) -> u8 {
arrays_equal( self.compress_edwards().as_bytes(), arrays_equal(self.compress_edwards().as_bytes(),
other.compress_edwards().as_bytes()) other.compress_edwards().as_bytes())
} }
} }
@ -551,7 +552,7 @@ impl ProjectivePoint {
/// Given (X:Y:Z) in Ɛ, passing to Ɛₑ can be performed in 3M+1S by /// Given (X:Y:Z) in Ɛ, passing to Ɛₑ can be performed in 3M+1S by
/// computing (XZ,YZ,XY,Z²). (Note that in that paper, points are /// computing (XZ,YZ,XY,Z²). (Note that in that paper, points are
/// (X:Y:T:Z) so this really does match the code below). /// (X:Y:T:Z) so this really does match the code below).
#[allow(dead_code)] // rustc complains this is unused even when it's used #[allow(dead_code)] // rustc complains this is unused even when it's used
fn to_extended(&self) -> ExtendedPoint { fn to_extended(&self) -> ExtendedPoint {
ExtendedPoint{ ExtendedPoint{
X: &self.X * &self.Z, X: &self.X * &self.Z,
@ -714,7 +715,7 @@ impl ExtendedPoint {
// Addition and Subtraction // Addition and Subtraction
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
impl<'a,'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint; type Output = CompletedPoint;
fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint {
@ -735,7 +736,7 @@ impl<'a,'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
} }
} }
impl<'a,'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint; type Output = CompletedPoint;
fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint {
@ -756,7 +757,7 @@ impl<'a,'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
} }
} }
impl<'a,'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint { impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint; type Output = CompletedPoint;
fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint { fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint {
@ -776,7 +777,7 @@ impl<'a,'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
} }
} }
impl<'a,'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint { impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint; type Output = CompletedPoint;
fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint { fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint {
@ -796,7 +797,7 @@ impl<'a,'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
} }
} }
impl<'a,'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint; type Output = ExtendedPoint;
fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint { fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint {
(self + &other.to_projective_niels()).to_extended() (self + &other.to_projective_niels()).to_extended()
@ -809,7 +810,7 @@ impl<'b> AddAssign<&'b ExtendedPoint> for ExtendedPoint {
} }
} }
impl<'a,'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint { impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint; type Output = ExtendedPoint;
fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint { fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint {
(self - &other.to_projective_niels()).to_extended() (self - &other.to_projective_niels()).to_extended()
@ -1006,7 +1007,7 @@ impl EdwardsBasepointTable {
// XXX can we skip the initialization without too much unsafety? // XXX can we skip the initialization without too much unsafety?
// stick 30K on the stack and call it a day. // stick 30K on the stack and call it a day.
let mut table = EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]); let mut table = EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]);
let mut P = basepoint.clone(); let mut P = *basepoint;
for i in 0..32 { for i in 0..32 {
// P = (16^2)^i * B // P = (16^2)^i * B
let mut jP = P.to_affine_niels(); 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 { for j in 1..9 {
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
t.conditional_assign(&points[j-1], 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. // Now t == |x| * P.
@ -1181,22 +1182,22 @@ pub mod vartime {
impl Index<usize> for OddMultiples { impl Index<usize> for OddMultiples {
type Output = ProjectiveNielsPoint; type Output = ProjectiveNielsPoint;
fn index<'a>(&'a self, _index: usize) -> &'a ProjectiveNielsPoint { fn index(&self, _index: usize) -> &ProjectiveNielsPoint {
&(self.0[_index]) &(self.0[_index])
} }
} }
/// Given a vector of public scalars and a vector of (possibly secret) /// Given a vector of public scalars and a vector of (possibly secret)
/// points, compute /// points, compute `c_1 P_1 + ... + c_n P_n`.
///
/// c_1 P_1 + ... + c_n P_n.
/// ///
/// # Input /// # Input
/// ///
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
/// error to call this function with two vectors of different lengths. /// 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) -> ExtendedPoint #[cfg(any(feature = "alloc", feature = "std"))]
where I: IntoIterator<Item=&'a Scalar>, J: IntoIterator<Item=&'b ExtendedPoint> 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>
{ {
//assert_eq!(scalars.len(), points.len()); //assert_eq!(scalars.len(), points.len());
@ -1654,7 +1655,7 @@ mod test {
// CBOR apparently has two bytes of overhead for a 32-byte string. // CBOR apparently has two bytes of overhead for a 32-byte string.
// Set the low byte of the compressed point to 1 to make it invalid. // Set the low byte of the compressed point to 1 to make it invalid.
output[2] = 1; output[2] = 1;
let parsed: Result<ExtendedPoint,_> = serde_cbor::from_slice(&output); let parsed: Result<ExtendedPoint, _> = serde_cbor::from_slice(&output);
assert!(parsed.is_err()); assert!(parsed.is_err());
} }
} }
@ -1669,7 +1670,7 @@ mod bench {
use test::Bencher; use test::Bencher;
use constants; use constants;
use super::*; use super::*;
use super::test::{A_SCALAR}; use super::test::A_SCALAR;
#[bench] #[bench]
fn edwards_decompress(b: &mut Bencher) { fn edwards_decompress(b: &mut Bencher) {
@ -1736,21 +1737,21 @@ mod bench {
fn projective_double_output_completed(b: &mut Bencher) { fn projective_double_output_completed(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT.to_projective(); let p1 = constants::ED25519_BASEPOINT.to_projective();
b.iter(|| p1.double() ); b.iter(|| p1.double());
} }
#[bench] #[bench]
fn extended_double_output_extended(b: &mut Bencher) { fn extended_double_output_extended(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT; let p1 = constants::ED25519_BASEPOINT;
b.iter(|| p1.double() ); b.iter(|| p1.double());
} }
#[bench] #[bench]
fn mult_by_cofactor(b: &mut Bencher) { fn mult_by_cofactor(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT; let p1 = constants::ED25519_BASEPOINT;
b.iter(|| p1.mult_by_cofactor() ); b.iter(|| p1.mult_by_cofactor());
} }
#[cfg(feature="basepoint_table_creation")] #[cfg(feature="basepoint_table_creation")]

View file

@ -60,7 +60,7 @@ pub struct CompressedDecaf(pub [u8; 32]);
/// The result of compressing a `DecafPoint`. /// The result of compressing a `DecafPoint`.
impl CompressedDecaf { impl CompressedDecaf {
/// View this `CompressedDecaf` as an array of bytes. /// View this `CompressedDecaf` as an array of bytes.
pub fn as_bytes<'a>(&'a self) -> &'a [u8;32] { pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] {
&self.0 &self.0
} }
@ -121,7 +121,7 @@ impl CompressedDecaf {
impl Identity for CompressedDecaf { impl Identity for CompressedDecaf {
fn identity() -> CompressedDecaf { fn identity() -> CompressedDecaf {
CompressedDecaf([0u8;32]) CompressedDecaf([0u8; 32])
} }
} }
@ -165,8 +165,9 @@ impl<'de> Deserialize<'de> for DecafPoint {
where E: serde::de::Error where E: serde::de::Error
{ {
if v.len() == 32 { if v.len() == 32 {
let arr32 = array_ref!(v,0,32); // &[u8;32] from &[u8] 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")) .ok_or(serde::de::Error::custom("decompression failed"))
} else { } else {
Err(serde::de::Error::invalid_length(v.len(), &self)) Err(serde::de::Error::invalid_length(v.len(), &self))
@ -193,10 +194,10 @@ impl DecafPoint {
pub fn compress(&self) -> CompressedDecaf { pub fn compress(&self) -> CompressedDecaf {
// Q: Do we want to encode twisted or untwisted? // Q: Do we want to encode twisted or untwisted?
// //
// Notes: // Notes:
// Recall that the twisted Edwards curve E_{a,d} is of the form // Recall that the twisted Edwards curve E_{a,d} is of the form
// //
// ax^2 + y^2 = 1 + dx^2y^2. // ax^2 + y^2 = 1 + dx^2y^2.
// //
// Internally, we operate on the curve with a = -1, d = // Internally, we operate on the curve with a = -1, d =
// -121665/121666, a.k.a., the twist. But maybe we would like // -121665/121666, a.k.a., the twist. But maybe we would like
@ -205,11 +206,11 @@ impl DecafPoint {
// //
// Fix i, a square root of -1 (mod p). // Fix i, a square root of -1 (mod p).
// //
// The map x -> ix is an isomorphism from E_{a,d} to E_{-a,-d}. // The map x -> ix is an isomorphism from E_{a,d} to E_{-a,-d}.
// Its inverse is x -> -ix. // Its inverse is x -> -ix.
// let untwisted_X = &self.X * &constants::MSQRT_M1; // let untwisted_X = &self.X * &constants::MSQRT_M1;
// etc. // etc.
//
// Step 0: pre-rotation, needed for Decaf with E[8] = Z/8. // 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 // We want to select a point (x,y) in the coset P + E[4] with
@ -247,7 +248,7 @@ impl DecafPoint {
// //
// 0 = (-X^2 + Y^2)*Z^2 - Z^4 - d*X^2*Y^2, // 0 = (-X^2 + Y^2)*Z^2 - Z^4 - d*X^2*Y^2,
// //
// so // so
// 0 = (-X^2 + Y^2)*Z^2 - Z^4 - d*T^2*Z^2 since XY=TZ // 0 = (-X^2 + Y^2)*Z^2 - Z^4 - d*T^2*Z^2 since XY=TZ
// = (-X^2 + Y^2 - Z^2 - d*T^2)*Z^2 // = (-X^2 + Y^2 - Z^2 - d*T^2)*Z^2
// = ( X^2 - Y^2 + Z^2 + d*T^2)*Z^2 mult by -1 // = ( X^2 - Y^2 + Z^2 + d*T^2)*Z^2 mult by -1
@ -304,7 +305,7 @@ impl DecafPoint {
let (tmp_is_nonzero_square, W) = tmp.invsqrt(); let (tmp_is_nonzero_square, W) = tmp.invsqrt();
// tmp should always be a square (why? related to being in the // tmp should always be a square (why? related to being in the
// image of the isogeny?) // image of the isogeny?)
debug_assert_eq!( tmp_is_nonzero_square | tmp.is_zero(), 1u8 ); debug_assert_eq!(tmp_is_nonzero_square | tmp.is_zero(), 1u8);
let xy = &T.square() * &(&W.square() * &(&TZ * &ZZ_plus_XX)); let xy = &T.square() * &(&W.square() * &(&TZ * &ZZ_plus_XX));
let rotate = 1u8 & !(Y.is_nonzero() & xy.is_nonnegative_decaf()); let rotate = 1u8 & !(Y.is_nonzero() & xy.is_nonnegative_decaf());
@ -363,7 +364,7 @@ impl DecafPoint {
let r_0_squared = r_0.square(); let r_0_squared = r_0.square();
let r = &r_0_squared + &r_0_squared; let r = &r_0_squared + &r_0_squared;
// 2. Compute D <--- (dr + (a-d)) * (dr - (d + ar)) // 2. Compute D <--- (dr + (a-d)) * (dr - (d + ar))
let dr = &constants::d * &r; let dr = &constants::d * &r;
// D = (dr + (a-d)) * (dr - (d + ar)) // D = (dr + (a-d)) * (dr - (d + ar))
// = (dr + (a-d)) * (dr - (d-r)) since a=-1 // = (dr + (a-d)) * (dr - (d-r)) since a=-1
@ -398,7 +399,7 @@ impl DecafPoint {
s *= &c; s *= &c;
// 6. Compute t <--- -c*N*(r-1)* ((a-2d)*e)^2 -1 // 6. Compute t <--- -c*N*(r-1)* ((a-2d)*e)^2 -1
let a_minus_2d_e_sq = (&(&minus_one-&constants::d2)*&e).square(); let a_minus_2d_e_sq = (&(&minus_one - &constants::d2) * &e).square();
let c_N_r_minus_1 = &c * &(&N * &(&r + &minus_one)); let c_N_r_minus_1 = &c * &(&N * &(&r + &minus_one));
let t = &minus_one - &(&c_N_r_minus_1 * &a_minus_2d_e_sq); let t = &minus_one - &(&c_N_r_minus_1 * &a_minus_2d_e_sq);
@ -467,7 +468,8 @@ impl DecafPoint {
/// ``` /// ```
/// ///
pub fn hash_from_bytes<D>(input: &[u8]) -> 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(); let mut hash = D::default();
hash.input(input); hash.input(input);
DecafPoint::from_hash(hash) DecafPoint::from_hash(hash)
@ -479,7 +481,8 @@ impl DecafPoint {
/// to stream data into the `Digest` than to pass a single byte /// to stream data into the `Digest` than to pass a single byte
/// slice. /// slice.
pub fn from_hash<D>(hash: D) -> DecafPoint pub fn from_hash<D>(hash: D) -> DecafPoint
where D: Digest<OutputSize=U32> + Default { where D: Digest<OutputSize = U32> + Default
{
// XXX this seems clumsy // XXX this seems clumsy
let mut output = [0u8; 32]; let mut output = [0u8; 32];
output.copy_from_slice(hash.result().as_slice()); output.copy_from_slice(hash.result().as_slice());
@ -617,10 +620,15 @@ impl CTAssignable for DecafPoint {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// #
/// # use subtle::CTAssignable;
/// #
/// # use curve25519_dalek::curve::Identity; /// # use curve25519_dalek::curve::Identity;
/// # use curve25519_dalek::decaf::DecafPoint; /// # use curve25519_dalek::decaf::DecafPoint;
/// # use curve25519_dalek::subtle::CTAssignable;
/// # use curve25519_dalek::constants; /// # use curve25519_dalek::constants;
/// # fn main() {
/// let A = DecafPoint::identity(); /// let A = DecafPoint::identity();
/// let B = constants::DECAF_ED25519_BASEPOINT; /// let B = constants::DECAF_ED25519_BASEPOINT;
/// ///
@ -630,6 +638,7 @@ impl CTAssignable for DecafPoint {
/// assert!(P == A); /// assert!(P == A);
/// P.conditional_assign(&B, 1u8); /// P.conditional_assign(&B, 1u8);
/// assert!(P == B); /// assert!(P == B);
/// # }
/// ``` /// ```
fn conditional_assign(&mut self, other: &DecafPoint, choice: u8) { fn conditional_assign(&mut self, other: &DecafPoint, choice: u8) {
self.0.X.conditional_assign(&other.0.X, choice); self.0.X.conditional_assign(&other.0.X, choice);
@ -674,8 +683,9 @@ pub mod vartime {
/// ///
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
/// error to call this function with two vectors of different lengths. /// 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 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); let extended_points = points.into_iter().map(|P| &P.0);
DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, extended_points)) DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, extended_points))
@ -836,4 +846,3 @@ mod bench {
b.iter(|| P.compress()); b.iter(|| P.compress());
} }
} }

View file

@ -116,7 +116,7 @@ impl Index<usize> for FieldElement {
impl IndexMut<usize> for FieldElement { impl IndexMut<usize> for FieldElement {
fn index_mut(&mut self, _index: usize) -> &mut Limb { fn index_mut(&mut self, _index: usize) -> &mut Limb {
&mut(self.0[_index]) &mut (self.0[_index])
} }
} }
@ -340,25 +340,33 @@ impl CTAssignable for FieldElement {
/// If `choice == 0`, replace `self` with `self`: /// If `choice == 0`, replace `self` with `self`:
/// ///
/// ``` /// ```
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::field::FieldElement; /// # 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 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 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]); /// let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 0); /// h.conditional_assign(&g, 0);
/// assert!(h == f); /// assert!(h == f);
/// # }
/// ``` /// ```
/// ///
/// If `choice == 1`, replace `self` with `f`: /// If `choice == 1`, replace `self` with `f`:
/// ///
/// ``` /// ```
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::field::FieldElement; /// # 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 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 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]); /// # let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 1); /// h.conditional_assign(&g, 1);
/// assert!(h == g); /// assert!(h == g);
/// # }
/// ``` /// ```
/// ///
/// # Preconditions /// # Preconditions
@ -456,7 +464,7 @@ impl FieldElement {
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
fn reduce(mut h: [i64; 10]) -> FieldElement { //FeCombine fn reduce(mut h: [i64; 10]) -> FieldElement { //FeCombine
let mut c = [0i64;10]; let mut c = [0i64; 10];
/* /*
|h[0]| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) |h[0]| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
@ -709,7 +717,7 @@ impl FieldElement {
// evidently 2^255 h10-2^255 q = 0. // evidently 2^255 h10-2^255 q = 0.
// Goal: Output h[0]+...+2^230 h[9]. // Goal: Output h[0]+...+2^230 h[9].
let mut s = [0u8;32]; let mut s = [0u8; 32];
s[0] = (h[0] >> 0) as u8; s[0] = (h[0] >> 0) as u8;
s[1] = (h[0] >> 8) as u8; s[1] = (h[0] >> 8) as u8;
s[2] = (h[0] >> 16) as u8; s[2] = (h[0] >> 16) as u8;
@ -826,7 +834,7 @@ impl FieldElement {
debug_assert!((s[31] & 0b1000_0000u8) == 0u8); debug_assert!((s[31] & 0b1000_0000u8) == 0u8);
s[31] &= 127u8; s[31] &= 127u8;
return s s
} }
/// Determine if this `FieldElement` is negative, in the sense /// Determine if this `FieldElement` is negative, in the sense
@ -1179,7 +1187,7 @@ impl FieldElement {
let r_prime = &constants::SQRT_M1 * &r; let r_prime = &constants::SQRT_M1 * &r;
r.conditional_assign(&r_prime, flipped_sign_sqrt); r.conditional_assign(&r_prime, flipped_sign_sqrt);
let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt; let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt;
(was_nonzero_square, r) (was_nonzero_square, r)
@ -1263,7 +1271,7 @@ mod test {
fn a_mul_a_vs_a_squared_constant() { fn a_mul_a_vs_a_squared_constant() {
let a = FieldElement::from_bytes(&A_BYTES); let a = FieldElement::from_bytes(&A_BYTES);
let asq = FieldElement::from_bytes(&ASQ_BYTES); let asq = FieldElement::from_bytes(&ASQ_BYTES);
assert_eq!(asq, &a*&a); assert_eq!(asq, &a * &a);
} }
#[test] #[test]
@ -1381,7 +1389,7 @@ mod bench {
#[bench] #[bench]
fn fieldelement_a_mul_a(b: &mut Bencher) { fn fieldelement_a_mul_a(b: &mut Bencher) {
let a = FieldElement::from_bytes(&A_BYTES); let a = FieldElement::from_bytes(&A_BYTES);
b.iter(|| &a*&a); b.iter(|| &a * &a);
} }
#[bench] #[bench]

View file

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

View file

@ -63,7 +63,7 @@ impl Debug for Scalar {
} }
} }
impl Eq for Scalar{} impl Eq for Scalar {}
impl PartialEq for Scalar { impl PartialEq for Scalar {
/// Test equality between two `Scalar`s. /// Test equality between two `Scalar`s.
/// ///
@ -101,7 +101,7 @@ impl Index<usize> for Scalar {
impl IndexMut<usize> for Scalar { impl IndexMut<usize> for Scalar {
fn index_mut(&mut self, _index: usize) -> &mut u8 { fn index_mut(&mut self, _index: usize) -> &mut u8 {
&mut(self.0[_index]) &mut (self.0[_index])
} }
} }
@ -151,15 +151,18 @@ impl<'a> Neg for &'a Scalar {
type Output = Scalar; type Output = Scalar;
fn neg(self) -> Scalar { fn neg(self) -> Scalar {
self * &constants::l_minus_1 self * &constants::l_minus_1
} }
} }
impl CTAssignable for Scalar { impl CTAssignable for Scalar {
/// Conditionally assign another Scalar to this one. /// Conditionally assign another Scalar to this one.
/// ///
/// ``` /// ```
/// # extern crate curve25519_dalek;
/// # extern crate subtle;
/// # use curve25519_dalek::scalar::Scalar; /// # 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, /// 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]); /// 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, /// 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]); /// assert!(t[0] == a[0]);
/// t.conditional_assign(&b, 1u8); /// t.conditional_assign(&b, 1u8);
/// assert!(t[0] == b[0]); /// assert!(t[0] == b[0]);
/// # }
/// ``` /// ```
/// ///
/// # Preconditions /// # Preconditions
@ -218,7 +222,7 @@ impl<'de> Deserialize<'de> for Scalar {
{ {
if v.len() == 32 { if v.len() == 32 {
// array_ref turns &[u8] into &[u8;32] // array_ref turns &[u8] into &[u8;32]
Ok(Scalar(*array_ref!(v,0,32))) Ok(Scalar(*array_ref!(v, 0, 32)))
} else { } else {
Err(serde::de::Error::invalid_length(v.len(), &self)) Err(serde::de::Error::invalid_length(v.len(), &self))
} }
@ -270,7 +274,8 @@ impl Scalar {
/// ``` /// ```
/// ///
pub fn hash_from_bytes<D>(input: &[u8]) -> 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(); let mut hash = D::default();
hash.input(input); hash.input(input);
Scalar::from_hash(hash) Scalar::from_hash(hash)
@ -282,9 +287,10 @@ impl Scalar {
/// to stream data into the `Digest` than to pass a single byte /// to stream data into the `Digest` than to pass a single byte
/// slice. /// slice.
pub fn from_hash<D>(hash: D) -> Scalar pub fn from_hash<D>(hash: D) -> Scalar
where D: Digest<OutputSize=U64> + Default { where D: Digest<OutputSize = U64> + Default
{
// XXX this seems clumsy // XXX this seems clumsy
let mut output = [0u8;64]; let mut output = [0u8; 64];
output.copy_from_slice(hash.result().as_slice()); output.copy_from_slice(hash.result().as_slice());
Scalar::reduce(&output) Scalar::reduce(&output)
} }
@ -320,7 +326,7 @@ impl Scalar {
} }
/// Get the bits of the scalar. /// Get the bits of the scalar.
pub fn bits(&self) -> [i8;256] { pub fn bits(&self) -> [i8; 256] {
let mut bits = [0i8; 256]; let mut bits = [0i8; 256];
for i in 0..256 { for i in 0..256 {
// As i runs from 0..256, the bottom 3 bits index the bit, // As i runs from 0..256, the bottom 3 bits index the bit,
@ -379,7 +385,7 @@ impl Scalar {
// Unpack a scalar into 12 21-bit limbs. // Unpack a scalar into 12 21-bit limbs.
fn unpack(&self) -> UnpackedScalar { fn unpack(&self) -> UnpackedScalar {
let mask_21bits: i64 = (1 << 21) -1; let mask_21bits: i64 = (1 << 21) - 1;
let mut a = UnpackedScalar([0i64; 12]); let mut a = UnpackedScalar([0i64; 12]);
a[ 0] = mask_21bits & load3(&self.0[ 0..]) ; a[ 0] = mask_21bits & load3(&self.0[ 0..]) ;
a[ 1] = mask_21bits & (load4(&self.0[ 2..]) >> 5); a[ 1] = mask_21bits & (load4(&self.0[ 2..]) >> 5);
@ -504,7 +510,7 @@ impl Index<usize> for UnpackedScalar {
impl IndexMut<usize> for UnpackedScalar { impl IndexMut<usize> for UnpackedScalar {
fn index_mut(&mut self, _index: usize) -> &mut i64 { fn index_mut(&mut self, _index: usize) -> &mut i64 {
&mut(self.0[_index]) &mut (self.0[_index])
} }
} }
@ -616,7 +622,7 @@ impl UnpackedScalar {
/// 2^252 = -27742317777372353535851937790883648493 (mod l). /// 2^252 = -27742317777372353535851937790883648493 (mod l).
/// ///
/// We can write the right-hand side in 21-bit limbs as /// We can write the right-hand side in 21-bit limbs as
/// ///
/// rhs = 666643 * 2^0 /// rhs = 666643 * 2^0
/// + 470296 * 2^21 /// + 470296 * 2^21
/// + 654183 * 2^42 /// + 654183 * 2^42
@ -640,7 +646,7 @@ impl UnpackedScalar {
fn reduce_limbs(mut limbs: &mut [i64; 24]) -> UnpackedScalar { fn reduce_limbs(mut limbs: &mut [i64; 24]) -> UnpackedScalar {
#[inline] #[inline]
#[allow(dead_code)] #[allow(dead_code)]
fn do_reduction(limbs: &mut [i64; 24], i:usize) { fn do_reduction(limbs: &mut [i64; 24], i: usize) {
limbs[i - 12] += limbs[i] * 666643; limbs[i - 12] += limbs[i] * 666643;
limbs[i - 11] += limbs[i] * 470296; limbs[i - 11] += limbs[i] * 470296;
limbs[i - 10] += limbs[i] * 654183; limbs[i - 10] += limbs[i] * 654183;
@ -662,7 +668,7 @@ impl UnpackedScalar {
#[allow(dead_code)] #[allow(dead_code)]
/// Carry excess from the `i`-th limb into the `(i+1)`-th limb. /// Carry excess from the `i`-th limb into the `(i+1)`-th limb.
/// Postcondition: `-2^20 <= limbs[i] < 2^20`. /// Postcondition: `-2^20 <= limbs[i] < 2^20`.
fn do_carry_centered(limbs: &mut [i64; 24], i:usize) { fn do_carry_centered(limbs: &mut [i64; 24], i: usize) {
let carry: i64 = (limbs[i] + (1<<20)) >> 21; let carry: i64 = (limbs[i] + (1<<20)) >> 21;
limbs[i+1] += carry; limbs[i+1] += carry;
limbs[i ] -= carry << 21; limbs[i ] -= carry << 21;
@ -717,7 +723,6 @@ impl UnpackedScalar {
UnpackedScalar(*array_ref!(limbs, 0, 12)) UnpackedScalar(*array_ref!(limbs, 0, 12))
} }
} }
#[cfg(test)] #[cfg(test)]
@ -901,7 +906,7 @@ mod bench {
#[bench] #[bench]
fn scalar_multiply_add(b: &mut Bencher) { fn scalar_multiply_add(b: &mut Bencher) {
b.iter(|| Scalar::multiply_add(&X, &Y, &Z) ); b.iter(|| Scalar::multiply_add(&X, &Y, &Z));
} }
#[bench] #[bench]
@ -915,6 +920,6 @@ mod bench {
let x = X.unpack(); let x = X.unpack();
let y = Y.unpack(); let y = Y.unpack();
let z = Z.unpack(); let z = Z.unpack();
b.iter(|| UnpackedScalar::multiply_add(&x, &y, &z) ); b.iter(|| UnpackedScalar::multiply_add(&x, &y, &z));
} }
} }

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);
}
}