@@ -12,6 +12,17 @@ pub trait WnafGroup: Group {
1212 /// Recommends a wNAF window size given the number of scalars you intend to multiply
1313 /// a base by. Always returns a number between 2 and 22, inclusive.
1414 fn recommended_wnaf_for_num_scalars ( num_scalars : usize ) -> usize ;
15+
16+ /// Returns the scalar's canonical byte representation in little-endian
17+ /// order, suitable for wNAF decomposition.
18+ ///
19+ /// The default implementation assumes
20+ /// [`PrimeField::to_repr`] already returns little-endian bytes.
21+ /// Implementations whose `Repr` is big-endian **must** override this
22+ /// to reverse the byte order.
23+ fn scalar_repr_to_le_bytes ( repr : & <<Self as Group >:: Scalar as PrimeField >:: Repr ) -> Vec < u8 > {
24+ repr. as_ref ( ) . to_vec ( )
25+ }
1526}
1627
1728/// Replaces the contents of `table` with a w-NAF window table for the given window size.
@@ -144,6 +155,13 @@ pub(crate) fn wnaf_form<S: AsRef<[u8]>>(wnaf: &mut Vec<i64>, c: S, window: usize
144155 pos += window;
145156 }
146157 }
158+
159+ // If there is a remaining carry (the scalar used all `bit_len` bits
160+ // and the last wNAF digit was negative), emit it so the
161+ // representation is exact.
162+ if carry != 0 {
163+ wnaf. push ( carry as i64 ) ;
164+ }
147165}
148166
149167/// Performs w-NAF exponentiation with the provided window table and w-NAF form scalar.
@@ -314,8 +332,9 @@ impl<G: WnafGroup> Wnaf<(), Vec<G>, Vec<i64>> {
314332 // We hard-code a window size of 4.
315333 let window_size = 4 ;
316334
317- // Compute the wNAF form of the scalar.
318- wnaf_form ( & mut self . scalar , scalar. to_repr ( ) , window_size) ;
335+ // Compute the wNAF form of the scalar in little-endian byte order.
336+ let le_bytes = G :: scalar_repr_to_le_bytes ( & scalar. to_repr ( ) ) ;
337+ wnaf_form ( & mut self . scalar , le_bytes, window_size) ;
319338
320339 // Return a Wnaf object that mutably borrows the base storage location, but
321340 // immutably borrows the computed wNAF form scalar location.
@@ -389,11 +408,12 @@ impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
389408
390409impl < B , S : AsMut < Vec < i64 > > > Wnaf < usize , B , S > {
391410 /// Performs exponentiation given a scalar.
392- pub fn scalar < G : Group > ( & mut self , scalar : & <G as Group >:: Scalar ) -> G
411+ pub fn scalar < G : WnafGroup > ( & mut self , scalar : & <G as Group >:: Scalar ) -> G
393412 where
394413 B : AsRef < [ G ] > ,
395414 {
396- wnaf_form ( self . scalar . as_mut ( ) , scalar. to_repr ( ) , self . window_size ) ;
415+ let le_bytes = G :: scalar_repr_to_le_bytes ( & scalar. to_repr ( ) ) ;
416+ wnaf_form ( self . scalar . as_mut ( ) , le_bytes, self . window_size ) ;
397417 wnaf_exp ( self . base . as_ref ( ) , self . scalar . as_mut ( ) )
398418 }
399419}
@@ -424,6 +444,10 @@ impl<F: PrimeField, const WINDOW_SIZE: usize> memuse::DynamicUsage for WnafScala
424444impl < F : PrimeField , const WINDOW_SIZE : usize > WnafScalar < F , WINDOW_SIZE > {
425445 /// Computes the w-NAF representation of the given scalar with the specified
426446 /// `WINDOW_SIZE`.
447+ ///
448+ /// **Important:** This assumes `F::to_repr()` returns little-endian
449+ /// bytes. For fields whose `Repr` is big-endian, use
450+ /// [`new_for_group`](Self::new_for_group) instead.
427451 pub fn new ( scalar : & F ) -> Self {
428452 let mut wnaf = vec ! [ ] ;
429453
@@ -435,6 +459,23 @@ impl<F: PrimeField, const WINDOW_SIZE: usize> WnafScalar<F, WINDOW_SIZE> {
435459 field : PhantomData :: default ( ) ,
436460 }
437461 }
462+
463+ /// Computes the w-NAF representation of the given scalar, using `G`'s
464+ /// [`WnafGroup::scalar_repr_to_le_bytes`] to handle byte-order
465+ /// normalization.
466+ pub fn new_for_group < G > ( scalar : & F ) -> Self
467+ where
468+ G : WnafGroup < Scalar = F > ,
469+ {
470+ let mut wnaf = vec ! [ ] ;
471+ let le_bytes = G :: scalar_repr_to_le_bytes ( & scalar. to_repr ( ) ) ;
472+ wnaf_form ( & mut wnaf, le_bytes, WINDOW_SIZE ) ;
473+
474+ WnafScalar {
475+ wnaf,
476+ field : PhantomData :: default ( ) ,
477+ }
478+ }
438479}
439480
440481/// A fixed window table for a group element, precomputed to improve the speed of scalar
0 commit comments