mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-03 20:13:48 +00:00
Aeneas-compat: make vartime_double_base::mul extraction-clean
Pure refactors (cargo check green under both feature sets), semantics of mul unchanged: - dsm_top_index / dsm_loop / dsm_step_p / dsm_step_b helpers: the main double-and-add loop becomes a strictly-decreasing while with a single-assignment body and parameter-rooted borrows (the original loop/break shape with match-updates fails Aeneas' loop fixed point); - the starting-index scan always returns 255: leading zero NAF digits double the identity (a no-op), so the result is unchanged - only the variable-time skip is dropped (constant-time behavior improves); - the downward break-scan (which failed Aeneas' symbolic join) is gone. With these, Charon+Aeneas extract the complete path - non_adjacent_form, NafLookupTable5::from/select, the affine basepoint table, the 256-step dsm_loop, and mul - with zero errors and zero sorries. This opens the double-scalar-multiplication verification campaign (the EdDSA verify equation's core).
This commit is contained in:
parent
26284959e4
commit
1bd5990856
1 changed files with 107 additions and 32 deletions
|
|
@ -12,7 +12,11 @@
|
|||
|
||||
use core::cmp::Ordering;
|
||||
|
||||
use crate::backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint};
|
||||
use crate::backend::serial::curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint};
|
||||
#[cfg(feature = "precomputed-tables")]
|
||||
use crate::backend::serial::curve_models::AffineNielsPoint;
|
||||
#[cfg(feature = "precomputed-tables")]
|
||||
use crate::window::NafLookupTable8;
|
||||
use crate::constants;
|
||||
use crate::edwards::EdwardsPoint;
|
||||
use crate::scalar::Scalar;
|
||||
|
|
@ -20,6 +24,105 @@ use crate::traits::Identity;
|
|||
use crate::window::NafLookupTable5;
|
||||
|
||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||
|
||||
/// AENEAS-COMPAT helper: highest index with a nonzero NAF digit (or 0).
|
||||
fn dsm_top_index(a_naf: &[i8; 256], b_naf: &[i8; 256]) -> usize {
|
||||
// AENEAS-COMPAT: always process all 256 digits. Leading zero digits
|
||||
// double the identity (a no-op), so the result of `mul` is unchanged;
|
||||
// only the variable-time skip is dropped. (The conditional-fold scan
|
||||
// fails Aeneas' loop fixed point.)
|
||||
let _ = a_naf;
|
||||
let _ = b_naf;
|
||||
255
|
||||
}
|
||||
|
||||
/// AENEAS-COMPAT helper: the double-and-add main loop over indices i..0,
|
||||
/// with all borrows rooted in parameters (pure refactor).
|
||||
#[cfg(feature = "precomputed-tables")]
|
||||
fn dsm_loop(
|
||||
i: usize,
|
||||
a_naf: &[i8; 256],
|
||||
b_naf: &[i8; 256],
|
||||
table_a: &NafLookupTable5<ProjectiveNielsPoint>,
|
||||
table_b: &NafLookupTable8<AffineNielsPoint>,
|
||||
) -> ProjectivePoint {
|
||||
let mut r = ProjectivePoint::identity();
|
||||
let mut j: usize = i + 1;
|
||||
while j > 0 {
|
||||
let idx = j - 1;
|
||||
let t0 = r.double();
|
||||
let t1 = dsm_step_p(t0, table_a, a_naf[idx]);
|
||||
let t2 = dsm_step_b(t1, table_b, b_naf[idx]);
|
||||
r = t2.as_projective();
|
||||
j -= 1;
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "precomputed-tables"))]
|
||||
fn dsm_loop(
|
||||
i: usize,
|
||||
a_naf: &[i8; 256],
|
||||
b_naf: &[i8; 256],
|
||||
table_a: &NafLookupTable5<ProjectiveNielsPoint>,
|
||||
table_b: &NafLookupTable5<ProjectiveNielsPoint>,
|
||||
) -> ProjectivePoint {
|
||||
let mut r = ProjectivePoint::identity();
|
||||
let mut j: usize = i + 1;
|
||||
while j > 0 {
|
||||
let idx = j - 1;
|
||||
let t0 = r.double();
|
||||
let t1 = dsm_step_p(t0, table_a, a_naf[idx]);
|
||||
let t2 = dsm_step_b(t1, table_b, b_naf[idx]);
|
||||
r = t2.as_projective();
|
||||
j -= 1;
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
/// AENEAS-COMPAT helper: one NAF-digit conditional add against a
|
||||
/// ProjectiveNiels table (hoisted out of the main loop so its body is
|
||||
/// single-assignment; pure refactor, semantics identical).
|
||||
fn dsm_step_p(
|
||||
t: CompletedPoint,
|
||||
table: &NafLookupTable5<ProjectiveNielsPoint>,
|
||||
d: i8,
|
||||
) -> CompletedPoint {
|
||||
if d > 0 {
|
||||
&t.as_extended() + &table.select(d as usize)
|
||||
} else if d < 0 {
|
||||
&t.as_extended() - &table.select((-d) as usize)
|
||||
} else {
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
/// AENEAS-COMPAT helper: as `dsm_step_p`, for the basepoint table.
|
||||
#[cfg(feature = "precomputed-tables")]
|
||||
fn dsm_step_b(
|
||||
t: CompletedPoint,
|
||||
table: &NafLookupTable8<AffineNielsPoint>,
|
||||
d: i8,
|
||||
) -> CompletedPoint {
|
||||
if d > 0 {
|
||||
&t.as_extended() + &table.select(d as usize)
|
||||
} else if d < 0 {
|
||||
&t.as_extended() - &table.select((-d) as usize)
|
||||
} else {
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
/// AENEAS-COMPAT helper: as `dsm_step_p` (no precomputed tables).
|
||||
#[cfg(not(feature = "precomputed-tables"))]
|
||||
fn dsm_step_b(
|
||||
t: CompletedPoint,
|
||||
table: &NafLookupTable5<ProjectiveNielsPoint>,
|
||||
d: i8,
|
||||
) -> CompletedPoint {
|
||||
dsm_step_p(t, table, d)
|
||||
}
|
||||
|
||||
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||
let a_naf = a.non_adjacent_form(5);
|
||||
|
||||
|
|
@ -28,14 +131,8 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
|||
#[cfg(not(feature = "precomputed-tables"))]
|
||||
let b_naf = b.non_adjacent_form(5);
|
||||
|
||||
// Find starting index
|
||||
let mut i: usize = 255;
|
||||
for j in (0..256).rev() {
|
||||
i = j;
|
||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Find starting index (AENEAS-COMPAT: helper, upward fold)
|
||||
let i = dsm_top_index(&a_naf, &b_naf);
|
||||
|
||||
let table_A = NafLookupTable5::<ProjectiveNielsPoint>::from(A);
|
||||
#[cfg(feature = "precomputed-tables")]
|
||||
|
|
@ -44,29 +141,7 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
|||
let table_B =
|
||||
&NafLookupTable5::<ProjectiveNielsPoint>::from(&constants::ED25519_BASEPOINT_POINT);
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
loop {
|
||||
let mut t = r.double();
|
||||
|
||||
match a_naf[i].cmp(&0) {
|
||||
Ordering::Greater => t = &t.as_extended() + &table_A.select(a_naf[i] as usize),
|
||||
Ordering::Less => t = &t.as_extended() - &table_A.select(-a_naf[i] as usize),
|
||||
Ordering::Equal => {}
|
||||
}
|
||||
|
||||
match b_naf[i].cmp(&0) {
|
||||
Ordering::Greater => t = &t.as_extended() + &table_B.select(b_naf[i] as usize),
|
||||
Ordering::Less => t = &t.as_extended() - &table_B.select(-b_naf[i] as usize),
|
||||
Ordering::Equal => {}
|
||||
}
|
||||
|
||||
r = t.as_projective();
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
let r = dsm_loop(i, &a_naf, &b_naf, &table_A, table_B);
|
||||
|
||||
r.as_extended()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue