mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Merge pull request #163 from hdevalence/fallible-multiscalar-mul
Allow Options in the VartimeMultiscalarMul trait
This commit is contained in:
commit
bb50700d77
4 changed files with 94 additions and 25 deletions
|
|
@ -558,12 +558,11 @@ impl MultiscalarMul for EdwardsPoint {
|
|||
impl VartimeMultiscalarMul for EdwardsPoint {
|
||||
type Point = EdwardsPoint;
|
||||
|
||||
fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<EdwardsPoint>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
J: IntoIterator<Item = Option<EdwardsPoint>>,
|
||||
{
|
||||
// XXX later when we do more fancy multiscalar mults, we can
|
||||
// delegate based on the iter's size hint -- hdevalence
|
||||
|
|
@ -572,13 +571,13 @@ impl VartimeMultiscalarMul for EdwardsPoint {
|
|||
#[cfg(all(feature="avx2_backend", target_feature="avx2"))]
|
||||
{
|
||||
use backend::avx2::scalar_mul::straus::Straus;
|
||||
Straus::vartime_multiscalar_mul(scalars, points)
|
||||
Straus::optional_multiscalar_mul(scalars, points)
|
||||
}
|
||||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(feature="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use scalar_mul::straus::Straus;
|
||||
Straus::vartime_multiscalar_mul(scalars, points)
|
||||
Straus::optional_multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -816,17 +816,16 @@ impl MultiscalarMul for RistrettoPoint {
|
|||
impl VartimeMultiscalarMul for RistrettoPoint {
|
||||
type Point = RistrettoPoint;
|
||||
|
||||
fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||
fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<RistrettoPoint>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<RistrettoPoint>,
|
||||
J: IntoIterator<Item = Option<RistrettoPoint>>,
|
||||
{
|
||||
let extended_points = points.into_iter().map(|P| P.borrow().0);
|
||||
RistrettoPoint(
|
||||
EdwardsPoint::vartime_multiscalar_mul(scalars, extended_points)
|
||||
)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,12 +152,11 @@ impl VartimeMultiscalarMul for Straus {
|
|||
/// The non-adjacent form has signed, odd digits. Using only odd
|
||||
/// digits halves the table size (since we only need odd
|
||||
/// multiples), or gives fewer additions for the same table size.
|
||||
fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<EdwardsPoint>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
J: IntoIterator<Item = Option<EdwardsPoint>>,
|
||||
{
|
||||
use curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint};
|
||||
use scalar_mul::window::NafLookupTable5;
|
||||
|
|
@ -167,10 +166,15 @@ impl VartimeMultiscalarMul for Straus {
|
|||
.into_iter()
|
||||
.map(|c| c.borrow().non_adjacent_form(5))
|
||||
.collect();
|
||||
let lookup_tables: Vec<_> = points
|
||||
|
||||
let lookup_tables = match points
|
||||
.into_iter()
|
||||
.map(|P| NafLookupTable5::<ProjectiveNielsPoint>::from(P.borrow()))
|
||||
.collect();
|
||||
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<ProjectiveNielsPoint>::from(&P)))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
{
|
||||
Some(x) => x,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
|
||||
|
|
@ -188,6 +192,6 @@ impl VartimeMultiscalarMul for Straus {
|
|||
r = t.to_projective();
|
||||
}
|
||||
|
||||
r.to_extended()
|
||||
Some(r.to_extended())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,11 +106,70 @@ 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
|
||||
/// Given an iterator of public scalars and an iterator of
|
||||
/// `Option`s of points, compute either `Some(Q)`, where
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n,
|
||||
/// $$
|
||||
/// if all points were `Some(P_i)`, or else return `None`.
|
||||
///
|
||||
/// This function is particularly useful when verifying statements
|
||||
/// involving compressed points. Accepting `Option<Point>` allows
|
||||
/// inlining point decompression into the multiscalar call,
|
||||
/// avoiding the need for temporary buffers.
|
||||
/// ```
|
||||
/// use curve25519_dalek::constants;
|
||||
/// use curve25519_dalek::traits::VartimeMultiscalarMul;
|
||||
/// 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);
|
||||
/// let abc = [a,b,c];
|
||||
///
|
||||
/// // Some points
|
||||
/// let P = constants::RISTRETTO_BASEPOINT_POINT;
|
||||
/// let Q = P + P;
|
||||
/// let R = P + Q;
|
||||
/// let PQR = [P, Q, R];
|
||||
///
|
||||
/// let compressed = [P.compress(), Q.compress(), R.compress()];
|
||||
///
|
||||
/// // Now we can compute A1 = a*P + b*Q + c*R using P, Q, R:
|
||||
/// let A1 = RistrettoPoint::vartime_multiscalar_mul(&abc, &PQR);
|
||||
///
|
||||
/// // Or using the compressed points:
|
||||
/// let A2 = RistrettoPoint::optional_multiscalar_mul(
|
||||
/// &abc,
|
||||
/// compressed.iter().map(|pt| pt.decompress()),
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(A2, Some(A1));
|
||||
///
|
||||
/// // It's also possible to mix compressed and uncompressed points:
|
||||
/// let A3 = RistrettoPoint::optional_multiscalar_mul(
|
||||
/// abc.iter()
|
||||
/// .chain(abc.iter()),
|
||||
/// compressed.iter().map(|pt| pt.decompress())
|
||||
/// .chain(PQR.iter().map(|&pt| Some(pt))),
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(A3, Some(A1+A1));
|
||||
/// ```
|
||||
fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<Self::Point>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator<Item = Option<Self::Point>>;
|
||||
|
||||
/// Given an iterator of public scalars and an iterator of
|
||||
/// public points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n,
|
||||
/// $$
|
||||
/// using variable-time operations.
|
||||
///
|
||||
/// It is an error to call this function with two iterators of different lengths.
|
||||
///
|
||||
|
|
@ -123,7 +182,7 @@ pub trait VartimeMultiscalarMul {
|
|||
///
|
||||
/// ```
|
||||
/// use curve25519_dalek::constants;
|
||||
/// use curve25519_dalek::traits::MultiscalarMul;
|
||||
/// use curve25519_dalek::traits::VartimeMultiscalarMul;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// use curve25519_dalek::scalar::Scalar;
|
||||
///
|
||||
|
|
@ -139,22 +198,30 @@ pub trait VartimeMultiscalarMul {
|
|||
///
|
||||
/// // A1 = a*P + b*Q + c*R
|
||||
/// let abc = [a,b,c];
|
||||
/// let A1 = RistrettoPoint::multiscalar_mul(&abc, &[P,Q,R]);
|
||||
/// let A1 = RistrettoPoint::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 = RistrettoPoint::multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// let A2 = RistrettoPoint::vartime_multiscalar_mul(minus_abc, &[P,Q,R]);
|
||||
/// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
|
||||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
#[allow(non_snake_case)]
|
||||
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>;
|
||||
J::Item: Borrow<Self::Point>,
|
||||
Self::Point: Clone,
|
||||
{
|
||||
Self::optional_multiscalar_mul(
|
||||
scalars,
|
||||
points.into_iter().map(|P| Some(P.borrow().clone()))
|
||||
).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue