mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-06 20:41:14 +00:00
Rewrite NAF code to work with more window sizes
Change Scalar::non_adjacent_form() to take a width parameter. This rewrite also makes it faster, although it's probably a ways off from optimal. I don't know how much it matters. TODO: write up description of why this computes the same thing. Thanks to @oleganza for pointing out an error reading bits across words in an earlier version of this code.
This commit is contained in:
parent
ece4bd715a
commit
7e0ddf6b98
8 changed files with 58 additions and 37 deletions
|
|
@ -41,6 +41,7 @@ harness = false
|
||||||
# match exactly, since the build.rs uses the crate itself as a library.
|
# match exactly, since the build.rs uses the crate itself as a library.
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
byteorder = "1"
|
||||||
digest = "0.7"
|
digest = "0.7"
|
||||||
generic-array = "0.9"
|
generic-array = "0.9"
|
||||||
clear_on_drop = "=0.2.3"
|
clear_on_drop = "=0.2.3"
|
||||||
|
|
@ -49,6 +50,7 @@ serde = { version = "1.0", optional = true }
|
||||||
rand = { version = "0.4", optional = true }
|
rand = { version = "0.4", optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
byteorder = "1"
|
||||||
digest = "0.7"
|
digest = "0.7"
|
||||||
generic-array = "0.9"
|
generic-array = "0.9"
|
||||||
clear_on_drop = "=0.2.3"
|
clear_on_drop = "=0.2.3"
|
||||||
|
|
|
||||||
1
build.rs
1
build.rs
|
|
@ -5,6 +5,7 @@
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
extern crate clear_on_drop;
|
extern crate clear_on_drop;
|
||||||
extern crate core;
|
extern crate core;
|
||||||
extern crate digest;
|
extern crate digest;
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ use backend::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE;
|
||||||
|
|
||||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||||
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||||
let a_naf = a.non_adjacent_form();
|
let a_naf = a.non_adjacent_form(5);
|
||||||
let b_naf = b.non_adjacent_form();
|
let b_naf = b.non_adjacent_form(5);
|
||||||
|
|
||||||
// Find starting index
|
// Find starting index
|
||||||
let mut i: usize = 255;
|
let mut i: usize = 255;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ where
|
||||||
{
|
{
|
||||||
let nafs: Vec<_> = scalars
|
let nafs: Vec<_> = scalars
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| c.borrow().non_adjacent_form())
|
.map(|c| c.borrow().non_adjacent_form(5))
|
||||||
.collect();
|
.collect();
|
||||||
let lookup_tables: Vec<_> = points
|
let lookup_tables: Vec<_> = points
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ extern crate alloc;
|
||||||
|
|
||||||
extern crate clear_on_drop;
|
extern crate clear_on_drop;
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
// The `Digest` trait is implemented using `generic_array`, so we need it
|
// The `Digest` trait is implemented using `generic_array`, so we need it
|
||||||
// too. Hopefully we can eliminate `generic_array` from `Digest` once const
|
// too. Hopefully we can eliminate `generic_array` from `Digest` once const
|
||||||
// generics land.
|
// generics land.
|
||||||
|
|
|
||||||
|
|
@ -493,7 +493,7 @@ impl Scalar {
|
||||||
bits
|
bits
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a width-5 "Non-Adjacent Form" of this scalar.
|
/// Compute a width-\\(w\\) "Non-Adjacent Form" of this 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
|
||||||
/// $$
|
/// $$
|
||||||
|
|
@ -507,37 +507,53 @@ impl Scalar {
|
||||||
/// 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 up to \\(2\^{w-1}\\) so that the
|
||||||
/// nonzero coefficients are as sparse as possible.
|
/// nonzero coefficients are as sparse as possible.
|
||||||
pub(crate) fn non_adjacent_form(&self) -> [i8; 256] {
|
pub(crate) fn non_adjacent_form(&self, w: usize) -> [i8; 256] {
|
||||||
// Step 1: write out bits of the scalar
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
let mut naf = self.bits();
|
|
||||||
|
|
||||||
// Step 2: zero coefficients by carrying them upwards or downwards
|
let mut naf = [0i8; 256];
|
||||||
'bits: for i in 0..256 {
|
|
||||||
if naf[i] == 0 { continue 'bits; }
|
let mut x_u64 = [0u64; 5];
|
||||||
'window: for b in 1..6 {
|
LittleEndian::read_u64_into(&self.bytes, &mut x_u64[0..4]);
|
||||||
if i+b >= 256 { break 'window; }
|
|
||||||
if naf[i+b] == 0 { continue 'window; }
|
let width = 1 << w;
|
||||||
let potential_carry = naf[i+b] << b;
|
let window_mask = width - 1;
|
||||||
if naf[i+b] + potential_carry <= 15 {
|
|
||||||
// Eliminate naf[i+b] by carrying its value onto naf[i]
|
let mut pos = 0;
|
||||||
naf[i] += potential_carry;
|
let mut carry = 0;
|
||||||
naf[i+b] = 0;
|
while pos < 256 {
|
||||||
} else if naf[i+b] - potential_carry >= -15 {
|
// Construct a buffer of bits of the scalar, starting at bit `pos`
|
||||||
// Eliminate naf[i+b] by carrying its value upwards.
|
let u64_idx = pos / 64;
|
||||||
naf[i] -= potential_carry; // Subtract 2^(i+b)
|
let bit_idx = pos % 64;
|
||||||
'carry: for k in i+b..256 {
|
let bit_buf: u64;
|
||||||
if naf[k] != 0 {
|
if bit_idx < 64 - w {
|
||||||
// Since naf[k] = 0 or 1 for k > i, naf[k] == 1.
|
// This window's bits are contained in a single u64
|
||||||
naf[k] = 0; // Subtract 2^k
|
bit_buf = x_u64[u64_idx] >> bit_idx;
|
||||||
} else {
|
} else {
|
||||||
// By now we have subtracted 2^k =
|
// Combine the current u64's bits with the bits from the next u64
|
||||||
// 2^(i+b) + 2^(i+b) + 2^(i+b+1) + ... + 2^(k-1).
|
bit_buf = (x_u64[u64_idx] >> bit_idx) | (x_u64[1+u64_idx] << (64 - bit_idx));
|
||||||
naf[k] = 1; // Add back 2^k.
|
|
||||||
break 'carry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the carry into the current window
|
||||||
|
let window = carry + (bit_buf & window_mask);
|
||||||
|
|
||||||
|
if window & 1 == 0 {
|
||||||
|
// If the window value is even, preserve the carry and continue.
|
||||||
|
// Why is the carry preserved?
|
||||||
|
// If carry == 0 and window & 1 == 0, then the next carry should be 0
|
||||||
|
// If carry == 1 and window & 1 == 0, then bit_buf & 1 == 1 so the next carry should be 1
|
||||||
|
pos += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if window < width/2 {
|
||||||
|
carry = 0;
|
||||||
|
naf[pos] = window as i8;
|
||||||
|
} else {
|
||||||
|
carry = 1;
|
||||||
|
naf[pos] = (window as i8) - (width as i8);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += w;
|
||||||
}
|
}
|
||||||
|
|
||||||
naf
|
naf
|
||||||
|
|
@ -789,7 +805,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn non_adjacent_form() {
|
fn non_adjacent_form() {
|
||||||
let naf = A_SCALAR.non_adjacent_form();
|
let naf = A_SCALAR.non_adjacent_form(5);
|
||||||
for i in 0..256 {
|
for i in 0..256 {
|
||||||
assert_eq!(naf[i], A_NAF[i]);
|
assert_eq!(naf[i], A_NAF[i]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ use scalar_mul::window::OddLookupTable;
|
||||||
|
|
||||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||||
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||||
let a_naf = a.non_adjacent_form();
|
let a_naf = a.non_adjacent_form(5);
|
||||||
let b_naf = b.non_adjacent_form();
|
let b_naf = b.non_adjacent_form(5);
|
||||||
|
|
||||||
// Find starting index
|
// Find starting index
|
||||||
let mut i: usize = 255;
|
let mut i: usize = 255;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ where
|
||||||
{
|
{
|
||||||
let nafs: Vec<_> = scalars
|
let nafs: Vec<_> = scalars
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| c.borrow().non_adjacent_form())
|
.map(|c| c.borrow().non_adjacent_form(5))
|
||||||
.collect();
|
.collect();
|
||||||
let lookup_tables: Vec<_> = points
|
let lookup_tables: Vec<_> = points
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue