group: Rewrite wNAF to remove dependency on ff::PrimeFieldRepr

Adapted from Scalar::non_adjacent_form in curve25519-dalek.
This commit is contained in:
Jack Grigg 2020-03-26 19:23:29 +13:00
parent 6e53cf3c4c
commit 69c60530d4
4 changed files with 78 additions and 48 deletions

View File

@ -2,7 +2,7 @@ use rand_core::RngCore;
use std::ops::{AddAssign, MulAssign}; use std::ops::{AddAssign, MulAssign};
use std::sync::Arc; use std::sync::Arc;
use ff::{Field, PrimeField}; use ff::Field;
use group::{CurveAffine, CurveProjective, Wnaf}; use group::{CurveAffine, CurveProjective, Wnaf};
use pairing::Engine; use pairing::Engine;
@ -273,7 +273,7 @@ where
exp.mul_assign(&coeff); exp.mul_assign(&coeff);
// Exponentiate // Exponentiate
*h = g1_wnaf.scalar(exp.into_repr()); *h = g1_wnaf.scalar(&exp);
} }
// Batch normalize // Batch normalize
@ -376,14 +376,14 @@ where
// Compute A query (in G1) // Compute A query (in G1)
if !at.is_zero() { if !at.is_zero() {
*a = g1_wnaf.scalar(at.into_repr()); *a = g1_wnaf.scalar(&at);
} }
// Compute B query (in G1/G2) // Compute B query (in G1/G2)
if !bt.is_zero() { if !bt.is_zero() {
let bt_repr = bt.into_repr(); ();
*b_g1 = g1_wnaf.scalar(bt_repr); *b_g1 = g1_wnaf.scalar(&bt);
*b_g2 = g2_wnaf.scalar(bt_repr); *b_g2 = g2_wnaf.scalar(&bt);
} }
at.mul_assign(&beta); at.mul_assign(&beta);
@ -394,7 +394,7 @@ where
e.add_assign(&ct); e.add_assign(&ct);
e.mul_assign(inv); e.mul_assign(inv);
*ext = g1_wnaf.scalar(e.into_repr()); *ext = g1_wnaf.scalar(&e);
} }
// Batch normalize // Batch normalize

View File

@ -15,6 +15,7 @@ repository = "https://github.com/ebfull/group"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
byteorder = { version = "1", default-features = false }
ff = { version = "0.6", path = "../ff" } ff = { version = "0.6", path = "../ff" }
rand = "0.7" rand = "0.7"
rand_xorshift = "0.2" rand_xorshift = "0.2"

View File

@ -85,12 +85,12 @@ fn random_wnaf_tests<G: CurveProjective>() {
for w in 2..14 { for w in 2..14 {
for _ in 0..100 { for _ in 0..100 {
let g = G::random(&mut rng); let g = G::random(&mut rng);
let s = G::Scalar::random(&mut rng).into_repr(); let s = G::Scalar::random(&mut rng);
let mut g1 = g; let mut g1 = g;
g1.mul_assign(s); g1.mul_assign(s);
wnaf_table(&mut table, g, w); wnaf_table(&mut table, g, w);
wnaf_form(&mut wnaf, s, w); wnaf_form(&mut wnaf, s.into_repr(), w);
let g2 = wnaf_exp(&table, &wnaf); let g2 = wnaf_exp(&table, &wnaf);
assert_eq!(g1, g2); assert_eq!(g1, g2);
@ -103,17 +103,17 @@ fn random_wnaf_tests<G: CurveProjective>() {
for _ in 0..100 { for _ in 0..100 {
let g = G::random(&mut rng); let g = G::random(&mut rng);
let s = G::Scalar::random(&mut rng).into_repr(); let s = G::Scalar::random(&mut rng);
let mut g1 = g; let mut g1 = g;
g1.mul_assign(s); g1.mul_assign(s);
let g2 = { let g2 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
wnaf.base(g, 1).scalar(s) wnaf.base(g, 1).scalar(&s)
}; };
let g3 = { let g3 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
wnaf.scalar(s).base(g) wnaf.scalar(&s).base(g)
}; };
let g4 = { let g4 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
@ -121,11 +121,11 @@ fn random_wnaf_tests<G: CurveProjective>() {
only_compiles_if_send(&shared); only_compiles_if_send(&shared);
shared.scalar(s) shared.scalar(&s)
}; };
let g5 = { let g5 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
let mut shared = wnaf.scalar(s).shared(); let mut shared = wnaf.scalar(&s).shared();
only_compiles_if_send(&shared); only_compiles_if_send(&shared);
@ -137,40 +137,40 @@ fn random_wnaf_tests<G: CurveProjective>() {
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr()); .scalar(&G::Scalar::random(&mut rng));
} }
wnaf.base(g, 1).scalar(s) wnaf.base(g, 1).scalar(&s)
}; };
let g7 = { let g7 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr()); .scalar(&G::Scalar::random(&mut rng));
} }
wnaf.scalar(s).base(g) wnaf.scalar(&s).base(g)
}; };
let g8 = { let g8 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr()); .scalar(&G::Scalar::random(&mut rng));
} }
let mut shared = wnaf.base(g, 1).shared(); let mut shared = wnaf.base(g, 1).shared();
only_compiles_if_send(&shared); only_compiles_if_send(&shared);
shared.scalar(s) shared.scalar(&s)
}; };
let g9 = { let g9 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr()); .scalar(&G::Scalar::random(&mut rng));
} }
let mut shared = wnaf.scalar(s).shared(); let mut shared = wnaf.scalar(&s).shared();
only_compiles_if_send(&shared); only_compiles_if_send(&shared);

View File

@ -1,4 +1,5 @@
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
use std::iter;
use super::CurveProjective; use super::CurveProjective;
@ -16,31 +17,60 @@ pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, wi
} }
} }
/// Replaces the contents of `wnaf` with the w-NAF representation of a scalar. /// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian
pub(crate) fn wnaf_form<S: PrimeFieldRepr>(wnaf: &mut Vec<i64>, mut c: S, window: usize) { /// scalar.
pub(crate) fn wnaf_form<S: AsRef<[u64]>>(wnaf: &mut Vec<i64>, c: S, window: usize) {
// Required by the NAF definition
debug_assert!(window >= 2);
// Required so that the NAF digits fit in i64
debug_assert!(window <= 64);
wnaf.truncate(0); wnaf.truncate(0);
while !c.is_zero() { let u64_len = c.as_ref().len();
let mut u; let bit_len = u64_len * 64;
if c.is_odd() {
u = (c.as_ref()[0] % (1 << (window + 1))) as i64;
if u > (1 << window) { let mut c_u64 = vec![0u64; u64_len + 1];
u -= 1 << (window + 1); c_u64[0..u64_len].copy_from_slice(c.as_ref());
}
if u > 0 { let width = 1u64 << window;
c.sub_noborrow(&S::from(u as u64)); let window_mask = width - 1;
let mut pos = 0;
let mut carry = 0;
while pos < bit_len {
// 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 = if bit_idx + window < 64 {
// This window's bits are contained in a single u64
c_u64[u64_idx] >> bit_idx
} else { } else {
c.add_nocarry(&S::from((-u) as u64)); // Combine the current u64's bits with the bits from the next u64
} (c_u64[u64_idx] >> bit_idx) | (c_u64[u64_idx + 1] << (64 - bit_idx))
};
// Add the carry into the current window
let window_val = carry + (bit_buf & window_mask);
if window_val & 1 == 0 {
// If the window value is even, preserve the carry and emit 0.
// Why is the carry preserved?
// If carry == 0 and window_val & 1 == 0, then the next carry should be 0
// If carry == 1 and window_val & 1 == 0, then bit_buf & 1 == 1 so the next carry should be 1
wnaf.push(0);
pos += 1;
} else { } else {
u = 0; wnaf.push(if window_val < width / 2 {
carry = 0;
window_val as i64
} else {
carry = 1;
(window_val as i64).wrapping_sub(width as i64)
});
wnaf.extend(iter::repeat(0).take(window - 1));
pos += window;
} }
wnaf.push(u);
c.div2();
} }
} }
@ -112,8 +142,10 @@ impl<G: CurveProjective> Wnaf<(), Vec<G>, Vec<i64>> {
/// exponentiations with `.base(..)`. /// exponentiations with `.base(..)`.
pub fn scalar( pub fn scalar(
&mut self, &mut self,
scalar: <<G as CurveProjective>::Scalar as PrimeField>::Repr, scalar: &<G as CurveProjective>::Scalar,
) -> Wnaf<usize, &mut Vec<G>, &[i64]> { ) -> Wnaf<usize, &mut Vec<G>, &[i64]> {
let scalar = scalar.into_repr();
// Compute the appropriate window size for the scalar. // Compute the appropriate window size for the scalar.
let window_size = G::recommended_wnaf_for_scalar(&scalar); let window_size = G::recommended_wnaf_for_scalar(&scalar);
@ -168,14 +200,11 @@ impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> { impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
/// Performs exponentiation given a scalar. /// Performs exponentiation given a scalar.
pub fn scalar<G: CurveProjective>( pub fn scalar<G: CurveProjective>(&mut self, scalar: &<G as CurveProjective>::Scalar) -> G
&mut self,
scalar: <<G as CurveProjective>::Scalar as PrimeField>::Repr,
) -> G
where where
B: AsRef<[G]>, B: AsRef<[G]>,
{ {
wnaf_form(self.scalar.as_mut(), scalar, self.window_size); wnaf_form(self.scalar.as_mut(), scalar.into_repr(), self.window_size);
wnaf_exp(self.base.as_ref(), self.scalar.as_mut()) wnaf_exp(self.base.as_ref(), self.scalar.as_mut())
} }
} }