mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Merge branch 'develop' into feature/avx2_r8
This commit is contained in:
commit
34f44dcf5d
7 changed files with 197 additions and 84 deletions
|
|
@ -42,6 +42,9 @@ version = "0.6"
|
|||
version = "^0.3"
|
||||
default-features = false
|
||||
|
||||
[dependencies.clear_on_drop]
|
||||
version = "=0.2.3"
|
||||
|
||||
[dependencies.generic-array]
|
||||
# same version that digest depends on
|
||||
version = "^0.8"
|
||||
|
|
@ -58,6 +61,7 @@ rand = "0.3"
|
|||
generic-array = "^0.8"
|
||||
digest = "0.6"
|
||||
arrayref = "0.3.4"
|
||||
clear_on_drop = "=0.2.3"
|
||||
stdsimd = { git = "https://github.com/rust-lang-nursery/stdsimd" }
|
||||
|
||||
[build-dependencies.serde]
|
||||
|
|
@ -65,7 +69,7 @@ version = "1.0"
|
|||
optional = true
|
||||
|
||||
[features]
|
||||
nightly = ["radix_51", "subtle/nightly"]
|
||||
nightly = ["radix_51", "subtle/nightly", "clear_on_drop/nightly"]
|
||||
default = ["std"]
|
||||
std = ["rand", "subtle/std"]
|
||||
alloc = []
|
||||
|
|
|
|||
2
build.rs
2
build.rs
|
|
@ -9,6 +9,7 @@ extern crate subtle;
|
|||
extern crate rand;
|
||||
extern crate digest;
|
||||
extern crate generic_array;
|
||||
extern crate clear_on_drop;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
|
|
@ -71,6 +72,7 @@ use backend::u32::field::FieldElement32;
|
|||
|
||||
use edwards::EdwardsBasepointTable;
|
||||
|
||||
use curve_models::window::LookupTable;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
||||
/// Table containing precomputed multiples of the basepoint `B = (x,4/5)`.
|
||||
|
|
|
|||
|
|
@ -134,6 +134,8 @@ use edwards::ExtendedPoint;
|
|||
use subtle::ConditionallyAssignable;
|
||||
use traits::ValidityCheck;
|
||||
|
||||
pub mod window;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal point representations
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -211,6 +213,12 @@ impl Identity for ProjectivePoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for ProjectivePoint {
|
||||
fn default() -> ProjectivePoint {
|
||||
ProjectivePoint::identity()
|
||||
}
|
||||
}
|
||||
|
||||
impl Identity for ProjectiveNielsPoint {
|
||||
fn identity() -> ProjectiveNielsPoint {
|
||||
ProjectiveNielsPoint{
|
||||
|
|
@ -222,6 +230,12 @@ impl Identity for ProjectiveNielsPoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for ProjectiveNielsPoint {
|
||||
fn default() -> ProjectiveNielsPoint {
|
||||
ProjectiveNielsPoint::identity()
|
||||
}
|
||||
}
|
||||
|
||||
impl Identity for AffineNielsPoint {
|
||||
fn identity() -> AffineNielsPoint {
|
||||
AffineNielsPoint{
|
||||
|
|
@ -232,6 +246,12 @@ impl Identity for AffineNielsPoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for AffineNielsPoint {
|
||||
fn default() -> AffineNielsPoint {
|
||||
AffineNielsPoint::identity()
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Validity checks (for debugging, not CT)
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
122
src/curve_models/window.rs
Normal file
122
src/curve_models/window.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! Code for fixed- and sliding-window functionality
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::fmt::Debug;
|
||||
|
||||
use subtle;
|
||||
use subtle::ConditionallyNegatable;
|
||||
use subtle::ConditionallyAssignable;
|
||||
|
||||
use traits::Identity;
|
||||
|
||||
/// A lookup table of precomputed multiples of a point \\(P\\), used to
|
||||
/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\).
|
||||
///
|
||||
/// The computation of \\( xP \\) is done in constant time by the `select` function.
|
||||
///
|
||||
/// Since `LookupTable` does not implement `Index`, it's more difficult
|
||||
/// to accidentally use the table directly. Unfortunately the table is
|
||||
/// only `pub(crate)` so that we can write hardcoded constants, so it's
|
||||
/// still technically possible. It would be nice to prevent direct
|
||||
/// access to the table.
|
||||
///
|
||||
/// XXX make this generic with respect to table size
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LookupTable<T>(pub(crate) [T; 8]);
|
||||
|
||||
use clear_on_drop::clear::ZeroSafe;
|
||||
|
||||
/// This type isn't actually zeroable (all zero bytes are not valid
|
||||
/// points), but we want to be able to use `clear_on_drop` to erase slices
|
||||
/// of `LookupTable`.
|
||||
///
|
||||
/// Since the `ZeroSafe` trait is only used by `clear_on_drop`, the only
|
||||
/// situation where this would be a problem is if code attempted to use
|
||||
/// a `ClearOnDrop` to erase a `LookupTable` and then used the table
|
||||
/// afterwards.
|
||||
///
|
||||
/// Normally this is not a problem, since the table's storage is usually
|
||||
/// dropped too.
|
||||
///
|
||||
/// XXX is this a good compromise?
|
||||
unsafe impl<T> ZeroSafe for LookupTable<T> {}
|
||||
|
||||
impl<T> LookupTable<T>
|
||||
where T: Identity + ConditionallyAssignable + ConditionallyNegatable
|
||||
{
|
||||
/// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time.
|
||||
pub fn select(&self, x: i8) -> T {
|
||||
debug_assert!(x >= -8); debug_assert!(x <= 8);
|
||||
|
||||
// Compute xabs = |x|
|
||||
let xmask = x >> 7;
|
||||
let xabs = (x + xmask) ^ xmask;
|
||||
|
||||
// Set t = 0 * P = identity
|
||||
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));
|
||||
}
|
||||
// Now t == |x| * P.
|
||||
|
||||
let neg_mask = (xmask & 1) as u8;
|
||||
t.conditional_negate(neg_mask);
|
||||
// Now t == x * P.
|
||||
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Default> Default for LookupTable<T> {
|
||||
fn default() -> LookupTable<T> {
|
||||
LookupTable([T::default(); 8])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for LookupTable<T> {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
write!(f, "LookupTable({:?})", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
use edwards::ExtendedPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
||||
impl<'a> From<&'a ExtendedPoint> for LookupTable<ProjectiveNielsPoint> {
|
||||
fn from(P: &'a ExtendedPoint) -> Self {
|
||||
let mut points = [P.to_projective_niels(); 8];
|
||||
for j in 0..7 {
|
||||
points[j+1] = (P + &points[j])
|
||||
.to_extended()
|
||||
.to_projective_niels();
|
||||
}
|
||||
LookupTable(points)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ExtendedPoint> for LookupTable<AffineNielsPoint> {
|
||||
fn from(P: &'a ExtendedPoint) -> Self {
|
||||
let mut points = [P.to_affine_niels(); 8];
|
||||
// XXX batch inversion would be good if perf mattered here
|
||||
for j in 0..7 {
|
||||
points[j+1] = (P + &points[j])
|
||||
.to_extended()
|
||||
.to_affine_niels()
|
||||
}
|
||||
LookupTable(points)
|
||||
}
|
||||
}
|
||||
|
|
@ -43,11 +43,11 @@ use curve_models::CompletedPoint;
|
|||
use curve_models::AffineNielsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
|
||||
use curve_models::window::LookupTable;
|
||||
|
||||
use traits::{Identity, IsIdentity};
|
||||
use traits::ValidityCheck;
|
||||
|
||||
use traits::select_precomputed_point;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Compressed points
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -235,7 +235,7 @@ impl Equal for ExtendedPoint {
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
impl ExtendedPoint {
|
||||
/// Convert to a `ProjectiveNielsPoint`
|
||||
/// Convert to a ProjectiveNielsPoint
|
||||
pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint {
|
||||
ProjectiveNielsPoint{
|
||||
Y_plus_X: &self.Y + &self.X,
|
||||
|
|
@ -441,12 +441,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
|
|||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(target_feature = "avx2", feature = "avx2_backend")))] {
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
let P = self.to_projective_niels();
|
||||
let mut lookup_table: [ProjectiveNielsPoint; 8] = [P; 8];
|
||||
for i in 0..7 {
|
||||
lookup_table[i+1] = (self + &lookup_table[i])
|
||||
.to_extended().to_projective_niels();
|
||||
}
|
||||
let lookup_table = LookupTable::<ProjectiveNielsPoint>::from(self);
|
||||
|
||||
// Setting s = scalar, compute
|
||||
//
|
||||
|
|
@ -464,13 +459,12 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
|
|||
// We sum right-to-left.
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
for i in (0..64).rev() {
|
||||
// Q = 16*Q
|
||||
// Q <-- 16*Q
|
||||
Q = Q.mult_by_pow_2(4);
|
||||
// R = s_i * Q
|
||||
let R = select_precomputed_point(scalar_digits[i], &lookup_table);
|
||||
// Q = Q + R
|
||||
Q = (&Q + &R).to_extended();
|
||||
// Q <-- Q + P * s_i
|
||||
Q = (&Q + &lookup_table.select(scalar_digits[i])).to_extended()
|
||||
}
|
||||
|
||||
Q
|
||||
}
|
||||
}
|
||||
|
|
@ -519,25 +513,28 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
|||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(target_feature = "avx2", feature = "avx2_backend")))] {
|
||||
//assert_eq!(scalars.len(), points.len());
|
||||
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
|
||||
let lookup_tables: Vec<_> = points.into_iter()
|
||||
.map(|P_i| {
|
||||
// Construct a lookup table of [P_i,2*P_i,3*P_i,4*P_i,5*P_i,6*P_i,7*P_i]
|
||||
let mut lookup_table = [P_i.to_projective_niels(); 8];
|
||||
for j in 0..7 {
|
||||
lookup_table[j+1] = (P_i + &lookup_table[j])
|
||||
.to_extended().to_projective_niels();
|
||||
}
|
||||
lookup_table
|
||||
}).collect();
|
||||
let lookup_tables_vec: Vec<_> = points.into_iter()
|
||||
.map(|P| LookupTable::<ProjectiveNielsPoint>::from(P) )
|
||||
.collect();
|
||||
|
||||
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
|
||||
|
||||
// Setting s_i = i-th scalar, compute
|
||||
//
|
||||
// s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
||||
let scalar_digits_list: Vec<_> = scalars.into_iter()
|
||||
.map(|c| c.to_radix_16()).collect();
|
||||
let scalar_digits_vec: Vec<_> = scalars.into_iter()
|
||||
.map(|c| c.to_radix_16())
|
||||
.collect();
|
||||
|
||||
// This above puts the scalar digits into a heap-allocated Vec.
|
||||
// To ensure that these are erased, pass ownership of the Vec into a
|
||||
// ClearOnDrop wrapper.
|
||||
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
|
||||
|
||||
// Compute s_1*P_1 + ... + s_n*P_n: since
|
||||
//
|
||||
|
|
@ -562,10 +559,10 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
|||
// 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);
|
||||
let it = scalar_digits_list.iter().zip(lookup_tables.iter());
|
||||
let it = scalar_digits.iter().zip(lookup_tables.iter());
|
||||
for (s_i, lookup_table_i) in it {
|
||||
// R_i = s_{i,j} * P_i
|
||||
let R_i = select_precomputed_point(s_i[j], lookup_table_i);
|
||||
let R_i = lookup_table_i.select(s_i[j]);
|
||||
// Q = Q + R_i
|
||||
Q = (&Q + &R_i).to_extended();
|
||||
}
|
||||
|
|
@ -581,7 +578,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
|||
/// The basepoint tables are reasonably large (30KB), so they should
|
||||
/// probably be boxed.
|
||||
#[derive(Clone)]
|
||||
pub struct EdwardsBasepointTable(pub(crate) [[AffineNielsPoint; 8]; 32]);
|
||||
pub struct EdwardsBasepointTable(pub(crate) [LookupTable<AffineNielsPoint>; 32]);
|
||||
|
||||
impl EdwardsBasepointTable {
|
||||
/// The computation uses Pippeneger's algorithm, as described on
|
||||
|
|
@ -590,7 +587,7 @@ impl EdwardsBasepointTable {
|
|||
/// $$
|
||||
/// a = a\_0 + a\_1 16\^1 + \cdots + a\_{63} 16\^{63},
|
||||
/// $$
|
||||
/// with \\(-8 \leq a_i < 8\\). Then
|
||||
/// with \\(-8 \leq a_i < 8\\), \\(-8 \leq a\_{63} \leq 8\\). Then
|
||||
/// $$
|
||||
/// a B = a\_0 B + a\_1 16\^1 B + \cdots + a\_{63} 16\^{63} B.
|
||||
/// $$
|
||||
|
|
@ -603,25 +600,28 @@ impl EdwardsBasepointTable {
|
|||
/// + 16(a\_1 16\^0 B +& a\_3 16\^2 B + \cdots + a\_{63} 16\^{62} B). \\\\
|
||||
/// \end{aligned}
|
||||
/// $$
|
||||
/// We then use the `select_precomputed_point` function, which
|
||||
/// takes \\(-8 \leq x < 8\\) and \\([16\^{2i} B, \ldots, 8\cdot16\^{2i} B]\\),
|
||||
/// and returns \\(x \cdot 16\^{2i} \cdot B\\) in constant time.
|
||||
/// For each \\(i = 0 \ldots 31\\), we create a lookup table of
|
||||
/// $$
|
||||
/// [16\^{2i} B, \ldots, 8\cdot16\^{2i} B],
|
||||
/// $$
|
||||
/// and use it to select \\( x \cdot 16\^{2i} \cdot B \\) in constant time.
|
||||
///
|
||||
/// The radix-\\(16\\) representation requires that the scalar is bounded
|
||||
/// by \\(2\^{255}\\), which is always the case.
|
||||
fn basepoint_mul(&self, scalar: &Scalar) -> ExtendedPoint {
|
||||
let a = scalar.to_radix_16();
|
||||
|
||||
let tables = &self.0;
|
||||
let mut P = ExtendedPoint::identity();
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 1) {
|
||||
P = (&P + &select_precomputed_point(a[i], &self.0[i/2])).to_extended();
|
||||
P = (&P + &tables[i/2].select(a[i])).to_extended();
|
||||
}
|
||||
|
||||
P = P.mult_by_pow_2(4);
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 0) {
|
||||
P = (&P + &select_precomputed_point(a[i], &self.0[i/2])).to_extended();
|
||||
P = (&P + &tables[i/2].select(a[i])).to_extended();
|
||||
}
|
||||
|
||||
P
|
||||
|
|
@ -652,29 +652,24 @@ impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
|
|||
impl EdwardsBasepointTable {
|
||||
/// Create a table of precomputed multiples of `basepoint`.
|
||||
pub fn create(basepoint: &ExtendedPoint) -> EdwardsBasepointTable {
|
||||
// Create the table storage
|
||||
// XXX can we skip the initialization without too much unsafety?
|
||||
// stick 30K on the stack and call it a day.
|
||||
let mut table = EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]);
|
||||
// XXX use init_with
|
||||
let mut table = EdwardsBasepointTable([LookupTable::default(); 32]);
|
||||
let mut P = *basepoint;
|
||||
for i in 0..32 {
|
||||
// P = (16^2)^i * B
|
||||
let mut jP = P.to_affine_niels();
|
||||
for j in 1..9 {
|
||||
// table[i][j-1] is supposed to be j*(16^2)^i*B
|
||||
table.0[i][j-1] = jP;
|
||||
jP = (&P + &jP).to_extended().to_affine_niels();
|
||||
}
|
||||
table.0[i] = LookupTable::from(&P);
|
||||
P = P.mult_by_pow_2(8);
|
||||
}
|
||||
table
|
||||
}
|
||||
|
||||
/// Get the basepoint for this table as an `ExtendedPoint`.
|
||||
///
|
||||
/// XXX maybe this would be better as a `From` impl
|
||||
pub fn basepoint(&self) -> ExtendedPoint {
|
||||
// self.0[0][0] has 1*(16^2)^0*B, but as an `AffineNielsPoint`
|
||||
// Add identity to convert to extended.
|
||||
(&ExtendedPoint::identity() + &self.0[0][0]).to_extended()
|
||||
// self.0[0].select(1) = 1*(16^2)^0*B
|
||||
// but as an `AffineNielsPoint`, so add identity to convert to extended.
|
||||
(&ExtendedPoint::identity() + &self.0[0].select(1)).to_extended()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1306,7 +1301,9 @@ mod bench {
|
|||
#[bench]
|
||||
#[cfg(feature="precomputed_tables")]
|
||||
fn bench_select_precomputed_point(b: &mut Bencher) {
|
||||
b.iter(|| select_precomputed_point(0, &constants::ED25519_BASEPOINT_TABLE.0[0]));
|
||||
use test::black_box;
|
||||
let table = &constants::ED25519_BASEPOINT_TABLE.0[0];
|
||||
b.iter(|| table.select(black_box(5)) );
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ extern crate rand;
|
|||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
extern crate clear_on_drop;
|
||||
|
||||
#[cfg(all(test, feature = "bench"))]
|
||||
extern crate test;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,7 @@
|
|||
|
||||
//! Module for common traits.
|
||||
|
||||
use core::ops::Neg;
|
||||
|
||||
use subtle;
|
||||
use subtle::ConditionallyAssignable;
|
||||
use subtle::ConditionallyNegatable;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Public Traits
|
||||
|
|
@ -55,33 +51,3 @@ pub(crate) trait ValidityCheck {
|
|||
/// Checks whether the point is on the curve. Not CT.
|
||||
fn is_valid(&self) -> bool;
|
||||
}
|
||||
|
||||
// This isn't a trait, but it is fully generic...
|
||||
|
||||
/// Given precomputed points `[P, 2P, 3P, ..., 8P]`, as well as `-8 ≤
|
||||
/// x ≤ 8`, compute `x * B` in constant time, i.e., without branching
|
||||
/// on x or using it as an array index.
|
||||
pub(crate) fn select_precomputed_point<T>(x: i8, points: &[T; 8]) -> T
|
||||
where T: Identity + ConditionallyAssignable, for<'a> &'a T: Neg<Output=T>
|
||||
{
|
||||
debug_assert!(x >= -8); debug_assert!(x <= 8);
|
||||
|
||||
// Compute xabs = |x|
|
||||
let xmask = x >> 7;
|
||||
let xabs = (x + xmask) ^ xmask;
|
||||
|
||||
// Set t = 0 * P = identity
|
||||
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(&points[j-1],
|
||||
subtle::bytes_equal(xabs as u8, j as u8));
|
||||
}
|
||||
// Now t == |x| * P.
|
||||
|
||||
let neg_mask = (xmask & 1) as u8;
|
||||
t.conditional_negate(neg_mask);
|
||||
// Now t == x * P.
|
||||
|
||||
t
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue