From f9468892d9a52bab5a242154d99601cb6a03ae63 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 31 Mar 2026 09:31:05 -0600 Subject: [PATCH] [WIP] Have wNAF use `PrimeField::to_le_repr` for scalars The wNAF implementation assumes a little endian representation for scalars, but `PrimeField::to_repr` returns an opaque representation which may be big endian and is in the case of our implementations of the NIST P-curves. RustCrypto/ff#10 added a stopgap API: `PrimeField::to_le_repr`, which is guaranteed to return a little endian representation. This commit switches `(rustcrypto-)group` to use it, which should make it compatible with our curves which otherwise use a big endian SEC1 representation. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/wnaf.rs | 13 ++++++++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23b5b62..ae10e5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "rustcrypto-ff" -version = "0.14.0-rc.0" +version = "0.14.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5db129183b2c139d7d87d08be57cba626c715789db17aec65c8866bfd767d1f" +checksum = "fd2a8adb347447693cd2ba0d218c4b66c62da9b0a5672b17b981e4291ec65ff6" dependencies = [ "rand_core", "subtle", diff --git a/Cargo.toml b/Cargo.toml index 56f5588..e8e57ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ homepage = "https://github.com/RustCrypto/group" repository = "https://github.com/RustCrypto/group" [dependencies] -ff = { version = "0.14.0-rc.0", package = "rustcrypto-ff", default-features = false } +ff = { version = "0.14.0-rc.1", package = "rustcrypto-ff", default-features = false } rand = { version = "0.10", optional = true, default-features = false } rand_core = { version = "0.10", default-features = false } rand_xorshift = { version = "0.5", optional = true } diff --git a/src/wnaf.rs b/src/wnaf.rs index fdcf432..63c886c 100644 --- a/src/wnaf.rs +++ b/src/wnaf.rs @@ -144,6 +144,13 @@ pub(crate) fn wnaf_form>(wnaf: &mut Vec, c: S, window: usize pos += window; } } + + // If there is a remaining carry (the scalar used all `bit_len` bits + // and the last wNAF digit was negative), emit it so the + // representation is exact. + if carry != 0 { + wnaf.push(carry as i64); + } } /// Performs w-NAF exponentiation with the provided window table and w-NAF form scalar. @@ -315,7 +322,7 @@ impl Wnaf<(), Vec, Vec> { let window_size = 4; // Compute the wNAF form of the scalar. - wnaf_form(&mut self.scalar, scalar.to_repr(), window_size); + wnaf_form(&mut self.scalar, scalar.to_le_repr(), window_size); // Return a Wnaf object that mutably borrows the base storage location, but // immutably borrows the computed wNAF form scalar location. @@ -393,7 +400,7 @@ impl>> Wnaf { where B: AsRef<[G]>, { - wnaf_form(self.scalar.as_mut(), scalar.to_repr(), self.window_size); + wnaf_form(self.scalar.as_mut(), scalar.to_le_repr(), self.window_size); wnaf_exp(self.base.as_ref(), self.scalar.as_mut()) } } @@ -428,7 +435,7 @@ impl WnafScalar { let mut wnaf = vec![]; // Compute the w-NAF form of the scalar. - wnaf_form(&mut wnaf, scalar.to_repr(), WINDOW_SIZE); + wnaf_form(&mut wnaf, scalar.to_le_repr(), WINDOW_SIZE); WnafScalar { wnaf,