diff --git a/Cargo.toml b/Cargo.toml index 9cb39f1..749700b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ harness = false # match exactly, since the build.rs uses the crate itself as a library. [dependencies] +byteorder = "1" digest = "0.7" generic-array = "0.9" clear_on_drop = "=0.2.3" @@ -49,6 +50,7 @@ serde = { version = "1.0", optional = true } rand = { version = "0.4", optional = true } [build-dependencies] +byteorder = "1" digest = "0.7" generic-array = "0.9" clear_on_drop = "=0.2.3" diff --git a/build.rs b/build.rs index 8331688..595d369 100644 --- a/build.rs +++ b/build.rs @@ -5,6 +5,7 @@ #![allow(non_snake_case)] #![allow(dead_code)] +extern crate byteorder; extern crate clear_on_drop; extern crate core; extern crate digest; diff --git a/src/backend/avx2/scalar_mul/vartime_double_base.rs b/src/backend/avx2/scalar_mul/vartime_double_base.rs index 1ba09f1..aa2aa97 100644 --- a/src/backend/avx2/scalar_mul/vartime_double_base.rs +++ b/src/backend/avx2/scalar_mul/vartime_double_base.rs @@ -18,8 +18,8 @@ use backend::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { - let a_naf = a.non_adjacent_form(); - let b_naf = b.non_adjacent_form(); + let a_naf = a.non_adjacent_form(5); + let b_naf = b.non_adjacent_form(5); // Find starting index let mut i: usize = 255; diff --git a/src/backend/avx2/scalar_mul/vartime_straus.rs b/src/backend/avx2/scalar_mul/vartime_straus.rs index 224713d..f05754b 100644 --- a/src/backend/avx2/scalar_mul/vartime_straus.rs +++ b/src/backend/avx2/scalar_mul/vartime_straus.rs @@ -27,7 +27,7 @@ where { let nafs: Vec<_> = scalars .into_iter() - .map(|c| c.borrow().non_adjacent_form()) + .map(|c| c.borrow().non_adjacent_form(5)) .collect(); let lookup_tables: Vec<_> = points .into_iter() diff --git a/src/lib.rs b/src/lib.rs index 0a8a1a3..3a3cb84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,8 @@ extern crate alloc; extern crate clear_on_drop; +extern crate byteorder; + // The `Digest` trait is implemented using `generic_array`, so we need it // too. Hopefully we can eliminate `generic_array` from `Digest` once const // generics land. diff --git a/src/scalar.rs b/src/scalar.rs index 7dae1e1..f4a86dd 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -493,7 +493,7 @@ impl Scalar { 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 /// $$ @@ -507,37 +507,53 @@ impl Scalar { /// Intuitively, this is like a binary expansion, except that we /// allow some coefficients to grow up to \\(2\^{w-1}\\) so that the /// nonzero coefficients are as sparse as possible. - pub(crate) fn non_adjacent_form(&self) -> [i8; 256] { - // Step 1: write out bits of the scalar - let mut naf = self.bits(); + pub(crate) fn non_adjacent_form(&self, w: usize) -> [i8; 256] { + use byteorder::{ByteOrder, LittleEndian}; - // Step 2: zero coefficients by carrying them upwards or downwards - 'bits: for i in 0..256 { - if naf[i] == 0 { continue 'bits; } - 'window: for b in 1..6 { - if i+b >= 256 { break 'window; } - if naf[i+b] == 0 { continue 'window; } - let potential_carry = naf[i+b] << b; - if naf[i+b] + potential_carry <= 15 { - // Eliminate naf[i+b] by carrying its value onto naf[i] - naf[i] += potential_carry; - naf[i+b] = 0; - } else if naf[i+b] - potential_carry >= -15 { - // Eliminate naf[i+b] by carrying its value upwards. - naf[i] -= potential_carry; // Subtract 2^(i+b) - 'carry: for k in i+b..256 { - if naf[k] != 0 { - // Since naf[k] = 0 or 1 for k > i, naf[k] == 1. - naf[k] = 0; // Subtract 2^k - } else { - // By now we have subtracted 2^k = - // 2^(i+b) + 2^(i+b) + 2^(i+b+1) + ... + 2^(k-1). - naf[k] = 1; // Add back 2^k. - break 'carry; - } - } - } + let mut naf = [0i8; 256]; + + let mut x_u64 = [0u64; 5]; + LittleEndian::read_u64_into(&self.bytes, &mut x_u64[0..4]); + + let width = 1 << w; + let window_mask = width - 1; + + let mut pos = 0; + let mut carry = 0; + while pos < 256 { + // Construct a buffer of bits of the scalar, starting at bit `pos` + let u64_idx = pos / 64; + let bit_idx = pos % 64; + let bit_buf: u64; + if bit_idx < 64 - w { + // This window's bits are contained in a single u64 + bit_buf = x_u64[u64_idx] >> bit_idx; + } else { + // Combine the current u64's bits with the bits from the next u64 + bit_buf = (x_u64[u64_idx] >> bit_idx) | (x_u64[1+u64_idx] << (64 - bit_idx)); } + + // 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 @@ -789,7 +805,7 @@ mod test { #[test] fn non_adjacent_form() { - let naf = A_SCALAR.non_adjacent_form(); + let naf = A_SCALAR.non_adjacent_form(5); for i in 0..256 { assert_eq!(naf[i], A_NAF[i]); } diff --git a/src/scalar_mul/vartime_double_base.rs b/src/scalar_mul/vartime_double_base.rs index 60c51e6..9fcd267 100644 --- a/src/scalar_mul/vartime_double_base.rs +++ b/src/scalar_mul/vartime_double_base.rs @@ -18,8 +18,8 @@ use scalar_mul::window::OddLookupTable; /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { - let a_naf = a.non_adjacent_form(); - let b_naf = b.non_adjacent_form(); + let a_naf = a.non_adjacent_form(5); + let b_naf = b.non_adjacent_form(5); // Find starting index let mut i: usize = 255; diff --git a/src/scalar_mul/vartime_straus.rs b/src/scalar_mul/vartime_straus.rs index c55ce21..b419c0a 100644 --- a/src/scalar_mul/vartime_straus.rs +++ b/src/scalar_mul/vartime_straus.rs @@ -27,7 +27,7 @@ where { let nafs: Vec<_> = scalars .into_iter() - .map(|c| c.borrow().non_adjacent_form()) + .map(|c| c.borrow().non_adjacent_form(5)) .collect(); let lookup_tables: Vec<_> = points .into_iter()