mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-05 20:30:57 +00:00
Document algorithm for NAFs
This commit is contained in:
parent
6b768c2a1a
commit
68bbd1bd03
1 changed files with 69 additions and 6 deletions
|
|
@ -80,6 +80,7 @@ pub struct Scalar {
|
||||||
///
|
///
|
||||||
/// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or equivalently the high bit of `bytes[31]` must be zero.
|
/// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or equivalently the high bit of `bytes[31]` must be zero.
|
||||||
///
|
///
|
||||||
|
/// This ensures that there is room for a carry bit when computing a NAF representation.
|
||||||
// XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could make the Scalar constructors const fns and use those instead.
|
// XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could make the Scalar constructors const fns and use those instead.
|
||||||
pub(crate) bytes: [u8; 32],
|
pub(crate) bytes: [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
@ -497,17 +498,79 @@ impl Scalar {
|
||||||
///
|
///
|
||||||
/// A width-\\(w\\) NAF of a positive integer \\(k\\) is an expression
|
/// A width-\\(w\\) NAF of a positive integer \\(k\\) is an expression
|
||||||
/// $$
|
/// $$
|
||||||
/// k = \sum_{i=0}\^n k\_i 2\^i,
|
/// k = \sum_{i=0}\^m n\_i 2\^i,
|
||||||
/// $$
|
/// $$
|
||||||
/// where each nonzero
|
/// where each nonzero
|
||||||
/// coefficient \\(k\_i\\) is odd and bounded by \\(|k\_i| < 2\^{w-1}\\),
|
/// coefficient \\(n\_i\\) is odd and bounded by \\(|n\_i| < 2\^{w-1}\\),
|
||||||
/// \\(k\_{n-1}\\) is nonzero, and at most one of any \\(w\\) consecutive
|
/// \\(n\_{m-1}\\) is nonzero, and at most one of any \\(w\\) consecutive
|
||||||
/// coefficients is nonzero. (Hankerson, Menezes, Vanstone; def 3.32).
|
/// coefficients is nonzero. (Hankerson, Menezes, Vanstone; def 3.32).
|
||||||
///
|
///
|
||||||
|
/// The length of the NAF is at most one more than the length of
|
||||||
|
/// the binary representation of \\(k\\). This is why the
|
||||||
|
/// `Scalar` type maintains an invariant that the top bit is
|
||||||
|
/// \\(0\\), so that the NAF of a scalar has at most 256 digits.
|
||||||
|
///
|
||||||
/// Intuitively, this is like a binary expansion, except that we
|
/// Intuitively, this is like a binary expansion, except that we
|
||||||
/// allow some coefficients to grow up to \\(2\^{w-1}\\) so that the
|
/// allow some coefficients to grow in magnitude up to
|
||||||
/// nonzero coefficients are as sparse as possible.
|
/// \\(2\^{w-1}\\) so that the nonzero coefficients are as sparse
|
||||||
|
/// as possible.
|
||||||
|
///
|
||||||
|
/// When doing scalar multiplication, we can then use a lookup
|
||||||
|
/// table of precomputed multiples of a point to add the nonzero
|
||||||
|
/// terms \\( k_i P \\). Using signed digits cuts the table size
|
||||||
|
/// in half, and using odd digits cuts the table size in half
|
||||||
|
/// again.
|
||||||
|
///
|
||||||
|
/// To compute a \\(w\\)-NAF, we use a modification of Algorithm 3.35 of HMV:
|
||||||
|
///
|
||||||
|
/// 1. \\( i \gets 0 \\)
|
||||||
|
/// 2. While \\( k \ge 1 \\):
|
||||||
|
/// 1. If \\(k\\) is odd, \\( n_i \gets k \operatorname{mods} 2^w \\), \\( k \gets k - n_i \\).
|
||||||
|
/// 2. If \\(k\\) is even, \\( n_i \gets 0 \\).
|
||||||
|
/// 3. \\( k \gets k / 2 \\), \\( i \gets i + 1 \\).
|
||||||
|
/// 3. Return \\( n_0, n_1, ... , \\)
|
||||||
|
///
|
||||||
|
/// Here \\( \bar x = x \operatorname{mods} 2^w \\) means the
|
||||||
|
/// \\( \bar x \\) with \\( \bar x \equiv x \pmod{2^w} \\) and
|
||||||
|
/// \\( -2^{w-1} \leq \bar x < 2^w \\).
|
||||||
|
///
|
||||||
|
/// We implement this by scanning across the bits of \\(k\\) from LSB to MSB.
|
||||||
|
/// Write the bits of \\(k\\) as
|
||||||
|
/// $$
|
||||||
|
/// k = \sum\_{i=0}\^m k\_i 2^i,
|
||||||
|
/// $$
|
||||||
|
/// and split the sum as
|
||||||
|
/// $$
|
||||||
|
/// k = \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \sum\_{i=0} k\_{i+w} 2^i
|
||||||
|
/// $$
|
||||||
|
/// where the first part is \\( k \mod 2^w \\).
|
||||||
|
///
|
||||||
|
/// If \\( k \mod 2^w\\) is odd, and \\( k \mod 2^w < 2^{w-1} \\), then we emit
|
||||||
|
/// \\( n_0 = k \mod 2^w \\). Instead of computing
|
||||||
|
/// \\( k - n_0 \\), we just advance \\(w\\) bits and reindex.
|
||||||
|
///
|
||||||
|
/// If \\( k \mod 2^w\\) is odd, and \\( k \mod 2^w \ge 2^{w-1} \\), then
|
||||||
|
/// \\( n_0 = k \operatorname{mods} 2^w = k \mod 2^w - 2^w \\).
|
||||||
|
/// The quantity \\( k - n_0 \\) is
|
||||||
|
/// $$
|
||||||
|
/// \begin{aligned}
|
||||||
|
/// k - n_0 &= \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \sum\_{i=0} k\_{i+w} 2^i
|
||||||
|
/// - \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \\\\
|
||||||
|
/// &= 2^w + 2^w \sum\_{i=0} k\_{i+w} 2^i
|
||||||
|
/// \end{aligned}
|
||||||
|
/// $$
|
||||||
|
/// so instead of computing the subtraction, we can set a carry
|
||||||
|
/// bit, advance \\(w\\) bits, and reindex.
|
||||||
|
///
|
||||||
|
/// If \\( k \mod 2^w\\) is even, we emit \\(0\\), advance 1 bit
|
||||||
|
/// and reindex. In fact, by setting all digits to \\(0\\)
|
||||||
|
/// initially, we don't need to emit anything.
|
||||||
pub(crate) fn non_adjacent_form(&self, w: usize) -> [i8; 256] {
|
pub(crate) fn non_adjacent_form(&self, w: usize) -> [i8; 256] {
|
||||||
|
// required by the NAF definition
|
||||||
|
debug_assert!( w >= 2 );
|
||||||
|
// required so that the NAF digits fit in i8
|
||||||
|
debug_assert!( w <= 8 );
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
|
|
||||||
let mut naf = [0i8; 256];
|
let mut naf = [0i8; 256];
|
||||||
|
|
@ -564,7 +627,7 @@ impl Scalar {
|
||||||
/// $$
|
/// $$
|
||||||
/// a = a\_0 + a\_1 16\^1 + \cdots + a_{63} 16\^{63},
|
/// a = a\_0 + a\_1 16\^1 + \cdots + a_{63} 16\^{63},
|
||||||
/// $$
|
/// $$
|
||||||
/// with \\(-8 \leq a_i < 8\\) for \\(0 \leq i < 63\\) and \\(-8 \leq a_63 \leq 8\\).
|
/// with \\(-8 \leq a_i < 8\\) for \\(0 \leq i < 63\\) and \\(-8 \leq a_{63} \leq 8\\).
|
||||||
pub(crate) fn to_radix_16(&self) -> [i8; 64] {
|
pub(crate) fn to_radix_16(&self) -> [i8; 64] {
|
||||||
debug_assert!(self[31] <= 127);
|
debug_assert!(self[31] <= 127);
|
||||||
let mut output = [0i8; 64];
|
let mut output = [0i8; 64];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue