Skip to content

Commit 0cef809

Browse files
authored
Merge pull request #6 from rustaceanrob/26-7-8-further-opt
.
2 parents aecdbca + 66dc80f commit 0cef809

3 files changed

Lines changed: 65 additions & 81 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# ectools
2+
3+
This repository implements finite field arithmetic, elliptic curves in short Weierstrass form, and other primitives that may be used in more complex protocols, such as pairings, isogenies, etc. When cryptographic protocols are proposed in academia, these crates may be used to implement them and assess performance and complexity.
4+
5+
## Crates
6+
- `curve` implementation of point addition and multiplication over a generic elliptic curve
7+
- `field` airthmetic over finite fields

curve/src/lib.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,22 @@ impl<F: Field> Point<F> {
213213
}
214214

215215
fn mul<G: Field>(&self, scalar: Scalar<G>, a: FieldElement<F>) -> Self {
216+
let mut table = [Self::infinity(); 16];
217+
table[1] = *self;
218+
for k in 2..16 {
219+
table[k] = table[k - 1].add(self, a);
220+
}
221+
222+
let limbs = scalar.0.as_ref();
223+
let n_windows = limbs.len() * 16;
216224
let mut result = Self::infinity();
217-
for &limb in scalar.0.as_ref().iter().rev() {
218-
for bit_idx in (0..u64::BITS).rev() {
219-
result = result.double(a);
220-
if (limb >> bit_idx) & 1 == 1 {
221-
result = result.add(self, a);
222-
}
223-
}
225+
for i in (0..n_windows).rev() {
226+
result = result.double(a);
227+
result = result.double(a);
228+
result = result.double(a);
229+
result = result.double(a);
230+
let chunk = ((limbs[i / 16] >> ((i % 16) * 4)) & 0xF) as usize;
231+
result = result.add(&table[chunk], a);
224232
}
225233
result
226234
}

field/src/lib.rs

Lines changed: 43 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -321,39 +321,6 @@ impl<P: Field<Limbs = [u64; 4]>> FieldElement<P> {
321321
}
322322
}
323323

324-
#[inline]
325-
fn wide_mul<P: Field>(a: &P::Limbs, b: &P::Limbs) -> (P::Limbs, P::Limbs) {
326-
let a_slice = a.as_ref();
327-
let b_slice = b.as_ref();
328-
let n = a_slice.len();
329-
let mut lo = P::Limbs::default();
330-
let mut hi = P::Limbs::default();
331-
{
332-
let lo_slice = lo.as_mut();
333-
let hi_slice = hi.as_mut();
334-
for i in 0..n {
335-
let mut carry = 0u64;
336-
for (j, &bj) in b_slice.iter().enumerate() {
337-
let idx = i + j;
338-
let cell = if idx < n {
339-
lo_slice[idx]
340-
} else {
341-
hi_slice[idx - n]
342-
};
343-
let (product, new_carry) = a_slice[i].carrying_mul_add(bj, cell, carry);
344-
if idx < n {
345-
lo_slice[idx] = product;
346-
} else {
347-
hi_slice[idx - n] = product;
348-
}
349-
carry = new_carry;
350-
}
351-
hi_slice[i] = carry;
352-
}
353-
}
354-
(lo, hi)
355-
}
356-
357324
#[inline]
358325
fn ge_modulus<P: Field>(x: &P::Limbs) -> bool {
359326
let x_slice = x.as_ref();
@@ -367,59 +334,61 @@ fn ge_modulus<P: Field>(x: &P::Limbs) -> bool {
367334
true
368335
}
369336

370-
fn montgomery_reduce<P: Field>(mut lo: P::Limbs, mut hi: P::Limbs) -> P::Limbs {
371-
let n = lo.as_ref().len();
337+
pub fn mont_mul<P: Field>(a: &P::Limbs, b: &P::Limbs) -> P::Limbs {
338+
let a = a.as_ref();
339+
let b = b.as_ref();
372340
let m = P::MODULUS;
373341
let p = m.as_ref();
374342
let p_inv = P::PARAMS.p_inv;
375-
let mut extra_carry = false;
343+
let n = a.len();
376344

377-
for i in 0..n {
378-
let m_i = lo.as_ref()[i].wrapping_mul(p_inv);
345+
let mut t = P::Limbs::default();
346+
let mut t_hi: u64 = 0;
347+
let mut t_hi1: u64 = 0;
348+
349+
for &bi in b {
379350
let mut carry = 0u64;
380-
for (j, &pj) in p.iter().enumerate() {
381-
let idx = i + j;
382-
let cell = if idx < n {
383-
lo.as_ref()[idx]
384-
} else {
385-
hi.as_ref()[idx - n]
386-
};
387-
let (prod, new_carry) = m_i.carrying_mul_add(pj, cell, carry);
388-
if idx < n {
389-
lo.as_mut()[idx] = prod;
390-
} else {
391-
hi.as_mut()[idx - n] = prod;
351+
{
352+
let t_mut = t.as_mut();
353+
for j in 0..n {
354+
let prod = (a[j] as u128) * (bi as u128) + (t_mut[j] as u128) + (carry as u128);
355+
t_mut[j] = prod as u64;
356+
carry = (prod >> 64) as u64;
392357
}
393-
carry = new_carry;
394-
}
395-
let mut k = i + n;
396-
while carry != 0 && k < 2 * n {
397-
let cell = hi.as_ref()[k - n];
398-
let (v, nc) = cell.overflowing_add(carry);
399-
hi.as_mut()[k - n] = v;
400-
carry = if nc { 1 } else { 0 };
401-
k += 1;
402358
}
403-
if carry != 0 {
404-
extra_carry = true;
359+
let s = (t_hi as u128) + (carry as u128);
360+
t_hi = s as u64;
361+
t_hi1 = t_hi1.wrapping_add((s >> 64) as u64);
362+
363+
let mm = t.as_ref()[0].wrapping_mul(p_inv);
364+
let prod0 = (mm as u128) * (p[0] as u128) + (t.as_ref()[0] as u128);
365+
let mut carry = (prod0 >> 64) as u64;
366+
{
367+
let t_mut = t.as_mut();
368+
for j in 1..n {
369+
let prod = (mm as u128) * (p[j] as u128) + (t_mut[j] as u128) + (carry as u128);
370+
t_mut[j - 1] = prod as u64;
371+
carry = (prod >> 64) as u64;
372+
}
405373
}
374+
let s = (t_hi as u128) + (carry as u128);
375+
t.as_mut()[n - 1] = s as u64;
376+
let cout = (s >> 64) as u64;
377+
let s2 = (t_hi1 as u128) + (cout as u128);
378+
t_hi = s2 as u64;
379+
t_hi1 = (s2 >> 64) as u64;
406380
}
407381

408-
let mut r = hi;
409-
if extra_carry || ge_modulus::<P>(&r) {
410-
let mut b = false;
411-
for (i, ri) in r.as_mut().iter_mut().enumerate() {
412-
let (d, nb) = ri.borrowing_sub(p[i], b);
413-
*ri = d;
414-
b = nb;
382+
if t_hi != 0 || ge_modulus::<P>(&t) {
383+
let t_mut = t.as_mut();
384+
let mut borrow = false;
385+
for i in 0..n {
386+
let (d, nb) = t_mut[i].borrowing_sub(p[i], borrow);
387+
t_mut[i] = d;
388+
borrow = nb;
415389
}
416390
}
417-
r
418-
}
419-
420-
pub fn mont_mul<P: Field>(a: &P::Limbs, b: &P::Limbs) -> P::Limbs {
421-
let (lo, hi) = wide_mul::<P>(a, b);
422-
montgomery_reduce::<P>(lo, hi)
391+
t
423392
}
424393

425394
impl<P: Field> Add for FieldElement<P> {

0 commit comments

Comments
 (0)