Merge branch 'release/1.0.0-pre.0'

This commit is contained in:
Henry de Valence 2018-11-05 16:21:57 -08:00
commit d58b663ea8
16 changed files with 333 additions and 240 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "curve25519-dalek"
version = "0.21.0"
version = "1.0.0-pre.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
@ -26,7 +26,7 @@ features = ["nightly"]
travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"}
[dev-dependencies]
sha2 = "0.7"
sha2 = { version = "0.8", default-features = false }
bincode = "1"
criterion = "0.2"
@ -43,20 +43,18 @@ harness = false
[dependencies]
rand = { version = "0.5", default-features = false }
byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] }
digest = "0.7"
generic-array = "0.9"
digest = { version = "0.8", default-features = false }
clear_on_drop = "=0.2.3"
subtle = { version = "1", default-features = false }
subtle = { version = "2.0.0-pre.0", default-features = false }
serde = { version = "1.0", optional = true }
packed_simd = { version = "0.3.0", features = ["into_bits"], optional = true }
[build-dependencies]
rand = { version = "0.5", default-features = false }
byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] }
digest = "0.7"
generic-array = "0.9"
digest = { version = "0.8", default-features = false }
clear_on_drop = "=0.2.3"
subtle = { version = "1", default-features = false }
subtle = { version = "2.0.0-pre.0", default-features = false }
serde = { version = "1.0", optional = true }
packed_simd = { version = "0.3.0", features = ["into_bits"], optional = true }
@ -80,3 +78,4 @@ avx2_backend = ["nightly", "u64_backend", "packed_simd"]
# into the build script. Then, the build.rs emits the stage2_build
# feature before the main-stage compilation.
stage2_build = []

View file

@ -45,7 +45,7 @@ make doc-internal
To import `curve25519-dalek`, add the following to the dependencies section of
your project's `Cargo.toml`:
```toml
curve25519-dalek = "0.21"
curve25519-dalek = "1.0.0-pre.0"
```
Then import the crate as:
```rust,no_run

View file

@ -10,7 +10,6 @@ extern crate byteorder;
extern crate clear_on_drop;
extern crate core;
extern crate digest;
extern crate generic_array;
extern crate rand;
extern crate subtle;

View file

@ -38,7 +38,7 @@ use core::convert::From;
use core::ops::{Add, Neg, Sub};
use subtle::Choice;
use subtle::ConditionallyAssignable;
use subtle::ConditionallySelectable;
use edwards;
use scalar_mul::window::{LookupTable, NafLookupTable5, NafLookupTable8};
@ -76,8 +76,12 @@ impl From<ExtendedPoint> for edwards::EdwardsPoint {
}
}
impl ConditionallyAssignable for ExtendedPoint {
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: Choice) {
impl ConditionallySelectable for ExtendedPoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
ExtendedPoint(FieldElement32x4::conditional_select(&a.0, &b.0, choice))
}
fn conditional_assign(&mut self, other: &Self, choice: Choice) {
self.0.conditional_assign(&other.0, choice);
}
}
@ -209,8 +213,12 @@ impl Identity for CachedPoint {
}
}
impl ConditionallyAssignable for CachedPoint {
fn conditional_assign(&mut self, other: &CachedPoint, choice: Choice) {
impl ConditionallySelectable for CachedPoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
CachedPoint(FieldElement32x4::conditional_select(&a.0, &b.0, choice))
}
fn conditional_assign(&mut self, other: &Self, choice: Choice) {
self.0.conditional_assign(&other.0, choice);
}
}

View file

@ -144,15 +144,37 @@ pub enum Shuffle {
pub struct FieldElement32x4(pub(crate) [u32x8; 5]);
use subtle::Choice;
use subtle::ConditionallyAssignable;
use subtle::ConditionallySelectable;
impl ConditionallyAssignable for FieldElement32x4 {
fn conditional_assign(&mut self, other: &FieldElement32x4, choice: Choice) {
impl ConditionallySelectable for FieldElement32x4 {
fn conditional_select(
a: &FieldElement32x4,
b: &FieldElement32x4,
choice: Choice,
) -> FieldElement32x4 {
let mask = (-(choice.unwrap_u8() as i32)) as u32;
let mask_vec = u32x8::splat(mask);
for i in 0..5 {
self.0[i] = self.0[i] ^ (mask_vec & (self.0[i] ^ other.0[i]));
}
FieldElement32x4([
a.0[0] ^ (mask_vec & (a.0[0] ^ b.0[0])),
a.0[1] ^ (mask_vec & (a.0[1] ^ b.0[1])),
a.0[2] ^ (mask_vec & (a.0[2] ^ b.0[2])),
a.0[3] ^ (mask_vec & (a.0[3] ^ b.0[3])),
a.0[4] ^ (mask_vec & (a.0[4] ^ b.0[4])),
])
}
fn conditional_assign(
&mut self,
other: &FieldElement32x4,
choice: Choice,
) {
let mask = (-(choice.unwrap_u8() as i32)) as u32;
let mask_vec = u32x8::splat(mask);
self.0[0] ^= mask_vec & (self.0[0] ^ other.0[0]);
self.0[1] ^= mask_vec & (self.0[1] ^ other.0[1]);
self.0[2] ^= mask_vec & (self.0[2] ^ other.0[2]);
self.0[3] ^= mask_vec & (self.0[3] ^ other.0[3]);
self.0[4] ^= mask_vec & (self.0[4] ^ other.0[4]);
}
}

View file

@ -16,13 +16,13 @@
//! of signed limbs.
use core::fmt::Debug;
use core::ops::{Add, AddAssign};
use core::ops::{Sub, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::Neg;
use core::ops::{Add, AddAssign};
use core::ops::{Mul, MulAssign};
use core::ops::{Sub, SubAssign};
use subtle::ConditionallyAssignable;
use subtle::Choice;
use subtle::ConditionallySelectable;
/// A `FieldElement32` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
@ -219,11 +219,50 @@ impl<'a> Neg for &'a FieldElement32 {
}
}
impl ConditionallyAssignable for FieldElement32 {
impl ConditionallySelectable for FieldElement32 {
fn conditional_select(
a: &FieldElement32,
b: &FieldElement32,
choice: Choice,
) -> FieldElement32 {
FieldElement32([
u32::conditional_select(&a.0[0], &b.0[0], choice),
u32::conditional_select(&a.0[1], &b.0[1], choice),
u32::conditional_select(&a.0[2], &b.0[2], choice),
u32::conditional_select(&a.0[3], &b.0[3], choice),
u32::conditional_select(&a.0[4], &b.0[4], choice),
u32::conditional_select(&a.0[5], &b.0[5], choice),
u32::conditional_select(&a.0[6], &b.0[6], choice),
u32::conditional_select(&a.0[7], &b.0[7], choice),
u32::conditional_select(&a.0[8], &b.0[8], choice),
u32::conditional_select(&a.0[9], &b.0[9], choice),
])
}
fn conditional_assign(&mut self, other: &FieldElement32, choice: Choice) {
for i in 0..10 {
self.0[i].conditional_assign(&other.0[i], choice);
}
self.0[0].conditional_assign(&other.0[0], choice);
self.0[1].conditional_assign(&other.0[1], choice);
self.0[2].conditional_assign(&other.0[2], choice);
self.0[3].conditional_assign(&other.0[3], choice);
self.0[4].conditional_assign(&other.0[4], choice);
self.0[5].conditional_assign(&other.0[5], choice);
self.0[6].conditional_assign(&other.0[6], choice);
self.0[7].conditional_assign(&other.0[7], choice);
self.0[8].conditional_assign(&other.0[8], choice);
self.0[9].conditional_assign(&other.0[9], choice);
}
fn conditional_swap(a: &mut FieldElement32, b: &mut FieldElement32, choice: Choice) {
u32::conditional_swap(&mut a.0[0], &mut b.0[0], choice);
u32::conditional_swap(&mut a.0[1], &mut b.0[1], choice);
u32::conditional_swap(&mut a.0[2], &mut b.0[2], choice);
u32::conditional_swap(&mut a.0[3], &mut b.0[3], choice);
u32::conditional_swap(&mut a.0[4], &mut b.0[4], choice);
u32::conditional_swap(&mut a.0[5], &mut b.0[5], choice);
u32::conditional_swap(&mut a.0[6], &mut b.0[6], choice);
u32::conditional_swap(&mut a.0[7], &mut b.0[7], choice);
u32::conditional_swap(&mut a.0[8], &mut b.0[8], choice);
u32::conditional_swap(&mut a.0[9], &mut b.0[9], choice);
}
}

View file

@ -12,13 +12,13 @@
//! limbs with \\(128\\)-bit products.
use core::fmt::Debug;
use core::ops::{Add, AddAssign};
use core::ops::{Sub, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::Neg;
use core::ops::{Add, AddAssign};
use core::ops::{Mul, MulAssign};
use core::ops::{Sub, SubAssign};
use subtle::ConditionallyAssignable;
use subtle::Choice;
use subtle::ConditionallySelectable;
/// A `FieldElement64` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
@ -209,11 +209,35 @@ impl<'a> Neg for &'a FieldElement64 {
}
}
impl ConditionallyAssignable for FieldElement64 {
impl ConditionallySelectable for FieldElement64 {
fn conditional_select(
a: &FieldElement64,
b: &FieldElement64,
choice: Choice,
) -> FieldElement64 {
FieldElement64([
u64::conditional_select(&a.0[0], &b.0[0], choice),
u64::conditional_select(&a.0[1], &b.0[1], choice),
u64::conditional_select(&a.0[2], &b.0[2], choice),
u64::conditional_select(&a.0[3], &b.0[3], choice),
u64::conditional_select(&a.0[4], &b.0[4], choice),
])
}
fn conditional_swap(a: &mut FieldElement64, b: &mut FieldElement64, choice: Choice) {
u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice);
u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice);
u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice);
u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice);
u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice);
}
fn conditional_assign(&mut self, other: &FieldElement64, choice: Choice) {
for i in 0..5 {
self.0[i].conditional_assign(&other.0[i], choice);
}
self.0[0].conditional_assign(&other.0[0], choice);
self.0[1].conditional_assign(&other.0[1], choice);
self.0[2].conditional_assign(&other.0[2], choice);
self.0[3].conditional_assign(&other.0[3], choice);
self.0[4].conditional_assign(&other.0[4], choice);
}
}

View file

@ -129,12 +129,13 @@ mod test {
}
}
/// Test that SQRT_M1 is the positive square root of -1
#[test]
/// Test that SQRT_M1 is a square root of -1
fn test_sqrt_minus_one() {
let minus_one = FieldElement::minus_one();
let sqrt_m1_sq = &constants::SQRT_M1 * &constants::SQRT_M1;
assert_eq!(minus_one, sqrt_m1_sq);
assert_eq!(constants::SQRT_M1.is_negative().unwrap_u8(), 0);
}
#[test]
@ -143,8 +144,6 @@ mod test {
let (was_nonzero_square, invsqrt_m1) = minus_one.invsqrt();
assert_eq!(was_nonzero_square.unwrap_u8(), 1u8);
let sign_test_sqrt = &invsqrt_m1 * &constants::SQRT_M1;
// XXX it seems we have flipped the sign relative to
// the invsqrt function?
assert_eq!(sign_test_sqrt, minus_one);
}

View file

@ -124,15 +124,15 @@
#![allow(non_snake_case)]
use core::fmt::Debug;
use core::ops::{Add, Sub, Neg};
use core::ops::{Add, Neg, Sub};
use subtle::ConditionallyAssignable;
use subtle::Choice;
use subtle::ConditionallySelectable;
use constants;
use field::FieldElement;
use edwards::EdwardsPoint;
use field::FieldElement;
use traits::ValidityCheck;
// ------------------------------------------------------------------------
@ -204,7 +204,7 @@ use traits::Identity;
impl Identity for ProjectivePoint {
fn identity() -> ProjectivePoint {
ProjectivePoint{
ProjectivePoint {
X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one(),
@ -268,8 +268,17 @@ impl ValidityCheck for ProjectivePoint {
// Constant-time assignment
// ------------------------------------------------------------------------
impl ConditionallyAssignable for ProjectiveNielsPoint {
fn conditional_assign(&mut self, other: &ProjectiveNielsPoint, choice: Choice) {
impl ConditionallySelectable for ProjectiveNielsPoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
ProjectiveNielsPoint {
Y_plus_X: FieldElement::conditional_select(&a.Y_plus_X, &b.Y_plus_X, choice),
Y_minus_X: FieldElement::conditional_select(&a.Y_minus_X, &b.Y_minus_X, choice),
Z: FieldElement::conditional_select(&a.Z, &b.Z, choice),
T2d: FieldElement::conditional_select(&a.T2d, &b.T2d, choice),
}
}
fn conditional_assign(&mut self, other: &Self, choice: Choice) {
self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice);
self.Y_minus_X.conditional_assign(&other.Y_minus_X, choice);
self.Z.conditional_assign(&other.Z, choice);
@ -277,9 +286,16 @@ impl ConditionallyAssignable for ProjectiveNielsPoint {
}
}
impl ConditionallyAssignable for AffineNielsPoint {
fn conditional_assign(&mut self, other: &AffineNielsPoint, choice: Choice) {
// PreComputedGroupElementCMove()
impl ConditionallySelectable for AffineNielsPoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
AffineNielsPoint {
y_plus_x: FieldElement::conditional_select(&a.y_plus_x, &b.y_plus_x, choice),
y_minus_x: FieldElement::conditional_select(&a.y_minus_x, &b.y_minus_x, choice),
xy2d: FieldElement::conditional_select(&a.xy2d, &b.xy2d, choice),
}
}
fn conditional_assign(&mut self, other: &Self, choice: Choice) {
self.y_plus_x.conditional_assign(&other.y_plus_x, choice);
self.y_minus_x.conditional_assign(&other.y_minus_x, choice);
self.xy2d.conditional_assign(&other.xy2d, choice);
@ -296,7 +312,7 @@ impl ProjectivePoint {
///
/// This costs \\(3 \mathrm M + 1 \mathrm S\\).
pub fn to_extended(&self) -> EdwardsPoint {
EdwardsPoint{
EdwardsPoint {
X: &self.X * &self.Z,
Y: &self.Y * &self.Z,
Z: self.Z.square(),
@ -311,7 +327,7 @@ impl CompletedPoint {
///
/// This costs \\(3 \mathrm M \\).
pub fn to_projective(&self) -> ProjectivePoint {
ProjectivePoint{
ProjectivePoint {
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
Z: &self.Z * &self.T,
@ -323,7 +339,7 @@ impl CompletedPoint {
///
/// This costs \\(4 \mathrm M \\).
pub fn to_extended(&self) -> EdwardsPoint {
EdwardsPoint{
EdwardsPoint {
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
Z: &self.Z * &self.T,

View file

@ -70,7 +70,7 @@
//! The Edwards arithmetic is implemented using the “extended twisted
//! coordinates” of Hisil, Wong, Carter, and Dawson, and the
//! corresponding complete formulas. For more details,
//! see the [`curve_models` submodule][curve_models]
//! see the [`curve_models` submodule][curve_models]
//! of the internal documentation.
//!
//! ## Validity Checking
@ -92,17 +92,17 @@
// affine and projective cakes and eat both of them too.
#![allow(non_snake_case)]
use core::borrow::Borrow;
use core::fmt::Debug;
use core::iter::Iterator;
use core::ops::{Add, Sub, Neg};
use core::iter::Sum;
use core::ops::{Add, Neg, Sub};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use core::iter::Sum;
use core::borrow::Borrow;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
use subtle::Choice;
use subtle::ConditionallyNegatable;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
use constants;
@ -169,9 +169,9 @@ impl CompressedEdwardsY {
let YY = Y.square();
let u = &YY - &Z; // u = y²-1
let v = &(&YY * &constants::EDWARDS_D) + &Z; // v = dy²+1
let (is_nonzero_square, mut X) = FieldElement::sqrt_ratio(&u, &v);
let (is_valid_y_coord, mut X) = FieldElement::sqrt_ratio_i(&u, &v);
if is_nonzero_square.unwrap_u8() != 1u8 { return None; }
if is_valid_y_coord.unwrap_u8() != 1u8 { return None; }
// Flip the sign of X if it's not correct
let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7);
@ -328,10 +328,12 @@ impl CompressedEdwardsY {
impl Identity for EdwardsPoint {
fn identity() -> EdwardsPoint {
EdwardsPoint{ X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one(),
T: FieldElement::zero() }
EdwardsPoint {
X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one(),
T: FieldElement::zero(),
}
}
}
@ -358,12 +360,14 @@ impl ValidityCheck for EdwardsPoint {
// Constant-time assignment
// ------------------------------------------------------------------------
impl ConditionallyAssignable for EdwardsPoint {
fn conditional_assign(&mut self, other: &EdwardsPoint, choice: Choice) {
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);
impl ConditionallySelectable for EdwardsPoint {
fn conditional_select(a: &EdwardsPoint, b: &EdwardsPoint, choice: Choice) -> EdwardsPoint {
EdwardsPoint {
X: FieldElement::conditional_select(&a.X, &b.X, choice),
Y: FieldElement::conditional_select(&a.Y, &b.Y, choice),
Z: FieldElement::conditional_select(&a.Z, &b.Z, choice),
T: FieldElement::conditional_select(&a.T, &b.T, choice),
}
}
}
@ -373,7 +377,9 @@ impl ConditionallyAssignable for EdwardsPoint {
impl ConstantTimeEq for EdwardsPoint {
fn ct_eq(&self, other: &EdwardsPoint) -> Choice {
self.compress().as_bytes().ct_eq(other.compress().as_bytes())
self.compress()
.as_bytes()
.ct_eq(other.compress().as_bytes())
}
}
@ -897,7 +903,7 @@ impl Debug for EdwardsBasepointTable {
mod test {
use field::FieldElement;
use scalar::Scalar;
use subtle::ConditionallyAssignable;
use subtle::ConditionallySelectable;
use constants;
use super::*;

View file

@ -24,7 +24,7 @@
use core::cmp::{Eq, PartialEq};
use subtle::ConditionallyAssignable;
use subtle::ConditionallySelectable;
use subtle::ConditionallyNegatable;
use subtle::Choice;
use subtle::ConstantTimeEq;
@ -195,40 +195,19 @@ impl FieldElement {
t21
}
/// Given `FieldElements` `u` and `v`, attempt to compute
/// `sqrt(u/v)` in constant time.
/// Given `FieldElements` `u` and `v`, compute either `sqrt(u/v)`
/// or `sqrt(i*u/v)` in constant time.
///
/// This function always returns the nonnegative square root, if it exists.
///
/// It would be much better to use an `Option` type here, but
/// doing so forces the caller to branch, which we don't want to
/// do. This seems like the least bad solution.
/// This function always returns the nonnegative square root.
///
/// # Return
///
/// - `(1u8, sqrt(u/v))` if `v` is nonzero and `u/v` is square;
/// - `(0u8, zero)` if `v` is zero;
/// - `(0u8, garbage)` if `u/v` is nonsquare.
/// - `(Choice(1), +sqrt(u/v)) ` if `v` is nonzero and `u/v` is square;
/// - `(Choice(1), zero) ` if `u` is zero;
/// - `(Choice(0), zero) ` if `v` is zero and `u` is nonzero;
/// - `(Choice(0), +sqrt(i*u/v))` if `u/v` is nonsquare (so `i*u/v` is square).
///
/// # Example
///
/// ```ignore
/// let one = FieldElement::one();
/// let two = &one + &one;
/// let four = &two * &two;
///
/// // two is nonsquare mod p
/// let (two_is_square, two_sqrt) = FieldElement::sqrt_ratio(&two, &one);
/// assert_eq!(two_is_square.unwrap_u8(), 0u8);
///
/// // four is square mod p
/// let (four_is_square, four_sqrt) = FieldElement::sqrt_ratio(&four, &one);
///
/// assert_eq!(four_is_square.unwrap_u8(), 1u8);
/// assert_eq!(four_sqrt.is_negative().unwrap_u8
/// ```
///
pub fn sqrt_ratio(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) {
pub fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) {
// Using the same trick as in ed25519 decoding, we merge the
// inversion, the square root, and the square test as follows.
//
@ -258,11 +237,14 @@ impl FieldElement {
let mut r = &(u * &v3) * &(u * &v7).pow_p58();
let check = v * &r.square();
let correct_sign_sqrt = check.ct_eq( u);
let flipped_sign_sqrt = check.ct_eq(&(-u));
let i = &constants::SQRT_M1;
let correct_sign_sqrt = check.ct_eq( u);
let flipped_sign_sqrt = check.ct_eq( &(-u));
let flipped_sign_sqrt_i = check.ct_eq(&(&(-u)*i));
let r_prime = &constants::SQRT_M1 * &r;
r.conditional_assign(&r_prime, flipped_sign_sqrt);
r.conditional_assign(&r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i);
// Choose the nonnegative square root.
let r_is_negative = r.is_negative();
@ -273,42 +255,20 @@ impl FieldElement {
(was_nonzero_square, r)
}
/// For `self` a nonzero square, compute 1/sqrt(self) in
/// constant time.
/// Attempt to compute `1/sqrt(self)` in constant time.
///
/// It would be much better to use an `Option` type here, but
/// doing so forces the caller to branch, which we don't want to
/// do. This seems like the least bad solution.
/// Convenience wrapper around `sqrt_ratio_i`.
///
/// This function always returns the nonnegative square root.
///
/// # Return
///
/// - `(1u8, 1/sqrt(self))` if `self` is a nonzero square;
/// - `(0u8, zero)` if `self` is zero;
/// - `(0u8, garbage)` if `self` is nonsquare.
/// - `(Choice(1), +sqrt(1/self)) ` if `self` is a nonzero square;
/// - `(Choice(0), zero) ` if `self` is zero;
/// - `(Choice(0), +sqrt(i*u/v)) ` if `self` is a nonzero nonsquare;
///
pub fn invsqrt(&self) -> (Choice, FieldElement) {
FieldElement::sqrt_ratio(&FieldElement::one(), self)
}
/// chi calculates `self^((p-1)/2)`.
///
/// # Return
///
/// * If this element is a non-zero square, returns `1`.
/// * If it is zero, returns `0`.
/// * If it is non-square, returns `-1`.
pub fn chi(&self) -> FieldElement { // extra25519.chi
// The bits of (p-1)/2 = 2^254 -10 are 0110111111...11.
//
// nonzero bits of exponent
let (t19, _) = self.pow22501(); // 249..0
let t20 = t19.pow2k(4); // 253..4
let t21 = self.square(); // 1
let t22 = t21.square(); // 2
let t23 = &t22 * &t21; // 2,1
let t24 = &t20 * &t23; // 253..4,2,1
t24
FieldElement::sqrt_ratio_i(&FieldElement::one(), self)
}
}
@ -392,6 +352,45 @@ mod test {
}
}
#[test]
fn sqrt_ratio_behavior() {
let zero = FieldElement::zero();
let one = FieldElement::one();
let i = constants::SQRT_M1;
let two = &one + &one; // 2 is nonsquare mod p.
let four = &two + &two; // 4 is square mod p.
// 0/0 should return (1, 0) since u is 0
let (choice, sqrt) = FieldElement::sqrt_ratio_i(&zero, &zero);
assert_eq!(choice.unwrap_u8(), 1);
assert_eq!(sqrt, zero);
assert_eq!(sqrt.is_negative().unwrap_u8(), 0);
// 1/0 should return (0, 0) since v is 0, u is nonzero
let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &zero);
assert_eq!(choice.unwrap_u8(), 0);
assert_eq!(sqrt, zero);
assert_eq!(sqrt.is_negative().unwrap_u8(), 0);
// 2/1 is nonsquare, so we expect (0, sqrt(i*2))
let (choice, sqrt) = FieldElement::sqrt_ratio_i(&two, &one);
assert_eq!(choice.unwrap_u8(), 0);
assert_eq!(sqrt.square(), &two * &i);
assert_eq!(sqrt.is_negative().unwrap_u8(), 0);
// 4/1 is square, so we expect (1, sqrt(4))
let (choice, sqrt) = FieldElement::sqrt_ratio_i(&four, &one);
assert_eq!(choice.unwrap_u8(), 1);
assert_eq!(sqrt.square(), four);
assert_eq!(sqrt.is_negative().unwrap_u8(), 0);
// 1/4 is square, so we expect (1, 1/sqrt(4))
let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &four);
assert_eq!(choice.unwrap_u8(), 1);
assert_eq!(&sqrt.square() * &four, one);
assert_eq!(sqrt.is_negative().unwrap_u8(), 0);
}
#[test]
fn a_p58_vs_ap58_constant() {
let a = FieldElement::from_bytes(&A_BYTES);
@ -399,17 +398,6 @@ mod test {
assert_eq!(ap58, a.pow_p58());
}
#[test]
fn chi_on_square_and_nonsquare() {
let a = FieldElement::from_bytes(&A_BYTES);
// a is square
assert_eq!(a.chi(), FieldElement::one());
let mut two_bytes = [0u8; 32]; two_bytes[0] = 2;
let two = FieldElement::from_bytes(&two_bytes);
// 2 is nonsquare
assert_eq!(two.chi(), FieldElement::minus_one());
}
#[test]
fn equality() {
let a = FieldElement::from_bytes(&A_BYTES);

View file

@ -44,12 +44,7 @@ extern crate packed_simd;
extern crate rand;
extern crate clear_on_drop;
extern crate byteorder;
// The `Digest` trait is implemented using `generic_array`, so we need it
// too. Hopefully we can eliminate `generic_array` from `Digest` once const
// generics land.
extern crate digest;
extern crate generic_array;
pub extern crate digest;
// Used for traits related to constant-time code.
extern crate subtle;

View file

@ -29,7 +29,7 @@
//!
//! Scalar multiplication on `MontgomeryPoint`s is provided by the `*`
//! operator, which implements the Montgomery ladder.
//!
//!
//! # Edwards Conversion
//!
//! The \\(2\\)-to-\\(1\\) map from the Edwards model to the Montgomery
@ -51,16 +51,15 @@
use core::ops::{Mul, MulAssign};
use constants::APLUS2_OVER_FOUR;
use edwards::{CompressedEdwardsY, EdwardsPoint};
use field::FieldElement;
use edwards::{EdwardsPoint, CompressedEdwardsY};
use scalar::Scalar;
use traits::Identity;
use subtle::ConditionallyAssignable;
use subtle::ConditionallySwappable;
use subtle::ConstantTimeEq;
use subtle::Choice;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of
/// Curve25519 or its twist.
@ -141,7 +140,7 @@ impl MontgomeryPoint {
/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer
/// line of the Montgomery curve.
#[derive(Copy, Clone, Debug)]
struct ProjectivePoint{
struct ProjectivePoint {
pub U: FieldElement,
pub W: FieldElement,
}
@ -161,10 +160,16 @@ impl Default for ProjectivePoint {
}
}
impl ConditionallyAssignable for ProjectivePoint {
fn conditional_assign(&mut self, that: &ProjectivePoint, choice: Choice) {
self.U.conditional_assign(&that.U, choice);
self.W.conditional_assign(&that.W, choice);
impl ConditionallySelectable for ProjectivePoint {
fn conditional_select(
a: &ProjectivePoint,
b: &ProjectivePoint,
choice: Choice,
) -> ProjectivePoint {
ProjectivePoint {
U: FieldElement::conditional_select(&a.U, &b.U, choice),
W: FieldElement::conditional_select(&a.W, &b.W, choice),
}
}
}
@ -196,7 +201,7 @@ impl ProjectivePoint {
/// (U\_Q : W\_Q) \gets u(P + Q).
/// $$
fn differential_add_and_double(
P: &mut ProjectivePoint,
P: &mut ProjectivePoint,
Q: &mut ProjectivePoint,
affine_PmQ: &FieldElement,
) {
@ -249,19 +254,22 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint {
// Algorithm 8 of Costello-Smith 2017
let affine_u = FieldElement::from_bytes(&self.0);
let mut x0 = ProjectivePoint::identity();
let mut x1 = ProjectivePoint{ U: affine_u, W: FieldElement::one() };
let mut x1 = ProjectivePoint {
U: affine_u,
W: FieldElement::one(),
};
let bits: [i8; 256] = scalar.bits();
for i in (0..255).rev() {
let choice: u8 = (bits[i+1] ^ bits[i]) as u8;
let choice: u8 = (bits[i + 1] ^ bits[i]) as u8;
debug_assert!(choice == 0 || choice == 1);
x0.conditional_swap(&mut x1, choice.into());
ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into());
differential_add_and_double(&mut x0, &mut x1, &affine_u);
}
x0.conditional_swap(&mut x1, Choice::from(bits[0] as u8));
ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8));
x0.to_affine()
}

View file

@ -157,28 +157,28 @@
//! [ristretto_main]:
//! https://ristretto.group/
use core::borrow::Borrow;
use core::fmt::Debug;
use core::ops::{Add, Sub, Neg};
use core::iter::Sum;
use core::ops::{Add, Neg, Sub};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use core::iter::Sum;
use core::borrow::Borrow;
use rand::{Rng, CryptoRng};
use rand::{CryptoRng, Rng};
use digest::generic_array::typenum::U64;
use digest::Digest;
use generic_array::typenum::U64;
use constants;
use field::FieldElement;
use subtle::ConditionallyAssignable;
use subtle::Choice;
use subtle::ConditionallySelectable;
use subtle::ConditionallyNegatable;
use subtle::ConstantTimeEq;
use subtle::Choice;
use edwards::EdwardsPoint;
use edwards::EdwardsBasepointTable;
use edwards::EdwardsPoint;
#[allow(unused_imports)]
use prelude::*;
@ -577,44 +577,32 @@ impl RistrettoPoint {
pub(crate) fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint {
let (i, d) = (&constants::SQRT_M1, &constants::EDWARDS_D);
let one = FieldElement::one();
let one_minus_d_sq = &one - &d.square();
let d_minus_one_sq = (d - &one).square();
let r = i * &r_0.square();
// D = (dr -a)(ar-d) = -(dr+1)(r+d)
let D = -&( &(&(d * &r) + &one) * &(&r + d) );
// N = a(d-a)(d+a)(r+1) = -(r+1)(d^2 -1)
let d_sq = d.square();
let N = -&( &(&d_sq - &one) * &(&r + &one) );
let mut s = FieldElement::zero();
let N_s = &(&r + &one) * &one_minus_d_sq;
let mut c = -&one;
let D = &(&c - &(d * &r)) * &(&r + d);
let (N_over_D_is_square, maybe_s) = FieldElement::sqrt_ratio(&N, &D);
// s = sqrt(N/D) if N/D is square
s.conditional_assign(&maybe_s, N_over_D_is_square);
let (Ns_D_is_sq, mut s) = FieldElement::sqrt_ratio_i(&N_s, &D);
let mut s_prime = &s * r_0;
let s_prime_is_pos = !s_prime.is_negative();
s_prime.conditional_negate(s_prime_is_pos);
// XXX how exactly do we reuse the computation of sqrt(N/D) to find sqrt(rN/D) ?
let (rN_over_D_is_square, mut maybe_s) = FieldElement::sqrt_ratio(&(&r*&N), &D);
maybe_s.negate();
// s = -sqrt(rN/D) if rN/D is square (should happen exactly when N/D is nonsquare)
debug_assert_eq!((N_over_D_is_square ^ rN_over_D_is_square).unwrap_u8(), 1u8);
s.conditional_assign(&maybe_s, rN_over_D_is_square);
c.conditional_assign(&r, rN_over_D_is_square);
// T = (c * (r - one) * (d-one).square()) - D;
let T = &(&c * &(&(&r - &one) * &((d - &one).square()))) - &D;
s.conditional_assign(&s_prime, !Ns_D_is_sq);
c.conditional_assign(&r, !Ns_D_is_sq);
let N_t = &(&(&c * &(&r - &one)) * &d_minus_one_sq) - &D;
let s_sq = s.square();
let P = CompletedPoint{
// The conversion from W_i is exactly the conversion from P1xP1.
RistrettoPoint(CompletedPoint{
X: &(&s + &s) * &D,
Z: &T * &constants::SQRT_AD_MINUS_ONE,
Z: &N_t * &constants::SQRT_AD_MINUS_ONE,
Y: &FieldElement::one() - &s_sq,
T: &FieldElement::one() + &s_sq,
};
// Convert to extended and return.
RistrettoPoint(P.to_extended())
}.to_extended())
}
/// Return a `RistrettoPoint` chosen uniformly at random using a user-provided RNG.
@ -870,7 +858,7 @@ define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint
#[cfg(feature = "alloc")]
impl MultiscalarMul for RistrettoPoint {
type Point = RistrettoPoint;
fn multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
where
I: IntoIterator,
@ -888,7 +876,7 @@ impl MultiscalarMul for RistrettoPoint {
#[cfg(feature = "alloc")]
impl VartimeMultiscalarMul for RistrettoPoint {
type Point = RistrettoPoint;
fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<RistrettoPoint>
where
I: IntoIterator,
@ -961,11 +949,11 @@ impl RistrettoBasepointTable {
}
// ------------------------------------------------------------------------
// Constant-time conditional assignment
// Constant-time conditional selection
// ------------------------------------------------------------------------
impl ConditionallyAssignable for RistrettoPoint {
/// Conditionally assign `other` to `self`, if `choice == Choice(1)`.
impl ConditionallySelectable for RistrettoPoint {
/// Conditionally select between `self` and `other`.
///
/// # Example
///
@ -973,7 +961,7 @@ impl ConditionallyAssignable for RistrettoPoint {
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// #
/// use subtle::ConditionallyAssignable;
/// use subtle::ConditionallySelectable;
/// use subtle::Choice;
/// #
/// # use curve25519_dalek::traits::Identity;
@ -986,17 +974,18 @@ impl ConditionallyAssignable for RistrettoPoint {
///
/// let mut P = A;
///
/// P.conditional_assign(&B, Choice::from(0));
/// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(0));
/// assert_eq!(P, A);
/// P.conditional_assign(&B, Choice::from(1));
/// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(1));
/// assert_eq!(P, B);
/// # }
/// ```
fn conditional_assign(&mut self, other: &RistrettoPoint, choice: Choice) {
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);
fn conditional_select(
a: &RistrettoPoint,
b: &RistrettoPoint,
choice: Choice,
) -> RistrettoPoint {
RistrettoPoint(EdwardsPoint::conditional_select(&a.0, &b.0, choice))
}
}

View file

@ -80,10 +80,10 @@
//! assert!(a == two);
//! ```
//!
//! There is also a constructor that reduces a \\(512\\)-bit integer,
//! There is also a constructor that reduces a \\(512\\)-bit integer,
//! [`Scalar::from_bytes_mod_order_wide`](struct.Scalar.html#method.from_bytes_mod_order_wide).
//!
//! To construct a `Scalar` as the hash of some input data, use
//! To construct a `Scalar` as the hash of some input data, use
//! [`Scalar::hash_from_bytes`](struct.Scalar.html#method.hash_from_bytes),
//! which takes a buffer, or
//! [`Scalar::from_hash`](struct.Scalar.html#method.from_hash),
@ -138,26 +138,26 @@
//! The resulting `Scalar` has exactly the specified bit pattern,
//! **except for the highest bit, which will be set to 0**.
use core::borrow::Borrow;
use core::cmp::{Eq, PartialEq};
use core::fmt::Debug;
use core::iter::{Product, Sum};
use core::ops::Index;
use core::ops::Neg;
use core::ops::{Add, AddAssign};
use core::ops::{Sub, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::{Index};
use core::cmp::{Eq, PartialEq};
use core::iter::{Product, Sum};
use core::borrow::Borrow;
use core::ops::{Sub, SubAssign};
#[allow(unused_imports)]
use prelude::*;
use rand::{Rng, CryptoRng};
use rand::{CryptoRng, Rng};
use digest::generic_array::typenum::U64;
use digest::Digest;
use generic_array::typenum::U64;
use subtle::Choice;
use subtle::ConditionallyAssignable;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
use backend;
@ -343,11 +343,13 @@ impl<'a> Neg for Scalar {
}
}
impl ConditionallyAssignable for Scalar {
fn conditional_assign(&mut self, other: &Scalar, choice: Choice) {
impl ConditionallySelectable for Scalar {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
let mut bytes = [0u8; 32];
for i in 0..32 {
self.bytes[i].conditional_assign(&other.bytes[i], choice);
bytes[i] = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice);
}
Scalar { bytes }
}
}
@ -579,14 +581,13 @@ impl Scalar {
/// use sha2::Sha512;
///
/// # fn main() {
/// let mut h = Sha512::default();
///
/// h.input(b"To really appreciate architecture, you may even need to commit a murder.");
/// h.input(b"While the programs used for The Manhattan Transcripts are of the most extreme");
/// h.input(b"nature, they also parallel the most common formula plot: the archetype of");
/// h.input(b"murder. Other phantasms were occasionally used to underline the fact that");
/// h.input(b"perhaps all architecture, rather than being about functional standards, is");
/// h.input(b"about love and death.");
/// let mut h = Sha512::new()
/// .chain("To really appreciate architecture, you may even need to commit a murder.")
/// .chain("While the programs used for The Manhattan Transcripts are of the most extreme")
/// .chain("nature, they also parallel the most common formula plot: the archetype of")
/// .chain("murder. Other phantasms were occasionally used to underline the fact that")
/// .chain("perhaps all architecture, rather than being about functional standards, is")
/// .chain("about love and death.");
///
/// let s = Scalar::from_hash(h);
///
@ -982,7 +983,7 @@ impl Scalar {
/// # extern crate curve25519_dalek;
/// # extern crate subtle;
/// # use curve25519_dalek::scalar::Scalar;
/// # use subtle::ConditionallyAssignable;
/// # use subtle::ConditionallySelectable;
/// # fn main() {
/// // 2^255 - 1, since `from_bits` clears the high bit
/// let _2_255_minus_1 = Scalar::from_bits([0xff;32]);

View file

@ -15,7 +15,7 @@
use core::fmt::Debug;
use subtle::ConditionallyNegatable;
use subtle::ConditionallyAssignable;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
use subtle::Choice;
@ -59,7 +59,7 @@ unsafe impl<T> ZeroSafe for LookupTable<T> {}
impl<T> LookupTable<T>
where
T: Identity + ConditionallyAssignable + ConditionallyNegatable,
T: Identity + ConditionallySelectable + ConditionallyNegatable,
{
/// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time.
pub fn select(&self, x: i8) -> T {