Skip to content

Commit

Permalink
Add the relaxed NAF (#302)
Browse files Browse the repository at this point in the history
* add the relaxed NAF

* fmt; rename

* simplify the algorithm

* CHANGELOG

* make find_relaxed_naf public

* Update CHANGELOG.md

* cleaned up

* show the usefulness
  • Loading branch information
weikengchen authored Feb 10, 2022
1 parent 7609f36 commit 4dd6c34
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 6 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
### Breaking changes

- [\#300](https://github.com/arkworks-rs/algebra/pull/300) (`ark-ec`) Change the implementation of `Hash` trait of `GroupProjective` to use the affine co-ordinates.
- [\#302](https://github.com/arkworks-rs/algebra/pull/302) (`ark-ff`) Rename `find_wnaf` to `find_naf`.
- [\#310](https://github.com/arkworks-rs/algebra/pull/310) (`ark-ec`, `ark-ff`) Remove unnecessary internal `PhantomData`.
- [\#333](https://github.com/arkworks-rs/algebra/pull/333) (`ark-poly`) Expose more properties of `EvaluationDomain`s.
- [\#338](https://github.com/arkworks-rs/algebra/pull/338) (`ark-ec`) Add missing `UniformRand` trait bound to `GroupAffine`.
- [\#338](https://github.com/arkworks-rs/algebra/pull/338) (workspace) Change to Rust 2021 edition.
- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (`ark-ec`, `ark-serialize`) Change the serialization format for Twisted Edwards Curves. We now encode the Y co-ordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860)
- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (`ark-ec`) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy.
- [\#359](https://github.com/arkworks-rs/algebra/pull/359) (ark-test-templates) Simplify the field and curve test macros.
- [\#359](https://github.com/arkworks-rs/algebra/pull/359) (`ark-test-templates`) Simplify the field and curve test macros.
- [\#365](https://github.com/arkworks-rs/algebra/pull/365) (`ark-ec`)
- Move `COFACTOR`, `COFACTOR_INV`, and `is_in_correct_subgroup_assuming_on_curve()` from `{SW,TE}ModelParameters` to `ModelParameters`.
- Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this.
Expand Down Expand Up @@ -42,6 +43,7 @@

### Improvements

- [\#302](https://github.com/arkworks-rs/algebra/pull/302) (`ark-ff`) Add the relaxed NAF computation.
- [\#306](https://github.com/arkworks-rs/algebra/pull/306) (`ark-ff`, `ark-ff-asm`) Make the assembly backend available on `stable`.
- [\#339](https://github.com/arkworks-rs/algebra/pull/339) (`ark-ff`) Remove duplicated code from `test_field` module and replace its usage with `ark-test-curves` crate.
- [\#352](https://github.com/arkworks-rs/algebra/pull/352) (`ark-ff`) Update `QuadExtField::sqrt` for better performance.
Expand Down
81 changes: 78 additions & 3 deletions ff/src/biginteger/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ark_std::vec::Vec;
use ark_std::{vec, vec::Vec};

macro_rules! adc {
($a:expr, $b:expr, &mut $carry:expr$(,)?) => {{
Expand Down Expand Up @@ -66,8 +66,8 @@ pub(crate) fn mac_discard(a: u64, b: u64, c: u64, carry: &mut u64) {
*carry = (tmp >> 64) as u64;
}

/// Compute the Window NAF (non-adjacent form) of num
pub fn find_wnaf(num: &[u64]) -> Vec<i64> {
/// Compute the NAF (non-adjacent form) of num
pub fn find_naf(num: &[u64]) -> Vec<i64> {
let is_zero = |num: &[u64]| num.iter().all(|x| *x == 0u64);
let is_odd = |num: &[u64]| num[0] & 1 == 1;
let sub_noborrow = |num: &mut [u64], z: u64| {
Expand Down Expand Up @@ -119,3 +119,78 @@ pub fn find_wnaf(num: &[u64]) -> Vec<i64> {

res
}

/// We define relaxed NAF as a variant of NAF with a very small tweak.
///
/// Note that the cost of scalar multiplication grows with the length of the sequence (for doubling)
/// plus the Hamming weight of the sequence (for addition, or subtraction).
///
/// NAF is optimizing for the Hamming weight only and therefore can be suboptimal.
/// For example, NAF may generate a sequence (in little-endian) of the form ...0 -1 0 1.
///
/// This can be rewritten as ...0 1 1 to avoid one doubling, at the cost that we are making an
/// exception of non-adjacence for the most significant bit.
///
/// Since this representation is no longer a strict NAF, we call it ``relaxed NAF''.
///
pub fn find_relaxed_naf(num: &[u64]) -> Vec<i64> {
let mut res = find_naf(num);

let len = res.len();
if res[len - 2] == 0 && res[len - 3] == -1 {
res[len - 3] = 1;
res[len - 2] = 1;
res.resize(len - 1, 0);
}

res
}

#[test]
fn test_find_relaxed_naf_usefulness() {
let vec = find_naf(&[12u64]);
assert_eq!(vec.len(), 5);

let vec = find_relaxed_naf(&[12u64]);
assert_eq!(vec.len(), 4);
}

#[test]
fn test_find_relaxed_naf_correctness() {
use ark_std::{One, UniformRand, Zero};
use num_bigint::BigInt;

let mut rng = ark_std::test_rng();

for _ in 0..10 {
let num = [
u64::rand(&mut rng),
u64::rand(&mut rng),
u64::rand(&mut rng),
u64::rand(&mut rng),
];
let relaxed_naf = find_relaxed_naf(&num);

let test = {
let mut sum = BigInt::zero();
let mut cur = BigInt::one();
for v in relaxed_naf {
sum += cur.clone() * v;
cur = cur * 2;
}
sum
};

let test_expected = {
let mut sum = BigInt::zero();
let mut cur = BigInt::one();
for v in num.iter() {
sum += cur.clone() * v;
cur = cur << 64;
}
sum
};

assert_eq!(test, test_expected);
}
}
2 changes: 1 addition & 1 deletion ff/src/fields/models/fp12_2over3over2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<P: Fp12Parameters> QuadExtConfig for Fp12ParamsWrapper<P> {
fe_inverse.conjugate();

let mut found_nonzero = false;
let naf = crate::biginteger::arithmetic::find_wnaf(exponent.as_ref());
let naf = crate::biginteger::arithmetic::find_naf(exponent.as_ref());

for &value in naf.iter().rev() {
if found_nonzero {
Expand Down
2 changes: 1 addition & 1 deletion ff/src/fields/models/quadratic_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub trait QuadExtConfig: 'static + Send + Sync + Sized {
self_inverse.conjugate();

let mut found_nonzero = false;
let naf = crate::biginteger::arithmetic::find_wnaf(exponent.as_ref());
let naf = crate::biginteger::arithmetic::find_naf(exponent.as_ref());

for &value in naf.iter().rev() {
if found_nonzero {
Expand Down

0 comments on commit 4dd6c34

Please sign in to comment.