Skip to content

Commit

Permalink
Add Ristretto precomputation facade.
Browse files Browse the repository at this point in the history
  • Loading branch information
hdevalence committed Feb 12, 2019
1 parent 8adcfb7 commit 27daa52
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 9 deletions.
10 changes: 4 additions & 6 deletions src/edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,17 +677,17 @@ impl VartimeMultiscalarMul for EdwardsPoint {
// 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(all(feature = "alloc", feature = "yolocrypto"))]
#[cfg(feature = "alloc")]
pub struct EdwardsPrecomputation(scalar_mul::precomputed_straus::PrecomputedStraus);

/// Precomputation for variable-time 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(all(feature = "alloc", feature = "yolocrypto"))]
#[cfg(feature = "alloc")]
pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus);

#[cfg(all(feature = "alloc", feature = "yolocrypto"))]
#[cfg(feature = "alloc")]
impl PrecomputedMultiscalarMul for EdwardsPrecomputation {
type Point = EdwardsPoint;

Expand Down Expand Up @@ -720,7 +720,7 @@ impl PrecomputedMultiscalarMul for EdwardsPrecomputation {
}
}

#[cfg(all(feature = "alloc", feature = "yolocrypto"))]
#[cfg(feature = "alloc")]
impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
type Point = EdwardsPoint;

Expand Down Expand Up @@ -1281,7 +1281,6 @@ mod test {
}

#[test]
#[cfg(feature = "yolocrypto")]
fn precomputed_vs_nonprecomputed_multiscalar() {
let mut rng = rand::thread_rng();

Expand Down Expand Up @@ -1325,7 +1324,6 @@ mod test {
}

#[test]
#[cfg(feature = "yolocrypto")]
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
let mut rng = rand::thread_rng();

Expand Down
194 changes: 191 additions & 3 deletions src/ristretto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,21 @@ use scalar::Scalar;

use traits::Identity;
#[cfg(any(feature = "alloc", feature = "std"))]
use traits::{MultiscalarMul, VartimeMultiscalarMul};
use traits::{
MultiscalarMul, PrecomputedMultiscalarMul, VartimeMultiscalarMul,
VartimePrecomputedMultiscalarMul,
};

#[cfg(not(all(
feature = "simd_backend",
any(target_feature = "avx2", target_feature = "avx512ifma")
)))]
use backend::serial::scalar_mul;
#[cfg(all(
feature = "simd_backend",
any(target_feature = "avx2", target_feature = "avx512ifma")
))]
use backend::vector::scalar_mul;

// ------------------------------------------------------------------------
// Compressed points
Expand Down Expand Up @@ -891,8 +905,96 @@ impl VartimeMultiscalarMul for RistrettoPoint {
{
let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.borrow().0));

EdwardsPoint::optional_multiscalar_mul(scalars, extended_points)
.map(|P| RistrettoPoint(P))
EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(|P| RistrettoPoint(P))
}
}

/// 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.
// 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 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")]
impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
type Point = RistrettoPoint;

fn new<I>(static_points: I) -> Self
where
I: IntoIterator,
I::Item: Borrow<Self::Point>,
{
Self(
scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(
static_points.into_iter().map(|P| P.borrow().0),
),
)
}

fn optional_mixed_multiscalar_mul<I, J, K>(
&self,
static_scalars: I,
dynamic_scalars: J,
dynamic_points: K,
) -> Option<Self::Point>
where
I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator,
J::Item: Borrow<Scalar>,
K: IntoIterator<Item = Option<Self::Point>>,
{
self.0
.optional_mixed_multiscalar_mul(
static_scalars,
dynamic_scalars,
dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)),
)
.map(|P_ed| RistrettoPoint(P_ed))
}
}

Expand Down Expand Up @@ -1263,4 +1365,90 @@ mod test {
P.compress();
}
}

#[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]
fn vartime_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 = VartimeRistrettoPrecomputation::new(static_points.iter());

let P = precomputation.vartime_mixed_multiscalar_mul(
&static_scalars,
&dynamic_scalars,
&dynamic_points,
);

use traits::VartimeMultiscalarMul;
let Q = RistrettoPoint::vartime_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());
}
}

0 comments on commit 27daa52

Please sign in to comment.