mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-06 20:41:14 +00:00
Merge remote-tracking branch 'hdevalence/feature/refine-multiscalar-trait-bounds' into develop
This commit is contained in:
commit
ea66ab469b
3 changed files with 192 additions and 73 deletions
|
|
@ -453,32 +453,19 @@ impl EdwardsBasepointTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a vector of (possibly secret) scalars and a vector of
|
/// Internal multiscalar code.
|
||||||
/// (possibly secret) points, compute `c_1 P_1 + ... + c_n P_n`.
|
|
||||||
///
|
|
||||||
/// This function has the same behaviour as
|
|
||||||
/// `vartime::multiscalar_mult` but is constant-time.
|
|
||||||
///
|
|
||||||
/// # Input
|
|
||||||
///
|
|
||||||
/// A vector of `Scalar`s and a vector of `EdwardsPoints`. It is an
|
|
||||||
/// error to call this function with two vectors of different lengths.
|
|
||||||
///
|
|
||||||
/// XXX this takes `edwards::EdwardsPoints` because we have to alloc scratch space here anyways,
|
|
||||||
/// and we need some space to store the converted points, so we may as well do the conversion here.
|
|
||||||
/// maybe there's a better way to avoid code duplication... however we can't quite just write a
|
|
||||||
/// generic `multiscalar_mult` because the non-vectorized code passes between models and this code
|
|
||||||
/// doesn't.
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
|
pub fn multiscalar_mult<I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator,
|
||||||
J: IntoIterator<Item = &'b edwards::EdwardsPoint>
|
I::Item: Borrow<Scalar>,
|
||||||
|
J: IntoIterator,
|
||||||
|
J::Item: Borrow<edwards::EdwardsPoint>,
|
||||||
{
|
{
|
||||||
//assert_eq!(scalars.len(), points.len());
|
//assert_eq!(scalars.len(), points.len());
|
||||||
|
|
||||||
use clear_on_drop::ClearOnDrop;
|
use clear_on_drop::ClearOnDrop;
|
||||||
let lookup_tables_vec: Vec<_> = points.into_iter()
|
let lookup_tables_vec: Vec<_> = points.into_iter()
|
||||||
.map(|P| LookupTable::from(ExtendedPoint::from(*P)) )
|
.map(|P| LookupTable::from(ExtendedPoint::from(*P.borrow())) )
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
|
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
|
||||||
|
|
@ -489,7 +476,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> edwards::Edwards
|
||||||
//
|
//
|
||||||
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
||||||
let scalar_digits_vec: Vec<_> = scalars.into_iter()
|
let scalar_digits_vec: Vec<_> = scalars.into_iter()
|
||||||
.map(|c| c.to_radix_16())
|
.map(|c| c.borrow().to_radix_16())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// The above puts the scalar digits into a heap-allocated Vec.
|
// The above puts the scalar digits into a heap-allocated Vec.
|
||||||
|
|
@ -606,27 +593,21 @@ pub mod vartime {
|
||||||
Q.into()
|
Q.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a vector of public scalars and a vector of public points, compute
|
/// Internal multiscalar function
|
||||||
/// $$
|
|
||||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
|
||||||
/// $$
|
|
||||||
///
|
|
||||||
/// # Input
|
|
||||||
///
|
|
||||||
/// A vector of `Scalar`s and a vector of `EdwardsPoints`. It is an
|
|
||||||
/// error to call this function with two vectors of different lengths.
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
|
pub fn multiscalar_mult<I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator,
|
||||||
J: IntoIterator<Item = &'b edwards::EdwardsPoint>
|
I::Item: Borrow<Scalar>,
|
||||||
|
J: IntoIterator,
|
||||||
|
J::Item: Borrow<edwards::EdwardsPoint>,
|
||||||
{
|
{
|
||||||
//assert_eq!(scalars.len(), points.len());
|
//assert_eq!(scalars.len(), points.len());
|
||||||
|
|
||||||
let nafs: Vec<_> = scalars.into_iter()
|
let nafs: Vec<_> = scalars.into_iter()
|
||||||
.map(|c| c.non_adjacent_form()).collect();
|
.map(|c| c.borrow().non_adjacent_form()).collect();
|
||||||
|
|
||||||
let odd_multiples: Vec<_> = points.into_iter()
|
let odd_multiples: Vec<_> = points.into_iter()
|
||||||
.map(|P| OddMultiples::create((*P).into()) ).collect();
|
.map(|P| OddMultiples::create((*P.borrow()).into()) ).collect();
|
||||||
|
|
||||||
let mut Q = ExtendedPoint::identity();
|
let mut Q = ExtendedPoint::identity();
|
||||||
|
|
||||||
|
|
|
||||||
106
src/edwards.rs
106
src/edwards.rs
|
|
@ -96,6 +96,7 @@ use core::ops::{Add, Sub, Neg};
|
||||||
use core::ops::{AddAssign, SubAssign};
|
use core::ops::{AddAssign, SubAssign};
|
||||||
use core::ops::{Mul, MulAssign};
|
use core::ops::{Mul, MulAssign};
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
use subtle::slices_equal;
|
use subtle::slices_equal;
|
||||||
use subtle::ConditionallyAssignable;
|
use subtle::ConditionallyAssignable;
|
||||||
|
|
@ -532,17 +533,49 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar {
|
||||||
/// This function has the same behaviour as
|
/// This function has the same behaviour as
|
||||||
/// `vartime::multiscalar_mult` but is constant-time.
|
/// `vartime::multiscalar_mult` but is constant-time.
|
||||||
///
|
///
|
||||||
/// # Input
|
/// It is an error to call this function with two iterators of different lengths.
|
||||||
///
|
///
|
||||||
/// A iterable of `Scalar`s and a iterable of `EdwardsPoints`. It is an
|
/// # Examples
|
||||||
/// error to call this function with two iterators of different 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<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_mult(&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_mult(minus_abc, &[P,Q,R]);
|
||||||
|
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||||
|
///
|
||||||
|
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||||
|
/// ```
|
||||||
// XXX later when we do more fancy multiscalar mults, we can delegate
|
// XXX later when we do more fancy multiscalar mults, we can delegate
|
||||||
// based on the iter's size hint -- hdevalence
|
// based on the iter's size hint -- hdevalence
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
|
pub fn multiscalar_mult<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator,
|
||||||
J: IntoIterator<Item = &'b EdwardsPoint>
|
I::Item: Borrow<Scalar>,
|
||||||
|
J: IntoIterator,
|
||||||
|
J::Item: Borrow<EdwardsPoint>,
|
||||||
{
|
{
|
||||||
// If we built with AVX2, use the AVX2 backend.
|
// If we built with AVX2, use the AVX2 backend.
|
||||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
||||||
|
|
@ -557,7 +590,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||||
use clear_on_drop::ClearOnDrop;
|
use clear_on_drop::ClearOnDrop;
|
||||||
|
|
||||||
let lookup_tables_vec: Vec<_> = points.into_iter()
|
let lookup_tables_vec: Vec<_> = points.into_iter()
|
||||||
.map(|P| LookupTable::<ProjectiveNielsPoint>::from(P) )
|
.map(|P| LookupTable::<ProjectiveNielsPoint>::from(P.borrow()) )
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
|
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
|
||||||
|
|
@ -568,7 +601,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||||
//
|
//
|
||||||
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
||||||
let scalar_digits_vec: Vec<_> = scalars.into_iter()
|
let scalar_digits_vec: Vec<_> = scalars.into_iter()
|
||||||
.map(|c| c.to_radix_16())
|
.map(|c| c.borrow().to_radix_16())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// This above puts the scalar digits into a heap-allocated Vec.
|
// This above puts the scalar digits into a heap-allocated Vec.
|
||||||
|
|
@ -867,20 +900,57 @@ pub mod vartime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given an iterable of public scalars and an iterable of public
|
/// Given an iterator of public scalars and an iterator of public points, compute
|
||||||
/// points, compute
|
|
||||||
/// $$
|
/// $$
|
||||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||||
/// $$
|
/// $$
|
||||||
///
|
///
|
||||||
/// # Input
|
/// This function has the same behaviour as
|
||||||
|
/// `edwards::multiscalar_mult` but operates on non-secret data.
|
||||||
///
|
///
|
||||||
/// A iterable of `Scalar`s and a iterable of `EdwardsPoints`. It is an
|
/// It is an error to call this function with two iterators of different lengths.
|
||||||
/// 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_mult(&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_mult(minus_abc, &[P,Q,R]);
|
||||||
|
/// // Note: minus_abc.into_iter(): Iterator<Item=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"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> EdwardsPoint
|
pub fn multiscalar_mult<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator,
|
||||||
J: IntoIterator<Item = &'b EdwardsPoint>
|
I::Item: Borrow<Scalar>,
|
||||||
|
J: IntoIterator,
|
||||||
|
J::Item: Borrow<EdwardsPoint>,
|
||||||
{
|
{
|
||||||
// If we built with AVX2, use the AVX2 backend.
|
// If we built with AVX2, use the AVX2 backend.
|
||||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
||||||
|
|
@ -893,9 +963,9 @@ pub mod vartime {
|
||||||
//assert_eq!(scalars.len(), points.len());
|
//assert_eq!(scalars.len(), points.len());
|
||||||
|
|
||||||
let nafs: Vec<_> = scalars.into_iter()
|
let nafs: Vec<_> = scalars.into_iter()
|
||||||
.map(|c| c.non_adjacent_form()).collect();
|
.map(|c| c.borrow().non_adjacent_form()).collect();
|
||||||
let odd_multiples: Vec<_> = points.into_iter()
|
let odd_multiples: Vec<_> = points.into_iter()
|
||||||
.map(|P| OddMultiples::create(P)).collect();
|
.map(|P| OddMultiples::create(P.borrow())).collect();
|
||||||
|
|
||||||
let mut r = ProjectivePoint::identity();
|
let mut r = ProjectivePoint::identity();
|
||||||
|
|
||||||
|
|
|
||||||
108
src/ristretto.rs
108
src/ristretto.rs
|
|
@ -463,6 +463,10 @@ mod notes {
|
||||||
}
|
}
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
use core::ops::{Add, Sub, Neg};
|
||||||
|
use core::ops::{AddAssign, SubAssign};
|
||||||
|
use core::ops::{Mul, MulAssign};
|
||||||
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
@ -473,10 +477,6 @@ use generic_array::typenum::U32;
|
||||||
use constants;
|
use constants;
|
||||||
use field::FieldElement;
|
use field::FieldElement;
|
||||||
|
|
||||||
use core::ops::{Add, Sub, Neg};
|
|
||||||
use core::ops::{AddAssign, SubAssign};
|
|
||||||
use core::ops::{Mul, MulAssign};
|
|
||||||
|
|
||||||
use subtle;
|
use subtle;
|
||||||
use subtle::ConditionallyAssignable;
|
use subtle::ConditionallyAssignable;
|
||||||
use subtle::ConditionallyNegatable;
|
use subtle::ConditionallyNegatable;
|
||||||
|
|
@ -1059,16 +1059,49 @@ define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint
|
||||||
/// This function has the same behaviour as
|
/// This function has the same behaviour as
|
||||||
/// `vartime::multiscalar_mult` but is constant-time.
|
/// `vartime::multiscalar_mult` but is constant-time.
|
||||||
///
|
///
|
||||||
/// # Input
|
/// It is an error to call this function with two iterators of different lengths.
|
||||||
///
|
///
|
||||||
/// An iterable of `Scalar`s and a iterable of `RistrettoPoints`. It is an
|
/// # Examples
|
||||||
/// error to call this function with two iterators of different 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<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_mult(&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_mult(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"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
|
pub fn multiscalar_mult<I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator,
|
||||||
J: IntoIterator<Item = &'b RistrettoPoint>,
|
I::Item: Borrow<Scalar>,
|
||||||
|
J: IntoIterator,
|
||||||
|
J::Item: Borrow<RistrettoPoint>,
|
||||||
{
|
{
|
||||||
let extended_points = points.into_iter().map(|P| &P.0);
|
let extended_points = points.into_iter().map(|P| P.borrow().0);
|
||||||
RistrettoPoint(edwards::multiscalar_mult(scalars, extended_points))
|
RistrettoPoint(edwards::multiscalar_mult(scalars, extended_points))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1169,22 +1202,57 @@ pub mod vartime {
|
||||||
//! Variable-time operations on ristretto points, useful for non-secret data.
|
//! Variable-time operations on ristretto points, useful for non-secret data.
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Given an iterable of public scalars and an iterable of public
|
/// Given an iterator of public scalars and an iterator of public points, compute
|
||||||
/// points, compute
|
|
||||||
/// $$
|
/// $$
|
||||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||||
/// $$
|
/// $$
|
||||||
///
|
///
|
||||||
/// # Input
|
/// This function has the same behaviour as
|
||||||
|
/// `vartime::multiscalar_mult` but is constant-time.
|
||||||
///
|
///
|
||||||
/// A iterable of `Scalar`s and a iterable of `RistrettoPoints`. It is an
|
/// It is an error to call this function with two iterators of different lengths.
|
||||||
/// 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_mult(&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_mult(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"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
|
pub fn multiscalar_mult<I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator,
|
||||||
J: IntoIterator<Item = &'b RistrettoPoint>
|
I::Item: Borrow<Scalar>,
|
||||||
|
J: IntoIterator,
|
||||||
|
J::Item: Borrow<RistrettoPoint>,
|
||||||
{
|
{
|
||||||
let extended_points = points.into_iter().map(|P| &P.0);
|
let extended_points = points.into_iter().map(|P| P.borrow().0);
|
||||||
RistrettoPoint(edwards::vartime::multiscalar_mult(scalars, extended_points))
|
RistrettoPoint(edwards::vartime::multiscalar_mult(scalars, extended_points))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue