mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Pull out constant-time straus implementation
This commit is contained in:
parent
ac739a3edd
commit
2864a422bc
6 changed files with 219 additions and 63 deletions
|
|
@ -9,3 +9,5 @@
|
|||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
pub mod variable_base;
|
||||
|
||||
pub mod straus;
|
||||
|
|
|
|||
57
src/backend/avx2/scalar_mul/straus.rs
Normal file
57
src/backend/avx2/scalar_mul/straus.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// -*- 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 clear_on_drop::ClearOnDrop;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use scalar_mul::window::LookupTable;
|
||||
use backend::avx2::edwards::{CachedPoint, ExtendedPoint};
|
||||
|
||||
/// Perform constant-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>,
|
||||
{
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
// for each input point P
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|point| {
|
||||
let avx2_point = ExtendedPoint::from(*point.borrow());
|
||||
LookupTable::<CachedPoint>::from(avx2_point)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let scalar_digits_vec: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|s| s.borrow().to_radix_16())
|
||||
.collect();
|
||||
// Pass ownership to a ClearOnDrop wrapper
|
||||
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
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]);
|
||||
}
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
|
|
@ -547,8 +547,6 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a 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_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
|
|
@ -556,70 +554,20 @@ pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
|||
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;
|
||||
// XXX later when we do more fancy multiscalar mults, we can
|
||||
// delegate based on the iter's size hint -- hdevalence
|
||||
|
||||
edwards_avx2::multiscalar_mul(scalars, points)
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use backend::avx2::scalar_mul::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());
|
||||
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
|
||||
let lookup_tables_vec: Vec<_> = points.into_iter()
|
||||
.map(|P| LookupTable::<ProjectiveNielsPoint>::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();
|
||||
|
||||
// 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
|
||||
//
|
||||
// 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 = 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.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
|
||||
let R_i = lookup_table_i.select(s_i[j]);
|
||||
// Q = Q + R_i
|
||||
Q = (&Q + &R_i).to_extended();
|
||||
}
|
||||
}
|
||||
Q
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))]
|
||||
{
|
||||
use scalar_mul::straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,3 +11,5 @@
|
|||
pub mod window;
|
||||
|
||||
pub mod variable_base;
|
||||
|
||||
pub mod straus;
|
||||
|
|
|
|||
83
src/scalar_mul/straus.rs
Normal file
83
src/scalar_mul/straus.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// -*- 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 clear_on_drop::ClearOnDrop;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use scalar_mul::window::LookupTable;
|
||||
|
||||
/// Perform constant-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>,
|
||||
{
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
// for each input point P
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|point| LookupTable::<ProjectiveNielsPoint>::from(point.borrow()))
|
||||
.collect();
|
||||
|
||||
// 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`.
|
||||
//
|
||||
// This 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_vec: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|s| s.borrow().to_radix_16())
|
||||
.collect();
|
||||
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 = EdwardsPoint::identity();
|
||||
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 {
|
||||
// R_i = s_{i,j} * P_i
|
||||
let R_i = lookup_table_i.select(s_i[j]);
|
||||
// Q = Q + R_i
|
||||
Q = (&Q + &R_i).to_extended();
|
||||
}
|
||||
}
|
||||
Q
|
||||
}
|
||||
64
src/scalar_mul/vartime_straus.rs
Normal file
64
src/scalar_mul/vartime_straus.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// -*- 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::ops::{Add, Sub};
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use scalar::Scalar;
|
||||
|
||||
//use super::window::OddLookupTable;
|
||||
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
|
||||
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,
|
||||
{
|
||||
let nafs: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|c| c.borrow().non_adjacent_form())
|
||||
.collect();
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|P| OddLookupTable::from(P.borrow()))
|
||||
.collect();
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
let mut t: CompletedPoint = r.double();
|
||||
|
||||
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);
|
||||
} else if naf[i] < 0 {
|
||||
t = &ExtendedPoint::from(t) - &lookup_table.select(-naf[i] as usize);
|
||||
}
|
||||
}
|
||||
|
||||
r = ProjectivePoint::from(t);
|
||||
}
|
||||
|
||||
ExtendedPoint::from(r)
|
||||
}
|
||||
Loading…
Reference in a new issue