Added wNAF scalar multiplication.
This commit is contained in:
parent
b965c58ac1
commit
021077b56b
@ -496,6 +496,14 @@ macro_rules! curve_impl {
|
||||
fn to_affine(&self) -> $affine {
|
||||
(*self).into()
|
||||
}
|
||||
|
||||
fn recommended_wnaf_for_scalar(scalar: <Self::Scalar as PrimeField>::Repr) -> Option<usize> {
|
||||
Self::empirical_recommended_wnaf_for_scalar(scalar)
|
||||
}
|
||||
|
||||
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
|
||||
Self::empirical_recommended_wnaf_for_num_scalars(num_scalars)
|
||||
}
|
||||
}
|
||||
|
||||
// The affine point X, Y is represented in the jacobian
|
||||
@ -555,8 +563,8 @@ macro_rules! curve_impl {
|
||||
|
||||
pub mod g1 {
|
||||
use rand::{Rand, Rng};
|
||||
use super::super::{Fq, Fr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, Field, BitIterator};
|
||||
use super::super::{Fq, Fr, FrRepr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, PrimeFieldRepr, Field, BitIterator};
|
||||
|
||||
curve_impl!(G1, G1Affine, G1Prepared, Fq, Fr);
|
||||
|
||||
@ -574,6 +582,40 @@ pub mod g1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl G1 {
|
||||
fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> Option<usize>
|
||||
{
|
||||
const RECOMMENDATIONS: [usize; 3] = [12, 34, 130];
|
||||
|
||||
let mut ret = None;
|
||||
let num_bits = scalar.num_bits() as usize;
|
||||
|
||||
for (i, r) in RECOMMENDATIONS.iter().enumerate() {
|
||||
if *r >= num_bits {
|
||||
ret = Some(i + 2)
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize
|
||||
{
|
||||
const RECOMMENDATIONS: [usize; 12] = [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569];
|
||||
|
||||
let mut ret = 4;
|
||||
for r in RECOMMENDATIONS.iter() {
|
||||
if num_scalars > *r {
|
||||
ret += 1;
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct G1Prepared(pub(crate) G1Affine);
|
||||
|
||||
@ -838,8 +880,8 @@ pub mod g1 {
|
||||
|
||||
pub mod g2 {
|
||||
use rand::{Rand, Rng};
|
||||
use super::super::{Fq2, Fr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, Field, BitIterator};
|
||||
use super::super::{Fq2, Fr, FrRepr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, PrimeFieldRepr, Field, BitIterator};
|
||||
|
||||
curve_impl!(G2, G2Affine, G2Prepared, Fq2, Fr);
|
||||
|
||||
@ -866,6 +908,40 @@ pub mod g2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl G2 {
|
||||
fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> Option<usize>
|
||||
{
|
||||
const RECOMMENDATIONS: [usize; 3] = [13, 37, 103];
|
||||
|
||||
let mut ret = None;
|
||||
let num_bits = scalar.num_bits() as usize;
|
||||
|
||||
for (i, r) in RECOMMENDATIONS.iter().enumerate() {
|
||||
if *r >= num_bits {
|
||||
ret = Some(i + 2)
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize
|
||||
{
|
||||
const RECOMMENDATIONS: [usize; 11] = [1, 3, 8, 20, 47, 126, 260, 826, 1501, 4555, 84071];
|
||||
|
||||
let mut ret = 4;
|
||||
for r in RECOMMENDATIONS.iter() {
|
||||
if num_scalars > *r {
|
||||
ret += 1;
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct G2Prepared {
|
||||
pub(crate) coeffs: Vec<(Fq2, Fq2, Fq2)>,
|
||||
|
10
src/lib.rs
10
src/lib.rs
@ -10,6 +10,7 @@ extern crate rand;
|
||||
pub mod tests;
|
||||
|
||||
pub mod bls12_381;
|
||||
pub mod wnaf;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
@ -123,6 +124,15 @@ pub trait CurveProjective: PartialEq +
|
||||
|
||||
/// Converts this element into its affine representation.
|
||||
fn to_affine(&self) -> Self::Affine;
|
||||
|
||||
/// Recommends a wNAF window table size given a scalar. Returns `None` if normal
|
||||
/// scalar multiplication is encouraged. If `Some` is returned, it will be between
|
||||
/// 2 and 22, inclusive.
|
||||
fn recommended_wnaf_for_scalar(scalar: <Self::Scalar as PrimeField>::Repr) -> Option<usize>;
|
||||
|
||||
/// Recommends a wNAF window size given the number of scalars you intend to multiply
|
||||
/// a base by. Always returns a number between 2 and 22, inclusive.
|
||||
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
|
||||
}
|
||||
|
||||
/// Affine representation of an elliptic curve point guaranteed to be
|
||||
|
@ -58,6 +58,32 @@ pub fn curve_tests<G: CurveProjective>()
|
||||
random_doubling_tests::<G>();
|
||||
random_negation_tests::<G>();
|
||||
random_transformation_tests::<G>();
|
||||
random_wnaf_tests::<G>();
|
||||
}
|
||||
|
||||
fn random_wnaf_tests<G: CurveProjective>() {
|
||||
use ::wnaf::*;
|
||||
use ::PrimeField;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let mut table = vec![];
|
||||
let mut wnaf = vec![];
|
||||
|
||||
for w in 2..14 {
|
||||
for _ in 0..100 {
|
||||
let g = G::rand(&mut rng);
|
||||
let s = G::Scalar::rand(&mut rng).into_repr();
|
||||
let mut g1 = g;
|
||||
g1.mul_assign(s);
|
||||
|
||||
wnaf_table(&mut table, g, w);
|
||||
wnaf_form(&mut wnaf, s, w);
|
||||
let g2 = wnaf_exp(&table, &wnaf);
|
||||
|
||||
assert_eq!(g1, g2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_negation_tests<G: CurveProjective>() {
|
||||
|
84
src/wnaf.rs
Normal file
84
src/wnaf.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use super::{CurveProjective, PrimeFieldRepr};
|
||||
|
||||
/// Replaces the contents of `table` with a wNAF window table for the given window size.
|
||||
///
|
||||
/// This function will panic if provided a window size below two, or above 22.
|
||||
pub fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, window: usize)
|
||||
{
|
||||
assert!(window < 23);
|
||||
assert!(window > 1);
|
||||
|
||||
table.truncate(0);
|
||||
table.reserve(1 << (window-1));
|
||||
|
||||
let mut dbl = base;
|
||||
dbl.double();
|
||||
|
||||
for _ in 0..(1 << (window-1)) {
|
||||
table.push(base);
|
||||
base.add_assign(&dbl);
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces the contents of `wnaf` with the wNAF representation of a scalar.
|
||||
///
|
||||
/// This function will panic if provided a window size below two, or above 22.
|
||||
pub fn wnaf_form<S: PrimeFieldRepr>(wnaf: &mut Vec<i64>, mut c: S, window: usize)
|
||||
{
|
||||
assert!(window < 23);
|
||||
assert!(window > 1);
|
||||
|
||||
wnaf.truncate(0);
|
||||
|
||||
while !c.is_zero() {
|
||||
let mut u;
|
||||
if c.is_odd() {
|
||||
u = (c.as_ref()[0] % (1 << (window+1))) as i64;
|
||||
|
||||
if u > (1 << window) {
|
||||
u -= 1 << (window+1);
|
||||
}
|
||||
|
||||
if u > 0 {
|
||||
c.sub_noborrow(&S::from(u as u64));
|
||||
} else {
|
||||
c.add_nocarry(&S::from((-u) as u64));
|
||||
}
|
||||
} else {
|
||||
u = 0;
|
||||
}
|
||||
|
||||
wnaf.push(u);
|
||||
|
||||
c.div2();
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs wNAF exponentiation with the provided window table and wNAF-form scalar.
|
||||
///
|
||||
/// This function must be provided a `table` and `wnaf` that were constructed with
|
||||
/// the same window size; otherwise, it may panic or produce invalid results.
|
||||
pub fn wnaf_exp<G: CurveProjective>(table: &[G], wnaf: &[i64]) -> G
|
||||
{
|
||||
let mut result = G::zero();
|
||||
|
||||
let mut found_one = false;
|
||||
|
||||
for n in wnaf.iter().rev() {
|
||||
if found_one {
|
||||
result.double();
|
||||
}
|
||||
|
||||
if *n != 0 {
|
||||
found_one = true;
|
||||
|
||||
if *n > 0 {
|
||||
result.add_assign(&table[(n/2) as usize]);
|
||||
} else {
|
||||
result.sub_assign(&table[((-n)/2) as usize]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
Loading…
Reference in New Issue
Block a user