mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
curve: Support MSM #static scalars <= #static points (#668)
This commit is contained in:
parent
83a57e591f
commit
0964f800ab
4 changed files with 163 additions and 11 deletions
|
|
@ -75,7 +75,7 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
|
|||
|
||||
let sp = self.static_lookup_tables.len();
|
||||
let dp = dynamic_lookup_tables.len();
|
||||
assert_eq!(sp, static_nafs.len());
|
||||
assert!(sp >= static_nafs.len());
|
||||
assert_eq!(dp, dynamic_nafs.len());
|
||||
|
||||
// We could save some doublings by looking for the highest
|
||||
|
|
@ -99,7 +99,7 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
|
|||
}
|
||||
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..sp {
|
||||
for i in 0..static_nafs.len() {
|
||||
let t_ij = static_nafs[i][j];
|
||||
match t_ij.cmp(&0) {
|
||||
Ordering::Greater => {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ pub mod spec {
|
|||
|
||||
let sp = self.static_lookup_tables.len();
|
||||
let dp = dynamic_lookup_tables.len();
|
||||
assert_eq!(sp, static_nafs.len());
|
||||
assert!(sp >= static_nafs.len());
|
||||
assert_eq!(dp, dynamic_nafs.len());
|
||||
|
||||
// We could save some doublings by looking for the highest
|
||||
|
|
@ -107,7 +107,7 @@ pub mod spec {
|
|||
}
|
||||
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..sp {
|
||||
for i in 0..static_nafs.len() {
|
||||
let t_ij = static_nafs[i][j];
|
||||
match t_ij.cmp(&0) {
|
||||
Ordering::Greater => {
|
||||
|
|
|
|||
|
|
@ -1869,4 +1869,148 @@ mod test {
|
|||
assert_eq!(P.compress(), R.compress());
|
||||
assert_eq!(Q.compress(), R.compress());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
fn partial_precomputed_mixed_multiscalar_empty() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let n_static = 16;
|
||||
let n_dynamic = 8;
|
||||
|
||||
let static_points = (0..n_static)
|
||||
.map(|_| RistrettoPoint::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Use zero scalars
|
||||
let static_scalars = Vec::new();
|
||||
|
||||
let dynamic_points = (0..n_dynamic)
|
||||
.map(|_| RistrettoPoint::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let dynamic_scalars = (0..n_dynamic)
|
||||
.map(|_| Scalar::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Compute the linear combination using precomputed multiscalar multiplication
|
||||
let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
|
||||
let result_multiscalar = precomputation.vartime_mixed_multiscalar_mul(
|
||||
&static_scalars,
|
||||
&dynamic_scalars,
|
||||
&dynamic_points,
|
||||
);
|
||||
|
||||
// Compute the linear combination manually
|
||||
let mut result_manual = RistrettoPoint::identity();
|
||||
for i in 0..static_scalars.len() {
|
||||
result_manual += static_points[i] * static_scalars[i];
|
||||
}
|
||||
for i in 0..n_dynamic {
|
||||
result_manual += dynamic_points[i] * dynamic_scalars[i];
|
||||
}
|
||||
|
||||
assert_eq!(result_multiscalar, result_manual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
fn partial_precomputed_mixed_multiscalar() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let n_static = 16;
|
||||
let n_dynamic = 8;
|
||||
|
||||
let static_points = (0..n_static)
|
||||
.map(|_| RistrettoPoint::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Use one fewer scalars
|
||||
let static_scalars = (0..n_static - 1)
|
||||
.map(|_| Scalar::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let dynamic_points = (0..n_dynamic)
|
||||
.map(|_| RistrettoPoint::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let dynamic_scalars = (0..n_dynamic)
|
||||
.map(|_| Scalar::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Compute the linear combination using precomputed multiscalar multiplication
|
||||
let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
|
||||
let result_multiscalar = precomputation.vartime_mixed_multiscalar_mul(
|
||||
&static_scalars,
|
||||
&dynamic_scalars,
|
||||
&dynamic_points,
|
||||
);
|
||||
|
||||
// Compute the linear combination manually
|
||||
let mut result_manual = RistrettoPoint::identity();
|
||||
for i in 0..static_scalars.len() {
|
||||
result_manual += static_points[i] * static_scalars[i];
|
||||
}
|
||||
for i in 0..n_dynamic {
|
||||
result_manual += dynamic_points[i] * dynamic_scalars[i];
|
||||
}
|
||||
|
||||
assert_eq!(result_multiscalar, result_manual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
fn partial_precomputed_multiscalar() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let n_static = 16;
|
||||
|
||||
let static_points = (0..n_static)
|
||||
.map(|_| RistrettoPoint::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Use one fewer scalars
|
||||
let static_scalars = (0..n_static - 1)
|
||||
.map(|_| Scalar::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Compute the linear combination using precomputed multiscalar multiplication
|
||||
let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
|
||||
let result_multiscalar = precomputation.vartime_multiscalar_mul(&static_scalars);
|
||||
|
||||
// Compute the linear combination manually
|
||||
let mut result_manual = RistrettoPoint::identity();
|
||||
for i in 0..static_scalars.len() {
|
||||
result_manual += static_points[i] * static_scalars[i];
|
||||
}
|
||||
|
||||
assert_eq!(result_multiscalar, result_manual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
fn partial_precomputed_multiscalar_empty() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let n_static = 16;
|
||||
|
||||
let static_points = (0..n_static)
|
||||
.map(|_| RistrettoPoint::random(&mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Use zero scalars
|
||||
let static_scalars = Vec::new();
|
||||
|
||||
// Compute the linear combination using precomputed multiscalar multiplication
|
||||
let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
|
||||
let result_multiscalar = precomputation.vartime_multiscalar_mul(&static_scalars);
|
||||
|
||||
// Compute the linear combination manually
|
||||
let mut result_manual = RistrettoPoint::identity();
|
||||
for i in 0..static_scalars.len() {
|
||||
result_manual += static_points[i] * static_scalars[i];
|
||||
}
|
||||
|
||||
assert_eq!(result_multiscalar, result_manual);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ pub trait VartimeMultiscalarMul {
|
|||
/// to be composed into the input iterators.
|
||||
///
|
||||
/// All methods require that the lengths of the input iterators be
|
||||
/// known and matching, as if they were `ExactSizeIterator`s. (It
|
||||
/// known, as if they were `ExactSizeIterator`s. (It
|
||||
/// does not require `ExactSizeIterator` only because that trait is
|
||||
/// broken).
|
||||
pub trait VartimePrecomputedMultiscalarMul: Sized {
|
||||
|
|
@ -306,8 +306,10 @@ pub trait VartimePrecomputedMultiscalarMul: Sized {
|
|||
/// $$
|
||||
/// where the \\(B_j\\) are the points that were supplied to `new`.
|
||||
///
|
||||
/// It is an error to call this function with iterators of
|
||||
/// inconsistent lengths.
|
||||
/// It is valid for \\(b_i\\) to have a shorter length than \\(B_j\\).
|
||||
/// In this case, any "unused" points are ignored in the computation.
|
||||
/// It is an error to call this function if \\(b_i\\) has a longer
|
||||
/// length than \\(B_j\\).
|
||||
///
|
||||
/// The trait bound aims for maximum flexibility: the input must
|
||||
/// be convertable to iterators (`I: IntoIter`), and the
|
||||
|
|
@ -337,8 +339,11 @@ pub trait VartimePrecomputedMultiscalarMul: Sized {
|
|||
/// $$
|
||||
/// where the \\(B_j\\) are the points that were supplied to `new`.
|
||||
///
|
||||
/// It is an error to call this function with iterators of
|
||||
/// inconsistent lengths.
|
||||
/// It is valid for \\(b_i\\) to have a shorter length than \\(B_j\\).
|
||||
/// In this case, any "unused" points are ignored in the computation.
|
||||
/// It is an error to call this function if \\(b_i\\) has a longer
|
||||
/// length than \\(B_j\\), or if \\(a_i\\) and \\(A_i\\) do not have
|
||||
/// the same length.
|
||||
///
|
||||
/// The trait bound aims for maximum flexibility: the inputs must be
|
||||
/// convertable to iterators (`I: IntoIter`), and the iterator's items
|
||||
|
|
@ -378,8 +383,11 @@ pub trait VartimePrecomputedMultiscalarMul: Sized {
|
|||
///
|
||||
/// If any of the dynamic points were `None`, return `None`.
|
||||
///
|
||||
/// It is an error to call this function with iterators of
|
||||
/// inconsistent lengths.
|
||||
/// It is valid for \\(b_i\\) to have a shorter length than \\(B_j\\).
|
||||
/// In this case, any "unused" points are ignored in the computation.
|
||||
/// It is an error to call this function if \\(b_i\\) has a longer
|
||||
/// length than \\(B_j\\), or if \\(a_i\\) and \\(A_i\\) do not have
|
||||
/// the same length.
|
||||
///
|
||||
/// This function is particularly useful when verifying statements
|
||||
/// involving compressed points. Accepting `Option<Point>` allows
|
||||
|
|
|
|||
Loading…
Reference in a new issue