mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Pull out variable-time straus implementation
This commit is contained in:
parent
2864a422bc
commit
2d99892eab
7 changed files with 156 additions and 156 deletions
|
|
@ -144,7 +144,7 @@ impl<'a> Neg for &'a ExtendedPoint {
|
|||
}
|
||||
|
||||
impl ExtendedPoint {
|
||||
fn double(&self) -> ExtendedPoint {
|
||||
pub fn double(&self) -> ExtendedPoint {
|
||||
unsafe {
|
||||
use stdsimd::vendor::_mm256_permute2x128_si256;
|
||||
use stdsimd::vendor::_mm256_permutevar8x32_epi32;
|
||||
|
|
@ -361,6 +361,18 @@ impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Implement subtraction by negating the point and adding.
|
||||
///
|
||||
/// Empirically, this seems about the same cost as a custom subtraction impl (maybe because the
|
||||
/// benefit is cancelled by increased code size?)
|
||||
fn sub(self, other: &'b CachedPoint) -> ExtendedPoint {
|
||||
self + &(-other)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtendedPoint> for LookupTable<CachedPoint> {
|
||||
fn from(P: ExtendedPoint) -> Self {
|
||||
let mut points = [CachedPoint::from(P); 8];
|
||||
|
|
@ -421,67 +433,18 @@ impl EdwardsBasepointTable {
|
|||
}
|
||||
}
|
||||
|
||||
/// Internal multiscalar code.
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
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 scalar_mul::window::OddLookupTable;
|
||||
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
let lookup_tables_vec: Vec<_> = points.into_iter()
|
||||
.map(|P| LookupTable::from(ExtendedPoint::from(*P.borrow())) )
|
||||
.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_vec: Vec<_> = scalars.into_iter()
|
||||
.map(|c| c.borrow().to_radix_16())
|
||||
.collect();
|
||||
|
||||
// The 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
|
||||
//
|
||||
// s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63)
|
||||
// s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63
|
||||
// s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...)
|
||||
//
|
||||
// we have the two-dimensional sum
|
||||
//
|
||||
// s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...)
|
||||
// + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...)
|
||||
// ...
|
||||
// + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...)
|
||||
//
|
||||
// We sum column-wise top-to-bottom, then right-to-left,
|
||||
// multiplying by 16 only once per column.
|
||||
//
|
||||
// This provides the speedup over doing n independent scalar
|
||||
// mults: we perform 63 multiplications by 16 instead of 63*n
|
||||
// multiplications, saving 252*(n-1) doublings.
|
||||
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.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
|
||||
Q = &Q + &lookup_table_i.select(s_i[j]);
|
||||
impl<'a> From<&'a ExtendedPoint> for OddLookupTable<CachedPoint> {
|
||||
fn from(A: &'a ExtendedPoint) -> Self {
|
||||
let mut Ai = [CachedPoint::from(*A); 8];
|
||||
let A2 = A.double();
|
||||
for i in 0..7 {
|
||||
Ai[i + 1] = (&A2 + &Ai[i]).into();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddLookupTable(Ai)
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
|
||||
pub mod vartime {
|
||||
|
|
@ -560,38 +523,6 @@ pub mod vartime {
|
|||
|
||||
Q.into()
|
||||
}
|
||||
|
||||
/// Internal multiscalar function
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
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.borrow().non_adjacent_form()).collect();
|
||||
|
||||
let odd_multiples: Vec<_> = points.into_iter()
|
||||
.map(|P| OddMultiples::create((*P.borrow()).into()) ).collect();
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
Q = Q.double();
|
||||
|
||||
for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) {
|
||||
if naf[i] > 0 {
|
||||
Q = &Q + &odd_multiple[( naf[i]/2) as usize];
|
||||
} else if naf[i] < 0 {
|
||||
Q = &Q - &odd_multiple[(-naf[i]/2) as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -11,3 +11,5 @@
|
|||
pub mod variable_base;
|
||||
|
||||
pub mod straus;
|
||||
|
||||
pub mod vartime_straus;
|
||||
|
|
|
|||
54
src/backend/avx2/scalar_mul/vartime_straus.rs
Normal file
54
src/backend/avx2/scalar_mul/vartime_straus.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
use backend::avx2::edwards::{CachedPoint, ExtendedPoint};
|
||||
|
||||
/// Perform variable-time, variable-base scalar multiplication.
|
||||
pub(crate) fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
let nafs: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|c| c.borrow().non_adjacent_form())
|
||||
.collect();
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|point| {
|
||||
let avx2_point = ExtendedPoint::from(*point.borrow());
|
||||
OddLookupTable::<CachedPoint>::from(&avx2_point)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
Q = Q.double();
|
||||
|
||||
for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) {
|
||||
if naf[i] > 0 {
|
||||
Q = &Q + &lookup_table.select(naf[i] as usize);
|
||||
} else if naf[i] < 0 {
|
||||
Q = &Q - &lookup_table.select(-naf[i] as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
|
|
@ -845,8 +845,6 @@ pub mod vartime {
|
|||
///
|
||||
/// 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_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
|
|
@ -854,38 +852,19 @@ pub mod vartime {
|
|||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
// XXX later when we do more fancy multiscalar mults, we can delegate
|
||||
// based on the iter's size hint -- hdevalence
|
||||
// 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_mul(scalars, points)
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use backend::avx2::scalar_mul::vartime_straus::multiscalar_mul;
|
||||
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.borrow().non_adjacent_form()).collect();
|
||||
let odd_multiples: Vec<_> = points.into_iter()
|
||||
.map(|P| OddMultiples::create(P.borrow())).collect();
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
let mut t = r.double();
|
||||
|
||||
for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) {
|
||||
if naf[i] > 0 {
|
||||
t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize];
|
||||
} else if naf[i] < 0 {
|
||||
t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize];
|
||||
}
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
}
|
||||
|
||||
r.to_extended()
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))]
|
||||
{
|
||||
use scalar_mul::vartime_straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,3 +13,5 @@ pub mod window;
|
|||
pub mod variable_base;
|
||||
|
||||
pub mod straus;
|
||||
|
||||
pub mod vartime_straus;
|
||||
|
|
|
|||
|
|
@ -9,31 +9,21 @@
|
|||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::ops::{Add, Sub};
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
|
||||
//use super::window::OddLookupTable;
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::{CompletedPoint, ProjectivePoint, ProjectiveNielsPoint};
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
use traits::{Doubleable, Identity};
|
||||
|
||||
/// Perform variable-time, variable-base scalar multiplication.
|
||||
pub(crate) fn multiscalar_mul<I, J, ExtendedPoint, CompletedPoint, ProjectivePoint, CachedPoint>(
|
||||
scalars: I,
|
||||
points: J,
|
||||
) -> ExtendedPoint
|
||||
pub(crate) fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<ExtendedPoint>,
|
||||
for<'a> OddLookupTable<CachedPoint>: From<&'a ExtendedPoint>,
|
||||
for<'a, 'b> &'a ExtendedPoint: Add<&'b CachedPoint, Output = CompletedPoint>,
|
||||
for<'a, 'b> &'a ExtendedPoint: Sub<&'b CachedPoint, Output = CompletedPoint>,
|
||||
ExtendedPoint: Identity + From<CompletedPoint> + From<ProjectivePoint>,
|
||||
ProjectivePoint: Identity + Doubleable<Output = CompletedPoint> + From<CompletedPoint>,
|
||||
CachedPoint: Copy,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
let nafs: Vec<_> = scalars
|
||||
.into_iter()
|
||||
|
|
@ -41,7 +31,7 @@ where
|
|||
.collect();
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|P| OddLookupTable::from(P.borrow()))
|
||||
.map(|P| OddLookupTable::<ProjectiveNielsPoint>::from(P.borrow()))
|
||||
.collect();
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
|
|
@ -51,14 +41,14 @@ where
|
|||
|
||||
for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) {
|
||||
if naf[i] > 0 {
|
||||
t = &ExtendedPoint::from(t) + &lookup_table.select(naf[i] as usize);
|
||||
t = &t.to_extended() + &lookup_table.select(naf[i] as usize);
|
||||
} else if naf[i] < 0 {
|
||||
t = &ExtendedPoint::from(t) - &lookup_table.select(-naf[i] as usize);
|
||||
t = &t.to_extended() - &lookup_table.select(-naf[i] as usize);
|
||||
}
|
||||
}
|
||||
|
||||
r = ProjectivePoint::from(t);
|
||||
r = t.to_projective();
|
||||
}
|
||||
|
||||
ExtendedPoint::from(r)
|
||||
r.to_extended()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ use subtle::Choice;
|
|||
|
||||
use traits::Identity;
|
||||
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
||||
/// A lookup table of precomputed multiples of a point \\(P\\), used to
|
||||
/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\).
|
||||
///
|
||||
|
|
@ -54,22 +58,24 @@ use clear_on_drop::clear::ZeroSafe;
|
|||
unsafe impl<T> ZeroSafe for LookupTable<T> {}
|
||||
|
||||
impl<T> LookupTable<T>
|
||||
where T: Identity + ConditionallyAssignable + ConditionallyNegatable
|
||||
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);
|
||||
debug_assert!(x >= -8);
|
||||
debug_assert!(x <= 8);
|
||||
|
||||
// Compute xabs = |x|
|
||||
let xmask = x >> 7;
|
||||
let xabs = (x + xmask) ^ xmask;
|
||||
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`.
|
||||
let c = (xabs as u8).ct_eq(&(j as u8));
|
||||
t.conditional_assign(&self.0[j-1], c);
|
||||
t.conditional_assign(&self.0[j - 1], c);
|
||||
}
|
||||
// Now t == |x| * P.
|
||||
|
||||
|
|
@ -93,17 +99,11 @@ impl<T: Debug> Debug for LookupTable<T> {
|
|||
}
|
||||
}
|
||||
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
||||
impl<'a> From<&'a EdwardsPoint> for LookupTable<ProjectiveNielsPoint> {
|
||||
fn from(P: &'a EdwardsPoint) -> 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();
|
||||
points[j + 1] = (P + &points[j]).to_extended().to_projective_niels();
|
||||
}
|
||||
LookupTable(points)
|
||||
}
|
||||
|
|
@ -114,10 +114,52 @@ impl<'a> From<&'a EdwardsPoint> for LookupTable<AffineNielsPoint> {
|
|||
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()
|
||||
points[j + 1] = (P + &points[j]).to_extended().to_affine_niels()
|
||||
}
|
||||
LookupTable(points)
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct OddLookupTable<T>(pub(crate) [T; 8]);
|
||||
|
||||
impl<T: Copy> OddLookupTable<T> {
|
||||
/// Given public, odd \\( x \\) with \\( 0 < x < 2^4 \\), return \\(xA\\).
|
||||
pub fn select(&self, x: usize) -> T {
|
||||
debug_assert_eq!(x & 1, 1);
|
||||
debug_assert!(x < 16);
|
||||
|
||||
self.0[x / 2]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for OddLookupTable<T> {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
write!(f, "OddLookupTable({:?})", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a EdwardsPoint> for OddLookupTable<ProjectiveNielsPoint> {
|
||||
fn from(A: &'a EdwardsPoint) -> Self {
|
||||
let mut Ai = [A.to_projective_niels(); 8];
|
||||
let A2 = A.double();
|
||||
for i in 0..7 {
|
||||
Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddLookupTable(Ai)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a EdwardsPoint> for OddLookupTable<AffineNielsPoint> {
|
||||
fn from(A: &'a EdwardsPoint) -> Self {
|
||||
let mut Ai = [A.to_affine_niels(); 8];
|
||||
let A2 = A.double();
|
||||
for i in 0..7 {
|
||||
Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddLookupTable(Ai)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue