mirror of
https://github.com/saymrwulf/anza-cryptography-source.git
synced 2026-09-05 20:30:51 +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
8e299cd0f5
commit
58894a049a
1 changed files with 107 additions and 32 deletions
|
|
@ -12,7 +12,11 @@
|
||||||
|
|
||||||
use core::cmp::Ordering;
|
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::constants;
|
||||||
use crate::edwards::EdwardsPoint;
|
use crate::edwards::EdwardsPoint;
|
||||||
use crate::scalar::Scalar;
|
use crate::scalar::Scalar;
|
||||||
|
|
@ -20,6 +24,105 @@ use crate::traits::Identity;
|
||||||
use crate::window::NafLookupTable5;
|
use crate::window::NafLookupTable5;
|
||||||
|
|
||||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
/// 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 {
|
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||||
let a_naf = a.non_adjacent_form(5);
|
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"))]
|
#[cfg(not(feature = "precomputed-tables"))]
|
||||||
let b_naf = b.non_adjacent_form(5);
|
let b_naf = b.non_adjacent_form(5);
|
||||||
|
|
||||||
// Find starting index
|
// Find starting index (AENEAS-COMPAT: helper, upward fold)
|
||||||
let mut i: usize = 255;
|
let i = dsm_top_index(&a_naf, &b_naf);
|
||||||
for j in (0..256).rev() {
|
|
||||||
i = j;
|
|
||||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let table_A = NafLookupTable5::<ProjectiveNielsPoint>::from(A);
|
let table_A = NafLookupTable5::<ProjectiveNielsPoint>::from(A);
|
||||||
#[cfg(feature = "precomputed-tables")]
|
#[cfg(feature = "precomputed-tables")]
|
||||||
|
|
@ -44,29 +141,7 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||||
let table_B =
|
let table_B =
|
||||||
&NafLookupTable5::<ProjectiveNielsPoint>::from(&constants::ED25519_BASEPOINT_POINT);
|
&NafLookupTable5::<ProjectiveNielsPoint>::from(&constants::ED25519_BASEPOINT_POINT);
|
||||||
|
|
||||||
let mut r = ProjectivePoint::identity();
|
let r = dsm_loop(i, &a_naf, &b_naf, &table_A, table_B);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
r.as_extended()
|
r.as_extended()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue