Merge branch 'release/0.16.0'

This commit is contained in:
Henry de Valence 2018-03-22 12:37:09 -07:00
commit ffeb8cfadd
22 changed files with 564 additions and 445 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "curve25519-dalek"
version = "0.15.1"
version = "0.16.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
@ -39,7 +39,7 @@ serde_cbor = "0.6"
digest = "0.7"
generic-array = "0.9"
clear_on_drop = "=0.2.3"
subtle = { version = "0.5", features = ["generic-impls"], default-features = false }
subtle = { version = "0.6", features = ["generic-impls"], default-features = false }
stdsimd = { version = "0.0.4", optional = true }
serde = { version = "1.0", optional = true }
rand = { version = "0.4", optional = true }
@ -48,7 +48,7 @@ rand = { version = "0.4", optional = true }
digest = "0.7"
generic-array = "0.9"
clear_on_drop = "=0.2.3"
subtle = { version = "0.5", features = ["generic-impls"], default-features = false }
subtle = { version = "0.6", features = ["generic-impls"], default-features = false }
stdsimd = { version = "0.0.4", optional = true }
serde = { version = "1.0", optional = true }
# Allowing rand to be optional during builds causes a build failure when compiling for no_std targets

View file

@ -1,10 +1,10 @@
# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://docs.rs/curve25519-dalek/badge.svg)](https://docs.rs/curve25519-dalek) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek)
# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fcurve25519-dalek%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek)
<img
width="33%"
align="right"
src="https://raw.githubusercontent.com/dalek-cryptography/curve25519-dalek/develop/dalek-logo-clear.png"/>
src="https://doc.dalek.rs/assets/dalek-logo-clear.png"/>
**A pure-Rust implementation of group operations on Ristretto and Curve25519.**
@ -118,3 +118,5 @@ contributions.
[ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek
[x25519-dalek]: https://github.com/dalek-cryptography/x25519-dalek
[contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md
[docs-external]: https://doc.dalek.rs/curve25519_dalek/
[docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/

View file

@ -1,6 +1,6 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/katex.min.css" integrity="sha384-B41nY7vEWuDrE9Mr+J2nBL0Liu+nl/rBXTdpQal730oTHdlrlXHzYMOhDU60cwde" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/katex.min.js" integrity="sha384-L9gv4ooDLrYwW0QCM6zY3EKSSPrsuUncpx26+erN0pJX4wv1B1FzVW1SvpcJPx/8" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/contrib/auto-render.min.js" integrity="sha384-RkgGHBDdR8eyBOoWeZ/vpGg1cOvSAJRflCUDACusAAIVwkwPrOUYykglPeqWakZu" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://doc.dalek.rs/assets/katex/katex.min.css">
<script src="https://doc.dalek.rs/assets/katex/katex.min.js"></script>
<script src="https://doc.dalek.rs/assets/katex/contrib/auto-render.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() { renderMathInElement(document.body); });
</script>

View file

@ -13,12 +13,14 @@
// just going to own it
#![allow(bad_style)]
use std::convert::From;
use std::ops::{Index, Add, Sub, Mul, Neg};
use core::convert::From;
use core::ops::{Index, Add, Sub, Mul, Neg};
use core::borrow::Borrow;
use stdsimd::simd::{u32x8, i32x8};
use subtle::ConditionallyAssignable;
use subtle::Choice;
use edwards;
use scalar::Scalar;
@ -51,7 +53,7 @@ impl From<ExtendedPoint> for edwards::EdwardsPoint {
}
impl ConditionallyAssignable for ExtendedPoint {
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: u8) {
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: Choice) {
self.0.conditional_assign(&other.0, choice);
}
}
@ -114,7 +116,7 @@ impl Identity for CachedPoint {
}
impl ConditionallyAssignable for CachedPoint {
fn conditional_assign(&mut self, other: &CachedPoint, choice: u8) {
fn conditional_assign(&mut self, other: &CachedPoint, choice: Choice) {
self.0.conditional_assign(&other.0, choice);
}
}
@ -236,7 +238,7 @@ impl ExtendedPoint {
}
}
pub fn mult_by_pow_2(&self, k: u32) -> ExtendedPoint {
pub fn mul_by_pow_2(&self, k: u32) -> ExtendedPoint {
let mut tmp: ExtendedPoint = *self;
for _ in 0..k {
tmp = tmp.double();
@ -395,7 +397,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
let mut Q = ExtendedPoint::identity();
for i in (0..64).rev() {
// Q = 16*Q
Q = Q.mult_by_pow_2(4);
Q = Q.mul_by_pow_2(4);
// Q += P*s_i
Q = &Q + &lookup_table.select(scalar_digits[i]);
}
@ -419,7 +421,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable {
P = &P + &tables[i/2].select(a[i]);
}
P = P.mult_by_pow_2(4);
P = P.mul_by_pow_2(4);
for i in (0..64).filter(|x| x % 2 == 0) {
P = &P + &tables[i/2].select(a[i]);
@ -447,38 +449,25 @@ impl EdwardsBasepointTable {
for i in 0..32 {
// P = (16^2)^i * B
table.0[i] = LookupTable::from(P);
P = P.mult_by_pow_2(8);
P = P.mul_by_pow_2(8);
}
table
}
}
/// Given a vector of (possibly secret) scalars and a vector of
/// (possibly secret) points, compute `c_1 P_1 + ... + c_n P_n`.
///
/// This function has the same behaviour as
/// `vartime::multiscalar_mult` but is constant-time.
///
/// # Input
///
/// A vector of `Scalar`s and a vector of `EdwardsPoints`. It is an
/// error to call this function with two vectors of different lengths.
///
/// XXX this takes `edwards::EdwardsPoints` because we have to alloc scratch space here anyways,
/// and we need some space to store the converted points, so we may as well do the conversion here.
/// maybe there's a better way to avoid code duplication... however we can't quite just write a
/// generic `multiscalar_mult` because the non-vectorized code passes between models and this code
/// doesn't.
/// Internal multiscalar code.
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b edwards::EdwardsPoint>
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
where I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator,
J::Item: Borrow<edwards::EdwardsPoint>,
{
//assert_eq!(scalars.len(), points.len());
use clear_on_drop::ClearOnDrop;
let lookup_tables_vec: Vec<_> = points.into_iter()
.map(|P| LookupTable::from(ExtendedPoint::from(*P)) )
.map(|P| LookupTable::from(ExtendedPoint::from(*P.borrow())) )
.collect();
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
@ -489,7 +478,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> edwards::Edwards
//
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
let scalar_digits_vec: Vec<_> = scalars.into_iter()
.map(|c| c.to_radix_16())
.map(|c| c.borrow().to_radix_16())
.collect();
// The above puts the scalar digits into a heap-allocated Vec.
@ -519,7 +508,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> edwards::Edwards
let mut Q = ExtendedPoint::identity();
// XXX this algorithm makes no effort to be cache-aware; maybe it could be improved?
for j in (0..64).rev() {
Q = Q.mult_by_pow_2(4);
Q = Q.mul_by_pow_2(4);
let it = scalar_digits.iter().zip(lookup_tables.iter());
for (s_i, lookup_table_i) in it {
// Q = Q + s_{i,j} * P_i
@ -562,7 +551,7 @@ pub mod vartime {
/// with x positive).
///
/// This is the same as calling the iterator-based function, but slightly faster.
pub fn double_scalar_mult_basepoint(a: &Scalar,
pub fn double_scalar_mul_basepoint(a: &Scalar,
A: &edwards::EdwardsPoint,
b: &Scalar) -> edwards::EdwardsPoint {
let a_naf = a.non_adjacent_form();
@ -606,27 +595,21 @@ pub mod vartime {
Q.into()
}
/// Given a vector of public scalars and a vector of public points, compute
/// $$
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
/// $$
///
/// # Input
///
/// A vector of `Scalar`s and a vector of `EdwardsPoints`. It is an
/// error to call this function with two vectors of different lengths.
/// Internal multiscalar function
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b edwards::EdwardsPoint>
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
where I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator,
J::Item: Borrow<edwards::EdwardsPoint>,
{
//assert_eq!(scalars.len(), points.len());
let nafs: Vec<_> = scalars.into_iter()
.map(|c| c.non_adjacent_form()).collect();
.map(|c| c.borrow().non_adjacent_form()).collect();
let odd_multiples: Vec<_> = points.into_iter()
.map(|P| OddMultiples::create((*P).into()) ).collect();
.map(|P| OddMultiples::create((*P.borrow()).into()) ).collect();
let mut Q = ExtendedPoint::identity();
@ -873,7 +856,7 @@ mod test {
}
#[test]
fn scalar_mult_vs_edwards_scalar_mult() {
fn scalar_mul_vs_edwards_scalar_mul() {
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
// some random bytes
let s = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
@ -885,7 +868,7 @@ mod test {
}
#[test]
fn scalar_mult_vs_basepoint_table_scalar_mult() {
fn scalar_mul_vs_basepoint_table_scalar_mul() {
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
let B_table = EdwardsBasepointTable::create(&B);
// some random bytes
@ -899,7 +882,7 @@ mod test {
}
#[test]
fn multiscalar_mult_vs_adding_scalar_mults() {
fn multiscalar_mul_vs_adding_scalar_muls() {
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
let s1 = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
let s2 = Scalar::from_bits([165, 30, 79, 89, 58, 24, 195, 245, 248, 146, 203, 236, 119, 43, 64, 119, 196, 111, 188, 251, 248, 53, 234, 59, 215, 28, 218, 13, 59, 120, 14, 4]);
@ -909,7 +892,7 @@ mod test {
let R = &(&P1 * &s1) + &(&P2 * &s2);
let R_multiscalar = multiscalar_mult(&[s1, s2], &[P1.into(), P2.into()]);
let R_multiscalar = multiscalar_mul(&[s1, s2], &[P1.into(), P2.into()]);
assert_eq!(edwards::EdwardsPoint::from(R).compress(),
R_multiscalar.compress());
@ -919,7 +902,7 @@ mod test {
use super::*;
#[test]
fn multiscalar_mult_vs_adding_scalar_mults() {
fn multiscalar_mul_vs_adding_scalar_muls() {
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
let s1 = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
let s2 = Scalar::from_bits([165, 30, 79, 89, 58, 24, 195, 245, 248, 146, 203, 236, 119, 43, 64, 119, 196, 111, 188, 251, 248, 53, 234, 59, 215, 28, 218, 13, 59, 120, 14, 4]);
@ -929,7 +912,7 @@ mod test {
let R = &(&P1 * &s1) + &(&P2 * &s2);
let R_multiscalar = vartime::multiscalar_mult(&[s1, s2], &[P1.into(), P2.into()]);
let R_multiscalar = vartime::multiscalar_mul(&[s1, s2], &[P1.into(), P2.into()]);
assert_eq!(edwards::EdwardsPoint::from(R).compress(),
R_multiscalar.compress());
@ -989,7 +972,7 @@ mod bench {
}
#[bench]
fn scalar_mult(b: &mut Bencher) {
fn scalar_mul(b: &mut Bencher) {
let B = &constants::ED25519_BASEPOINT_TABLE;
let P = ExtendedPoint::from(B * &Scalar::from_u64(83973422));
let s = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
@ -1014,7 +997,7 @@ mod bench {
}
#[bench]
fn ten_fold_scalar_mult(b: &mut Bencher) {
fn ten_fold_scalar_mul(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();
@ -1022,7 +1005,7 @@ mod bench {
let B = &constants::ED25519_BASEPOINT_TABLE;
let points: Vec<_> = scalars.iter().map(|s| B * s).collect();
b.iter(|| multiscalar_mult(&scalars, &points));
b.iter(|| multiscalar_mul(&scalars, &points));
}
mod vartime {
@ -1030,18 +1013,18 @@ mod bench {
use super::{constants, Bencher, OsRng};
#[bench]
fn double_scalar_mult(b: &mut Bencher) {
fn double_scalar_mul(b: &mut Bencher) {
let mut csprng: OsRng = OsRng::new().unwrap();
// Create 2 random scalars
let s1 = Scalar::random(&mut csprng);
let s2 = Scalar::random(&mut csprng);
let P = &s1 * &constants::ED25519_BASEPOINT_TABLE;
b.iter(|| vartime::double_scalar_mult_basepoint(&s2, &P, &s1) );
b.iter(|| vartime::double_scalar_mul_basepoint(&s2, &P, &s1) );
}
#[bench]
fn ten_fold_scalar_mult(b: &mut Bencher) {
fn ten_fold_scalar_mul(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();
@ -1049,7 +1032,7 @@ mod bench {
let B = &constants::ED25519_BASEPOINT_TABLE;
let points: Vec<_> = scalars.iter().map(|s| B * s).collect();
b.iter(|| vartime::multiscalar_mult(&scalars, &points));
b.iter(|| vartime::multiscalar_mul(&scalars, &points));
}
}
}

View file

@ -25,7 +25,7 @@ pub const D_LANES64: u8 = 0b11_00_00_00;
pub const ALL_LANES: u8 = A_LANES | B_LANES | C_LANES | D_LANES;
use std::ops::Mul;
use core::ops::Mul;
use stdsimd::simd::{u32x8, i32x8, u64x4};
@ -38,10 +38,11 @@ use backend::avx2::constants::{P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_16_LO, P_TIME
pub(crate) struct FieldElement32x4(pub(crate) [u32x8; 5]);
use subtle::ConditionallyAssignable;
use subtle::Choice;
impl ConditionallyAssignable for FieldElement32x4 {
fn conditional_assign(&mut self, other: &FieldElement32x4, choice: u8) {
let mask = (-(choice as i32)) as u32;
fn conditional_assign(&mut self, other: &FieldElement32x4, choice: Choice) {
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]));

View file

@ -463,18 +463,12 @@
//! `ymm16..ymm31` registers from AVX512VL), and of approximately 1.0x
//! for Ryzen (which implements AVX2 at half rate).
//!
//! When used for variable-time double-base scalar multiplication \\( aA
//! + bB \\) for fixed \\(B\\) (as in, e.g., signature verification),
//! When used for variable-time double-base scalar multiplication
//! \\( aA + bB \\) for fixed \\(B\\) (as in, e.g., signature verification),
//! this strategy provides a 1.4x speedup on Skylake-X over the same
//! operation as implemented in `ed25519-donna`, the fastest
//! production-quality Ed25519 implementation.
//!
//! (Note: since testing this, the experimental `llvm50` Rust branch
//! used to compile the experimental `stdsimd` intrinsics have fallen
//! out of sync and it is no longer possible to compile for
//! `skylake-avx512`. This is why all of this branch is part of the
//! `yolocrypto` feature, pending upstream work.)
//!
//! [sandy2x]: https://eprint.iacr.org/2015/943.pdf
//! [avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28
//! [hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf

View file

@ -46,22 +46,11 @@ pub(crate) const SQRT_M1: FieldElement32 = FieldElement32([
33281959, 41962654, 31548777, 326685, 11406482,
]);
/// In Montgomery form y² = x³+Ax²+x, Curve25519 has A=486662.
pub(crate) const MONTGOMERY_A: FieldElement32 = FieldElement32([
486662, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]);
/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.)
pub(crate) const APLUS2_OVER_FOUR: FieldElement32 = FieldElement32([
121666, 0, 0, 0, 0, 0, 0, 0, 0, 0
]);
/// `SQRT_MINUS_APLUS2` is sqrt(-486664)
pub(crate) const SQRT_MINUS_APLUS2: FieldElement32 = FieldElement32([
54885894, 25242303, 55597453, 9067496, 51808079,
33312638, 25456129, 14121551, 54921728, 3972023,
]);
/// `L` is the order of base point, i.e. 2^252 +
/// 27742317777372353535851937790883648493
pub(crate) const L: Scalar32 = Scalar32([ 0x1cf5d3ed, 0x009318d2, 0x1de73596, 0x1df3bd45,

View file

@ -22,6 +22,7 @@ use core::ops::{Mul, MulAssign};
use core::ops::Neg;
use subtle::ConditionallyAssignable;
use subtle::Choice;
/// A `FieldElement32` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
@ -219,10 +220,9 @@ impl<'a> Neg for &'a FieldElement32 {
}
impl ConditionallyAssignable for FieldElement32 {
fn conditional_assign(&mut self, f: &FieldElement32, choice: u8) {
let mask = (-(choice as i32)) as u32;
fn conditional_assign(&mut self, other: &FieldElement32, choice: Choice) {
for i in 0..10 {
self.0[i] ^= mask & (self.0[i] ^ f.0[i]);
self.0[i].conditional_assign(&other.0[i], choice);
}
}
}

View file

@ -341,6 +341,7 @@ impl Scalar32 {
/// Compute `a^2` (mod l).
#[inline(never)]
#[allow(dead_code)] // XXX we don't expose square() via the Scalar API
pub fn square(&self) -> Scalar32 {
let aa = Scalar32::montgomery_reduce(&Scalar32::square_internal(self));
Scalar32::montgomery_reduce(&Scalar32::mul_internal(&aa, &constants::RR))

View file

@ -33,15 +33,9 @@ pub(crate) const INVSQRT_A_MINUS_D: FieldElement64 = FieldElement64([
/// Precomputed value of one of the square roots of -1 (mod p)
pub(crate) const SQRT_M1: FieldElement64 = FieldElement64([1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133]);
/// In Montgomery form y² = x³+Ax²+x, Curve25519 has A=486662.
pub(crate) const MONTGOMERY_A: FieldElement64 = FieldElement64([486662, 0, 0, 0, 0]);
/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.)
pub(crate) const APLUS2_OVER_FOUR: FieldElement64 = FieldElement64([121666, 0, 0, 0, 0]);
/// `SQRT_MINUS_APLUS2` is sqrt(-486664)
pub(crate) const SQRT_MINUS_APLUS2: FieldElement64 = FieldElement64([1693982333959686, 608509411481997, 2235573344831311, 947681270984193, 266558006233600]);
/// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493
pub(crate) const L: Scalar64 = Scalar64([ 0x0002631a5cf5d3ed, 0x000dea2f79cd6581, 0x000000000014def9, 0x0000000000000000, 0x0000100000000000 ]);

View file

@ -18,6 +18,7 @@ use core::ops::{Mul, MulAssign};
use core::ops::Neg;
use subtle::ConditionallyAssignable;
use subtle::Choice;
/// A `FieldElement64` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
@ -209,10 +210,9 @@ impl<'a> Neg for &'a FieldElement64 {
}
impl ConditionallyAssignable for FieldElement64 {
fn conditional_assign(&mut self, f: &FieldElement64, choice: u8) {
let mask = (-(choice as i64)) as u64;
fn conditional_assign(&mut self, other: &FieldElement64, choice: Choice) {
for i in 0..5 {
self.0[i] ^= mask & (self.0[i] ^ f.0[i]);
self.0[i].conditional_assign(&other.0[i], choice);
}
}
}

View file

@ -270,6 +270,7 @@ impl Scalar64 {
/// Compute `a^2` (mod l)
#[inline(never)]
#[allow(dead_code)] // XXX we don't expose square() via the Scalar API
pub fn square(&self) -> Scalar64 {
let aa = Scalar64::montgomery_reduce(&Scalar64::square_internal(self));
Scalar64::montgomery_reduce(&Scalar64::mul_internal(&aa, &constants::RR))

View file

@ -105,7 +105,7 @@ mod test {
#[test]
fn test_eight_torsion() {
for i in 0..8 {
let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(3);
let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(3);
assert!(Q.is_valid());
assert!(Q.is_identity());
}
@ -114,7 +114,7 @@ mod test {
#[test]
fn test_four_torsion() {
for i in (0..8).filter(|i| i % 2 == 0) {
let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(2);
let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(2);
assert!(Q.is_valid());
assert!(Q.is_identity());
}
@ -123,36 +123,12 @@ mod test {
#[test]
fn test_two_torsion() {
for i in (0..8).filter(|i| i % 4 == 0) {
let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(1);
let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(1);
assert!(Q.is_valid());
assert!(Q.is_identity());
}
}
/// Test that the constant for sqrt(-486664) really is a square
/// root of -486664.
#[test]
#[cfg(feature="radix_51")]
fn sqrt_minus_aplus2() {
use backend::u64::field::FieldElement64;
let minus_aplus2 = -&FieldElement64([486664,0,0,0,0]);
let sqrt = constants::SQRT_MINUS_APLUS2;
let sq = &sqrt * &sqrt;
assert_eq!(sq, minus_aplus2);
}
/// Test that the constant for sqrt(-486664) really is a square
/// root of -486664.
#[test]
#[cfg(not(feature="radix_51"))]
fn sqrt_minus_aplus2() {
use backend::u32::field::FieldElement32;
let minus_aplus2 = -&FieldElement32([486664,0,0,0,0,0,0,0,0,0]);
let sqrt = constants::SQRT_MINUS_APLUS2;
let sq = &sqrt * &sqrt;
assert_eq!(sq, minus_aplus2);
}
#[test]
/// Test that SQRT_M1 is a square root of -1
fn test_sqrt_minus_one() {
@ -165,7 +141,7 @@ mod test {
fn test_sqrt_constants_sign() {
let minus_one = FieldElement::minus_one();
let (was_nonzero_square, invsqrt_m1) = minus_one.invsqrt();
assert_eq!(was_nonzero_square, 1u8);
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?

View file

@ -126,11 +126,13 @@
use core::fmt::Debug;
use core::ops::{Add, Sub, Neg};
use subtle::ConditionallyAssignable;
use subtle::Choice;
use constants;
use field::FieldElement;
use edwards::EdwardsPoint;
use subtle::ConditionallyAssignable;
use traits::ValidityCheck;
pub mod window;
@ -275,7 +277,7 @@ impl ValidityCheck for ProjectivePoint {
// ------------------------------------------------------------------------
impl ConditionallyAssignable for ProjectiveNielsPoint {
fn conditional_assign(&mut self, other: &ProjectiveNielsPoint, choice: u8) {
fn conditional_assign(&mut self, other: &ProjectiveNielsPoint, 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);
@ -284,7 +286,7 @@ impl ConditionallyAssignable for ProjectiveNielsPoint {
}
impl ConditionallyAssignable for AffineNielsPoint {
fn conditional_assign(&mut self, other: &AffineNielsPoint, choice: u8) {
fn conditional_assign(&mut self, other: &AffineNielsPoint, choice: Choice) {
// PreComputedGroupElementCMove()
self.y_plus_x.conditional_assign(&other.y_plus_x, choice);
self.y_minus_x.conditional_assign(&other.y_minus_x, choice);

View file

@ -14,9 +14,10 @@
use core::fmt::Debug;
use subtle;
use subtle::ConditionallyNegatable;
use subtle::ConditionallyAssignable;
use subtle::ConstantTimeEq;
use subtle::Choice;
use traits::Identity;
@ -67,12 +68,12 @@ where T: Identity + ConditionallyAssignable + ConditionallyNegatable
let mut t = T::identity();
for j in 1..9 {
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
t.conditional_assign(&self.0[j-1],
subtle::bytes_equal(xabs as u8, j as u8));
let c = (xabs as u8).ct_eq(&(j as u8));
t.conditional_assign(&self.0[j-1], c);
}
// Now t == |x| * P.
let neg_mask = (xmask & 1) as u8;
let neg_mask = Choice::from((xmask & 1) as u8);
t.conditional_negate(neg_mask);
// Now t == x * P.

View file

@ -17,9 +17,9 @@
//!
//! ## Equality Testing
//!
//! The `EdwardsPoint` struct implements the `subtle::Equal` trait for
//! constant-time equality checking, and the Rust `Eq` trait for
//! variable-time equality checking.
//! The `EdwardsPoint` struct implements the `subtle::ConstantTimeEq`
//! trait for constant-time equality checking, and the Rust `Eq` trait
//! for variable-time equality checking.
//!
//! ## Cofactor-related functions
//!
@ -37,7 +37,7 @@
//! To test if a point is in \\( \mathcal E[\ell] \\), use
//! `EdwardsPoint::is_torsion_free()`.
//!
//! To multiply by the cofactor, use `EdwardsPoint::mult_by_cofactor()`.
//! To multiply by the cofactor, use `EdwardsPoint::mul_by_cofactor()`.
//!
//! To avoid dealing with cofactors entirely, consider using Ristretto.
//!
@ -57,10 +57,10 @@
//! `EdwardsBasepointTable`, which performs constant-time fixed-base
//! scalar multiplication;
//!
//! * the `edwards::multiscalar_mult` function, which performs
//! * the `edwards::multiscalar_mul` function, which performs
//! constant-time variable-base multiscalar multiplication;
//!
//! * the `edwards::vartime::multiscalar_mult` function, which
//! * the `edwards::vartime::multiscalar_mul` function, which
//! performs variable-time variable-base multiscalar multiplication.
//!
//! ## Implementation
@ -68,7 +68,8 @@
//! 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 of the internal documentation.
//! see the [`curve_models` submodule][curve_models]
//! of the internal documentation.
//!
//! ## Validity Checking
//!
@ -80,6 +81,8 @@
//! unrepresentable: `EdwardsPoint` objects can only be created via
//! successful decompression of a compressed point, or else by
//! operations on other (valid) `EdwardsPoint`s.
//!
//! [curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/curve_models/index.html
// We allow non snake_case names because coordinates in projective space are
// traditionally denoted by the capitalisation of their respective
@ -96,12 +99,12 @@ use core::ops::{Add, Sub, Neg};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::Index;
use core::borrow::Borrow;
use subtle::slices_equal;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
// XXX subtle::Equal
use subtle::Equal;
use subtle::Choice;
use subtle::ConstantTimeEq;
use constants;
@ -160,11 +163,12 @@ impl CompressedEdwardsY {
let v = &(&YY * &constants::EDWARDS_D) + &Z; // v = dy²+1
let (is_nonzero_square, mut X) = FieldElement::sqrt_ratio(&u, &v);
if is_nonzero_square != 1u8 { return None; }
if is_nonzero_square.unwrap_u8() != 1u8 { return None; }
// Flip the sign of X if it's not correct
let compressed_sign_bit = self.as_bytes()[31] >> 7;
let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7);
let current_sign_bit = X.is_negative();
X.conditional_negate(current_sign_bit ^ compressed_sign_bit);
Some(EdwardsPoint{ X: X, Y: Y, Z: Z, T: &X * &Y })
@ -278,7 +282,7 @@ impl ValidityCheck for EdwardsPoint {
// ------------------------------------------------------------------------
impl ConditionallyAssignable for EdwardsPoint {
fn conditional_assign(&mut self, other: &EdwardsPoint, choice: u8) {
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);
@ -290,16 +294,15 @@ impl ConditionallyAssignable for EdwardsPoint {
// Equality
// ------------------------------------------------------------------------
impl Equal for EdwardsPoint {
fn ct_eq(&self, other: &EdwardsPoint) -> u8 {
slices_equal(self.compress().as_bytes(),
other.compress().as_bytes())
impl ConstantTimeEq for EdwardsPoint {
fn ct_eq(&self, other: &EdwardsPoint) -> Choice {
self.compress().as_bytes().ct_eq(other.compress().as_bytes())
}
}
impl PartialEq for EdwardsPoint {
fn eq(&self, other: &EdwardsPoint) -> bool {
self.ct_eq(other) == 1u8
self.ct_eq(other).unwrap_u8() == 1u8
}
}
@ -370,8 +373,8 @@ impl EdwardsPoint {
let y = &self.Y * &recip;
let mut s: [u8; 32];
s = y.to_bytes();
s[31] ^= (x.is_negative() << 7) as u8;
s = y.to_bytes();
s[31] ^= x.is_negative().unwrap_u8() << 7;
CompressedEdwardsY(s)
}
}
@ -501,7 +504,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint {
let mut Q = EdwardsPoint::identity();
for i in (0..64).rev() {
// Q <-- 16*Q
Q = Q.mult_by_pow_2(4);
Q = Q.mul_by_pow_2(4);
// Q <-- Q + P * s_i
Q = (&Q + &lookup_table.select(scalar_digits[i])).to_extended()
}
@ -530,25 +533,57 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar {
/// $$
///
/// This function has the same behaviour as
/// `vartime::multiscalar_mult` but is constant-time.
/// `vartime::multiscalar_mul` but is constant-time.
///
/// # Input
/// It is an error to call this function with two iterators of different lengths.
///
/// A iterable of `Scalar`s and a iterable of `EdwardsPoints`. It is an
/// error to call this function with two iterators of different lengths.
/// # Examples
///
/// The trait bound aims for maximum flexibility: the inputs must be
/// convertable to iterators (`I: IntoIter`), and the iterator's items
/// must be `Borrow<Scalar>` (or `Borrow<EdwardsPoint>`), to allow
/// iterators returning either `Scalar`s or `&Scalar`s.
///
/// ```
/// use curve25519_dalek::{constants, edwards};
/// use curve25519_dalek::scalar::Scalar;
///
/// // Some scalars
/// let a = Scalar::from_u64(87329482);
/// let b = Scalar::from_u64(37264829);
/// let c = Scalar::from_u64(98098098);
///
/// // Some points
/// let P = constants::ED25519_BASEPOINT_POINT;
/// let Q = P + P;
/// let R = P + Q;
///
/// // A1 = a*P + b*Q + c*R
/// let abc = [a,b,c];
/// let A1 = edwards::multiscalar_mul(&abc, &[P,Q,R]);
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
///
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
/// let minus_abc = abc.iter().map(|x| -x);
/// let A2 = edwards::multiscalar_mul(minus_abc, &[P,Q,R]);
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
///
/// assert_eq!(A1.compress(), (-A2).compress());
/// ```
// XXX later when we do more fancy multiscalar mults, we can delegate
// based on the iter's size hint -- hdevalence
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b EdwardsPoint>
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
where I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator,
J::Item: Borrow<EdwardsPoint>,
{
// If we built with AVX2, use the AVX2 backend.
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
use backend::avx2::edwards as edwards_avx2;
edwards_avx2::multiscalar_mult(scalars, points)
edwards_avx2::multiscalar_mul(scalars, points)
}
// Otherwise, proceed as normal:
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] {
@ -557,7 +592,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
use clear_on_drop::ClearOnDrop;
let lookup_tables_vec: Vec<_> = points.into_iter()
.map(|P| LookupTable::<ProjectiveNielsPoint>::from(P) )
.map(|P| LookupTable::<ProjectiveNielsPoint>::from(P.borrow()) )
.collect();
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
@ -568,7 +603,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
//
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
let scalar_digits_vec: Vec<_> = scalars.into_iter()
.map(|c| c.to_radix_16())
.map(|c| c.borrow().to_radix_16())
.collect();
// This above puts the scalar digits into a heap-allocated Vec.
@ -598,7 +633,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
let mut Q = EdwardsPoint::identity();
// XXX this impl makes no effort to be cache-aware; maybe it could be improved?
for j in (0..64).rev() {
Q = Q.mult_by_pow_2(4);
Q = Q.mul_by_pow_2(4);
let it = scalar_digits.iter().zip(lookup_tables.iter());
for (s_i, lookup_table_i) in it {
// R_i = s_{i,j} * P_i
@ -658,7 +693,7 @@ impl EdwardsBasepointTable {
P = (&P + &tables[i/2].select(a[i])).to_extended();
}
P = P.mult_by_pow_2(4);
P = P.mul_by_pow_2(4);
for i in (0..64).filter(|x| x % 2 == 0) {
P = (&P + &tables[i/2].select(a[i])).to_extended();
@ -698,7 +733,7 @@ impl EdwardsBasepointTable {
for i in 0..32 {
// P = (16^2)^i * B
table.0[i] = LookupTable::from(&P);
P = P.mult_by_pow_2(8);
P = P.mul_by_pow_2(8);
}
table
}
@ -715,12 +750,12 @@ impl EdwardsBasepointTable {
impl EdwardsPoint {
/// Multiply by the cofactor: return \\([8]P\\).
pub fn mult_by_cofactor(&self) -> EdwardsPoint {
self.mult_by_pow_2(3)
pub fn mul_by_cofactor(&self) -> EdwardsPoint {
self.mul_by_pow_2(3)
}
/// Compute \\([2\^k] P \\) by successive doublings. Requires \\( k > 0 \\).
pub(crate) fn mult_by_pow_2(&self, k: u32) -> EdwardsPoint {
pub(crate) fn mul_by_pow_2(&self, k: u32) -> EdwardsPoint {
debug_assert!( k > 0 );
let mut r: CompletedPoint;
let mut s = self.to_projective();
@ -755,7 +790,7 @@ impl EdwardsPoint {
/// assert_eq!(Q.is_small_order(), true);
/// ```
pub fn is_small_order(&self) -> bool {
self.mult_by_cofactor().is_identity()
self.mul_by_cofactor().is_identity()
}
/// Determine if this point is “torsion-free”, i.e., is contained in
@ -789,31 +824,6 @@ impl EdwardsPoint {
}
}
// ------------------------------------------------------------------------
// Elligator2 (uniform encoding/decoding of curve points)
// ------------------------------------------------------------------------
// XXX should this be in another module, with types and `From` impls, like `CompressedEdwardsY`?
impl EdwardsPoint {
/// Use Elligator2 to try to convert `self` to a uniformly random
/// string.
///
/// Returns `Some<[u8;32]>` if `self` is in the image of the
/// Elligator2 map. For a random point on the curve, this happens
/// with probability 1/2. Otherwise, returns `None`.
fn to_uniform_representative(&self) -> Option<[u8; 32]> {
unimplemented!();
}
/// Use Elligator2 to convert a uniformly random string to a curve
/// point.
#[allow(unused_variables)] // REMOVE WHEN IMPLEMENTED
fn from_uniform_representative(bytes: &[u8; 32]) -> EdwardsPoint {
unimplemented!();
}
}
// ------------------------------------------------------------------------
// Debug traits
// ------------------------------------------------------------------------
@ -867,35 +877,72 @@ pub mod vartime {
}
}
/// Given an iterable of public scalars and an iterable of public
/// points, compute
/// Given an iterator of public scalars and an iterator of public points, compute
/// $$
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
/// $$
///
/// # Input
/// This function has the same behaviour as
/// `edwards::multiscalar_mul` but operates on non-secret data.
///
/// A iterable of `Scalar`s and a iterable of `EdwardsPoints`. It is an
/// error to call this function with two iterators of different lengths.
/// It is an error to call this function with two iterators of different lengths.
///
/// # Examples
///
/// The trait bound aims for maximum flexibility: the inputs must be
/// convertable to iterators (`I: IntoIter`), and the iterator's items
/// must be `Borrow<Scalar>` (or `Borrow<EdwardsPoint>`), to allow
/// iterators returning either `Scalar`s or `&Scalar`s.
///
/// ```
/// use curve25519_dalek::{constants, edwards};
/// use curve25519_dalek::scalar::Scalar;
///
/// // Some scalars
/// let a = Scalar::from_u64(87329482);
/// let b = Scalar::from_u64(37264829);
/// let c = Scalar::from_u64(98098098);
///
/// // Some points
/// let P = constants::ED25519_BASEPOINT_POINT;
/// let Q = P + P;
/// let R = P + Q;
///
/// // A1 = a*P + b*Q + c*R
/// let abc = [a,b,c];
/// let A1 = edwards::vartime::multiscalar_mul(&abc, &[P,Q,R]);
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
///
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
/// let minus_abc = abc.iter().map(|x| -x);
/// let A2 = edwards::vartime::multiscalar_mul(minus_abc, &[P,Q,R]);
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
///
/// assert_eq!(A1.compress(), (-A2).compress());
/// ```
// XXX later when we do more fancy multiscalar mults, we can delegate
// based on the iter's size hint -- hdevalence
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b EdwardsPoint>
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
where I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator,
J::Item: Borrow<EdwardsPoint>,
{
// If we built with AVX2, use the AVX2 backend.
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
use backend::avx2::edwards as edwards_avx2;
edwards_avx2::vartime::multiscalar_mult(scalars, points)
edwards_avx2::vartime::multiscalar_mul(scalars, points)
}
// Otherwise, proceed as normal:
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] {
//assert_eq!(scalars.len(), points.len());
let nafs: Vec<_> = scalars.into_iter()
.map(|c| c.non_adjacent_form()).collect();
.map(|c| c.borrow().non_adjacent_form()).collect();
let odd_multiples: Vec<_> = points.into_iter()
.map(|P| OddMultiples::create(P)).collect();
.map(|P| OddMultiples::create(P.borrow())).collect();
let mut r = ProjectivePoint::identity();
@ -921,7 +968,7 @@ pub mod vartime {
/// \\(aA+bB\\), where \\(B\\) is the Ed25519 basepoint (i.e., \\(B = (x,4/5)\\)
/// with x positive).
#[cfg(feature="precomputed_tables")]
pub fn double_scalar_mult_basepoint(
pub fn double_scalar_mul_basepoint(
a: &Scalar,
A: &EdwardsPoint,
b: &Scalar,
@ -930,7 +977,7 @@ pub mod vartime {
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
use backend::avx2::edwards as edwards_avx2;
edwards_avx2::vartime::double_scalar_mult_basepoint(a, A, b)
edwards_avx2::vartime::double_scalar_mul_basepoint(a, A, b)
}
// Otherwise, proceed as normal:
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] {
@ -1130,7 +1177,7 @@ mod test {
Z: FieldElement::from_bytes(&two_bytes),
T: FieldElement::zero()
};
assert!(id1.ct_eq(&id2) == 1u8);
assert_eq!(id1.ct_eq(&id2).unwrap_u8(), 1u8);
}
/// Sanity check for conversion to precomputed points
@ -1172,9 +1219,9 @@ mod test {
assert_eq!(aB_1.compress(), aB_2.compress());
}
/// Test scalar_mult versus a known scalar multiple from ed25519.py
/// Test scalar_mul versus a known scalar multiple from ed25519.py
#[test]
fn scalar_mult_vs_ed25519py() {
fn scalar_mul_vs_ed25519py() {
let aB = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR;
assert_eq!(aB.compress(), A_TIMES_BASEPOINT);
}
@ -1203,10 +1250,10 @@ mod test {
constants::ED25519_BASEPOINT_COMPRESSED);
}
/// Test computing 16*basepoint vs mult_by_pow_2(4)
/// Test computing 16*basepoint vs mul_by_pow_2(4)
#[test]
fn basepoint16_vs_mult_by_pow_2_4() {
let bp16 = constants::ED25519_BASEPOINT_POINT.mult_by_pow_2(4);
fn basepoint16_vs_mul_by_pow_2_4() {
let bp16 = constants::ED25519_BASEPOINT_POINT.mul_by_pow_2(4);
assert_eq!(bp16.compress(), BASE16_CMPRSSD);
}
@ -1217,9 +1264,9 @@ mod test {
let mut p1 = AffineNielsPoint::identity();
let bp = constants::ED25519_BASEPOINT_POINT.to_affine_niels();
p1.conditional_assign(&bp, 0);
p1.conditional_assign(&bp, Choice::from(0));
assert_eq!(p1, id);
p1.conditional_assign(&bp, 1);
p1.conditional_assign(&bp, Choice::from(1));
assert_eq!(p1, bp);
}
@ -1258,7 +1305,7 @@ mod test {
#[test]
fn monte_carlo_overflow_underflow_debug_assert_test() {
let mut P = constants::ED25519_BASEPOINT_POINT;
// N.B. each scalar_mult does 1407 field mults, 1024 field squarings,
// N.B. each scalar_mul does 1407 field mults, 1024 field squarings,
// so this does ~ 1M of each operation.
for _ in 0..1_000 {
P *= &A_SCALAR;
@ -1280,19 +1327,19 @@ mod test {
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 double_scalar_mul_vartime vs ed25519.py
#[test]
#[cfg(feature="precomputed_tables")]
fn double_scalar_mult_basepoint_vs_ed25519py() {
fn double_scalar_mul_basepoint_vs_ed25519py() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR);
let result = vartime::double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR);
assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT);
}
#[test]
fn multiscalar_mult_vs_ed25519py() {
fn multiscalar_mul_vs_ed25519py() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = vartime::multiscalar_mult(
let result = vartime::multiscalar_mul(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT_POINT]
);
@ -1300,13 +1347,13 @@ mod test {
}
#[test]
fn multiscalar_mult_vartime_vs_consttime() {
fn multiscalar_mul_vartime_vs_consttime() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result_vartime = vartime::multiscalar_mult(
let result_vartime = vartime::multiscalar_mul(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT_POINT]
);
let result_consttime = multiscalar_mult(
let result_consttime = multiscalar_mul(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT_POINT]
);
@ -1370,7 +1417,7 @@ mod bench {
}
#[bench]
fn scalar_mult(b: &mut Bencher) {
fn scalar_mul(b: &mut Bencher) {
let B = &constants::ED25519_BASEPOINT_POINT;
b.iter(|| B * &A_SCALAR);
}
@ -1430,10 +1477,10 @@ mod bench {
}
#[bench]
fn mult_by_cofactor(b: &mut Bencher) {
fn mul_by_cofactor(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT_POINT;
b.iter(|| p1.mult_by_cofactor());
b.iter(|| p1.mul_by_cofactor());
}
#[bench]
@ -1445,7 +1492,7 @@ mod bench {
#[bench]
#[cfg(feature="precomputed_tables")]
fn ten_fold_scalar_mult(b: &mut Bencher) {
fn ten_fold_scalar_mul(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();
@ -1453,7 +1500,7 @@ mod bench {
let B = &constants::ED25519_BASEPOINT_TABLE;
let points: Vec<_> = scalars.iter().map(|s| B * &s).collect();
b.iter(|| multiscalar_mult(&scalars, &points));
b.iter(|| multiscalar_mul(&scalars, &points));
}
mod vartime {
@ -1462,14 +1509,14 @@ mod bench {
use super::{Bencher, OsRng};
#[bench]
fn bench_double_scalar_mult_basepoint(b: &mut Bencher) {
fn bench_double_scalar_mul_basepoint(b: &mut Bencher) {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
b.iter(|| vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR));
b.iter(|| vartime::double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR));
}
#[bench]
#[cfg(feature="precomputed_tables")]
fn ten_fold_scalar_mult(b: &mut Bencher) {
fn ten_fold_scalar_mul(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();
@ -1483,7 +1530,7 @@ mod bench {
//
// Since this is a variable-time function, this means the
// benchmark is only useful as a ballpark measurement.
b.iter(|| vartime::multiscalar_mult(&scalars, &points));
b.iter(|| vartime::multiscalar_mul(&scalars, &points));
}
}
}

View file

@ -24,11 +24,10 @@
use core::cmp::{Eq, PartialEq};
use subtle::slices_equal;
use subtle::byte_is_nonzero;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
use subtle::Equal;
use subtle::Choice;
use subtle::ConstantTimeEq;
use constants;
use backend;
@ -54,37 +53,19 @@ pub use backend::u32::field::*;
pub type FieldElement = backend::u32::field::FieldElement32;
impl Eq for FieldElement {}
impl PartialEq for FieldElement {
/// Test equality between two `FieldElement`s. Since the
/// internal representation is not canonical, the field elements
/// are normalized to wire format before comparison.
///
/// # Warning
///
/// This comparison is *not* constant time. It could easily be
/// made to be, but the main use of an `Eq` implementation is for
/// branching, so it seems pointless to do so.
fn eq(&self, other: &FieldElement) -> bool {
let self_bytes = self.to_bytes();
let other_bytes = other.to_bytes();
let mut are_equal: bool = true;
for i in 0..32 {
are_equal &= self_bytes[i] == other_bytes[i];
}
are_equal
self.ct_eq(other).unwrap_u8() == 1u8
}
}
impl Equal for FieldElement {
impl ConstantTimeEq for FieldElement {
/// Test equality between two `FieldElement`s. Since the
/// internal representation is not canonical, the field elements
/// are normalized to wire format before comparison.
///
/// # Returns
///
/// `1u8` if the two `FieldElement`s are equal, and `0u8` otherwise.
fn ct_eq(&self, other: &FieldElement) -> u8 {
slices_equal(&self.to_bytes(), &other.to_bytes())
fn ct_eq(&self, other: &FieldElement) -> Choice {
self.to_bytes().ct_eq(&other.to_bytes())
}
}
@ -95,33 +76,22 @@ impl FieldElement {
///
/// # Return
///
/// If negative, return `1u8`. Otherwise, return `0u8`.
pub fn is_negative(&self) -> u8 {
/// If negative, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_negative(&self) -> Choice {
let bytes = self.to_bytes();
(bytes[0] & 1) as u8
(bytes[0] & 1).into()
}
/// Determine if this `FieldElement` is zero.
///
/// # Return
///
/// If zero, return `1u8`. Otherwise, return `0u8`.
pub fn is_zero(&self) -> u8 {
1u8 & (!self.is_nonzero())
}
/// Determine if this `FieldElement` is non-zero.
///
/// # Return
///
/// If non-zero, return `1u8`. Otherwise, return `0u8`.
pub fn is_nonzero(&self) -> u8 { //FeIsNonZero
/// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`.
pub fn is_zero(&self) -> Choice {
let zero = [0u8; 32];
let bytes = self.to_bytes();
let mut x = 0u8;
for b in &bytes {
x |= *b;
}
byte_is_nonzero(x)
bytes.ct_eq(&zero)
}
/// Compute (self^(2^250-1), self^11), used as a helper function
@ -275,7 +245,25 @@ impl FieldElement {
/// - `(0u8, zero)` if `v` is zero;
/// - `(0u8, garbage)` if `u/v` is nonsquare.
///
pub fn sqrt_ratio(u: &FieldElement, v: &FieldElement) -> (u8, FieldElement) {
/// # 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) {
// Using the same trick as in ed25519 decoding, we merge the
// inversion, the square root, and the square test as follows.
//
@ -333,7 +321,7 @@ impl FieldElement {
/// - `(0u8, zero)` if `self` is zero;
/// - `(0u8, garbage)` if `self` is nonsquare.
///
pub fn invsqrt(&self) -> (u8, FieldElement) {
pub fn invsqrt(&self) -> (Choice, FieldElement) {
FieldElement::sqrt_ratio(&FieldElement::one(), self)
}
@ -487,11 +475,11 @@ mod test {
let one = FieldElement::one();
let minus_one = FieldElement::minus_one();
let mut x = one;
x.conditional_negate(1u8);
x.conditional_negate(Choice::from(1));
assert_eq!(x, minus_one);
x.conditional_negate(0u8);
x.conditional_negate(Choice::from(0));
assert_eq!(x, minus_one);
x.conditional_negate(1u8);
x.conditional_negate(Choice::from(1));
assert_eq!(x, one);
}

View file

@ -24,7 +24,7 @@
#![cfg_attr(feature = "nightly", deny(missing_docs))]
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#![doc(html_logo_url = "https://github.com/dalek-cryptography/curve25519-dalek/blob/develop/dalek-logo-clear.png?raw=true")]
#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
//------------------------------------------------------------------------
// External dependencies:

View file

@ -50,18 +50,17 @@
use core::ops::{Mul, MulAssign};
use constants;
use constants::APLUS2_OVER_FOUR;
use field::FieldElement;
use edwards::{EdwardsPoint, CompressedEdwardsY};
use scalar::Scalar;
use traits::{Identity, ValidityCheck};
use traits::Identity;
use subtle::ConditionallyAssignable;
use subtle::ConditionallySwappable;
use subtle::Equal;
use subtle::Mask;
use subtle::ConstantTimeEq;
use subtle::Choice;
/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of
/// Curve25519 or its twist.
@ -69,8 +68,8 @@ use subtle::Mask;
pub struct MontgomeryPoint(pub [u8; 32]);
/// Equality of `MontgomeryPoint`s is defined mod p.
impl Equal for MontgomeryPoint {
fn ct_eq(&self, other: &MontgomeryPoint) -> u8 {
impl ConstantTimeEq for MontgomeryPoint {
fn ct_eq(&self, other: &MontgomeryPoint) -> Choice {
let self_fe = FieldElement::from_bytes(&self.0);
let other_fe = FieldElement::from_bytes(&other.0);
@ -80,7 +79,7 @@ impl Equal for MontgomeryPoint {
impl PartialEq for MontgomeryPoint {
fn eq(&self, other: &MontgomeryPoint) -> bool {
self.ct_eq(other) == 1u8
self.ct_eq(other).unwrap_u8() == 1u8
}
}
@ -157,7 +156,7 @@ impl Identity for ProjectivePoint {
}
impl ConditionallyAssignable for ProjectivePoint {
fn conditional_assign(&mut self, that: &ProjectivePoint, choice: Mask) {
fn conditional_assign(&mut self, that: &ProjectivePoint, choice: Choice) {
self.U.conditional_assign(&that.U, choice);
self.W.conditional_assign(&that.W, choice);
}
@ -244,14 +243,14 @@ impl Mul<Scalar> for MontgomeryPoint {
let bits: [i8; 256] = scalar.bits();
for i in (0..255).rev() {
let mask: u8 = (bits[i+1] ^ bits[i]) as u8;
let choice: u8 = (bits[i+1] ^ bits[i]) as u8;
debug_assert!(mask == 0 || mask == 1);
debug_assert!(choice == 0 || choice == 1);
x0.conditional_swap(&mut x1, mask);
x0.conditional_swap(&mut x1, choice.into());
differential_add_and_double(&mut x0, &mut x1, &affine_u);
}
x0.conditional_swap(&mut x1, bits[0] as u8);
x0.conditional_swap(&mut x1, Choice::from(bits[0] as u8));
x0.to_affine()
}
@ -277,8 +276,7 @@ impl Mul<MontgomeryPoint> for Scalar {
#[cfg(test)]
mod test {
use constants::X25519_BASEPOINT;
use traits::Identity;
use constants;
use super::*;
use rand::OsRng;

View file

@ -57,9 +57,10 @@
//! checking in the Ristretto group can be done in projective
//! coordinates without requiring an inversion, so it is much faster.
//!
//! The `RistrettoPoint` struct implements the `subtle::Equal` trait for
//! constant-time equality checking, and the Rust `Eq` trait for
//! variable-time equality checking.
//! The `RistrettoPoint` struct implements the
//! `subtle::ConstantTimeEq` trait for constant-time equality
//! checking, and the Rust `Eq` trait for variable-time equality
//! checking.
//!
//! ## Scalars
//!
@ -78,10 +79,10 @@
//! `RistrettoBasepointTable`, which performs constant-time fixed-base
//! scalar multiplication;
//!
//! * the `ristretto::multiscalar_mult` function, which performs
//! * the `ristretto::multiscalar_mul` function, which performs
//! constant-time variable-base multiscalar multiplication;
//!
//! * the `ristretto::vartime::multiscalar_mult` function, which
//! * the `ristretto::vartime::multiscalar_mul` function, which
//! performs variable-time variable-base multiscalar multiplication.
//!
//! ## Random Points and Hashing to Ristretto
@ -129,7 +130,7 @@
//! gives the _Ristretto_ encoding.
//!
//! Notes on the details of the encoding can be found in the
//! `ristretto::notes` submodule of the internal `curve25519-dalek`
//! [`ristretto::notes`][ristretto_notes] submodule of the internal `curve25519-dalek`
//! documentation.
//!
//! [cryptonote]:
@ -138,6 +139,8 @@
//! https://moderncrypto.org/mail-archive/curves/2017/000858.html
//! [ristretto_coffee]:
//! https://en.wikipedia.org/wiki/Ristretto
//! [ristretto_notes]:
//! https://doc-internal.dalek.rs/curve25519_dalek/ristretto/notes/index.html
mod notes {
@ -463,24 +466,24 @@ mod notes {
}
use core::fmt::Debug;
use core::ops::{Add, Sub, Neg};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use core::borrow::Borrow;
#[cfg(feature = "std")]
use rand::Rng;
use digest::Digest;
use generic_array::typenum::U32;
use generic_array::typenum::U64;
use constants;
use field::FieldElement;
use core::ops::{Add, Sub, Neg};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use subtle;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
use subtle::Equal;
use subtle::ConstantTimeEq;
use subtle::Choice;
use edwards;
use edwards::EdwardsPoint;
@ -536,10 +539,10 @@ impl CompressedRistretto {
let s = FieldElement::from_bytes(self.as_bytes());
let s_bytes_check = s.to_bytes();
let s_encoding_is_canonical =
subtle::slices_equal(&s_bytes_check[..], self.as_bytes());
&s_bytes_check[..].ct_eq(self.as_bytes());
let s_is_negative = s.is_negative();
if s_encoding_is_canonical == 0u8 || s_is_negative == 1u8 {
if s_encoding_is_canonical.unwrap_u8() == 0u8 || s_is_negative.unwrap_u8() == 1u8 {
return None;
}
@ -563,7 +566,7 @@ impl CompressedRistretto {
let t = &x * &y;
if ok == 0u8 || t.is_negative() == 1u8 || y.is_zero() == 1u8 {
if ok.unwrap_u8() == 0u8 || t.is_negative().unwrap_u8() == 1u8 || y.is_zero().unwrap_u8() == 1u8 {
return None;
} else {
return Some(RistrettoPoint(EdwardsPoint{X: x, Y: y, Z: one, T: t}));
@ -813,7 +816,7 @@ impl RistrettoPoint {
///
/// This method is not public because it's just used for hashing
/// to a point -- proper elligator support is deferred for now.
pub(crate) fn elligator_ristretto_flavour(r_0: &FieldElement) -> RistrettoPoint {
pub(crate) fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint {
let (i, d) = (&constants::SQRT_M1, &constants::EDWARDS_D);
let one = FieldElement::one();
@ -837,7 +840,7 @@ impl RistrettoPoint {
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, 1u8);
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);
@ -868,27 +871,40 @@ impl RistrettoPoint {
///
/// # Implementation
///
/// Uses the Ristretto-flavoured Elligator 2 map, so that the discrete log of the
/// output point with respect to any other point should be unknown.
/// Uses the Ristretto-flavoured Elligator 2 map, so that the
/// discrete log of the output point with respect to any other
/// point should be unknown. The map is applied twice and the
/// results are added, to ensure a uniform distribution.
#[cfg(feature = "std")]
pub fn random<T: Rng>(rng: &mut T) -> Self {
let mut field_bytes = [0u8; 32];
rng.fill_bytes(&mut field_bytes);
let r_0 = FieldElement::from_bytes(&field_bytes);
RistrettoPoint::elligator_ristretto_flavour(&r_0)
let r_1 = FieldElement::from_bytes(&field_bytes);
let R_1 = RistrettoPoint::elligator_ristretto_flavor(&r_1);
rng.fill_bytes(&mut field_bytes);
let r_2 = FieldElement::from_bytes(&field_bytes);
let R_2 = RistrettoPoint::elligator_ristretto_flavor(&r_2);
// Applying Elligator twice and adding the results ensures a
// uniform distribution.
&R_1 + &R_2
}
/// Hash a slice of bytes into a `RistrettoPoint`.
///
/// Takes a type parameter `D`, which is any `Digest` producing 32
/// bytes (256 bits) of output.
/// Takes a type parameter `D`, which is any `Digest` producing 64
/// bytes of output.
///
/// Convenience wrapper around `from_hash`.
///
/// # Implementation
///
/// Uses the Ristretto-flavoured Elligator 2 map, so that the discrete log of the
/// output point with respect to any other point should be unknown.
/// Uses the Ristretto-flavoured Elligator 2 map, so that the
/// discrete log of the output point with respect to any other
/// point should be unknown. The map is applied twice and the
/// results are added, to ensure a uniform distribution.
///
/// # Example
///
@ -896,18 +912,18 @@ impl RistrettoPoint {
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::ristretto::RistrettoPoint;
/// extern crate sha2;
/// use sha2::Sha256;
/// use sha2::Sha512;
///
/// # // Need fn main() here in comment so the doctest compiles
/// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
/// # fn main() {
/// let msg = "To really appreciate architecture, you may even need to commit a murder";
/// let P = RistrettoPoint::hash_from_bytes::<Sha256>(msg.as_bytes());
/// let P = RistrettoPoint::hash_from_bytes::<Sha512>(msg.as_bytes());
/// # }
/// ```
///
pub fn hash_from_bytes<D>(input: &[u8]) -> RistrettoPoint
where D: Digest<OutputSize = U32> + Default
where D: Digest<OutputSize = U64> + Default
{
let mut hash = D::default();
hash.input(input);
@ -920,13 +936,24 @@ impl RistrettoPoint {
/// to stream data into the `Digest` than to pass a single byte
/// slice.
pub fn from_hash<D>(hash: D) -> RistrettoPoint
where D: Digest<OutputSize = U32> + Default
where D: Digest<OutputSize = U64> + Default
{
// XXX this seems clumsy
let mut output = [0u8; 32];
output.copy_from_slice(hash.result().as_slice());
let r_0 = FieldElement::from_bytes(&output);
RistrettoPoint::elligator_ristretto_flavour(&r_0)
// dealing with generic arrays is clumsy, until const generics land
let output = hash.result();
let mut r_1_bytes = [0u8; 32];
r_1_bytes.copy_from_slice(&output.as_slice()[0..32]);
let r_1 = FieldElement::from_bytes(&r_1_bytes);
let R_1 = RistrettoPoint::elligator_ristretto_flavor(&r_1);
let mut r_2_bytes = [0u8; 32];
r_2_bytes.copy_from_slice(&output.as_slice()[0..32]);
let r_2 = FieldElement::from_bytes(&r_2_bytes);
let R_2 = RistrettoPoint::elligator_ristretto_flavor(&r_2);
// Applying Elligator twice and adding the results ensures a
// uniform distribution.
&R_1 + &R_2
}
}
@ -942,17 +969,18 @@ impl Identity for RistrettoPoint {
impl PartialEq for RistrettoPoint {
fn eq(&self, other: &RistrettoPoint) -> bool {
self.ct_eq(other) == 1u8
self.ct_eq(other).unwrap_u8() == 1u8
}
}
impl Equal for RistrettoPoint {
impl ConstantTimeEq for RistrettoPoint {
/// Test equality between two `RistrettoPoint`s.
///
/// # Returns
///
/// `1u8` if the two `RistrettoPoint`s are equal, and `0u8` otherwise.
fn ct_eq(&self, other: &RistrettoPoint) -> u8 {
/// * `Choice(1)` if the two `RistrettoPoint`s are equal;
/// * `Choice(0)` otherwise.
fn ct_eq(&self, other: &RistrettoPoint) -> Choice {
let X1Y2 = &self.0.X * &other.0.Y;
let Y1X2 = &self.0.Y * &other.0.X;
let X1X2 = &self.0.X * &other.0.X;
@ -1057,19 +1085,52 @@ define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint
/// $$
///
/// This function has the same behaviour as
/// `vartime::multiscalar_mult` but is constant-time.
/// `vartime::multiscalar_mul` but is constant-time.
///
/// # Input
/// It is an error to call this function with two iterators of different lengths.
///
/// An iterable of `Scalar`s and a iterable of `RistrettoPoints`. It is an
/// error to call this function with two iterators of different lengths.
/// # Examples
///
/// The trait bound aims for maximum flexibility: the inputs must be
/// convertable to iterators (`I: IntoIter`), and the iterator's items
/// must be `Borrow<Scalar>` (or `Borrow<RistrettoPoint>`), to allow
/// iterators returning either `Scalar`s or `&Scalar`s.
///
/// ```
/// use curve25519_dalek::{constants, ristretto};
/// use curve25519_dalek::scalar::Scalar;
///
/// // Some scalars
/// let a = Scalar::from_u64(87329482);
/// let b = Scalar::from_u64(37264829);
/// let c = Scalar::from_u64(98098098);
///
/// // Some points
/// let P = constants::RISTRETTO_BASEPOINT_POINT;
/// let Q = P + P;
/// let R = P + Q;
///
/// // A1 = a*P + b*Q + c*R
/// let abc = [a,b,c];
/// let A1 = ristretto::multiscalar_mul(&abc, &[P,Q,R]);
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
///
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
/// let minus_abc = abc.iter().map(|x| -x);
/// let A2 = ristretto::multiscalar_mul(minus_abc, &[P,Q,R]);
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
///
/// assert_eq!(A1.compress(), (-A2).compress());
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b RistrettoPoint>,
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
where I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator,
J::Item: Borrow<RistrettoPoint>,
{
let extended_points = points.into_iter().map(|P| &P.0);
RistrettoPoint(edwards::multiscalar_mult(scalars, extended_points))
let extended_points = points.into_iter().map(|P| P.borrow().0);
RistrettoPoint(edwards::multiscalar_mul(scalars, extended_points))
}
/// A precomputed table of multiples of a basepoint, used to accelerate
@ -1110,7 +1171,7 @@ impl RistrettoBasepointTable {
// ------------------------------------------------------------------------
impl ConditionallyAssignable for RistrettoPoint {
/// Conditionally assign `other` to `self`, if `choice == 1u8`.
/// Conditionally assign `other` to `self`, if `choice == Choice(1)`.
///
/// # Example
///
@ -1118,24 +1179,26 @@ impl ConditionallyAssignable for RistrettoPoint {
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// #
/// # use subtle::ConditionallyAssignable;
/// use subtle::ConditionallyAssignable;
/// use subtle::Choice;
/// #
/// # use curve25519_dalek::traits::Identity;
/// # use curve25519_dalek::ristretto::RistrettoPoint;
/// # use curve25519_dalek::constants;
/// # fn main() {
///
/// let A = RistrettoPoint::identity();
/// let B = constants::RISTRETTO_BASEPOINT_POINT;
///
/// let mut P = A;
///
/// P.conditional_assign(&B, 0u8);
/// assert!(P == A);
/// P.conditional_assign(&B, 1u8);
/// assert!(P == B);
/// P.conditional_assign(&B, Choice::from(0));
/// assert_eq!(P, A);
/// P.conditional_assign(&B, Choice::from(1));
/// assert_eq!(P, B);
/// # }
/// ```
fn conditional_assign(&mut self, other: &RistrettoPoint, choice: u8) {
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);
@ -1169,23 +1232,58 @@ pub mod vartime {
//! Variable-time operations on ristretto points, useful for non-secret data.
use super::*;
/// Given an iterable of public scalars and an iterable of public
/// points, compute
/// Given an iterator of public scalars and an iterator of public points, compute
/// $$
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
/// $$
///
/// # Input
/// This function has the same behaviour as
/// `vartime::multiscalar_mul` but is constant-time.
///
/// A iterable of `Scalar`s and a iterable of `RistrettoPoints`. It is an
/// error to call this function with two iterators of different lengths.
/// It is an error to call this function with two iterators of different lengths.
///
/// # Examples
///
/// The trait bound aims for maximum flexibility: the inputs must be
/// convertable to iterators (`I: IntoIter`), and the iterator's items
/// must be `Borrow<Scalar>` (or `Borrow<RistrettoPoint>`), to allow
/// iterators returning either `Scalar`s or `&Scalar`s.
///
/// ```
/// use curve25519_dalek::{constants, ristretto};
/// use curve25519_dalek::scalar::Scalar;
///
/// // Some scalars
/// let a = Scalar::from_u64(87329482);
/// let b = Scalar::from_u64(37264829);
/// let c = Scalar::from_u64(98098098);
///
/// // Some points
/// let P = constants::RISTRETTO_BASEPOINT_POINT;
/// let Q = P + P;
/// let R = P + Q;
///
/// // A1 = a*P + b*Q + c*R
/// let abc = [a,b,c];
/// let A1 = ristretto::vartime::multiscalar_mul(&abc, &[P,Q,R]);
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
///
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
/// let minus_abc = abc.iter().map(|x| -x);
/// let A2 = ristretto::vartime::multiscalar_mul(minus_abc, &[P,Q,R]);
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
///
/// assert_eq!(A1.compress(), (-A2).compress());
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b RistrettoPoint>
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
where I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator,
J::Item: Borrow<RistrettoPoint>,
{
let extended_points = points.into_iter().map(|P| &P.0);
RistrettoPoint(edwards::vartime::multiscalar_mult(scalars, extended_points))
let extended_points = points.into_iter().map(|P| P.borrow().0);
RistrettoPoint(edwards::vartime::multiscalar_mul(scalars, extended_points))
}
}
@ -1257,7 +1355,7 @@ mod test {
let bp_recaf = bp_compressed_ristretto.decompress().unwrap().0;
// Check that bp_recaf differs from bp by a point of order 4
let diff = &constants::RISTRETTO_BASEPOINT_POINT.0 - &bp_recaf;
let diff4 = diff.mult_by_pow_2(2);
let diff4 = diff.mul_by_pow_2(2);
assert_eq!(diff4.compress(), CompressedEdwardsY::identity());
}
@ -1357,7 +1455,7 @@ mod test {
];
for i in 0..16 {
let r_0 = FieldElement::from_bytes(&bytes[i]);
let Q = RistrettoPoint::elligator_ristretto_flavour(&r_0);
let Q = RistrettoPoint::elligator_ristretto_flavor(&r_0);
assert_eq!(Q.compress(), encoded_images[i]);
}
}

View file

@ -26,9 +26,9 @@ use rand::Rng;
use digest::Digest;
use generic_array::typenum::U64;
use subtle::slices_equal;
use subtle::Choice;
use subtle::ConditionallyAssignable;
use subtle::Equal;
use subtle::ConstantTimeEq;
use backend;
use constants;
@ -145,29 +145,14 @@ impl Debug for Scalar {
impl Eq for Scalar {}
impl PartialEq for Scalar {
/// Test equality between two `Scalar`s.
///
/// # Warning
///
/// This function is *not* guaranteed to be constant time and should only be
/// used for debugging purposes.
///
/// # Returns
///
/// True if they are equal, and false otherwise.
fn eq(&self, other: &Self) -> bool {
slices_equal(&self.bytes, &other.bytes) == 1u8
self.ct_eq(other).unwrap_u8() == 1u8
}
}
impl Equal for Scalar {
/// Test equality between two `Scalar`s in constant time.
///
/// # Returns
///
/// `1u8` if they are equal, and `0u8` otherwise.
fn ct_eq(&self, other: &Self) -> u8 {
slices_equal(&self.bytes, &other.bytes)
impl ConstantTimeEq for Scalar {
fn ct_eq(&self, other: &Self) -> Choice {
self.bytes.ct_eq(&other.bytes)
}
}
@ -246,34 +231,9 @@ impl<'a> Neg for Scalar {
}
impl ConditionallyAssignable for Scalar {
/// Conditionally assign another Scalar to this one.
///
/// ```
/// # extern crate curve25519_dalek;
/// # extern crate subtle;
/// # use curve25519_dalek::scalar::Scalar;
/// # use subtle::ConditionallyAssignable;
/// # fn main() {
/// let a = Scalar::from_bits([0u8;32]);
/// let b = Scalar::from_bits([1u8;32]);
/// let mut t = a;
/// t.conditional_assign(&b, 0u8);
/// assert!(t[0] == a[0]);
/// t.conditional_assign(&b, 1u8);
/// assert!(t[0] == b[0]);
/// # }
/// ```
///
/// # Preconditions
///
/// * `choice` in {0,1}
// XXX above test checks first byte because Scalar does not impl Eq
fn conditional_assign(&mut self, other: &Scalar, choice: u8) {
// if choice = 0u8, mask = (-0i8) as u8 = 00000000
// if choice = 1u8, mask = (-1i8) as u8 = 11111111
let mask = -(choice as i8) as u8;
fn conditional_assign(&mut self, other: &Scalar, choice: Choice) {
for i in 0..32 {
self.bytes[i] ^= mask & (self.bytes[i] ^ other.bytes[i]);
self.bytes[i].conditional_assign(&other.bytes[i], choice);
}
}
}
@ -433,6 +393,95 @@ impl Scalar {
self.unpack().invert().pack()
}
/// Given a slice of nonzero (possibly secret) `Scalar`s,
/// compute their inverses in a batch.
///
/// # Return
///
/// Each element of `inputs` is replaced by its inverse.
///
/// The product of all inverses is returned.
///
/// # Warning
///
/// All input `Scalars` **MUST** be nonzero. If you cannot
/// *prove* that this is the case, you **SHOULD NOT USE THIS
/// FUNCTION**.
///
/// This function is most efficient when the batch size (slice
/// length) is a power of 2.
///
/// # Example
///
/// ```
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::scalar::Scalar;
/// # fn main() {
///
/// let mut scalars = [
/// Scalar::from_u64(3),
/// Scalar::from_u64(5),
/// Scalar::from_u64(7),
/// Scalar::from_u64(11),
/// ];
///
/// let allinv = Scalar::batch_invert(&mut scalars);
///
/// assert_eq!(allinv, Scalar::from_u64(3*5*7*11).invert());
/// assert_eq!(scalars[0], Scalar::from_u64(3).invert());
/// assert_eq!(scalars[1], Scalar::from_u64(5).invert());
/// assert_eq!(scalars[2], Scalar::from_u64(7).invert());
/// assert_eq!(scalars[3], Scalar::from_u64(11).invert());
/// # }
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn batch_invert(inputs: &mut [Scalar]) -> Scalar {
// This code is essentially identical to the FieldElement
// implementation, and is documented there. Unfortunately,
// it's not easy to write it generically, since here we want
// to use `UnpackedScalar`s internally, and `Scalar`s
// externally, but there's no corresponding distinction for
// field elements.
use clear_on_drop::ClearOnDrop;
use clear_on_drop::clear::ZeroSafe;
// Mark UnpackedScalars as zeroable.
unsafe impl ZeroSafe for UnpackedScalar {}
let n = inputs.len().next_power_of_two();
let one: UnpackedScalar = Scalar::one().unpack().to_montgomery();
// Wrap the tree storage in a ClearOnDrop to wipe it when we
// pass out of scope.
let tree_vec = vec![one; 2*n];
let mut tree = ClearOnDrop::new(tree_vec);
for i in 0..inputs.len() {
tree[n+i] = inputs[i].unpack().to_montgomery();
}
for i in (1..n).rev() {
tree[i] = UnpackedScalar::montgomery_mul(&tree[2*i], &tree[2*i+1]);
}
// tree[1] is zero iff any of the inputs are zero.
debug_assert!(tree[1].from_montgomery().pack() != Scalar::zero());
let allinv = tree[1].montgomery_invert();
for i in 0..inputs.len() {
let mut inv = allinv;
let mut node = n + i;
while node > 1 {
inv = UnpackedScalar::montgomery_mul(&inv, &tree[node ^1]);
node = node >> 1;
}
inputs[i] = inv.from_montgomery().pack();
}
allinv.from_montgomery().pack()
}
/// Get the bits of the scalar.
pub(crate) fn bits(&self) -> [i8; 256] {
let mut bits = [0i8; 256];
@ -535,6 +584,7 @@ impl Scalar {
}
/// Reduce this `Scalar` modulo \\(\ell\\).
#[allow(non_snake_case)]
pub fn reduce(&self) -> Scalar {
let x = self.unpack();
let xR = UnpackedScalar::mul_internal(&x, &constants::R);
@ -571,13 +621,11 @@ impl UnpackedScalar {
Scalar{ bytes: self.to_bytes() }
}
/// Compute the multiplicative inverse of this scalar.
pub fn invert(&self) -> UnpackedScalar {
// This is a direct transliteration of the addition chain from
/// Inverts an UnpackedScalar in Montgomery form.
pub fn montgomery_invert(&self) -> UnpackedScalar {
// Uses the addition chain from
// https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion
// as it was published on 2017-09-03.
let _1 = self.to_montgomery();
let _1 = self;
let _10 = _1.montgomery_square();
let _100 = _10.montgomery_square();
let _11 = UnpackedScalar::montgomery_mul(&_10, &_1);
@ -626,7 +674,12 @@ impl UnpackedScalar {
square_multiply(&mut y, 3, &_101);
square_multiply(&mut y, 1 + 2, &_11);
y.from_montgomery()
y
}
/// Inverts an UnpackedScalar not in Montgomery form.
pub fn invert(&self) -> UnpackedScalar {
self.to_montgomery().montgomery_invert().from_montgomery()
}
}
@ -662,24 +715,6 @@ mod test {
0xe8, 0xef, 0x7a, 0xc3, 0x1f, 0x35, 0xbb, 0x05,
],
};
/// z = 5033871415930814945849241457262266927579821285980625165479289807629491019013
pub static Z: Scalar = Scalar{
bytes: [
0x05, 0x9d, 0x3e, 0x0b, 0x09, 0x26, 0x50, 0x3d,
0xa3, 0x84, 0xa1, 0x3c, 0x92, 0x7a, 0xc2, 0x06,
0x41, 0x98, 0xcf, 0x34, 0x3a, 0x24, 0xd5, 0xb7,
0xeb, 0x33, 0x6a, 0x2d, 0xfc, 0x11, 0x21, 0x0b,
],
};
/// w = 3486911242272497535104403593250518247409663771668155364040899665266216860804
static W: Scalar = Scalar{
bytes: [
0x84, 0xfc, 0xbc, 0x4f, 0x78, 0x12, 0xa0, 0x06,
0xd7, 0x91, 0xd9, 0x7a, 0x3a, 0x27, 0xdd, 0x1e,
0x21, 0x43, 0x45, 0xf7, 0xb1, 0xb9, 0x56, 0x7a,
0x81, 0x30, 0x73, 0x44, 0x96, 0x85, 0xb5, 0x07,
],
};
/// x*y = 5690045403673944803228348699031245560686958845067437804563560795922180092780
static X_TIMES_Y: Scalar = Scalar{
@ -775,7 +810,7 @@ mod test {
}
#[test]
fn scalar_multiply_by_one() {
fn scalar_mul_by_one() {
let test_scalar = &X * &Scalar::one();
for i in 0..32 {
assert!(test_scalar[i] == X[i]);
@ -927,6 +962,15 @@ mod test {
let parsed: Scalar = serde_cbor::from_slice(&output).unwrap();
assert_eq!(parsed, X);
}
#[test]
#[should_panic]
fn batch_invert_with_a_zero_input_panics() {
let mut xs = vec![Scalar::one(); 16];
xs[3] = Scalar::zero();
// This should panic in debug mode.
Scalar::batch_invert(&mut xs);
}
}
#[cfg(all(test, feature = "bench"))]

View file

@ -32,9 +32,9 @@ pub trait IsIdentity {
/// Implement generic identity equality testing for a point representations
/// which have constant-time equality testing and a defined identity
/// constructor.
impl<T> IsIdentity for T where T: subtle::Equal + Identity {
impl<T> IsIdentity for T where T: subtle::ConstantTimeEq + Identity {
fn is_identity(&self) -> bool {
self.ct_eq(&T::identity()) == 1u8
self.ct_eq(&T::identity()).unwrap_u8() == 1u8
}
}