Merge branch 'release/0.7.0'

This commit is contained in:
Isis Lovecruft 2017-05-14 09:49:53 +00:00
commit 19dbf62d3d
Failed to extract signature
8 changed files with 711 additions and 365 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "curve25519-dalek" name = "curve25519-dalek"
version = "0.6.0" version = "0.7.0"
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"
@ -36,12 +36,10 @@ version = "^0.6"
version = "0.4" version = "0.4"
[features] [features]
nightly = ["basepoint_table_creation", "radix_51"] nightly = ["radix_51"]
default = ["std"] default = ["std"]
std = ["rand"] std = ["rand"]
yolocrypto = [] yolocrypto = []
# Needs nightly for placement new
basepoint_table_creation = []
bench = [] bench = []
# Radix-51 arithmetic using u128 # Radix-51 arithmetic using u128
radix_51 = [] radix_51 = []

View file

@ -44,7 +44,7 @@ Extensive documentation is available [here](https://docs.rs/curve25519-dalek).
To install, add the following to the dependencies section of your project's To install, add the following to the dependencies section of your project's
`Cargo.toml`: `Cargo.toml`:
curve25519-dalek = "^0.6" curve25519-dalek = "^0.7"
Then, in your library or executable source, add: Then, in your library or executable source, add:

View file

@ -24,6 +24,8 @@ use curve::ExtendedPoint;
use curve::AffineNielsPoint; use curve::AffineNielsPoint;
use curve::CompressedEdwardsY; use curve::CompressedEdwardsY;
use curve::EdwardsBasepointTable; use curve::EdwardsBasepointTable;
#[cfg(feature = "yolocrypto")]
use decaf::{DecafPoint, DecafBasepointTable};
use scalar::Scalar; use scalar::Scalar;
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
@ -70,7 +72,7 @@ pub const SQRT_M1: FieldElement = FieldElement([
pub const SQRT_M1: FieldElement = FieldElement([1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133]); pub const SQRT_M1: FieldElement = FieldElement([1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133]);
/// Precomputed value of the other square root of -1 (mod p), /// Precomputed value of the other square root of -1 (mod p),
/// i.e., MSQRT_M1 = -SQRT_M1. /// i.e., `MSQRT_M1 = -SQRT_M1`.
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
pub const MSQRT_M1: FieldElement = FieldElement([ pub const MSQRT_M1: FieldElement = FieldElement([
32595792, 7943725, -9377950, -3500415, -12389472, 32595792, 7943725, -9377950, -3500415, -12389472,
@ -92,7 +94,7 @@ pub const A: FieldElement = FieldElement([
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub const A: FieldElement = FieldElement([486662, 0, 0, 0, 0]); pub const A: FieldElement = FieldElement([486662, 0, 0, 0, 0]);
/// SQRT_MINUS_A is sqrt(-486662) /// `SQRT_MINUS_A` is sqrt(-486662)
// XXX I think that this was used in Adam's code for his elligator // XXX I think that this was used in Adam's code for his elligator
// implementation, but that should maybe be using sqrt(-486664) // implementation, but that should maybe be using sqrt(-486664)
// instead...? - hdevalence // instead...? - hdevalence
@ -103,7 +105,7 @@ pub const SQRT_MINUS_A: FieldElement = FieldElement([ // sqrtMinusA
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub const SQRT_MINUS_A: FieldElement = FieldElement([557817479725543, 1643290402203250, 16226468853936, 1304118542701054, 1985241807451647]); pub const SQRT_MINUS_A: FieldElement = FieldElement([557817479725543, 1643290402203250, 16226468853936, 1304118542701054, 1985241807451647]);
/// SQRT_MINUS_APLUS2 is sqrt(-486664) /// `SQRT_MINUS_APLUS2` is sqrt(-486664)
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([ pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([
-12222970, -8312128, -11511410, 9067497, -15300785, -12222970, -8312128, -11511410, 9067497, -15300785,
@ -111,7 +113,7 @@ pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([1693982333959686, 608509411481997, 2235573344831311, 947681270984193, 266558006233600]); pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([1693982333959686, 608509411481997, 2235573344831311, 947681270984193, 266558006233600]);
/// SQRT_MINUS_HALF is sqrt(-1/2) /// `SQRT_MINUS_HALF` is sqrt(-1/2)
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
pub const SQRT_MINUS_HALF: FieldElement = FieldElement([ // sqrtMinusHalf pub const SQRT_MINUS_HALF: FieldElement = FieldElement([ // sqrtMinusHalf
-17256545, 3971863, 28865457, -1750208, 27359696, -17256545, 3971863, 28865457, -1750208, 27359696,
@ -119,7 +121,7 @@ pub const SQRT_MINUS_HALF: FieldElement = FieldElement([ // sqrtMinusHalf
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub const SQRT_MINUS_HALF: FieldElement = FieldElement([266547196637087, 2134345371906993, 1135042577398223, 67298593331632, 743161882051057]); pub const SQRT_MINUS_HALF: FieldElement = FieldElement([266547196637087, 2134345371906993, 1135042577398223, 67298593331632, 743161882051057]);
/// HALF_Q_MINUS_1_BYTES is (2^255-20)/2 expressed in little endian form. /// `HALF_Q_MINUS_1_BYTES` is (2^255-20)/2 expressed in little endian form.
pub const HALF_Q_MINUS_1_BYTES: [u8; 32] = [ // halfQMinus1Bytes pub const HALF_Q_MINUS_1_BYTES: [u8; 32] = [ // halfQMinus1Bytes
0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@ -136,6 +138,10 @@ pub const BASE_CMPRSSD: CompressedEdwardsY =
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]); 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]);
/// The Ed25519 basepoint, as a `DecafPoint`.
#[cfg(feature = "yolocrypto")]
pub const DECAF_ED25519_BASEPOINT: DecafPoint = DecafPoint(ED25519_BASEPOINT);
/// Basepoint has y = 4/5. /// Basepoint has y = 4/5.
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
pub const ED25519_BASEPOINT: ExtendedPoint = ExtendedPoint{ pub const ED25519_BASEPOINT: ExtendedPoint = ExtendedPoint{
@ -159,12 +165,20 @@ pub const l: Scalar = Scalar([ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]);
/// `lminus1` is the order of base point minus one, i.e. 2^252 + /// `l_minus_1` is the order of base point minus one, i.e. 2^252 +
/// 27742317777372353535851937790883648493 - 1, in little-endian form /// 27742317777372353535851937790883648493 - 1, in little-endian form
pub const lminus1: Scalar = Scalar([ 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, pub const l_minus_1: Scalar = Scalar([ 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]);
/// `lminus1` is the order of base point minus two, i.e. 2^252 +
/// 27742317777372353535851937790883648493 - 2, in little-endian form
pub const l_minus_2: Scalar = Scalar([ 0xeb, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]);
/// The 8-torsion subgroup Ɛ[8]. /// The 8-torsion subgroup Ɛ[8].
/// ///
/// In the case of Curve25519, it is cyclic; the `i`th element of the /// In the case of Curve25519, it is cyclic; the `i`th element of the
@ -376,6 +390,11 @@ pub const bi: [AffineNielsPoint; 8] = [
} }
]; ];
#[cfg(feature = "yolocrypto")]
/// The Ed25519 basepoint
pub const DECAF_ED25519_BASEPOINT_TABLE: DecafBasepointTable
= DecafBasepointTable(ED25519_BASEPOINT_TABLE);
/// Table containing precomputed multiples of the basepoint `B = (x,4/5)`. /// Table containing precomputed multiples of the basepoint `B = (x,4/5)`.
/// ///
/// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`, /// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`,

View file

@ -59,15 +59,15 @@
//! implementation for [Ed25519](https://ed25519.cr.yp.to/ed25519-20110926.pdf), //! implementation for [Ed25519](https://ed25519.cr.yp.to/ed25519-20110926.pdf),
//! we use several different models for curve points: //! we use several different models for curve points:
//! //!
//! * CompletedPoint: points in 𝗣^1 x 𝗣^1; //! * `CompletedPoint`: points in 𝗣^1 x 𝗣^1;
//! * ExtendedPoint: points in 𝗣^3; //! * `ExtendedPoint`: points in 𝗣^3;
//! * ProjectivePoint: points in 𝗣^2. //! * `ProjectivePoint`: points in 𝗣^2.
//! //!
//! Finally, to accelerate additions, we use two cached point formats, //! Finally, to accelerate additions, we use two cached point formats,
//! one for the affine model and one for the 𝗣^3 model: //! one for the affine model and one for the 𝗣^3 model:
//! //!
//! * AffineNielsPoint: `(y+x, y-x, 2dxy)` //! * `AffineNielsPoint`: `(y+x, y-x, 2dxy)`
//! * ProjectiveNielsPoint: `(Y+X, Y-X, Z, 2dXY)` //! * `ProjectiveNielsPoint`: `(Y+X, Y-X, Z, 2dXY)`
//! //!
//! [1]: https://moderncrypto.org/mail-archive/curves/2016/000807.html //! [1]: https://moderncrypto.org/mail-archive/curves/2016/000807.html
@ -80,8 +80,12 @@
use core::fmt::Debug; use core::fmt::Debug;
use core::iter::Iterator; use core::iter::Iterator;
use core::ops::{Add, Sub, Neg}; use core::ops::{Add, Sub, Neg};
use core::ops::{Mul, MulAssign};
use core::ops::Index;
use constants; use constants;
#[cfg(feature = "yolocrypto")]
use decaf::DecafPoint;
use field::FieldElement; use field::FieldElement;
use scalar::Scalar; use scalar::Scalar;
use subtle::arrays_equal_ct; use subtle::arrays_equal_ct;
@ -90,11 +94,6 @@ use subtle::CTAssignable;
use subtle::CTEq; use subtle::CTEq;
use subtle::CTNegatable; use subtle::CTNegatable;
#[cfg(all(not(feature = "std"), feature = "basepoint_table_creation"))]
use collections::boxed::Box;
#[cfg(all(feature = "std", feature = "basepoint_table_creation"))]
use std::boxed::Box;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Compressed points // Compressed points
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -103,7 +102,7 @@ use std::boxed::Box;
/// determined by the `y`-coordinate and the sign of `x`, marshalled /// determined by the `y`-coordinate and the sign of `x`, marshalled
/// into a 32-byte array. /// into a 32-byte array.
/// ///
/// The first 255 bits of a CompressedEdwardsY represent the /// The first 255 bits of a `CompressedEdwardsY` represent the
/// y-coordinate. The high bit of the 32nd byte gives the sign of `x`. /// y-coordinate. The high bit of the 32nd byte gives the sign of `x`.
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq)]
pub struct CompressedEdwardsY(pub [u8; 32]); pub struct CompressedEdwardsY(pub [u8; 32]);
@ -116,7 +115,7 @@ impl Debug for CompressedEdwardsY {
impl CompressedEdwardsY { impl CompressedEdwardsY {
/// View this `CompressedEdwardsY` as an array of bytes. /// View this `CompressedEdwardsY` as an array of bytes.
pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { pub fn as_bytes(&self) -> &[u8; 32] {
&self.0 &self.0
} }
@ -232,7 +231,7 @@ impl CompressedMontgomeryU {
/// Montgomery `v` corresponding to this `u`. /// Montgomery `v` corresponding to this `u`.
pub fn to_montgomery_v(u: &FieldElement) -> (u8, FieldElement) { pub fn to_montgomery_v(u: &FieldElement) -> (u8, FieldElement) {
let one: FieldElement = FieldElement::one(); let one: FieldElement = FieldElement::one();
let v_squared: FieldElement = u * &(&(&u.square() + &(&(&constants::A * u) + &one))); let v_squared: FieldElement = u * &(&u.square() + &(&(&constants::A * u) + &one));
let (okay, v_inv) = v_squared.invsqrt(); let (okay, v_inv) = v_squared.invsqrt();
let v = &v_inv * &v_squared; let v = &v_inv * &v_squared;
@ -303,7 +302,7 @@ pub struct ProjectivePoint {
Z: FieldElement, Z: FieldElement,
} }
/// A CompletedPoint is a point ((X:Z), (Y:T)) in 𝗣¹(𝔽ₚ)×𝗣¹(𝔽ₚ). /// A `CompletedPoint` is a point ((X:Z), (Y:T)) in 𝗣¹(𝔽ₚ)×𝗣¹(𝔽ₚ).
/// A point (x,y) in the affine model corresponds to ((x:1),(y:1)). /// A point (x,y) in the affine model corresponds to ((x:1),(y:1)).
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct CompletedPoint { pub struct CompletedPoint {
@ -448,6 +447,15 @@ impl CTAssignable for AffineNielsPoint {
} }
} }
impl CTAssignable for ExtendedPoint {
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: u8) {
self.X.conditional_assign(&other.X, choice);
self.Y.conditional_assign(&other.Y, choice);
self.Z.conditional_assign(&other.Z, choice);
self.T.conditional_assign(&other.T, choice);
}
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Constant-time Equality // Constant-time Equality
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -470,13 +478,7 @@ pub trait IsIdentity {
/// constructor. /// constructor.
impl<T> IsIdentity for T where T: CTEq + Identity { impl<T> IsIdentity for T where T: CTEq + Identity {
fn is_identity(&self) -> bool { fn is_identity(&self) -> bool {
let identity: T = T::identity(); self.ct_eq(&T::identity()) == 1u8
if self.ct_eq(&identity) == 1u8 {
return true;
} else {
return false;
}
} }
} }
@ -795,18 +797,20 @@ impl<'a> Neg for &'a AffineNielsPoint {
// Scalar multiplication // Scalar multiplication
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// Trait for scalar multiplication of an arbitrary point. impl<'b> MulAssign<&'b Scalar> for ExtendedPoint {
pub trait ScalarMult<S> { fn mul_assign(&mut self, scalar: &'b Scalar) {
/// Compute `scalar * self`. let result = (self as &ExtendedPoint) * scalar;
fn scalar_mult(&self, scalar: &S) -> Self; *self = result;
}
} }
impl ScalarMult<Scalar> for ExtendedPoint { impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
type Output = ExtendedPoint;
/// Scalar multiplication: compute `scalar * self`. /// Scalar multiplication: compute `scalar * self`.
/// ///
/// Uses a window of size 4. Note: for scalar multiplication of /// Uses a window of size 4. Note: for scalar multiplication of
/// the basepoint, `basepoint_mult` is approximately 4x faster. /// the basepoint, `basepoint_mult` is approximately 4x faster.
fn scalar_mult(&self, scalar: &Scalar) -> ExtendedPoint { fn mul(self, scalar: &'b Scalar) -> ExtendedPoint {
let A = self.to_projective_niels(); let A = self.to_projective_niels();
let mut As: [ProjectiveNielsPoint; 8] = [A; 8]; let mut As: [ProjectiveNielsPoint; 8] = [A; 8];
for i in 0..7 { for i in 0..7 {
@ -824,31 +828,35 @@ impl ScalarMult<Scalar> for ExtendedPoint {
} }
} }
impl<'a, 'b> Mul<&'b ExtendedPoint> for &'a Scalar {
type Output = ExtendedPoint;
/// Scalar multiplication: compute `self * point`.
///
/// Uses a window of size 4. Note: for scalar multiplication of
/// the basepoint, `basepoint_mult` is approximately 4x faster.
fn mul(self, point: &'b ExtendedPoint) -> ExtendedPoint {
point * &self
}
}
#[cfg(feature = "yolocrypto")]
impl<'a, 'b> Mul<&'b DecafPoint> for &'a Scalar {
type Output = DecafPoint;
/// Scalar multiplication: compute `self * scalar`.
fn mul(self, point: &'b DecafPoint) -> DecafPoint {
DecafPoint(self * &point.0)
}
}
/// Precomputation /// Precomputation
#[derive(Clone)] #[derive(Clone)]
pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]); pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]);
impl EdwardsBasepointTable { impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable {
/// Create a table of precomputed multiples of `basepoint`. type Output = ExtendedPoint;
#[cfg(feature="basepoint_table_creation")]
pub fn create(basepoint: &ExtendedPoint) -> Box<EdwardsBasepointTable> {
// Create the table storage
// XXX can we be assured that this is not allocated on the stack?
// XXX can we skip the initialization without too much unsafety?
let mut table = box EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]);
let mut P = basepoint.clone();
for i in 0..32 {
// P = (16^2)^i * B
let mut jP = P.to_affine_niels();
for j in 1..9 {
// table[i][j-1] is supposed to be j*(16^2)^i*B
table.0[i][j-1] = jP;
jP = (&P + &jP).to_extended().to_affine_niels();
}
P = P.mult_by_pow_2(8);
}
return table
}
/// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by /// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by
/// computing the multiple `aB` of the basepoint `B`. /// computing the multiple `aB` of the basepoint `B`.
@ -875,7 +883,7 @@ impl EdwardsBasepointTable {
/// We then use the `select_precomputed_point` function, which /// We then use the `select_precomputed_point` function, which
/// takes `-8 ≤ x < 8` and `[16^2i * B, ..., 8 * 16^2i * B]`, /// takes `-8 ≤ x < 8` and `[16^2i * B, ..., 8 * 16^2i * B]`,
/// and returns `x * 16^2i * B` in constant time. /// and returns `x * 16^2i * B` in constant time.
pub fn basepoint_mult(&self, scalar: &Scalar) -> ExtendedPoint { fn mul(self, scalar: &'b Scalar) -> ExtendedPoint {
let e = scalar.to_radix_16(); let e = scalar.to_radix_16();
let mut h = ExtendedPoint::identity(); let mut h = ExtendedPoint::identity();
let mut t: CompletedPoint; let mut t: CompletedPoint;
@ -896,21 +904,65 @@ impl EdwardsBasepointTable {
} }
} }
/// Trait for scalar multiplication of a distinguished basepoint. impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
pub trait BasepointMult<S> { type Output = ExtendedPoint;
/// Return the basepoint `B`.
fn basepoint() -> Self; /// Construct an `ExtendedPoint` by via this `Scalar` times
/// Compute `scalar * B`. /// a the basepoint, `B` included in a precomputed `basepoint_table`.
fn basepoint_mult(scalar: &S) -> Self; ///
/// Precondition: this scalar must be reduced.
///
/// The computation proceeds as follows, as described on page 13
/// of the Ed25519 paper. Write this scalar `a` in radix 16 with
/// coefficients in [-8,8), i.e.,
///
/// a = a_0 + a_1*16^1 + ... + a_63*16^63,
///
/// with -8 ≤ a_i < 8. Then
///
/// a*B = a_0*B + a_1*16^1*B + ... + a_63*16^63*B.
///
/// Grouping even and odd coefficients gives
///
/// a*B = a_0*16^0*B + a_2*16^2*B + ... + a_62*16^62*B
/// + a_1*16^1*B + a_3*16^3*B + ... + a_63*16^63*B
/// = (a_0*16^0*B + a_2*16^2*B + ... + a_62*16^62*B)
/// + 16*(a_1*16^0*B + a_3*16^2*B + ... + a_63*16^62*B).
///
/// We then use the `select_precomputed_point` function, which
/// takes `-8 ≤ x < 8` and `[16^2i * B, ..., 8 * 16^2i * B]`,
/// and returns `x * 16^2i * B` in constant time.
fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> ExtendedPoint {
basepoint_table * &self
}
} }
impl BasepointMult<Scalar> for ExtendedPoint { impl EdwardsBasepointTable {
fn basepoint() -> ExtendedPoint { /// Create a table of precomputed multiples of `basepoint`.
constants::ED25519_BASEPOINT pub fn create(basepoint: &ExtendedPoint) -> EdwardsBasepointTable {
// Create the table storage
// 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();
for i in 0..32 {
// P = (16^2)^i * B
let mut jP = P.to_affine_niels();
for j in 1..9 {
// table[i][j-1] is supposed to be j*(16^2)^i*B
table.0[i][j-1] = jP;
jP = (&P + &jP).to_extended().to_affine_niels();
}
P = P.mult_by_pow_2(8);
}
table
} }
fn basepoint_mult(scalar: &Scalar) -> ExtendedPoint { /// Get the basepoint for this table as an `ExtendedPoint`.
constants::ED25519_BASEPOINT_TABLE.basepoint_mult(scalar) pub fn basepoint(&self) -> ExtendedPoint {
// self.0[0][0] has 1*(16^2)^0*B, but as an `AffineNielsPoint`
// Add identity to convert to extended.
(&ExtendedPoint::identity() + &self.0[0][0]).to_extended()
} }
} }
@ -933,8 +985,7 @@ impl ExtendedPoint {
r = s.double(); s = r.to_projective(); r = s.double(); s = r.to_projective();
} }
// Unroll last iteration so we can go directly to_extended() // Unroll last iteration so we can go directly to_extended()
r = s.double(); s.double().to_extended()
return r.to_extended();
} }
/// Determine if this point is of small order. /// Determine if this point is of small order.
@ -947,73 +998,10 @@ impl ExtendedPoint {
/// ///
/// True if it is of small order; false otherwise. /// True if it is of small order; false otherwise.
pub fn is_small_order(&self) -> bool { pub fn is_small_order(&self) -> bool {
let p8: ExtendedPoint = self.mult_by_pow_2(3); self.mult_by_cofactor().is_identity()
if p8.is_identity() {
return true;
} else {
return false;
}
} }
} }
/// Given a point `A` and scalars `a` and `b`, compute the point
/// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)`
/// with x positive).
///
/// # Warning
///
/// This function is *not* constant time, hence its name.
// XXX should return ExtendedPoint?
pub fn double_scalar_mult_vartime(a: &Scalar, A: &ExtendedPoint, b: &Scalar) -> ProjectivePoint {
let a_naf = a.non_adjacent_form();
let b_naf = b.non_adjacent_form();
// Build a lookup table of odd multiples of A
let mut Ai = [ProjectiveNielsPoint::identity(); 8];
let A2 = A.double();
Ai[0] = A.to_projective_niels();
for i in 0..7 {
Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
}
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
// Find starting index
let mut i: usize = 255;
for j in (0..255).rev() {
i = j;
if a_naf[i] != 0 || b_naf[i] != 0 {
break;
}
}
let mut r = ProjectivePoint::identity();
loop {
let mut t = r.double();
if a_naf[i] > 0 {
t = &t.to_extended() + &Ai[( a_naf[i]/2) as usize];
} else if a_naf[i] < 0 {
t = &t.to_extended() - &Ai[(-a_naf[i]/2) as usize];
}
if b_naf[i] > 0 {
t = &t.to_extended() + &constants::bi[( b_naf[i]/2) as usize];
} else if b_naf[i] < 0 {
t = &t.to_extended() - &constants::bi[(-b_naf[i]/2) as usize];
}
r = t.to_projective();
if i == 0 {
break;
}
i -= 1;
}
r
}
/// Given precomputed points `[P, 2P, 3P, ..., 8P]`, as well as `-8 ≤ /// Given precomputed points `[P, 2P, 3P, ..., 8P]`, as well as `-8 ≤
/// x ≤ 8`, compute `x * B` in constant time, i.e., without branching /// x ≤ 8`, compute `x * B` in constant time, i.e., without branching
/// on x or using it as an array index. /// on x or using it as an array index.
@ -1053,14 +1041,14 @@ impl ExtendedPoint {
/// Returns `Some<[u8;32]>` if `self` is in the image of the /// Returns `Some<[u8;32]>` if `self` is in the image of the
/// Elligator2 map. For a random point on the curve, this happens /// Elligator2 map. For a random point on the curve, this happens
/// with probability 1/2. Otherwise, returns `None`. /// with probability 1/2. Otherwise, returns `None`.
pub fn to_uniform_representative(&self) -> Option<[u8;32]> { pub fn to_uniform_representative(&self) -> Option<[u8; 32]> {
unimplemented!(); unimplemented!();
} }
/// Use Elligator2 to convert a uniformly random string to a curve /// Use Elligator2 to convert a uniformly random string to a curve
/// point. /// point.
#[allow(unused_variables)] // REMOVE WHEN IMPLEMENTED #[allow(unused_variables)] // REMOVE WHEN IMPLEMENTED
pub fn from_uniform_representative(bytes: &[u8;32]) -> ExtendedPoint { pub fn from_uniform_representative(bytes: &[u8; 32]) -> ExtendedPoint {
unimplemented!(); unimplemented!();
} }
} }
@ -1104,12 +1092,133 @@ impl Debug for ProjectiveNielsPoint {
} }
} }
// ------------------------------------------------------------------------
// Variable-time functions
// ------------------------------------------------------------------------
pub mod vartime {
//! Variable-time operations on curve points, useful for non-secret data.
use super::*;
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
struct OddMultiples([ProjectiveNielsPoint; 8]);
impl OddMultiples {
fn create(A: &ExtendedPoint) -> OddMultiples {
let mut Ai = [ProjectiveNielsPoint::identity(); 8];
let A2 = A.double();
Ai[0] = A.to_projective_niels();
for i in 0..7 {
Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
}
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
OddMultiples(Ai)
}
}
impl Index<usize> for OddMultiples {
type Output = ProjectiveNielsPoint;
fn index<'a>(&'a self, _index: usize) -> &'a 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.
///
/// # 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.
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());
let nafs: Vec<_> = scalars.into_iter()
.map(|c| c.non_adjacent_form()).collect();
let odd_multiples: Vec<_> = points.into_iter()
.map(|P| OddMultiples::create(P)).collect();
let mut r = ProjectivePoint::identity();
for i in (0..255).rev() {
let mut t = r.double();
for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) {
if naf[i] > 0 {
t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize];
} else if naf[i] < 0 {
t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize];
}
}
r = t.to_projective();
}
r.to_extended()
}
/// Given a point `A` and scalars `a` and `b`, compute the point
/// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)`
/// with x positive).
pub fn double_scalar_mult_basepoint(a: &Scalar,
A: &ExtendedPoint,
b: &Scalar) -> ProjectivePoint {
let a_naf = a.non_adjacent_form();
let b_naf = b.non_adjacent_form();
// Find starting index
let mut i: usize = 255;
for j in (0..255).rev() {
i = j;
if a_naf[i] != 0 || b_naf[i] != 0 {
break;
}
}
let odd_multiples_of_A = OddMultiples::create(A);
let mut r = ProjectivePoint::identity();
loop {
let mut t = r.double();
if a_naf[i] > 0 {
t = &t.to_extended() + &odd_multiples_of_A[( a_naf[i]/2) as usize];
} else if a_naf[i] < 0 {
t = &t.to_extended() - &odd_multiples_of_A[(-a_naf[i]/2) as usize];
}
if b_naf[i] > 0 {
t = &t.to_extended() + &constants::bi[( b_naf[i]/2) as usize];
} else if b_naf[i] < 0 {
t = &t.to_extended() - &constants::bi[(-b_naf[i]/2) as usize];
}
r = t.to_projective();
if i == 0 {
break;
}
i -= 1;
}
r
}
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Tests // Tests
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
#[cfg(test)] #[cfg(test)]
mod test { mod test {
#[cfg(feature = "yolocrypto")]
use decaf::DecafPoint;
use field::FieldElement; use field::FieldElement;
use scalar::Scalar; use scalar::Scalar;
use subtle::CTAssignable; use subtle::CTAssignable;
@ -1236,11 +1345,18 @@ mod test {
/// Test that computing 1*basepoint gives the correct basepoint. /// Test that computing 1*basepoint gives the correct basepoint.
#[test] #[test]
fn basepoint_mult_one_vs_basepoint() { fn basepoint_mult_one_vs_basepoint() {
let bp = ExtendedPoint::basepoint_mult(&Scalar::one()); let bp = &constants::ED25519_BASEPOINT_TABLE * &Scalar::one();
let compressed = bp.compress_edwards(); let compressed = bp.compress_edwards();
assert_eq!(compressed, constants::BASE_CMPRSSD); assert_eq!(compressed, constants::BASE_CMPRSSD);
} }
/// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint.
#[test]
fn basepoint_table_basepoint_function_correct() {
let bp = constants::ED25519_BASEPOINT_TABLE.basepoint();
assert_eq!(bp.compress_edwards(), constants::BASE_CMPRSSD);
}
/// Test `impl Add<ExtendedPoint> for ExtendedPoint` /// Test `impl Add<ExtendedPoint> for ExtendedPoint`
/// using basepoint + basepoint versus the 2*basepoint constant. /// using basepoint + basepoint versus the 2*basepoint constant.
#[test] #[test]
@ -1288,7 +1404,7 @@ mod test {
#[test] #[test]
fn to_affine_niels_clears_denominators() { fn to_affine_niels_clears_denominators() {
// construct a point as aB so it has denominators (ie. Z != 1) // construct a point as aB so it has denominators (ie. Z != 1)
let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR;
let aB_affine_niels = aB.to_affine_niels(); let aB_affine_niels = aB.to_affine_niels();
let also_aB = (&ExtendedPoint::identity() + &aB_affine_niels).to_extended(); let also_aB = (&ExtendedPoint::identity() + &aB_affine_niels).to_extended();
assert_eq!( aB.compress_edwards(), assert_eq!( aB.compress_edwards(),
@ -1298,14 +1414,15 @@ mod test {
/// Test basepoint_mult versus a known scalar multiple from ed25519.py /// Test basepoint_mult versus a known scalar multiple from ed25519.py
#[test] #[test]
fn basepoint_mult_vs_ed25519py() { fn basepoint_mult_vs_ed25519py() {
let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR;
assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT);
} }
/// Test that multiplication by the basepoint order kills the basepoint /// Test that multiplication by the basepoint order kills the basepoint
#[test] #[test]
fn basepoint_mult_by_basepoint_order() { fn basepoint_mult_by_basepoint_order() {
let should_be_id = ExtendedPoint::basepoint_mult(&constants::l); let B = &constants::ED25519_BASEPOINT_TABLE;
let should_be_id = B * &constants::l;
assert!(should_be_id.is_identity()); assert!(should_be_id.is_identity());
} }
@ -1314,27 +1431,18 @@ mod test {
#[cfg(feature="basepoint_table_creation")] #[cfg(feature="basepoint_table_creation")]
fn test_precomputed_basepoint_mult() { fn test_precomputed_basepoint_mult() {
let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT); let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT);
let aB_1 = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR;
let aB_2 = table.basepoint_mult(&A_SCALAR); let aB_2 = &table * &A_SCALAR;
assert_eq!(aB_1.compress_edwards(), assert_eq!(aB_1.compress_edwards(), aB_2.compress_edwards());
aB_2.compress_edwards());
} }
/// Test scalar_mult versus a known scalar multiple from ed25519.py /// Test scalar_mult versus a known scalar multiple from ed25519.py
#[test] #[test]
fn scalar_mult_vs_ed25519py() { fn scalar_mult_vs_ed25519py() {
let aB = constants::ED25519_BASEPOINT.scalar_mult(&A_SCALAR); let aB = &constants::ED25519_BASEPOINT * &A_SCALAR;
assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT);
} }
/// Test double_scalar_mult_vartime vs ed25519.py
#[test]
fn double_scalar_mult_vartime_vs_ed25519py() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR);
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
}
/// Test basepoint.double() versus the 2*basepoint constant. /// Test basepoint.double() versus the 2*basepoint constant.
#[test] #[test]
fn basepoint_double_vs_basepoint2() { fn basepoint_double_vs_basepoint2() {
@ -1346,7 +1454,7 @@ mod test {
#[test] #[test]
fn basepoint_mult_two_vs_basepoint2() { fn basepoint_mult_two_vs_basepoint2() {
let mut two_bytes = [0u8; 32]; two_bytes[0] = 2; let mut two_bytes = [0u8; 32]; two_bytes[0] = 2;
let bp2 = ExtendedPoint::basepoint_mult(&Scalar(two_bytes)); let bp2 = &constants::ED25519_BASEPOINT_TABLE * &Scalar(two_bytes);
assert_eq!(bp2.compress_edwards(), BASE2_CMPRSSD); assert_eq!(bp2.compress_edwards(), BASE2_CMPRSSD);
} }
@ -1412,11 +1520,57 @@ mod test {
/// the type system and prove correctness). /// the type system and prove correctness).
#[test] #[test]
fn monte_carlo_overflow_underflow_debug_assert_test() { fn monte_carlo_overflow_underflow_debug_assert_test() {
let mut P = ExtendedPoint::basepoint(); let mut P = constants::ED25519_BASEPOINT;
// N.B. each scalar_mult does 1407 field mults, 1024 field squarings, // N.B. each scalar_mult does 1407 field mults, 1024 field squarings,
// so this does ~ 1M of each operation. // so this does ~ 1M of each operation.
for _ in 0..1_000 { for _ in 0..1_000 {
P = P.scalar_mult(&A_SCALAR); P *= &A_SCALAR;
}
}
#[test]
fn scalarmult_extended_point_works_both_ways() {
let G: ExtendedPoint = constants::ED25519_BASEPOINT;
let s: Scalar = A_SCALAR;
let P1 = &G * &s;
let P2 = &s * &G;
assert!(P1.compress_edwards().to_bytes() == P2.compress_edwards().to_bytes());
}
#[test]
#[cfg(feature = "yolocrypto")]
fn scalarmult_decafpoint_works_both_ways() {
let P: DecafPoint = DecafPoint(constants::ED25519_BASEPOINT);
let s: Scalar = A_SCALAR;
let P1 = &P * &s;
let P2 = &s * &P;
assert!(P1.compress().as_bytes() == P2.compress().as_bytes());
}
mod vartime {
use super::super::*;
use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT};
/// Test double_scalar_mult_vartime vs ed25519.py
#[test]
fn double_scalar_mult_basepoint_vs_ed25519py() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR);
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
}
#[test]
fn k_fold_scalar_mult_vs_ed25519py() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = vartime::k_fold_scalar_mult(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT]
);
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
} }
} }
} }
@ -1427,6 +1581,7 @@ mod test {
#[cfg(all(test, feature = "bench"))] #[cfg(all(test, feature = "bench"))]
mod bench { mod bench {
use rand::OsRng;
use test::Bencher; use test::Bencher;
use constants; use constants;
use super::*; use super::*;
@ -1434,13 +1589,14 @@ mod bench {
#[bench] #[bench]
fn basepoint_mult(b: &mut Bencher) { fn basepoint_mult(b: &mut Bencher) {
b.iter(|| ExtendedPoint::basepoint_mult(&A_SCALAR)); let B = &constants::ED25519_BASEPOINT_TABLE;
b.iter(|| B * &A_SCALAR);
} }
#[bench] #[bench]
fn scalar_mult(b: &mut Bencher) { fn scalar_mult(b: &mut Bencher) {
let bp = constants::ED25519_BASEPOINT; let B = &constants::ED25519_BASEPOINT;
b.iter(|| bp.scalar_mult(&A_SCALAR)); b.iter(|| B * &A_SCALAR);
} }
#[bench] #[bench]
@ -1448,12 +1604,6 @@ mod bench {
b.iter(|| select_precomputed_point(0, &constants::ED25519_BASEPOINT_TABLE.0[0])); b.iter(|| select_precomputed_point(0, &constants::ED25519_BASEPOINT_TABLE.0[0]));
} }
#[bench]
fn bench_double_scalar_mult_vartime(b: &mut Bencher) {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
b.iter(|| double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR));
}
#[bench] #[bench]
fn add_extended_and_projective_niels_output_completed(b: &mut Bencher) { fn add_extended_and_projective_niels_output_completed(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT; let p1 = constants::ED25519_BASEPOINT;
@ -1510,7 +1660,37 @@ mod bench {
#[cfg(feature="basepoint_table_creation")] #[cfg(feature="basepoint_table_creation")]
#[bench] #[bench]
fn create_basepoint_table(b: &mut Bencher) { fn create_basepoint_table(b: &mut Bencher) {
let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR;
b.iter(|| EdwardsBasepointTable::create(&aB)); b.iter(|| EdwardsBasepointTable::create(&aB));
} }
mod vartime {
use super::super::*;
use super::super::test::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT};
use super::{Bencher, OsRng};
#[bench]
fn bench_double_scalar_mult_basepoint(b: &mut Bencher) {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
b.iter(|| vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR));
}
#[bench]
fn ten_fold_scalar_mult(b: &mut Bencher) {
let mut csprng: OsRng = OsRng::new().unwrap();
// Create 10 random scalars
let scalars: Vec<_> = (0..10).map(|_| Scalar::random(&mut csprng)).collect();
// Create 10 points (by doing scalar mults)
let B = &constants::ED25519_BASEPOINT_TABLE;
let points: Vec<_> = scalars.iter().map(|s| B * &s).collect();
// XXX Currently Rust's benchmarking implementation doesn't
// allow you to specify a sequence of random inputs, but only
// many trials of the same input.
//
// Since this is a variable-time function, this means the
// benchmark is only useful as a ballpark measurement.
b.iter(|| vartime::k_fold_scalar_mult(&scalars, &points));
}
}
} }

View file

@ -30,16 +30,11 @@ use subtle::CTAssignable;
use subtle::CTNegatable; use subtle::CTNegatable;
use core::ops::{Add, Sub, Neg}; use core::ops::{Add, Sub, Neg};
use core::ops::{Mul, MulAssign};
#[cfg(all(not(feature = "std"), feature = "basepoint_table_creation"))] use curve;
use collections::boxed::Box;
#[cfg(all(feature = "std", feature = "basepoint_table_creation"))]
use std::boxed::Box;
use curve::ExtendedPoint; use curve::ExtendedPoint;
use curve::EdwardsBasepointTable; use curve::EdwardsBasepointTable;
use curve::BasepointMult;
use curve::ScalarMult;
use curve::Identity; use curve::Identity;
use scalar::Scalar; use scalar::Scalar;
@ -249,40 +244,82 @@ impl<'a> Neg for &'a DecafPoint {
} }
} }
impl ScalarMult<Scalar> for DecafPoint { impl<'b> MulAssign<&'b Scalar> for DecafPoint {
fn scalar_mult(&self, scalar: &Scalar) -> DecafPoint { fn mul_assign(&mut self, scalar: &'b Scalar) {
DecafPoint(self.0.scalar_mult(scalar)) let result = (self as &DecafPoint) * scalar;
*self = result;
} }
} }
impl BasepointMult<Scalar> for DecafPoint { impl<'a, 'b> Mul<&'b Scalar> for &'a DecafPoint {
// XXX is this actually in the image of the isogeny, type Output = DecafPoint;
// or do we need a different basepoint? /// Scalar multiplication: compute `scalar * self`.
fn basepoint() -> DecafPoint { fn mul(self, scalar: &'b Scalar) -> DecafPoint {
DecafPoint(ExtendedPoint::basepoint()) DecafPoint(&self.0 * scalar)
}
fn basepoint_mult(scalar: &Scalar) -> DecafPoint {
DecafPoint(ExtendedPoint::basepoint_mult(scalar))
} }
} }
/// Precomputation /// Precomputation
#[derive(Clone)] #[derive(Clone)]
pub struct DecafBasepointTable(EdwardsBasepointTable); pub struct DecafBasepointTable(pub EdwardsBasepointTable);
impl<'a, 'b> Mul<&'b Scalar> for &'a DecafBasepointTable {
type Output = DecafPoint;
fn mul(self, scalar: &'b Scalar) -> DecafPoint {
DecafPoint(&self.0 * scalar)
}
}
impl<'a, 'b> Mul<&'a DecafBasepointTable> for &'b Scalar {
type Output = DecafPoint;
fn mul(self, basepoint_table: &'a DecafBasepointTable) -> DecafPoint {
DecafPoint(self * &basepoint_table.0)
}
}
impl DecafBasepointTable { impl DecafBasepointTable {
/// Create a precomputed table of multiples of the given `basepoint`. /// Create a precomputed table of multiples of the given `basepoint`.
#[cfg(feature = "basepoint_table_creation")] pub fn create(basepoint: &DecafPoint) -> DecafBasepointTable {
pub fn create(basepoint: &DecafPoint) -> Box<DecafBasepointTable> { DecafBasepointTable(EdwardsBasepointTable::create(&basepoint.0))
let edwards_table = EdwardsBasepointTable::create(&basepoint.0);
box DecafBasepointTable(*edwards_table)
} }
/// Use the precomputed table to quickly compute `scalar * basepoint` /// Get the basepoint for this table as a `DecafPoint`.
pub fn basepoint_mult(&self, scalar: &Scalar) -> DecafPoint { pub fn basepoint(&self) -> DecafPoint {
DecafPoint(self.0.basepoint_mult(scalar)) DecafPoint(self.0.basepoint())
}
}
// ------------------------------------------------------------------------
// Constant-time conditional assignment
// ------------------------------------------------------------------------
impl CTAssignable for DecafPoint {
/// Conditionally assign `other` to `self`, if `choice == 1u8`.
///
/// # Example
///
/// ```
/// # use curve25519_dalek::curve::Identity;
/// # use curve25519_dalek::decaf::DecafPoint;
/// # use curve25519_dalek::subtle::CTAssignable;
/// # use curve25519_dalek::constants;
/// let A = DecafPoint::identity();
/// let B = constants::DECAF_ED25519_BASEPOINT;
///
/// let mut P = A;
///
/// P.conditional_assign(&B, 0u8);
/// 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);
self.0.Y.conditional_assign(&other.0.Y, choice);
self.0.Z.conditional_assign(&other.0.Z, choice);
self.0.T.conditional_assign(&other.0.T, choice);
} }
} }
@ -304,6 +341,31 @@ impl Debug for DecafPoint {
} }
} }
// ------------------------------------------------------------------------
// Variable-time functions
// ------------------------------------------------------------------------
pub mod vartime {
//! Variable-time operations on decaf points, useful for non-secret data.
use super::*;
/// Given a vector of public scalars and a vector of (possibly secret)
/// 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.
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>
{
let extended_points = points.into_iter().map(|P| &P.0);
DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, extended_points))
}
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Tests // Tests
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -316,7 +378,6 @@ mod test {
use constants; use constants;
use curve::CompressedEdwardsY; use curve::CompressedEdwardsY;
use curve::ExtendedPoint; use curve::ExtendedPoint;
use curve::BasepointMult;
use curve::Identity; use curve::Identity;
use super::*; use super::*;
@ -342,17 +403,17 @@ mod test {
#[test] #[test]
fn decaf_basepoint_roundtrip() { fn decaf_basepoint_roundtrip() {
let bp_compressed_decaf = DecafPoint::basepoint().compress(); let bp_compressed_decaf = constants::DECAF_ED25519_BASEPOINT.compress();
let bp_recaf = bp_compressed_decaf.decompress().unwrap().0; let bp_recaf = bp_compressed_decaf.decompress().unwrap().0;
// Check that bp_recaf differs from bp by a point of order 4 // Check that bp_recaf differs from bp by a point of order 4
let diff = &ExtendedPoint::basepoint() - &bp_recaf; let diff = &constants::ED25519_BASEPOINT - &bp_recaf;
let diff4 = diff.mult_by_pow_2(4); let diff4 = diff.mult_by_pow_2(4); // XXX this is wrong
assert_eq!(diff4.compress_edwards(), CompressedEdwardsY::identity()); assert_eq!(diff4.compress_edwards(), CompressedEdwardsY::identity());
} }
#[test] #[test]
fn decaf_four_torsion_basepoint() { fn decaf_four_torsion_basepoint() {
let bp = DecafPoint::basepoint(); let bp = constants::DECAF_ED25519_BASEPOINT;
let bp_coset = bp.coset4(); let bp_coset = bp.coset4();
for i in 0..4 { for i in 0..4 {
assert_eq!(bp, DecafPoint(bp_coset[i])); assert_eq!(bp, DecafPoint(bp_coset[i]));
@ -362,8 +423,8 @@ mod test {
#[test] #[test]
fn decaf_four_torsion_random() { fn decaf_four_torsion_random() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let s = Scalar::random(&mut rng); let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
let P = DecafPoint::basepoint_mult(&s); let P = B * &Scalar::random(&mut rng);
let P_coset = P.coset4(); let P_coset = P.coset4();
for i in 0..4 { for i in 0..4 {
assert_eq!(P, DecafPoint(P_coset[i])); assert_eq!(P, DecafPoint(P_coset[i]));
@ -373,27 +434,14 @@ mod test {
#[test] #[test]
fn decaf_random_roundtrip() { fn decaf_random_roundtrip() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
for _ in 0..100 { for _ in 0..100 {
let s = Scalar::random(&mut rng); let P = B * &Scalar::random(&mut rng);
let P = DecafPoint::basepoint_mult(&s);
let compressed_P = P.compress(); let compressed_P = P.compress();
let Q = compressed_P.decompress().unwrap(); let Q = compressed_P.decompress().unwrap();
assert_eq!(P, Q); assert_eq!(P, Q);
} }
} }
/// Test basepoint_mult versus a newly-generated DecafBasepointTable
#[test]
#[cfg(feature = "basepoint_table_creation")]
fn basepoint_mult_vs_decafbasepointtable() {
let table = DecafBasepointTable::create(&DecafPoint::basepoint());
let mut rng = OsRng::new().unwrap();
let s = Scalar::random(&mut rng);
let basepoint_mult_s = DecafPoint::basepoint_mult(&s);
let table_basepoint_mult_s = table.basepoint_mult(&s);
assert_eq!(basepoint_mult_s, table_basepoint_mult_s);
}
} }
#[cfg(all(test, feature = "bench"))] #[cfg(all(test, feature = "bench"))]
@ -406,8 +454,8 @@ mod bench {
#[bench] #[bench]
fn decompression(b: &mut Bencher) { fn decompression(b: &mut Bencher) {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let s = Scalar::random(&mut rng); let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
let P = DecafPoint::basepoint_mult(&s); let P = B * &Scalar::random(&mut rng);
let P_compressed = P.compress(); let P_compressed = P.compress();
b.iter(|| P_compressed.decompress().unwrap()); b.iter(|| P_compressed.decompress().unwrap());
} }
@ -415,8 +463,8 @@ mod bench {
#[bench] #[bench]
fn compression(b: &mut Bencher) { fn compression(b: &mut Bencher) {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let s = Scalar::random(&mut rng); let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
let P = DecafPoint::basepoint_mult(&s); let P = B * &Scalar::random(&mut rng);
b.iter(|| P.compress()); b.iter(|| P.compress());
} }
} }

View file

@ -15,7 +15,6 @@
//! Based on Adam Langley's curve25519-donna and (Golang) ed25519 //! Based on Adam Langley's curve25519-donna and (Golang) ed25519
//! implementations. //! implementations.
use core::clone::Clone;
use core::fmt::Debug; use core::fmt::Debug;
use core::ops::{Add, AddAssign}; use core::ops::{Add, AddAssign};
use core::ops::{Sub, SubAssign}; use core::ops::{Sub, SubAssign};
@ -41,25 +40,27 @@ use constants;
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub type Limb = u64; pub type Limb = u64;
/// FieldElement represents an element of the field GF(2^255 - 19). An element /// A `FieldElement` represents an element of the field GF(2^255 - 19).
/// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 ///
/// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on /// With the `radix_51` feature, a `FieldElement` is represented in
/// context. /// radix 2^51 as five `u64`s; the coefficients are allowed to grow up
/// to 2^54 between reductions mod `p`.
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct FieldElement(pub [u64; 5]); pub struct FieldElement(pub [u64; 5]);
/// FieldElements are represented as an array of ten "Limbs", which are radix /// Without the `radix51` feature enabled, `FieldElements` are represented
/// 25.5, that is, each Limb of a FieldElement alternates between being /// in radix 2^25.5 as ten `i32`s.
/// represented as a factor of 2^25 or 2^26 more than the last corresponding
/// integer.
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
pub type Limb = i32; pub type Limb = i32;
/// FieldElement represents an element of the field GF(2^255 - 19). An element /// A `FieldElement` represents an element of the field GF(2^255 - 19).
/// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 ///
/// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on /// With the `radix_51` feature, a `FieldElement` is represented in
/// context. /// radix 2^25.5 as ten `i32`s, so that an element t, entries
/// t[0],...,t[9], represents the integer t[0]+2^26 t[1]+2^51
/// t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i]
/// vary depending on context.
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct FieldElement(pub [i32; 10]); pub struct FieldElement(pub [i32; 10]);
@ -84,7 +85,7 @@ impl PartialEq for FieldElement {
for i in 0..32 { for i in 0..32 {
are_equal &= self_bytes[i] == other_bytes[i]; are_equal &= self_bytes[i] == other_bytes[i];
} }
return are_equal; are_equal
} }
} }
@ -108,16 +109,14 @@ impl Debug for FieldElement {
impl Index<usize> for FieldElement { impl Index<usize> for FieldElement {
type Output = Limb; type Output = Limb;
fn index<'a>(&'a self, _index: usize) -> &'a Limb { fn index(&self, _index: usize) -> &Limb {
let ret: &'a Limb = &(self.0[_index]); &(self.0[_index])
ret
} }
} }
impl IndexMut<usize> for FieldElement { impl IndexMut<usize> for FieldElement {
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Limb { fn index_mut(&mut self, _index: usize) -> &mut Limb {
let ret: &'a mut Limb = &mut(self.0[_index]); &mut(self.0[_index])
ret
} }
} }
@ -132,7 +131,7 @@ impl<'b> AddAssign<&'b FieldElement> for FieldElement {
impl<'a, 'b> Add<&'b FieldElement> for &'a FieldElement { impl<'a, 'b> Add<&'b FieldElement> for &'a FieldElement {
type Output = FieldElement; type Output = FieldElement;
fn add(self, _rhs: &'b FieldElement) -> FieldElement { fn add(self, _rhs: &'b FieldElement) -> FieldElement {
let mut output = self.clone(); let mut output = *self;
output += _rhs; output += _rhs;
output output
} }
@ -158,7 +157,7 @@ impl<'a, 'b> Sub<&'b FieldElement> for &'a FieldElement {
type Output = FieldElement; type Output = FieldElement;
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
fn sub(self, _rhs: &'b FieldElement) -> FieldElement { fn sub(self, _rhs: &'b FieldElement) -> FieldElement {
let mut output = self.clone(); let mut output = *self;
output -= _rhs; output -= _rhs;
output output
} }
@ -319,14 +318,14 @@ impl<'a, 'b> Mul<&'b FieldElement> for &'a FieldElement {
let h8 = f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19; let h8 = f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19;
let h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0; let h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0;
FieldElement::reduce(&[h0, h1, h2, h3, h4, h5, h6, h7, h8, h9]) FieldElement::reduce([h0, h1, h2, h3, h4, h5, h6, h7, h8, h9])
} }
} }
impl<'a> Neg for &'a FieldElement { impl<'a> Neg for &'a FieldElement {
type Output = FieldElement; type Output = FieldElement;
fn neg(self) -> FieldElement { fn neg(self) -> FieldElement {
let mut output = self.clone(); let mut output = *self;
output.negate(); output.negate();
output output
} }
@ -454,10 +453,10 @@ impl FieldElement {
FieldElement(limbs) FieldElement(limbs)
} }
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
fn reduce(input: &[i64;10]) -> FieldElement { //FeCombine fn reduce(mut h: [i64; 10]) -> FieldElement { //FeCombine
let mut c = [0i64;10]; let mut c = [0i64;10];
let mut h = input.clone();
/* /*
|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))
@ -533,7 +532,7 @@ impl FieldElement {
/* |h[0]| <= 2^25; from now on fits into int32 unchanged */ /* |h[0]| <= 2^25; from now on fits into int32 unchanged */
/* |h[1]| <= 1.01*2^24 */ /* |h[1]| <= 1.01*2^24 */
let mut output = FieldElement([0i32;10]); let mut output = FieldElement([0i32; 10]);
output[0] = h[0] as i32; output[0] = h[0] as i32;
output[1] = h[1] as i32; output[1] = h[1] as i32;
output[2] = h[2] as i32; output[2] = h[2] as i32;
@ -581,11 +580,11 @@ impl FieldElement {
h[8] = load3(&data[26..]) << 4; h[8] = load3(&data[26..]) << 4;
h[9] = (load3(&data[29..]) & 8388607) << 2; h[9] = (load3(&data[29..]) & 8388607) << 2;
FieldElement::reduce(&h) FieldElement::reduce(h)
} }
/// Parse a `FieldElement` from 32 bytes. /// Parse a `FieldElement` from 32 bytes.
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub fn from_bytes(bytes: &[u8;32]) -> FieldElement { pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement {
let low_51_bit_mask = (1u64 << 51) - 1; let low_51_bit_mask = (1u64 << 51) - 1;
FieldElement( FieldElement(
// load bits [ 0, 64), no shift // load bits [ 0, 64), no shift
@ -621,7 +620,7 @@ impl FieldElement {
/// assert!(data == bytes); /// assert!(data == bytes);
/// ``` /// ```
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
pub fn to_bytes(&self) -> [u8;32] { //FeToBytes pub fn to_bytes(&self) -> [u8; 32] { //FeToBytes
// Comment preserved from ed25519.go (presumably originally from ref10): // Comment preserved from ed25519.go (presumably originally from ref10):
// //
// # Preconditions // # Preconditions
@ -656,7 +655,7 @@ impl FieldElement {
// so floor(2^-255 * (h + 19 * 2^-25 * h9 + 2^-1)) = q. // so floor(2^-255 * (h + 19 * 2^-25 * h9 + 2^-1)) = q.
// //
let mut carry = [0i32; 10]; let mut carry = [0i32; 10];
let mut h = self.clone(); let mut h: [i32; 10] = self.0;
let mut q:i32 = (19*h[9] + (1 << 24)) >> 25; let mut q:i32 = (19*h[9] + (1 << 24)) >> 25;
q = (h[0] + q) >> 26; q = (h[0] + q) >> 26;
@ -752,7 +751,7 @@ impl FieldElement {
} }
/// Serialize this `FieldElement` to bytes. /// Serialize this `FieldElement` to bytes.
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub fn to_bytes(&self) -> [u8;32] { pub fn to_bytes(&self) -> [u8; 32] {
// This reduces to the range [0,2^255), but we need [0,2^255-19) // This reduces to the range [0,2^255), but we need [0,2^255-19)
let mut limbs = FieldElement::reduce(self.0).0; let mut limbs = FieldElement::reduce(self.0).0;
// Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204. // Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204.
@ -830,32 +829,6 @@ impl FieldElement {
return s return s
} }
/// XXX clarify documentation
/// Determine if this field element, represented as a byte array,
/// is less than or equal to another field element represented as
/// a byte array.
///
/// # Returns
///
/// Returns `1u8` if `self.to_bytes() <= other.to_bytes()`, and `0u8` otherwise.
pub fn bytes_equal_less_than(&self, other: &[u8; 32]) -> u8 { // feBytesLess
// XXX cleanup
let mut equal_so_far: i32 = -1i32;
let mut greater: i32 = 0i32;
let this: [u8; 32] = self.to_bytes();
for i in 32 .. 0 {
let x: i32 = this[i-1] as i32;
let y: i32 = other[i-1] as i32;
greater = (!equal_so_far & greater) | (equal_so_far & ((x - y) >> 31));
equal_so_far = equal_so_far & (((x ^ y) - 1) >> 31);
}
(!equal_so_far & 1 & greater) as u8
}
/// Determine if this `FieldElement` is negative, in the sense /// Determine if this `FieldElement` is negative, in the sense
/// used in the ed25519 paper: `x` is negative if the low bit is /// used in the ed25519 paper: `x` is negative if the low bit is
/// set. /// set.
@ -907,7 +880,7 @@ impl FieldElement {
/// ///
/// If zero, return `1u8`. Otherwise, return `0u8`. /// If zero, return `1u8`. Otherwise, return `0u8`.
pub fn is_zero(&self) -> u8 { pub fn is_zero(&self) -> u8 {
return 1u8 & (!self.is_nonzero()); 1u8 & (!self.is_nonzero())
} }
/// Determine if this `FieldElement` is non-zero. /// Determine if this `FieldElement` is non-zero.
@ -921,11 +894,11 @@ impl FieldElement {
for b in &bytes { for b in &bytes {
x |= *b; x |= *b;
} }
return byte_is_nonzero(x); byte_is_nonzero(x)
} }
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
fn square_inner(&self) -> [i64;10] { fn square_inner(&self) -> [i64; 10] {
let f0 = self[0] as i64; let f0 = self[0] as i64;
let f1 = self[1] as i64; let f1 = self[1] as i64;
let f2 = self[2] as i64; let f2 = self[2] as i64;
@ -964,6 +937,7 @@ impl FieldElement {
h h
} }
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
#[inline(always)] #[inline(always)]
fn square_inner(&self) -> [u64; 5] { fn square_inner(&self) -> [u64; 5] {
@ -1028,12 +1002,12 @@ impl FieldElement {
/// * |h[i]| bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc. /// * |h[i]| bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc.
#[cfg(not(feature="radix_51"))] #[cfg(not(feature="radix_51"))]
pub fn square(&self) -> FieldElement { pub fn square(&self) -> FieldElement {
FieldElement::reduce(&self.square_inner()) FieldElement::reduce(self.square_inner())
} }
/// Compute `self^2`. /// Compute `self^2`.
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
pub fn square(&self) -> FieldElement { pub fn square(&self) -> FieldElement {
FieldElement::reduce( self.square_inner()) FieldElement::reduce(self.square_inner())
} }
/// Square this field element and multiply the result by 2. /// Square this field element and multiply the result by 2.
@ -1058,7 +1032,7 @@ impl FieldElement {
for i in 0..self.0.len() { for i in 0..self.0.len() {
coeffs[i] += coeffs[i]; coeffs[i] += coeffs[i];
} }
FieldElement::reduce(&coeffs) FieldElement::reduce(coeffs)
} }
/// Compute `2 * self^2`. /// Compute `2 * self^2`.
#[cfg(feature="radix_51")] #[cfg(feature="radix_51")]
@ -1170,8 +1144,7 @@ impl FieldElement {
/// - `(0u8, zero)` if `v` is zero; /// - `(0u8, zero)` if `v` is zero;
/// - `(0u8, garbage)` if `u/v` is nonsquare. /// - `(0u8, garbage)` if `u/v` is nonsquare.
/// ///
pub fn sqrt_ratio(u: &FieldElement, v: &FieldElement) pub fn sqrt_ratio(u: &FieldElement, v: &FieldElement) -> (u8, FieldElement) {
-> (u8, FieldElement) {
// Using the same trick as in ed25519 decoding, we merge the // Using the same trick as in ed25519 decoding, we merge the
// inversion, the square root, and the square test as follows. // inversion, the square root, and the square test as follows.
// //
@ -1259,28 +1232,28 @@ mod test {
/// Random element a of GF(2^255-19), from Sage /// Random element a of GF(2^255-19), from Sage
/// a = 1070314506888354081329385823235218444233221\ /// a = 1070314506888354081329385823235218444233221\
/// 2228051251926706380353716438957572 /// 2228051251926706380353716438957572
pub static A_BYTES: [u8;32] = pub static A_BYTES: [u8; 32] =
[ 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68, [ 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68,
0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, 0x03, 0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, 0x03,
0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4, 0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4,
0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, 0xa9, 0x17]; 0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, 0xa9, 0x17];
/// Byte representation of a**2 /// Byte representation of a**2
static ASQ_BYTES: [u8;32] = static ASQ_BYTES: [u8; 32] =
[ 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab, [ 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab,
0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, 0x5d, 0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, 0x5d,
0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2, 0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2,
0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, 0xe3, 0x62]; 0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, 0xe3, 0x62];
/// Byte representation of 1/a /// Byte representation of 1/a
static AINV_BYTES: [u8;32] = static AINV_BYTES: [u8; 32] =
[0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a, [0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a,
0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, 0x70, 0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, 0x70,
0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b, 0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b,
0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, 0xe6, 0x30]; 0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, 0xe6, 0x30];
/// Byte representation of a^((p-5)/8) /// Byte representation of a^((p-5)/8)
static AP58_BYTES: [u8;32] = static AP58_BYTES: [u8; 32] =
[0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36, [0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36,
0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, 0x59, 0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, 0x59,
0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f, 0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f,
@ -1352,7 +1325,7 @@ mod test {
#[test] #[test]
fn from_bytes_highbit_is_ignored() { fn from_bytes_highbit_is_ignored() {
let mut cleared_bytes = B_BYTES.clone(); let mut cleared_bytes = B_BYTES;
cleared_bytes[31] &= 127u8; cleared_bytes[31] &= 127u8;
let with_highbit_set = FieldElement::from_bytes(&B_BYTES); let with_highbit_set = FieldElement::from_bytes(&B_BYTES);
let without_highbit_set = FieldElement::from_bytes(&cleared_bytes); let without_highbit_set = FieldElement::from_bytes(&cleared_bytes);

View file

@ -11,10 +11,10 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(collections))] #![cfg_attr(not(feature = "std"), feature(collections))]
#![cfg_attr(feature = "nightly", feature(box_syntax))]
#![cfg_attr(feature = "nightly", feature(i128_type))] #![cfg_attr(feature = "nightly", feature(i128_type))]
#![allow(unused_features)]
#![cfg_attr(feature = "bench", feature(test))] #![cfg_attr(feature = "bench", feature(test))]
#![allow(unused_features)]
#![deny(missing_docs)] // refuse to compile if documentation is missing #![deny(missing_docs)] // refuse to compile if documentation is missing
//! # curve25519-dalek //! # curve25519-dalek

View file

@ -29,9 +29,13 @@
//! between two scalars, the `UnpackedScalar` struct is stored as //! between two scalars, the `UnpackedScalar` struct is stored as
//! limbs. //! limbs.
use core::cmp::{Eq, PartialEq};
use core::ops::{Neg, Index, IndexMut};
use core::fmt::Debug; use core::fmt::Debug;
use core::ops::Neg;
use core::ops::{Add, AddAssign};
use core::ops::{Sub, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::{Index, IndexMut};
use core::cmp::{Eq, PartialEq};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use rand::Rng; use rand::Rng;
@ -72,13 +76,7 @@ impl PartialEq for Scalar {
/// ///
/// True if they are equal, and false otherwise. /// True if they are equal, and false otherwise.
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
let equal: u8 = arrays_equal_ct(&self.0, &other.0); arrays_equal_ct(&self.0, &other.0) == 1u8
if equal == 1u8 {
return true;
} else {
return false;
}
} }
} }
@ -96,28 +94,66 @@ impl CTEq for Scalar {
impl Index<usize> for Scalar { impl Index<usize> for Scalar {
type Output = u8; type Output = u8;
fn index<'a>(&'a self, _index: usize) -> &'a u8 { fn index(&self, _index: usize) -> &u8 {
let ret: &'a u8 = &(self.0[_index]); &(self.0[_index])
ret
} }
} }
impl IndexMut<usize> for Scalar { impl IndexMut<usize> for Scalar {
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut u8 { fn index_mut(&mut self, _index: usize) -> &mut u8 {
let ret: &'a mut u8 = &mut(self.0[_index]); &mut(self.0[_index])
ret
} }
} }
impl Neg for Scalar { impl<'b> MulAssign<&'b Scalar> for Scalar {
type Output = Scalar; fn mul_assign(&mut self, _rhs: &'b Scalar) {
let result = (self as &Scalar) * _rhs;
/// Negate this scalar by computing (l - 1) * self - 0 (mod l). self.0 = result.0;
fn neg(self) -> Scalar {
Scalar::multiply_add(&constants::lminus1, &self, &Scalar::zero())
} }
} }
impl<'a, 'b> Mul<&'b Scalar> for &'a Scalar {
type Output = Scalar;
fn mul(self, _rhs: &'b Scalar) -> Scalar {
Scalar::multiply_add(self, _rhs, &Scalar::zero())
}
}
impl<'b> AddAssign<&'b Scalar> for Scalar {
fn add_assign(&mut self, _rhs: &'b Scalar) {
*self = Scalar::multiply_add(&Scalar::one(), self, _rhs);
}
}
impl<'a, 'b> Add<&'b Scalar> for &'a Scalar {
type Output = Scalar;
fn add(self, _rhs: &'b Scalar) -> Scalar {
Scalar::multiply_add(&Scalar::one(), self, _rhs)
}
}
impl<'b> SubAssign<&'b Scalar> for Scalar {
fn sub_assign(&mut self, _rhs: &'b Scalar) {
// (l-1)*_rhs + self = self - _rhs
*self = Scalar::multiply_add(&constants::l_minus_1, _rhs, self);
}
}
impl<'a, 'b> Sub<&'b Scalar> for &'a Scalar {
type Output = Scalar;
fn sub(self, _rhs: &'b Scalar) -> Scalar {
// (l-1)*_rhs + self = self - _rhs
Scalar::multiply_add(&constants::l_minus_1, _rhs, self)
}
}
impl<'a> Neg for &'a Scalar {
type Output = Scalar;
fn neg(self) -> Scalar {
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.
/// ///
@ -150,21 +186,19 @@ impl CTAssignable for Scalar {
} }
impl Scalar { impl Scalar {
/// Return a `Scalar` chosen uniformly at random using a CSPRNG. /// Return a `Scalar` chosen uniformly at random using a user-provided RNG.
/// Panics if the operating system's CSPRNG is unavailable.
/// ///
/// # Inputs /// # Inputs
/// ///
/// * `cspring`: any cryptographically secure PRNG which /// * `rng`: any RNG which implements the `rand::Rng` interface.
/// implements the `rand::Rng` interface.
/// ///
/// # Returns /// # Returns
/// ///
/// A random scalar within /l. /// A random scalar within /l.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn random<T: Rng>(csprng: &mut T) -> Self { pub fn random<T: Rng>(rng: &mut T) -> Self {
let mut scalar_bytes = [0u8; 64]; let mut scalar_bytes = [0u8; 64];
csprng.fill_bytes(&mut scalar_bytes); rng.fill_bytes(&mut scalar_bytes);
Scalar::reduce(&scalar_bytes) Scalar::reduce(&scalar_bytes)
} }
@ -173,6 +207,8 @@ impl Scalar {
/// Takes a type parameter `D`, which is any `Digest` producing 64 /// Takes a type parameter `D`, which is any `Digest` producing 64
/// bytes (512 bits) of output. /// bytes (512 bits) of output.
/// ///
/// Convenience wrapper around `from_hash`.
///
/// # Example /// # Example
/// ///
/// ``` /// ```
@ -190,9 +226,19 @@ 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)
}
/// Construct a scalar from an existing `Digest` instance.
///
/// Use this instead of `hash_from_bytes` if it is more convenient
/// 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 {
// 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());
@ -200,7 +246,7 @@ impl Scalar {
} }
/// View this `Scalar` as a sequence of bytes. /// View this `Scalar` as a sequence of bytes.
pub fn as_bytes<'a>(&'a self) -> &'a [u8;32] { pub fn as_bytes(&self) -> &[u8; 32] {
&self.0 &self.0
} }
@ -215,6 +261,31 @@ impl 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 ])
} }
/// Construct a scalar from the given `u64`.
pub fn from_u64(x: u64) -> Scalar {
let mut s = Scalar::zero();
for i in 0..8 {
s[i] = (x >> (i*8)) as u8;
}
s
}
/// Compute the multiplicative inverse of this scalar.
pub fn invert(&self) -> Scalar {
self.unpack().invert().pack()
}
/// Get the bits of the scalar.
pub fn bits(&self) -> [i8;256] {
let mut bits = [0i8; 256];
for i in 0..256 {
// As i runs from 0..256, the bottom 3 bits index the bit,
// while the upper bits index the byte.
bits[i] = ((self.0[i>>3] >> (i&7)) & 1u8) as i8;
}
bits
}
/// Compute a width-5 "Non-Adjacent Form" of this scalar. /// Compute a width-5 "Non-Adjacent Form" of this scalar.
/// ///
/// A width-`w` NAF of a positive integer `k` is an expression /// A width-`w` NAF of a positive integer `k` is an expression
@ -226,14 +297,9 @@ impl Scalar {
/// Intuitively, this is like a binary expansion, except that we /// Intuitively, this is like a binary expansion, except that we
/// allow some coefficients to grow up to `2^(w-1)` so that the /// allow some coefficients to grow up to `2^(w-1)` so that the
/// nonzero coefficients are as sparse as possible. /// nonzero coefficients are as sparse as possible.
pub fn non_adjacent_form(&self) -> [i8;256] { pub fn non_adjacent_form(&self) -> [i8; 256] {
// Step 1: write out bits of the scalar // Step 1: write out bits of the scalar
let mut naf = [0i8; 256]; let mut naf = self.bits();
for i in 0..256 {
// As i runs from 0..256, the bottom 3 bits index the bit,
// while the upper bits index the byte.
naf[i] = ((self.0[i>>3] >> (i&7)) & 1u8) as i8;
}
// Step 2: zero coefficients by carrying them upwards or downwards // Step 2: zero coefficients by carrying them upwards or downwards
'bits: for i in 0..256 { 'bits: for i in 0..256 {
@ -270,7 +336,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);
a[ 2] = mask_21bits & (load3(&self.0[ 5..]) >> 2); a[ 2] = mask_21bits & (load3(&self.0[ 5..]) >> 2);
@ -296,7 +362,7 @@ impl Scalar {
/// ///
/// Precondition: self[31] <= 127. This is the case whenever /// Precondition: self[31] <= 127. This is the case whenever
/// `self` is reduced. /// `self` is reduced.
pub fn to_radix_16(&self) -> [i8;64] { pub fn to_radix_16(&self) -> [i8; 64] {
debug_assert!(self[31] <= 127); debug_assert!(self[31] <= 127);
let mut output = [0i8; 64]; let mut output = [0i8; 64];
@ -339,8 +405,8 @@ impl Scalar {
} }
/// Reduce a 512-bit little endian number mod l /// Reduce a 512-bit little endian number mod l
pub fn reduce(input: &[u8;64]) -> Scalar { pub fn reduce(input: &[u8; 64]) -> Scalar {
let mut s = [0i64;24]; let mut s = [0i64; 24];
// XXX express this as two unpack_limbs // XXX express this as two unpack_limbs
// some issues re: masking with the top byte of the 32byte input // some issues re: masking with the top byte of the 32byte input
@ -387,16 +453,14 @@ pub struct UnpackedScalar(pub [i64; 12]);
impl Index<usize> for UnpackedScalar { impl Index<usize> for UnpackedScalar {
type Output = i64; type Output = i64;
fn index<'a>(&'a self, _index: usize) -> &'a i64 { fn index(&self, _index: usize) -> &i64 {
let ret: &'a i64 = &(self.0[_index]); &(self.0[_index])
ret
} }
} }
impl IndexMut<usize> for UnpackedScalar { impl IndexMut<usize> for UnpackedScalar {
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut i64 { fn index_mut(&mut self, _index: usize) -> &mut i64 {
let ret: &'a mut i64 = &mut(self.0[_index]); &mut(self.0[_index])
ret
} }
} }
@ -440,11 +504,34 @@ impl UnpackedScalar {
s s
} }
/// Return the zero scalar.
pub fn zero() -> UnpackedScalar {
UnpackedScalar([0,0,0,0,0,0,0,0,0,0,0,0])
}
/// Return the one scalar.
pub fn one() -> UnpackedScalar {
UnpackedScalar([1,0,0,0,0,0,0,0,0,0,0,0])
}
/// Compute the multiplicative inverse of this scalar.
pub fn invert(&self) -> UnpackedScalar {
let mut y = UnpackedScalar::one();
// Run through bits of l-2 from highest to least
for bit in constants::l_minus_2.bits().iter().rev() {
y = UnpackedScalar::multiply_add(&y, &y, &UnpackedScalar::zero());
if *bit == 1 {
y = UnpackedScalar::multiply_add(&y, self, &UnpackedScalar::zero());
}
}
y
}
/// Compute `ab+c (mod l)`. /// Compute `ab+c (mod l)`.
pub fn multiply_add(a: &UnpackedScalar, pub fn multiply_add(a: &UnpackedScalar,
b: &UnpackedScalar, b: &UnpackedScalar,
c: &UnpackedScalar) -> UnpackedScalar { c: &UnpackedScalar) -> UnpackedScalar {
let mut result = [0i64;24]; let mut result = [0i64; 24];
// Multiply a and b, and add c // Multiply a and b, and add c
result[0] = c[0] + a[0]*b[0]; result[0] = c[0] + a[0]*b[0];
@ -506,10 +593,10 @@ impl UnpackedScalar {
/// limbs. Reduction mod l amounts to eliminating all of the /// limbs. Reduction mod l amounts to eliminating all of the
/// high limbs while carrying as appropriate to prevent /// high limbs while carrying as appropriate to prevent
/// overflows in the lower limbs. /// overflows in the lower limbs.
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;
@ -531,7 +618,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;
@ -584,8 +671,7 @@ impl UnpackedScalar {
do_carry_uncentered(&mut limbs, i); do_carry_uncentered(&mut limbs, i);
} }
// XXX better way to get [i64;12] from [i64;24] ? UnpackedScalar(*array_ref!(limbs, 0, 12))
UnpackedScalar(*array_ref!(limbs,0,12))
} }
} }
@ -632,7 +718,7 @@ mod test {
0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09]); 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09]);
static A_NAF: [i8;256] = static A_NAF: [i8; 256] =
[0,13,0,0,0,0,0,0,0,7,0,0,0,0,0,0,-9,0,0,0,0,-11,0,0,0,0,3,0,0,0,0,1, [0,13,0,0,0,0,0,0,0,7,0,0,0,0,0,0,-9,0,0,0,0,-11,0,0,0,0,3,0,0,0,0,1,
0,0,0,0,9,0,0,0,0,-5,0,0,0,0,0,0,3,0,0,0,0,11,0,0,0,0,11,0,0,0,0,0, 0,0,0,0,9,0,0,0,0,-5,0,0,0,0,0,0,3,0,0,0,0,11,0,0,0,0,11,0,0,0,0,0,
-9,0,0,0,0,0,-3,0,0,0,0,9,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,0,0,0,9,0, -9,0,0,0,0,0,-3,0,0,0,0,9,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,0,0,0,9,0,
@ -650,6 +736,20 @@ mod test {
} }
} }
#[test]
fn from_unsigned() {
let val = 0xdeadbeefdeadbeef;
let s = Scalar::from_u64(val);
assert_eq!(s[7], 0xde);
assert_eq!(s[6], 0xad);
assert_eq!(s[5], 0xbe);
assert_eq!(s[4], 0xef);
assert_eq!(s[3], 0xde);
assert_eq!(s[2], 0xad);
assert_eq!(s[1], 0xbe);
assert_eq!(s[0], 0xef);
}
#[test] #[test]
fn scalar_multiply_by_one() { fn scalar_multiply_by_one() {
let one = Scalar::one(); let one = Scalar::one();
@ -661,12 +761,25 @@ mod test {
} }
#[test] #[test]
fn scalar_multiply_only() { fn impl_add() {
let zero = Scalar::zero(); let mut two = Scalar::zero(); two[0] = 2;
let test_scalar = Scalar::multiply_add(&X, &Y, &zero); let two = two;
for i in 0..32 { let one = Scalar::one();
assert!(test_scalar[i] == X_TIMES_Y[i]); let should_be_two = &one + &one;
} assert_eq!(should_be_two, two);
}
#[test]
fn impl_sub() {
let should_be_one = &constants::l - &constants::l_minus_1;
assert_eq!(should_be_one, Scalar::one());
}
#[allow(non_snake_case)]
#[test]
fn impl_mul() {
let should_be_X_times_Y = &X * &Y;
assert_eq!(should_be_X_times_Y, X_TIMES_Y);
} }
#[test] #[test]
@ -679,7 +792,7 @@ mod test {
#[test] #[test]
fn scalar_reduce() { fn scalar_reduce() {
let mut bignum = [0u8;64]; let mut bignum = [0u8; 64];
// set bignum = x + 2^256x // set bignum = x + 2^256x
for i in 0..32 { for i in 0..32 {
bignum[ i] = X[i]; bignum[ i] = X[i];
@ -697,13 +810,22 @@ mod test {
} }
} }
// Negating a scalar twice should result in the original scalar. #[allow(non_snake_case)]
#[test] #[test]
fn scalar_neg() { fn invert() {
let negative_x: Scalar = -X; let inv_X = X.invert();
let orig: Scalar = -negative_x; let should_be_one = &inv_X * &X;
assert_eq!(should_be_one, Scalar::one());
}
assert!(orig == X); // Negating a scalar twice should result in the original scalar.
#[allow(non_snake_case)]
#[test]
fn neg_twice_is_identity() {
let negative_X = -&X;
let should_be_X = -&negative_X;
assert_eq!(should_be_X, X);
} }
} }
@ -727,6 +849,12 @@ mod bench {
b.iter(|| Scalar::multiply_add(&X, &Y, &Z) ); b.iter(|| Scalar::multiply_add(&X, &Y, &Z) );
} }
#[bench]
fn invert(b: &mut Bencher) {
let x = X.unpack();
b.iter(|| x.invert());
}
#[bench] #[bench]
fn scalar_unpacked_multiply_add(b: &mut Bencher) { fn scalar_unpacked_multiply_add(b: &mut Bencher) {
let x = X.unpack(); let x = X.unpack();