mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Add MultiscalarMul and VartimeMultiscalarMul traits.
These traits have the same interface, but with different names, so that it's not possible to use them interchangeably. (Constant-time and variable-time routines should not be used interchangeably). This commit changes the external API to use these traits, replacing ``` edwards::multiscalar_mul edwards::vartime::multiscalar_mul ``` with ``` EdwardsPoint::multiscalar_mul (as an impl) EdwardsPoint::vartime_multiscalar_mul (as an impl) ``` and similarly for Ristretto. Refactoring the backend is for a later commit. Multiscalar multiplication with precomputation is for a later commit. The `edwards::vartime` module is retained since it's used for `vartime_double_base_scalar_mul`. It should be subsumed into the precomputation API in a later commit.
This commit is contained in:
parent
83280ca181
commit
e3bf9b0213
4 changed files with 236 additions and 252 deletions
|
|
@ -18,7 +18,10 @@ static MULTISCALAR_SIZES: [usize; 13] = [1, 2, 4, 8, 16, 32, 64, 128, 256, 384,
|
|||
|
||||
mod edwards_benches {
|
||||
use super::*;
|
||||
use curve25519_dalek::edwards::{self, EdwardsPoint};
|
||||
use curve25519_dalek::edwards;
|
||||
use curve25519_dalek::edwards::EdwardsPoint;
|
||||
use curve25519_dalek::traits::MultiscalarMul;
|
||||
use curve25519_dalek::traits::VartimeMultiscalarMul;
|
||||
|
||||
fn compress(c: &mut Criterion) {
|
||||
let B = &constants::ED25519_BASEPOINT_POINT;
|
||||
|
|
@ -70,7 +73,7 @@ mod edwards_benches {
|
|||
.iter()
|
||||
.map(|s| s * &constants::ED25519_BASEPOINT_TABLE)
|
||||
.collect();
|
||||
b.iter(|| edwards::multiscalar_mul(&scalars, &points));
|
||||
b.iter(|| EdwardsPoint::multiscalar_mul(&scalars, &points));
|
||||
},
|
||||
&MULTISCALAR_SIZES,
|
||||
);
|
||||
|
|
@ -86,7 +89,7 @@ mod edwards_benches {
|
|||
.iter()
|
||||
.map(|s| s * &constants::ED25519_BASEPOINT_TABLE)
|
||||
.collect();
|
||||
b.iter(|| edwards::vartime::multiscalar_mul(&scalars, &points));
|
||||
b.iter(|| EdwardsPoint::vartime_multiscalar_mul(&scalars, &points));
|
||||
},
|
||||
&MULTISCALAR_SIZES,
|
||||
);
|
||||
|
|
|
|||
201
src/edwards.rs
201
src/edwards.rs
|
|
@ -112,6 +112,7 @@ use field::FieldElement;
|
|||
use scalar::Scalar;
|
||||
|
||||
use montgomery::MontgomeryPoint;
|
||||
|
||||
use curve_models::ProjectivePoint;
|
||||
use curve_models::CompletedPoint;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
|
@ -121,6 +122,8 @@ use scalar_mul::window::LookupTable;
|
|||
|
||||
use traits::{Identity, IsIdentity};
|
||||
use traits::ValidityCheck;
|
||||
use traits::MultiscalarMul;
|
||||
use traits::VartimeMultiscalarMul;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Compressed points
|
||||
|
|
@ -516,71 +519,68 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given an iterator of (possibly secret) scalars and an iterator of
|
||||
/// (possibly secret) points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// This function has the same behaviour as
|
||||
/// `vartime::multiscalar_mul` but is constant-time.
|
||||
///
|
||||
/// It is an error to call this function with two iterators of different lengths.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// 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<EdwardsPoint>`), to allow
|
||||
/// iterators returning either `Scalar`s or `&Scalar`s.
|
||||
///
|
||||
/// ```
|
||||
/// use curve25519_dalek::{constants, edwards};
|
||||
/// use curve25519_dalek::scalar::Scalar;
|
||||
///
|
||||
/// // Some scalars
|
||||
/// let a = Scalar::from_u64(87329482);
|
||||
/// let b = Scalar::from_u64(37264829);
|
||||
/// let c = Scalar::from_u64(98098098);
|
||||
///
|
||||
/// // Some points
|
||||
/// let P = constants::ED25519_BASEPOINT_POINT;
|
||||
/// let Q = P + P;
|
||||
/// let R = P + Q;
|
||||
///
|
||||
/// // A1 = a*P + b*Q + c*R
|
||||
/// let abc = [a,b,c];
|
||||
/// let A1 = edwards::multiscalar_mul(&abc, &[P,Q,R]);
|
||||
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
|
||||
///
|
||||
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
|
||||
/// let minus_abc = abc.iter().map(|x| -x);
|
||||
/// let A2 = edwards::multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
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
|
||||
// ------------------------------------------------------------------------
|
||||
// Multiscalar Multiplication impls
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="avx2_backend", target_feature="avx2"))]
|
||||
// These use the iterator's size hint and the target settings to
|
||||
// forward to a specific backend implementation.
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
impl MultiscalarMul for EdwardsPoint {
|
||||
type Point = EdwardsPoint;
|
||||
|
||||
fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
use backend::avx2::scalar_mul::straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
// 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="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="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use scalar_mul::straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(feature="avx2_backend", target_feature="avx2")))]
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
impl VartimeMultiscalarMul for EdwardsPoint {
|
||||
type Point = EdwardsPoint;
|
||||
|
||||
fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
use scalar_mul::straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
// 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="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="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use scalar_mul::vartime_straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -787,78 +787,17 @@ impl Debug for EdwardsBasepointTable {
|
|||
// Variable-time functions
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// Variable-time operations on curve points, useful for non-secret data.
|
||||
///
|
||||
/// XXX delete this whole module
|
||||
pub mod vartime {
|
||||
//! Variable-time operations on curve points, useful for non-secret data.
|
||||
use super::*;
|
||||
|
||||
/// Given an iterator of public scalars and an iterator of public points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// This function has the same behaviour as
|
||||
/// `edwards::multiscalar_mul` but operates on non-secret data.
|
||||
///
|
||||
/// It is an error to call this function with two iterators of different lengths.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// 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<EdwardsPoint>`), to allow
|
||||
/// iterators returning either `Scalar`s or `&Scalar`s.
|
||||
///
|
||||
/// ```
|
||||
/// use curve25519_dalek::{constants, edwards};
|
||||
/// use curve25519_dalek::scalar::Scalar;
|
||||
///
|
||||
/// // Some scalars
|
||||
/// let a = Scalar::from_u64(87329482);
|
||||
/// let b = Scalar::from_u64(37264829);
|
||||
/// let c = Scalar::from_u64(98098098);
|
||||
///
|
||||
/// // Some points
|
||||
/// let P = constants::ED25519_BASEPOINT_POINT;
|
||||
/// let Q = P + P;
|
||||
/// let R = P + Q;
|
||||
///
|
||||
/// // A1 = a*P + b*Q + c*R
|
||||
/// let abc = [a,b,c];
|
||||
/// let A1 = edwards::vartime::multiscalar_mul(&abc, &[P,Q,R]);
|
||||
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
|
||||
///
|
||||
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
|
||||
/// let minus_abc = abc.iter().map(|x| -x);
|
||||
/// let A2 = edwards::vartime::multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
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="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="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use scalar_mul::vartime_straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||
#[cfg(feature="stage2_build")]
|
||||
///
|
||||
/// XXX eliminate this function when we have the precomputation API
|
||||
#[cfg(feature = "stage2_build")]
|
||||
pub fn double_scalar_mul_basepoint(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="avx2_backend", target_feature="avx2"))]
|
||||
|
|
@ -1211,7 +1150,7 @@ mod test {
|
|||
#[test]
|
||||
fn multiscalar_mul_vs_ed25519py() {
|
||||
let A = A_TIMES_BASEPOINT.decompress().unwrap();
|
||||
let result = vartime::multiscalar_mul(
|
||||
let result = EdwardsPoint::vartime_multiscalar_mul(
|
||||
&[A_SCALAR, B_SCALAR],
|
||||
&[A, constants::ED25519_BASEPOINT_POINT]
|
||||
);
|
||||
|
|
@ -1221,11 +1160,11 @@ mod test {
|
|||
#[test]
|
||||
fn multiscalar_mul_vartime_vs_consttime() {
|
||||
let A = A_TIMES_BASEPOINT.decompress().unwrap();
|
||||
let result_vartime = vartime::multiscalar_mul(
|
||||
let result_vartime = EdwardsPoint::vartime_multiscalar_mul(
|
||||
&[A_SCALAR, B_SCALAR],
|
||||
&[A, constants::ED25519_BASEPOINT_POINT]
|
||||
);
|
||||
let result_consttime = multiscalar_mul(
|
||||
let result_consttime = EdwardsPoint::multiscalar_mul(
|
||||
&[A_SCALAR, B_SCALAR],
|
||||
&[A, constants::ED25519_BASEPOINT_POINT]
|
||||
);
|
||||
|
|
|
|||
157
src/ristretto.rs
157
src/ristretto.rs
|
|
@ -186,7 +186,6 @@ use subtle::ConditionallyNegatable;
|
|||
use subtle::ConstantTimeEq;
|
||||
use subtle::Choice;
|
||||
|
||||
use edwards;
|
||||
use edwards::EdwardsPoint;
|
||||
use edwards::EdwardsBasepointTable;
|
||||
|
||||
|
|
@ -194,7 +193,7 @@ use scalar::Scalar;
|
|||
|
||||
use curve_models::CompletedPoint;
|
||||
|
||||
use traits::Identity;
|
||||
use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Compressed points
|
||||
|
|
@ -790,60 +789,47 @@ define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar);
|
|||
define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint);
|
||||
define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Multiscalar Multiplication impls
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// These use iterator combinators to unwrap the underlying points and
|
||||
// forward to the EdwardsPoint implementations.
|
||||
|
||||
/// Given an iterator of (possibly secret) scalars and an iterator of
|
||||
/// (possibly secret) points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// This function has the same behaviour as
|
||||
/// `vartime::multiscalar_mul` but is constant-time.
|
||||
///
|
||||
/// It is an error to call this function with two iterators of different lengths.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// 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<RistrettoPoint>`), to allow
|
||||
/// iterators returning either `Scalar`s or `&Scalar`s.
|
||||
///
|
||||
/// ```
|
||||
/// use curve25519_dalek::{constants, ristretto};
|
||||
/// use curve25519_dalek::scalar::Scalar;
|
||||
///
|
||||
/// // Some scalars
|
||||
/// let a = Scalar::from_u64(87329482);
|
||||
/// let b = Scalar::from_u64(37264829);
|
||||
/// let c = Scalar::from_u64(98098098);
|
||||
///
|
||||
/// // Some points
|
||||
/// let P = constants::RISTRETTO_BASEPOINT_POINT;
|
||||
/// let Q = P + P;
|
||||
/// let R = P + Q;
|
||||
///
|
||||
/// // A1 = a*P + b*Q + c*R
|
||||
/// let abc = [a,b,c];
|
||||
/// let A1 = ristretto::multiscalar_mul(&abc, &[P,Q,R]);
|
||||
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
|
||||
///
|
||||
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
|
||||
/// let minus_abc = abc.iter().map(|x| -x);
|
||||
/// let A2 = ristretto::multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||
where I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<RistrettoPoint>,
|
||||
{
|
||||
let extended_points = points.into_iter().map(|P| P.borrow().0);
|
||||
RistrettoPoint(edwards::multiscalar_mul(scalars, extended_points))
|
||||
impl MultiscalarMul for RistrettoPoint {
|
||||
type Point = RistrettoPoint;
|
||||
|
||||
fn multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<RistrettoPoint>,
|
||||
{
|
||||
let extended_points = points.into_iter().map(|P| P.borrow().0);
|
||||
RistrettoPoint(
|
||||
EdwardsPoint::multiscalar_mul(scalars, extended_points)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
impl VartimeMultiscalarMul for RistrettoPoint {
|
||||
type Point = RistrettoPoint;
|
||||
|
||||
fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<RistrettoPoint>,
|
||||
{
|
||||
let extended_points = points.into_iter().map(|P| P.borrow().0);
|
||||
RistrettoPoint(
|
||||
EdwardsPoint::vartime_multiscalar_mul(scalars, extended_points)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A precomputed table of multiples of a basepoint, used to accelerate
|
||||
|
|
@ -947,69 +933,6 @@ impl Debug for RistrettoPoint {
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variable-time functions
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
pub mod vartime {
|
||||
//! Variable-time operations on ristretto points, useful for non-secret data.
|
||||
use super::*;
|
||||
|
||||
/// Given an iterator of public scalars and an iterator of public points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// This function has the same behaviour as
|
||||
/// `vartime::multiscalar_mul` but is constant-time.
|
||||
///
|
||||
/// It is an error to call this function with two iterators of different lengths.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// 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<RistrettoPoint>`), to allow
|
||||
/// iterators returning either `Scalar`s or `&Scalar`s.
|
||||
///
|
||||
/// ```
|
||||
/// use curve25519_dalek::{constants, ristretto};
|
||||
/// use curve25519_dalek::scalar::Scalar;
|
||||
///
|
||||
/// // Some scalars
|
||||
/// let a = Scalar::from_u64(87329482);
|
||||
/// let b = Scalar::from_u64(37264829);
|
||||
/// let c = Scalar::from_u64(98098098);
|
||||
///
|
||||
/// // Some points
|
||||
/// let P = constants::RISTRETTO_BASEPOINT_POINT;
|
||||
/// let Q = P + P;
|
||||
/// let R = P + Q;
|
||||
///
|
||||
/// // A1 = a*P + b*Q + c*R
|
||||
/// let abc = [a,b,c];
|
||||
/// let A1 = ristretto::vartime::multiscalar_mul(&abc, &[P,Q,R]);
|
||||
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
|
||||
///
|
||||
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
|
||||
/// let minus_abc = abc.iter().map(|x| -x);
|
||||
/// let A2 = ristretto::vartime::multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||
where I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<RistrettoPoint>,
|
||||
{
|
||||
let extended_points = points.into_iter().map(|P| P.borrow().0);
|
||||
RistrettoPoint(edwards::vartime::multiscalar_mul(scalars, extended_points))
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
121
src/traits.rs
121
src/traits.rs
|
|
@ -10,8 +10,12 @@
|
|||
|
||||
//! Module for common traits.
|
||||
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use subtle;
|
||||
|
||||
use scalar::Scalar;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Public Traits
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -32,12 +36,127 @@ pub trait IsIdentity {
|
|||
/// Implement generic identity equality testing for a point representations
|
||||
/// which have constant-time equality testing and a defined identity
|
||||
/// constructor.
|
||||
impl<T> IsIdentity for T where T: subtle::ConstantTimeEq + Identity {
|
||||
impl<T> IsIdentity for T
|
||||
where
|
||||
T: subtle::ConstantTimeEq + Identity,
|
||||
{
|
||||
fn is_identity(&self) -> bool {
|
||||
self.ct_eq(&T::identity()).unwrap_u8() == 1u8
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for constant-time multiscalar multiplication without precomputation.
|
||||
pub trait MultiscalarMul {
|
||||
/// The type of point being multiplied, e.g., `RistrettoPoint`.
|
||||
type Point;
|
||||
|
||||
/// Given an iterator of (possibly secret) scalars and an iterator of
|
||||
/// public points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// It is an error to call this function with two iterators of different lengths.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// ```
|
||||
/// use curve25519_dalek::constants;
|
||||
/// use curve25519_dalek::traits::MultiscalarMul;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// use curve25519_dalek::scalar::Scalar;
|
||||
///
|
||||
/// // Some scalars
|
||||
/// let a = Scalar::from_u64(87329482);
|
||||
/// let b = Scalar::from_u64(37264829);
|
||||
/// let c = Scalar::from_u64(98098098);
|
||||
///
|
||||
/// // Some points
|
||||
/// let P = constants::RISTRETTO_BASEPOINT_POINT;
|
||||
/// let Q = P + P;
|
||||
/// let R = P + Q;
|
||||
///
|
||||
/// // A1 = a*P + b*Q + c*R
|
||||
/// let abc = [a,b,c];
|
||||
/// let A1 = RistrettoPoint::multiscalar_mul(&abc, &[P,Q,R]);
|
||||
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
|
||||
///
|
||||
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
|
||||
/// let minus_abc = abc.iter().map(|x| -x);
|
||||
/// let A2 = RistrettoPoint::multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
fn multiscalar_mul<I, J>(scalars: I, points: J) -> Self::Point
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<Self::Point>;
|
||||
}
|
||||
|
||||
/// A trait for variable-time multiscalar multiplication without precomputation.
|
||||
pub trait VartimeMultiscalarMul {
|
||||
/// The type of point being multiplied, e.g., `RistrettoPoint`.
|
||||
type Point;
|
||||
|
||||
/// Given an iterator of (possibly secret) scalars and an iterator of
|
||||
/// public points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// It is an error to call this function with two iterators of different lengths.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// ```
|
||||
/// use curve25519_dalek::constants;
|
||||
/// use curve25519_dalek::traits::MultiscalarMul;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// use curve25519_dalek::scalar::Scalar;
|
||||
///
|
||||
/// // Some scalars
|
||||
/// let a = Scalar::from_u64(87329482);
|
||||
/// let b = Scalar::from_u64(37264829);
|
||||
/// let c = Scalar::from_u64(98098098);
|
||||
///
|
||||
/// // Some points
|
||||
/// let P = constants::RISTRETTO_BASEPOINT_POINT;
|
||||
/// let Q = P + P;
|
||||
/// let R = P + Q;
|
||||
///
|
||||
/// // A1 = a*P + b*Q + c*R
|
||||
/// let abc = [a,b,c];
|
||||
/// let A1 = RistrettoPoint::multiscalar_mul(&abc, &[P,Q,R]);
|
||||
/// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
|
||||
///
|
||||
/// // A2 = (-a)*P + (-b)*Q + (-c)*R
|
||||
/// let minus_abc = abc.iter().map(|x| -x);
|
||||
/// let A2 = RistrettoPoint::multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self::Point
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<Self::Point>;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Private Traits
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue