From 91a7c641c26c79a653130f0a319439145026c1b6 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sun, 3 Sep 2017 16:49:26 -1000 Subject: [PATCH 1/3] Use more efficient addition chain for scalar inversion. Use the addition chain from https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion. In my benchmarking, this consistently runs at least 20% faster. --- src/scalar.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index b306aee..5490a21 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -2,11 +2,13 @@ // // This file is part of curve25519-dalek. // Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Portions Copyright 2017 Brian Smith // See LICENSE for licensing information. // // Authors: // - Isis Agora Lovecruft // - Henry de Valence +// - Brian Smith //! Arithmetic for scalar multiplication. //! @@ -565,14 +567,59 @@ impl UnpackedScalar { /// Compute the multiplicative inverse of this scalar. pub fn invert(&self) -> UnpackedScalar { - let mut y = UnpackedScalar::one(); - // Run through bits of l-2 from highest to least - for bit in constants::l_minus_2.bits().iter().rev() { - y = y.square(); - if *bit == 1 { - y = UnpackedScalar::multiply_add(&y, self, &UnpackedScalar::zero()); + // This is a direct transliteration of the addition chain from + // https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion + // as it was published on 2017-09-03. + + let _1 = *self; + let _10 = _1.square(); + let _11 = UnpackedScalar::multiply_add(&_10, &_1, &UnpackedScalar::zero()); + let _101 = UnpackedScalar::multiply_add(&_11, &_10, &UnpackedScalar::zero()); + let _111 = UnpackedScalar::multiply_add(&_101, &_10, &UnpackedScalar::zero()); + let _1001 = UnpackedScalar::multiply_add(&_111, &_10, &UnpackedScalar::zero()); + let _1011 = UnpackedScalar::multiply_add(&_1001, &_10, &UnpackedScalar::zero()); + let _1101 = UnpackedScalar::multiply_add(&_1011, &_10, &UnpackedScalar::zero()); + let _1111 = UnpackedScalar::multiply_add(&_1101, &_10, &UnpackedScalar::zero()); + + // 0b10000 + let mut y = UnpackedScalar::multiply_add(&_1111, &_1, &UnpackedScalar::zero()); + + #[inline] + fn square_multiply(y: &mut UnpackedScalar, squarings: usize, x: &UnpackedScalar) { + for _ in 0..squarings { + *y = y.square(); } + *y = UnpackedScalar::multiply_add(y, x, &UnpackedScalar::zero()); } + + square_multiply(&mut y, 123 + 3, &_101); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 4, &_1001); + square_multiply(&mut y, 4, &_1101); + square_multiply(&mut y, 3, &_111); + square_multiply(&mut y, 1 + 3, &_101); + square_multiply(&mut y, 3 + 3, &_101); + square_multiply(&mut y, 3, &_111); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 2 + 3, &_111); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1011); + square_multiply(&mut y, 2 + 4, &_1011); + square_multiply(&mut y, 6 + 4, &_1001); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 3 + 2, &_11); + square_multiply(&mut y, 3 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1001); + square_multiply(&mut y, 1 + 3, &_111); + square_multiply(&mut y, 2 + 4, &_1111); + square_multiply(&mut y, 1 + 4, &_1011); + square_multiply(&mut y, 3, &_101); + square_multiply(&mut y, 2 + 4, &_1111); + square_multiply(&mut y, 3, &_101); + square_multiply(&mut y, 1 + 2, &_11); + y } From 028140bb334a1d49b0acee05fea8fe4f42bc210f Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 4 Sep 2017 09:19:58 -1000 Subject: [PATCH 2/3] Reformat addition chain window building code to better show pattern. Make the 2 digit, `_10`, the first argument to more closely match the Haskell code in the source article. Align the code into columns to further clarify the patterns. --- src/scalar.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 5490a21..8cf4c95 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -571,17 +571,17 @@ impl UnpackedScalar { // https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion // as it was published on 2017-09-03. - let _1 = *self; - let _10 = _1.square(); - let _11 = UnpackedScalar::multiply_add(&_10, &_1, &UnpackedScalar::zero()); - let _101 = UnpackedScalar::multiply_add(&_11, &_10, &UnpackedScalar::zero()); - let _111 = UnpackedScalar::multiply_add(&_101, &_10, &UnpackedScalar::zero()); - let _1001 = UnpackedScalar::multiply_add(&_111, &_10, &UnpackedScalar::zero()); - let _1011 = UnpackedScalar::multiply_add(&_1001, &_10, &UnpackedScalar::zero()); - let _1101 = UnpackedScalar::multiply_add(&_1011, &_10, &UnpackedScalar::zero()); - let _1111 = UnpackedScalar::multiply_add(&_1101, &_10, &UnpackedScalar::zero()); + let _1 = *self; + let _10 = _1.square(); + let _11 = UnpackedScalar::multiply_add(&_10, &_1, &UnpackedScalar::zero()); + let _101 = UnpackedScalar::multiply_add(&_10, &_11, &UnpackedScalar::zero()); + let _111 = UnpackedScalar::multiply_add(&_10, &_101, &UnpackedScalar::zero()); + let _1001 = UnpackedScalar::multiply_add(&_10, &_111, &UnpackedScalar::zero()); + let _1011 = UnpackedScalar::multiply_add(&_10, &_1001, &UnpackedScalar::zero()); + let _1101 = UnpackedScalar::multiply_add(&_10, &_1011, &UnpackedScalar::zero()); + let _1111 = UnpackedScalar::multiply_add(&_10, &_1101, &UnpackedScalar::zero()); - // 0b10000 + // _10000 let mut y = UnpackedScalar::multiply_add(&_1111, &_1, &UnpackedScalar::zero()); #[inline] From 7ed9eb8617c5de3b7af533f19c871bc7d6e4c930 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 4 Sep 2017 09:34:04 -1000 Subject: [PATCH 3/3] Replace one multiplication with a squaring in scalar inversion. This brings the code up to date with the 2017-09-04 version of the source article. --- src/scalar.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 8cf4c95..00124c1 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -573,13 +573,13 @@ impl UnpackedScalar { let _1 = *self; let _10 = _1.square(); - let _11 = UnpackedScalar::multiply_add(&_10, &_1, &UnpackedScalar::zero()); - let _101 = UnpackedScalar::multiply_add(&_10, &_11, &UnpackedScalar::zero()); - let _111 = UnpackedScalar::multiply_add(&_10, &_101, &UnpackedScalar::zero()); - let _1001 = UnpackedScalar::multiply_add(&_10, &_111, &UnpackedScalar::zero()); - let _1011 = UnpackedScalar::multiply_add(&_10, &_1001, &UnpackedScalar::zero()); - let _1101 = UnpackedScalar::multiply_add(&_10, &_1011, &UnpackedScalar::zero()); - let _1111 = UnpackedScalar::multiply_add(&_10, &_1101, &UnpackedScalar::zero()); + let _100 = _10.square(); + let _11 = UnpackedScalar::multiply_add(&_10, &_1, &UnpackedScalar::zero()); + let _101 = UnpackedScalar::multiply_add(&_10, &_11, &UnpackedScalar::zero()); + let _111 = UnpackedScalar::multiply_add(&_10, &_101, &UnpackedScalar::zero()); + let _1001 = UnpackedScalar::multiply_add(&_10, &_111, &UnpackedScalar::zero()); + let _1011 = UnpackedScalar::multiply_add(&_10, &_1001, &UnpackedScalar::zero()); + let _1111 = UnpackedScalar::multiply_add(&_100, &_1011, &UnpackedScalar::zero()); // _10000 let mut y = UnpackedScalar::multiply_add(&_1111, &_1, &UnpackedScalar::zero()); @@ -597,8 +597,8 @@ impl UnpackedScalar { square_multiply(&mut y, 1 + 4, &_1111); square_multiply(&mut y, 1 + 4, &_1111); square_multiply(&mut y, 4, &_1001); - square_multiply(&mut y, 4, &_1101); - square_multiply(&mut y, 3, &_111); + square_multiply(&mut y, 2, &_11); + square_multiply(&mut y, 1 + 4, &_1111); square_multiply(&mut y, 1 + 3, &_101); square_multiply(&mut y, 3 + 3, &_101); square_multiply(&mut y, 3, &_111);