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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
use ff::{PrimeField, PrimeFieldRepr};
use ff::PrimeField;
use std::iter;
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.
pub(crate) fn wnaf_form<S: PrimeFieldRepr>(wnaf: &mut Vec<i64>, mut c: S, window: usize) {
/// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian
/// 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);
while !c.is_zero() {
let mut u;
if c.is_odd() {
u = (c.as_ref()[0] % (1 << (window + 1))) as i64;
let u64_len = c.as_ref().len();
let bit_len = u64_len * 64;
if u > (1 << window) {
u -= 1 << (window + 1);
}
let mut c_u64 = vec![0u64; u64_len + 1];
c_u64[0..u64_len].copy_from_slice(c.as_ref());
if u > 0 {
c.sub_noborrow(&S::from(u as u64));
} else {
c.add_nocarry(&S::from((-u) as u64));
}
let width = 1u64 << window;
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 {
u = 0;
// 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 {
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(..)`.
pub fn scalar(
&mut self,
scalar: <<G as CurveProjective>::Scalar as PrimeField>::Repr,
scalar: &<G as CurveProjective>::Scalar,
) -> Wnaf<usize, &mut Vec<G>, &[i64]> {
let scalar = scalar.into_repr();
// Compute the appropriate window size for the 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> {
/// Performs exponentiation given a scalar.
pub fn scalar<G: CurveProjective>(
&mut self,
scalar: <<G as CurveProjective>::Scalar as PrimeField>::Repr,
) -> G
pub fn scalar<G: CurveProjective>(&mut self, scalar: &<G as CurveProjective>::Scalar) -> G
where
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())
}
}