Skip to content

Commit

Permalink
Partial precomputation
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronFeickert committed Mar 22, 2024
1 parent cc3421a commit a5f2e21
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 12 deletions.
Expand Up @@ -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
Expand All @@ -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 => {
Expand Down
Expand Up @@ -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
Expand All @@ -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 => {
Expand Down
74 changes: 74 additions & 0 deletions curve25519-dalek/src/ristretto.rs
Expand Up @@ -1869,4 +1869,78 @@ mod test {
assert_eq!(P.compress(), R.compress());
assert_eq!(Q.compress(), R.compress());
}

#[test]
#[cfg(feature = "alloc")]
fn partial_precomputed_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 full_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);
}
}
22 changes: 14 additions & 8 deletions curve25519-dalek/src/traits.rs
Expand Up @@ -285,8 +285,8 @@ 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
/// does not require `ExactSizeIterator` only because that trait is
/// known, as if they were `ExactSizeIterator`s. (It does not
/// require `ExactSizeIterator` only because that trait is
/// broken).
pub trait VartimePrecomputedMultiscalarMul: Sized {
/// The type of point to be multiplied, e.g., `RistrettoPoint`.
Expand All @@ -306,8 +306,8 @@ 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_i\\).
/// In this case, any "unused" points are ignored in the computation.
///
/// The trait bound aims for maximum flexibility: the input must
/// be convertable to iterators (`I: IntoIter`), and the
Expand Down Expand Up @@ -337,8 +337,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_i\\).
/// In this case, any "unused" points are ignored in the computation.
///
/// It is an error to call this function if the iterators \\(a_i\\)
/// and \\(A_i\\) do not have equal lengths.
///
/// The trait bound aims for maximum flexibility: the inputs must be
/// convertable to iterators (`I: IntoIter`), and the iterator's items
Expand Down Expand Up @@ -378,8 +381,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_i\\).
/// In this case, any "unused" points are ignored in the computation.
///
/// It is an error to call this function if the iterators \\(a_i\\)
/// and \\(A_i\\) do not have equal lengths.
///
/// This function is particularly useful when verifying statements
/// involving compressed points. Accepting `Option<Point>` allows
Expand Down

0 comments on commit a5f2e21

Please sign in to comment.