mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Remove constant-time multiscalar precomputation.
This doesn't (yet) give any speedup over the non-precomputed multiscalar multiplication, and it's not clear that it's a good idea to commit to supporting it in the future. Removing it means that it's not committed-to as part of the public API, but the source is still there in the tree if we want to revisit it later.
This commit is contained in:
parent
27daa5215e
commit
092ff52cb0
6 changed files with 6 additions and 465 deletions
|
|
@ -110,37 +110,6 @@ mod multiscalar_benches {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precomputed_ct_straus_helper(c: &mut Criterion, dynamic_fraction: f64) {
|
|
||||||
let label = format!(
|
|
||||||
"Constant-time mixed-base Straus ({:.2}pct dyn)",
|
|
||||||
100.0*dynamic_fraction,
|
|
||||||
);
|
|
||||||
c.bench_function_over_inputs(
|
|
||||||
&label,
|
|
||||||
move |b, &&total_size| {
|
|
||||||
let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize;
|
|
||||||
let static_size = total_size - dynamic_size;
|
|
||||||
|
|
||||||
let (static_scalars, static_points) = construct(static_size);
|
|
||||||
let (dynamic_scalars, dynamic_points) = construct(dynamic_size);
|
|
||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPrecomputation;
|
|
||||||
use curve25519_dalek::traits::PrecomputedMultiscalarMul;
|
|
||||||
|
|
||||||
let precomp = EdwardsPrecomputation::new(&static_points);
|
|
||||||
|
|
||||||
b.iter(|| {
|
|
||||||
precomp.mixed_multiscalar_mul(
|
|
||||||
&static_scalars,
|
|
||||||
&dynamic_scalars,
|
|
||||||
&dynamic_points,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
&MULTISCALAR_SIZES,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn precomputed_vt_straus_helper(c: &mut Criterion, dynamic_fraction: f64) {
|
fn precomputed_vt_straus_helper(c: &mut Criterion, dynamic_fraction: f64) {
|
||||||
let label = format!(
|
let label = format!(
|
||||||
"Variable-time mixed-base Straus ({:.2}pct dyn)",
|
"Variable-time mixed-base Straus ({:.2}pct dyn)",
|
||||||
|
|
@ -172,18 +141,6 @@ mod multiscalar_benches {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precomputed_ct_straus_00_pct_dynamic(c: &mut Criterion) {
|
|
||||||
precomputed_ct_straus_helper(c, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn precomputed_ct_straus_20_pct_dynamic(c: &mut Criterion) {
|
|
||||||
precomputed_ct_straus_helper(c, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn precomputed_ct_straus_50_pct_dynamic(c: &mut Criterion) {
|
|
||||||
precomputed_ct_straus_helper(c, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn precomputed_vt_straus_00_pct_dynamic(c: &mut Criterion) {
|
fn precomputed_vt_straus_00_pct_dynamic(c: &mut Criterion) {
|
||||||
precomputed_vt_straus_helper(c, 0.0);
|
precomputed_vt_straus_helper(c, 0.0);
|
||||||
}
|
}
|
||||||
|
|
@ -203,9 +160,6 @@ mod multiscalar_benches {
|
||||||
targets =
|
targets =
|
||||||
consttime_multiscalar_mul,
|
consttime_multiscalar_mul,
|
||||||
vartime_multiscalar_mul,
|
vartime_multiscalar_mul,
|
||||||
precomputed_ct_straus_00_pct_dynamic,
|
|
||||||
precomputed_ct_straus_20_pct_dynamic,
|
|
||||||
precomputed_ct_straus_50_pct_dynamic,
|
|
||||||
precomputed_vt_straus_00_pct_dynamic,
|
precomputed_vt_straus_00_pct_dynamic,
|
||||||
precomputed_vt_straus_20_pct_dynamic,
|
precomputed_vt_straus_20_pct_dynamic,
|
||||||
precomputed_vt_straus_50_pct_dynamic,
|
precomputed_vt_straus_50_pct_dynamic,
|
||||||
|
|
|
||||||
|
|
@ -13,99 +13,18 @@
|
||||||
|
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
use clear_on_drop::ClearOnDrop;
|
|
||||||
|
|
||||||
use backend::serial::curve_models::{
|
use backend::serial::curve_models::{
|
||||||
AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint,
|
AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint,
|
||||||
};
|
};
|
||||||
use edwards::EdwardsPoint;
|
use edwards::EdwardsPoint;
|
||||||
use scalar::Scalar;
|
use scalar::Scalar;
|
||||||
use traits::Identity;
|
use traits::Identity;
|
||||||
use traits::{PrecomputedMultiscalarMul, VartimePrecomputedMultiscalarMul};
|
use traits::VartimePrecomputedMultiscalarMul;
|
||||||
use window::{LookupTable, NafLookupTable5, NafLookupTable8};
|
use window::{NafLookupTable5, NafLookupTable8};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
pub struct PrecomputedStraus {
|
|
||||||
static_lookup_tables: Vec<LookupTable<AffineNielsPoint>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrecomputedMultiscalarMul for PrecomputedStraus {
|
|
||||||
type Point = EdwardsPoint;
|
|
||||||
|
|
||||||
fn new<I>(static_points: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
PrecomputedStraus {
|
|
||||||
static_lookup_tables: static_points
|
|
||||||
.into_iter()
|
|
||||||
.map(|point| LookupTable::<AffineNielsPoint>::from(point.borrow()))
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mixed_multiscalar_mul<I, J, K>(
|
|
||||||
&self,
|
|
||||||
static_scalars: I,
|
|
||||||
dynamic_scalars: J,
|
|
||||||
dynamic_points: K,
|
|
||||||
) -> Self::Point
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Scalar>,
|
|
||||||
J: IntoIterator,
|
|
||||||
J::Item: Borrow<Scalar>,
|
|
||||||
K: IntoIterator,
|
|
||||||
K::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
// This does two allocs for the scalar digits instead of
|
|
||||||
// putting them in a contiguous array, which makes handling
|
|
||||||
// the two kinds of lookup tables slightly easier.
|
|
||||||
// Use a ClearOnDrop wrapper.
|
|
||||||
|
|
||||||
let static_scalar_digits_vec: Vec<_> = static_scalars
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| s.borrow().to_radix_16())
|
|
||||||
.collect();
|
|
||||||
let static_scalar_digits = ClearOnDrop::new(static_scalar_digits_vec);
|
|
||||||
|
|
||||||
let dynamic_scalar_digits_vec: Vec<_> = dynamic_scalars
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| s.borrow().to_radix_16())
|
|
||||||
.collect();
|
|
||||||
let dynamic_scalar_digits = ClearOnDrop::new(dynamic_scalar_digits_vec);
|
|
||||||
|
|
||||||
// Build lookup tables for dynamic points
|
|
||||||
let dynamic_lookup_tables: Vec<_> = dynamic_points
|
|
||||||
.into_iter()
|
|
||||||
.map(|point| LookupTable::<ProjectiveNielsPoint>::from(point.borrow()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let sp = self.static_lookup_tables.len();
|
|
||||||
let dp = dynamic_lookup_tables.len();
|
|
||||||
assert_eq!(sp, static_scalar_digits.len());
|
|
||||||
assert_eq!(dp, dynamic_scalar_digits.len());
|
|
||||||
|
|
||||||
let mut R = EdwardsPoint::identity();
|
|
||||||
for j in (0..64).rev() {
|
|
||||||
R = R.mul_by_pow_2(4);
|
|
||||||
for i in 0..dp {
|
|
||||||
let t_ij = dynamic_scalar_digits[i][j];
|
|
||||||
R = (&R + &dynamic_lookup_tables[i].select(t_ij)).to_extended();
|
|
||||||
}
|
|
||||||
for i in 0..sp {
|
|
||||||
let s_ij = static_scalar_digits[i][j];
|
|
||||||
R = (&R + &self.static_lookup_tables[i].select(s_ij)).to_extended();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
R
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VartimePrecomputedStraus {
|
pub struct VartimePrecomputedStraus {
|
||||||
static_lookup_tables: Vec<NafLookupTable8<AffineNielsPoint>>,
|
static_lookup_tables: Vec<NafLookupTable8<AffineNielsPoint>>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,96 +13,16 @@
|
||||||
|
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
use clear_on_drop::ClearOnDrop;
|
|
||||||
|
|
||||||
use backend::vector::{CachedPoint, ExtendedPoint};
|
use backend::vector::{CachedPoint, ExtendedPoint};
|
||||||
use edwards::EdwardsPoint;
|
use edwards::EdwardsPoint;
|
||||||
use scalar::Scalar;
|
use scalar::Scalar;
|
||||||
use traits::Identity;
|
use traits::Identity;
|
||||||
use traits::{PrecomputedMultiscalarMul, VartimePrecomputedMultiscalarMul};
|
use traits::VartimePrecomputedMultiscalarMul;
|
||||||
use window::{LookupTable, NafLookupTable5, NafLookupTable8};
|
use window::{NafLookupTable5, NafLookupTable8};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
pub struct PrecomputedStraus {
|
|
||||||
static_lookup_tables: Vec<LookupTable<CachedPoint>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrecomputedMultiscalarMul for PrecomputedStraus {
|
|
||||||
type Point = EdwardsPoint;
|
|
||||||
|
|
||||||
fn new<I>(static_points: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
PrecomputedStraus {
|
|
||||||
static_lookup_tables: static_points
|
|
||||||
.into_iter()
|
|
||||||
.map(|point| LookupTable::<CachedPoint>::from(point.borrow()))
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mixed_multiscalar_mul<I, J, K>(
|
|
||||||
&self,
|
|
||||||
static_scalars: I,
|
|
||||||
dynamic_scalars: J,
|
|
||||||
dynamic_points: K,
|
|
||||||
) -> Self::Point
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Scalar>,
|
|
||||||
J: IntoIterator,
|
|
||||||
J::Item: Borrow<Scalar>,
|
|
||||||
K: IntoIterator,
|
|
||||||
K::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
// This does two allocs for the scalar digits instead of
|
|
||||||
// putting them in a contiguous array, which makes handling
|
|
||||||
// the two kinds of lookup tables slightly easier.
|
|
||||||
// Use a ClearOnDrop wrapper.
|
|
||||||
|
|
||||||
let static_scalar_digits_vec: Vec<_> = static_scalars
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| s.borrow().to_radix_16())
|
|
||||||
.collect();
|
|
||||||
let static_scalar_digits = ClearOnDrop::new(static_scalar_digits_vec);
|
|
||||||
|
|
||||||
let dynamic_scalar_digits_vec: Vec<_> = dynamic_scalars
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| s.borrow().to_radix_16())
|
|
||||||
.collect();
|
|
||||||
let dynamic_scalar_digits = ClearOnDrop::new(dynamic_scalar_digits_vec);
|
|
||||||
|
|
||||||
// Build lookup tables for dynamic points
|
|
||||||
let dynamic_lookup_tables: Vec<_> = dynamic_points
|
|
||||||
.into_iter()
|
|
||||||
.map(|point| LookupTable::<CachedPoint>::from(point.borrow()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let sp = self.static_lookup_tables.len();
|
|
||||||
let dp = dynamic_lookup_tables.len();
|
|
||||||
assert_eq!(sp, static_scalar_digits.len());
|
|
||||||
assert_eq!(dp, dynamic_scalar_digits.len());
|
|
||||||
|
|
||||||
let mut R = ExtendedPoint::identity();
|
|
||||||
for j in (0..64).rev() {
|
|
||||||
R = R.mul_by_pow_2(4);
|
|
||||||
for i in 0..dp {
|
|
||||||
let t_ij = dynamic_scalar_digits[i][j];
|
|
||||||
R = &R + &dynamic_lookup_tables[i].select(t_ij);
|
|
||||||
}
|
|
||||||
for i in 0..sp {
|
|
||||||
let s_ij = static_scalar_digits[i][j];
|
|
||||||
R = &R + &self.static_lookup_tables[i].select(s_ij);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
R.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VartimePrecomputedStraus {
|
pub struct VartimePrecomputedStraus {
|
||||||
static_lookup_tables: Vec<NafLookupTable8<CachedPoint>>,
|
static_lookup_tables: Vec<NafLookupTable8<CachedPoint>>,
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ use traits::ValidityCheck;
|
||||||
use traits::{Identity, IsIdentity};
|
use traits::{Identity, IsIdentity};
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use traits::{MultiscalarMul, PrecomputedMultiscalarMul};
|
use traits::MultiscalarMul;
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
|
use traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
|
||||||
|
|
||||||
|
|
@ -673,13 +673,6 @@ impl VartimeMultiscalarMul for EdwardsPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precomputation for multiscalar multiplication with `EdwardsPoint`s.
|
|
||||||
// This wraps the inner implementation in a facade type so that we can
|
|
||||||
// decouple stability of the inner type from the stability of the
|
|
||||||
// outer type.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
pub struct EdwardsPrecomputation(scalar_mul::precomputed_straus::PrecomputedStraus);
|
|
||||||
|
|
||||||
/// Precomputation for variable-time multiscalar multiplication with `EdwardsPoint`s.
|
/// Precomputation for variable-time multiscalar multiplication with `EdwardsPoint`s.
|
||||||
// This wraps the inner implementation in a facade type so that we can
|
// This wraps the inner implementation in a facade type so that we can
|
||||||
// decouple stability of the inner type from the stability of the
|
// decouple stability of the inner type from the stability of the
|
||||||
|
|
@ -687,39 +680,6 @@ pub struct EdwardsPrecomputation(scalar_mul::precomputed_straus::PrecomputedStra
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus);
|
pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus);
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
impl PrecomputedMultiscalarMul for EdwardsPrecomputation {
|
|
||||||
type Point = EdwardsPoint;
|
|
||||||
|
|
||||||
fn new<I>(static_points: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
Self(scalar_mul::precomputed_straus::PrecomputedStraus::new(
|
|
||||||
static_points,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mixed_multiscalar_mul<I, J, K>(
|
|
||||||
&self,
|
|
||||||
static_scalars: I,
|
|
||||||
dynamic_scalars: J,
|
|
||||||
dynamic_points: K,
|
|
||||||
) -> Self::Point
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Scalar>,
|
|
||||||
J: IntoIterator,
|
|
||||||
J::Item: Borrow<Scalar>,
|
|
||||||
K: IntoIterator,
|
|
||||||
K::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
self.0
|
|
||||||
.mixed_multiscalar_mul(static_scalars, dynamic_scalars, dynamic_points)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
|
impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
|
||||||
type Point = EdwardsPoint;
|
type Point = EdwardsPoint;
|
||||||
|
|
@ -1280,49 +1240,6 @@ mod test {
|
||||||
assert!(P1.compress().to_bytes() == P2.compress().to_bytes());
|
assert!(P1.compress().to_bytes() == P2.compress().to_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn precomputed_vs_nonprecomputed_multiscalar() {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
let B = &::constants::ED25519_BASEPOINT_TABLE;
|
|
||||||
|
|
||||||
let static_scalars = (0..128)
|
|
||||||
.map(|_| Scalar::random(&mut rng))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let dynamic_scalars = (0..128)
|
|
||||||
.map(|_| Scalar::random(&mut rng))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let check_scalar: Scalar = static_scalars
|
|
||||||
.iter()
|
|
||||||
.chain(dynamic_scalars.iter())
|
|
||||||
.map(|s| s * s)
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
let static_points = static_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
|
||||||
let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let precomputation = EdwardsPrecomputation::new(static_points.iter());
|
|
||||||
|
|
||||||
let P = precomputation.mixed_multiscalar_mul(
|
|
||||||
&static_scalars,
|
|
||||||
&dynamic_scalars,
|
|
||||||
&dynamic_points,
|
|
||||||
);
|
|
||||||
|
|
||||||
use traits::MultiscalarMul;
|
|
||||||
let Q = EdwardsPoint::multiscalar_mul(
|
|
||||||
static_scalars.iter().chain(dynamic_scalars.iter()),
|
|
||||||
static_points.iter().chain(dynamic_points.iter()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let R = &check_scalar * B;
|
|
||||||
|
|
||||||
assert_eq!(P.compress(), R.compress());
|
|
||||||
assert_eq!(Q.compress(), R.compress());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
|
||||||
|
|
@ -187,10 +187,7 @@ use scalar::Scalar;
|
||||||
|
|
||||||
use traits::Identity;
|
use traits::Identity;
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use traits::{
|
use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
|
||||||
MultiscalarMul, PrecomputedMultiscalarMul, VartimeMultiscalarMul,
|
|
||||||
VartimePrecomputedMultiscalarMul,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(not(all(
|
#[cfg(not(all(
|
||||||
feature = "simd_backend",
|
feature = "simd_backend",
|
||||||
|
|
@ -909,13 +906,6 @@ impl VartimeMultiscalarMul for RistrettoPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precomputation for multiscalar multiplication with `RistrettoPoint`s.
|
|
||||||
// This wraps the inner implementation in a facade type so that we can
|
|
||||||
// decouple stability of the inner type from the stability of the
|
|
||||||
// outer type.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
pub struct RistrettoPrecomputation(scalar_mul::precomputed_straus::PrecomputedStraus);
|
|
||||||
|
|
||||||
/// Precomputation for variable-time multiscalar multiplication with `RistrettoPoint`s.
|
/// Precomputation for variable-time multiscalar multiplication with `RistrettoPoint`s.
|
||||||
// This wraps the inner implementation in a facade type so that we can
|
// This wraps the inner implementation in a facade type so that we can
|
||||||
// decouple stability of the inner type from the stability of the
|
// decouple stability of the inner type from the stability of the
|
||||||
|
|
@ -923,42 +913,6 @@ pub struct RistrettoPrecomputation(scalar_mul::precomputed_straus::PrecomputedSt
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus);
|
pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus);
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
impl PrecomputedMultiscalarMul for RistrettoPrecomputation {
|
|
||||||
type Point = RistrettoPoint;
|
|
||||||
|
|
||||||
fn new<I>(static_points: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
Self(scalar_mul::precomputed_straus::PrecomputedStraus::new(
|
|
||||||
static_points.into_iter().map(|P| P.borrow().0),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mixed_multiscalar_mul<I, J, K>(
|
|
||||||
&self,
|
|
||||||
static_scalars: I,
|
|
||||||
dynamic_scalars: J,
|
|
||||||
dynamic_points: K,
|
|
||||||
) -> Self::Point
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Scalar>,
|
|
||||||
J: IntoIterator,
|
|
||||||
J::Item: Borrow<Scalar>,
|
|
||||||
K: IntoIterator,
|
|
||||||
K::Item: Borrow<Self::Point>,
|
|
||||||
{
|
|
||||||
RistrettoPoint(self.0.mixed_multiscalar_mul(
|
|
||||||
static_scalars,
|
|
||||||
dynamic_scalars,
|
|
||||||
dynamic_points.into_iter().map(|P| P.borrow().0),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
|
impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
|
||||||
type Point = RistrettoPoint;
|
type Point = RistrettoPoint;
|
||||||
|
|
@ -1366,49 +1320,6 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn precomputed_vs_nonprecomputed_multiscalar() {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
let B = &::constants::RISTRETTO_BASEPOINT_TABLE;
|
|
||||||
|
|
||||||
let static_scalars = (0..128)
|
|
||||||
.map(|_| Scalar::random(&mut rng))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let dynamic_scalars = (0..128)
|
|
||||||
.map(|_| Scalar::random(&mut rng))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let check_scalar: Scalar = static_scalars
|
|
||||||
.iter()
|
|
||||||
.chain(dynamic_scalars.iter())
|
|
||||||
.map(|s| s * s)
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
let static_points = static_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
|
||||||
let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let precomputation = RistrettoPrecomputation::new(static_points.iter());
|
|
||||||
|
|
||||||
let P = precomputation.mixed_multiscalar_mul(
|
|
||||||
&static_scalars,
|
|
||||||
&dynamic_scalars,
|
|
||||||
&dynamic_points,
|
|
||||||
);
|
|
||||||
|
|
||||||
use traits::MultiscalarMul;
|
|
||||||
let Q = RistrettoPoint::multiscalar_mul(
|
|
||||||
static_scalars.iter().chain(dynamic_scalars.iter()),
|
|
||||||
static_points.iter().chain(dynamic_points.iter()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let R = &check_scalar * B;
|
|
||||||
|
|
||||||
assert_eq!(P.compress(), R.compress());
|
|
||||||
assert_eq!(Q.compress(), R.compress());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
|
||||||
|
|
@ -225,86 +225,6 @@ pub trait VartimeMultiscalarMul {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for constant-time multiscalar multiplication with precomputation.
|
|
||||||
///
|
|
||||||
/// A general multiscalar multiplication with precomputation can be written as
|
|
||||||
/// $$
|
|
||||||
/// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m,
|
|
||||||
/// $$
|
|
||||||
/// where the \\(B_i\\) are *static* points, for which precomputation
|
|
||||||
/// is possible, and the \\(A_j\\) are *dynamic* points, for which
|
|
||||||
/// precomputation is not possible.
|
|
||||||
pub trait PrecomputedMultiscalarMul: Sized {
|
|
||||||
/// The type of point to be multiplied, e.g., `RistrettoPoint`.
|
|
||||||
type Point;
|
|
||||||
|
|
||||||
/// Given the static points \\( B_i \\), perform precomputation
|
|
||||||
/// and return the precomputation data.
|
|
||||||
fn new<I>(static_points: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Self::Point>;
|
|
||||||
|
|
||||||
/// Given `static_scalars`, an iterator of (possibly secret)
|
|
||||||
/// scalars \\(b_i\\), `dynamic_scalars`, an iterator of (possibly
|
|
||||||
/// secret) scalars \\(a_i\\), and `dynamic_points`, an iterator
|
|
||||||
/// of points \\(A_i\\), compute
|
|
||||||
/// $$
|
|
||||||
/// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m,
|
|
||||||
/// $$
|
|
||||||
/// where the \\(B_j\\) are the points that were supplied to `new`.
|
|
||||||
///
|
|
||||||
/// It is an error to call this function with iterators of
|
|
||||||
/// inconsistent lengths.
|
|
||||||
///
|
|
||||||
/// 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<Point>`), to allow
|
|
||||||
/// iterators returning either `Scalar`s or `&Scalar`s.
|
|
||||||
fn mixed_multiscalar_mul<I, J, K>(
|
|
||||||
&self,
|
|
||||||
static_scalars: I,
|
|
||||||
dynamic_scalars: J,
|
|
||||||
dynamic_points: K,
|
|
||||||
) -> Self::Point
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Scalar>,
|
|
||||||
J: IntoIterator,
|
|
||||||
J::Item: Borrow<Scalar>,
|
|
||||||
K: IntoIterator,
|
|
||||||
K::Item: Borrow<Self::Point>;
|
|
||||||
|
|
||||||
/// Given `static_scalars`, an iterator of (possibly secret)
|
|
||||||
/// scalars \\(b_i\\), compute
|
|
||||||
/// $$
|
|
||||||
/// Q = b_1 B_1 + \cdots + b_m B_m,
|
|
||||||
/// $$
|
|
||||||
/// where the \\(B_j\\) are the points that were supplied to `new`.
|
|
||||||
///
|
|
||||||
/// It is an error to call this function with iterators of
|
|
||||||
/// inconsistent lengths.
|
|
||||||
///
|
|
||||||
/// The trait bound aims for maximum flexibility: the input must
|
|
||||||
/// be convertable to iterators (`I: IntoIter`), and the
|
|
||||||
/// iterator's items must be `Borrow<Scalar>`, to allow iterators
|
|
||||||
/// returning either `Scalar`s or `&Scalar`s.
|
|
||||||
fn multiscalar_mul<I>(&self, static_scalars: I) -> Self::Point
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<Scalar>,
|
|
||||||
{
|
|
||||||
use core::iter;
|
|
||||||
|
|
||||||
Self::mixed_multiscalar_mul(
|
|
||||||
self,
|
|
||||||
static_scalars,
|
|
||||||
iter::empty::<Scalar>(),
|
|
||||||
iter::empty::<Self::Point>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for variable-time multiscalar multiplication with precomputation.
|
/// A trait for variable-time multiscalar multiplication with precomputation.
|
||||||
///
|
///
|
||||||
/// A general multiscalar multiplication with precomputation can be written as
|
/// A general multiscalar multiplication with precomputation can be written as
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue