patch: index-based pow_vartime loops (Aeneas/Charon compatibility)

iter().rev() / (0..64).rev() double-ended range iterators have no Aeneas
model. Iteration order and arithmetic identical to upstream: limbs most- to
least-significant, bits high to low. Crate tests: 11/11 fp tests pass
(incl. test_inv, test_inv_2, test_pow_by_t_minus1_over2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mrwulf 2026-07-02 16:53:27 +02:00
parent 7f3278863b
commit ea23c12d6a

View file

@ -588,15 +588,26 @@ impl ff::Field for Fp {
}
fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
// PATCH (Aeneas compatibility): index-based loops instead of
// `iter().rev()` / `(0..64).rev()` (double-ended range iterators have
// no Aeneas model). Iteration order and arithmetic are IDENTICAL to
// upstream: limbs from most- to least-significant, bits from high to
// low, square-then-conditionally-multiply.
let mut res = Self::one();
let mut found_one = false;
for e in exp.as_ref().iter().rev() {
for i in (0..64).rev() {
let exp = exp.as_ref();
let mut j = exp.len();
while j > 0 {
j -= 1;
let e = exp[j];
let mut i = 64u32;
while i > 0 {
i -= 1;
if found_one {
res = res.square();
}
if ((*e >> i) & 1) == 1 {
if ((e >> i) & 1) == 1 {
found_one = true;
res *= self;
}