Skip to content

Commit 3eef6c5

Browse files
committed
feat(wnaf): add scalar_repr_to_le_bytes()
1 parent 5203ec9 commit 3eef6c5

1 file changed

Lines changed: 45 additions & 4 deletions

File tree

src/wnaf.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

390409
impl<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
424444
impl<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

Comments
 (0)