mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-01 08:12:14 +00:00
group: Rewrite wNAF to remove dependency on ff::PrimeFieldRepr
Adapted from Scalar::non_adjacent_form in curve25519-dalek.
This commit is contained in:
parent
6e53cf3c4c
commit
69c60530d4
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user