From ea23c12d6a0fb88dd9d30828fcdc7397060ea925 Mon Sep 17 00:00:00 2001 From: mrwulf Date: Thu, 2 Jul 2026 16:53:27 +0200 Subject: [PATCH] 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 --- src/fields/fp.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/fields/fp.rs b/src/fields/fp.rs index c475d98..45605cb 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -588,15 +588,26 @@ impl ff::Field for Fp { } fn pow_vartime>(&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; }