mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-04 20:03:40 +00:00
Add serial implementation of precomputation.
This commit is contained in:
parent
5daff66079
commit
c6acdfd5e2
4 changed files with 380 additions and 11 deletions
|
|
@ -20,8 +20,6 @@ mod edwards_benches {
|
||||||
use super::*;
|
use super::*;
|
||||||
use curve25519_dalek::edwards;
|
use curve25519_dalek::edwards;
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
use curve25519_dalek::traits::MultiscalarMul;
|
|
||||||
use curve25519_dalek::traits::VartimeMultiscalarMul;
|
|
||||||
|
|
||||||
fn compress(c: &mut Criterion) {
|
fn compress(c: &mut Criterion) {
|
||||||
let B = &constants::ED25519_BASEPOINT_POINT;
|
let B = &constants::ED25519_BASEPOINT_POINT;
|
||||||
|
|
@ -126,10 +124,10 @@ mod multiscalar_benches {
|
||||||
let (static_scalars, static_points) = construct(static_size);
|
let (static_scalars, static_points) = construct(static_size);
|
||||||
let (dynamic_scalars, dynamic_points) = construct(dynamic_size);
|
let (dynamic_scalars, dynamic_points) = construct(dynamic_size);
|
||||||
|
|
||||||
use curve25519_dalek::edwards::PrecomputedStraus;
|
use curve25519_dalek::edwards::EdwardsPrecomputation;
|
||||||
use curve25519_dalek::traits::PrecomputedMultiscalarMul;
|
use curve25519_dalek::traits::PrecomputedMultiscalarMul;
|
||||||
|
|
||||||
let precomp = PrecomputedStraus::new(&static_points);
|
let precomp = EdwardsPrecomputation::new(&static_points);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
precomp.mixed_multiscalar_mul(
|
precomp.mixed_multiscalar_mul(
|
||||||
|
|
@ -157,10 +155,10 @@ mod multiscalar_benches {
|
||||||
let (static_scalars, static_points) = construct(static_size);
|
let (static_scalars, static_points) = construct(static_size);
|
||||||
let (dynamic_scalars, dynamic_points) = construct(dynamic_size);
|
let (dynamic_scalars, dynamic_points) = construct(dynamic_size);
|
||||||
|
|
||||||
use curve25519_dalek::edwards::VartimePrecomputedStraus;
|
use curve25519_dalek::edwards::VartimeEdwardsPrecomputation;
|
||||||
use curve25519_dalek::traits::VartimePrecomputedMultiscalarMul;
|
use curve25519_dalek::traits::VartimePrecomputedMultiscalarMul;
|
||||||
|
|
||||||
let precomp = VartimePrecomputedStraus::new(&static_points);
|
let precomp = VartimeEdwardsPrecomputation::new(&static_points);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
precomp.vartime_mixed_multiscalar_mul(
|
precomp.vartime_mixed_multiscalar_mul(
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,6 @@ pub mod vartime_double_base;
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub mod straus;
|
pub mod straus;
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub mod precomputed_straus;
|
||||||
|
|
|
||||||
202
src/backend/serial/scalar_mul/precomputed_straus.rs
Normal file
202
src/backend/serial/scalar_mul/precomputed_straus.rs
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
// -*- mode: rust; -*-
|
||||||
|
//
|
||||||
|
// This file is part of curve25519-dalek.
|
||||||
|
// Copyright (c) 2019 Henry de Valence.
|
||||||
|
// See LICENSE for licensing information.
|
||||||
|
//
|
||||||
|
// Authors:
|
||||||
|
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||||
|
|
||||||
|
//! Precomputation for Straus's method.
|
||||||
|
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
|
use clear_on_drop::ClearOnDrop;
|
||||||
|
|
||||||
|
use backend::serial::curve_models::{
|
||||||
|
AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint,
|
||||||
|
};
|
||||||
|
use edwards::EdwardsPoint;
|
||||||
|
use scalar::Scalar;
|
||||||
|
use traits::Identity;
|
||||||
|
use traits::{PrecomputedMultiscalarMul, VartimePrecomputedMultiscalarMul};
|
||||||
|
use window::{LookupTable, NafLookupTable5, NafLookupTable8};
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
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>,
|
||||||
|
{
|
||||||
|
let mut static_scalars = static_scalars.into_iter();
|
||||||
|
let mut dynamic_scalars = dynamic_scalars.into_iter();
|
||||||
|
let mut dynamic_points = dynamic_points.into_iter();
|
||||||
|
|
||||||
|
// Check that the input lengths are consistent with each other:
|
||||||
|
let (ss_lo, ss_hi) = static_scalars.by_ref().size_hint();
|
||||||
|
let (ds_lo, ds_hi) = dynamic_scalars.by_ref().size_hint();
|
||||||
|
let (dp_lo, dp_hi) = dynamic_points.by_ref().size_hint();
|
||||||
|
|
||||||
|
// Static points match static scalars
|
||||||
|
let sp = self.static_lookup_tables.len();
|
||||||
|
assert_eq!(ss_lo, sp);
|
||||||
|
assert_eq!(ss_hi, Some(sp));
|
||||||
|
|
||||||
|
// Dynamic points match dynamic scalars
|
||||||
|
assert_eq!(ds_lo, dp_lo);
|
||||||
|
assert_eq!(ds_hi, Some(ds_lo));
|
||||||
|
assert_eq!(ds_hi, dp_hi);
|
||||||
|
let dp = dp_lo;
|
||||||
|
|
||||||
|
// 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.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.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
|
||||||
|
.map(|point| LookupTable::<ProjectiveNielsPoint>::from(point.borrow()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
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 {
|
||||||
|
static_lookup_tables: Vec<NafLookupTable8<AffineNielsPoint>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
|
||||||
|
type Point = EdwardsPoint;
|
||||||
|
|
||||||
|
fn new<I>(static_points: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
I::Item: Borrow<Self::Point>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
static_lookup_tables: static_points
|
||||||
|
.into_iter()
|
||||||
|
.map(|P| NafLookupTable8::<AffineNielsPoint>::from(P.borrow()))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vartime_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>,
|
||||||
|
{
|
||||||
|
let static_nafs = static_scalars
|
||||||
|
.into_iter()
|
||||||
|
.map(|c| c.borrow().non_adjacent_form(5))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let dynamic_nafs: Vec<_> = dynamic_scalars
|
||||||
|
.into_iter()
|
||||||
|
.map(|c| c.borrow().non_adjacent_form(5))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let dynamic_lookup_tables = dynamic_points
|
||||||
|
.into_iter()
|
||||||
|
.map(|P| NafLookupTable5::<ProjectiveNielsPoint>::from(P.borrow()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let sp = self.static_lookup_tables.len();
|
||||||
|
let dp = dynamic_lookup_tables.len();
|
||||||
|
assert_eq!(sp, static_nafs.len());
|
||||||
|
assert_eq!(dp, dynamic_nafs.len());
|
||||||
|
|
||||||
|
// We could save some doublings by looking for the highest
|
||||||
|
// nonzero NAF coefficient, but since we might have a lot of
|
||||||
|
// them to search, it's not clear it's worthwhile to check.
|
||||||
|
let mut S = ProjectivePoint::identity();
|
||||||
|
for j in (0..255).rev() {
|
||||||
|
let mut R: CompletedPoint = S.double();
|
||||||
|
|
||||||
|
for i in 0..dp {
|
||||||
|
let t_ij = dynamic_nafs[i][j];
|
||||||
|
if t_ij > 0 {
|
||||||
|
R = &R.to_extended() + &dynamic_lookup_tables[i].select(t_ij as usize);
|
||||||
|
} else if t_ij < 0 {
|
||||||
|
R = &R.to_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..sp {
|
||||||
|
let t_ij = static_nafs[i][j];
|
||||||
|
if t_ij > 0 {
|
||||||
|
R = &R.to_extended() + &self.static_lookup_tables[i].select(t_ij as usize);
|
||||||
|
} else if t_ij < 0 {
|
||||||
|
R = &R.to_extended() - &self.static_lookup_tables[i].select(-t_ij as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S = R.to_projective();
|
||||||
|
}
|
||||||
|
|
||||||
|
S.to_extended()
|
||||||
|
}
|
||||||
|
}
|
||||||
176
src/edwards.rs
176
src/edwards.rs
|
|
@ -112,23 +112,23 @@ use scalar::Scalar;
|
||||||
|
|
||||||
use montgomery::MontgomeryPoint;
|
use montgomery::MontgomeryPoint;
|
||||||
|
|
||||||
use backend::serial::curve_models::ProjectivePoint;
|
|
||||||
use backend::serial::curve_models::CompletedPoint;
|
|
||||||
use backend::serial::curve_models::AffineNielsPoint;
|
use backend::serial::curve_models::AffineNielsPoint;
|
||||||
|
use backend::serial::curve_models::CompletedPoint;
|
||||||
use backend::serial::curve_models::ProjectiveNielsPoint;
|
use backend::serial::curve_models::ProjectiveNielsPoint;
|
||||||
|
use backend::serial::curve_models::ProjectivePoint;
|
||||||
|
|
||||||
use window::LookupTable;
|
use window::LookupTable;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use traits::{Identity, IsIdentity};
|
|
||||||
use traits::ValidityCheck;
|
use traits::ValidityCheck;
|
||||||
|
use traits::{Identity, IsIdentity};
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use traits::MultiscalarMul;
|
use traits::{MultiscalarMul, PrecomputedMultiscalarMul};
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use traits::VartimeMultiscalarMul;
|
use traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
|
||||||
|
|
||||||
#[cfg(not(all(
|
#[cfg(not(all(
|
||||||
feature = "simd_backend",
|
feature = "simd_backend",
|
||||||
|
|
@ -673,6 +673,84 @@ 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(all(feature = "alloc", feature = "yolocrypto"))]
|
||||||
|
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"))]
|
||||||
|
pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus);
|
||||||
|
|
||||||
|
#[cfg(all(feature = "alloc", feature = "yolocrypto"))]
|
||||||
|
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(all(feature = "alloc", feature = "yolocrypto"))]
|
||||||
|
impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
|
||||||
|
type Point = EdwardsPoint;
|
||||||
|
|
||||||
|
fn new<I>(static_points: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
I::Item: Borrow<Self::Point>,
|
||||||
|
{
|
||||||
|
Self(scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vartime_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
|
||||||
|
.vartime_mixed_multiscalar_mul(static_scalars, dynamic_scalars, dynamic_points)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EdwardsPoint {
|
impl EdwardsPoint {
|
||||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||||
#[cfg(feature = "stage2_build")]
|
#[cfg(feature = "stage2_build")]
|
||||||
|
|
@ -1203,6 +1281,94 @@ mod test {
|
||||||
assert!(P1.compress().to_bytes() == P2.compress().to_bytes());
|
assert!(P1.compress().to_bytes() == P2.compress().to_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "yolocrypto")]
|
||||||
|
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]
|
||||||
|
#[cfg(feature = "yolocrypto")]
|
||||||
|
fn vartime_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 = VartimeEdwardsPrecomputation::new(static_points.iter());
|
||||||
|
|
||||||
|
let P = precomputation.vartime_mixed_multiscalar_mul(
|
||||||
|
&static_scalars,
|
||||||
|
&dynamic_scalars,
|
||||||
|
&dynamic_points,
|
||||||
|
);
|
||||||
|
|
||||||
|
use traits::VartimeMultiscalarMul;
|
||||||
|
let Q = EdwardsPoint::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());
|
||||||
|
}
|
||||||
|
|
||||||
mod vartime {
|
mod vartime {
|
||||||
use super::super::*;
|
use super::super::*;
|
||||||
use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT};
|
use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue