From fa849e014c0497ea4651473e80bf089c87468e32 Mon Sep 17 00:00:00 2001 From: root <287494524@qq.com> Date: Mon, 2 Sep 2019 11:26:11 +0800 Subject: [PATCH 01/45] errata for vpmuludq --- docs/avx2-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/avx2-notes.md b/docs/avx2-notes.md index 87992b3..ccb5022 100644 --- a/docs/avx2-notes.md +++ b/docs/avx2-notes.md @@ -12,7 +12,7 @@ representation (which uses radix \\(2^{51}\\)) amounts to regrouping digits. The field element representation is oriented around the AVX2 -`vpmuluqdq` instruction, which multiplies the low 32 bits of each +`vpmuludq` instruction, which multiplies the low 32 bits of each 64-bit lane of each operand to produce a 64-bit result. ```text,no_run From f6015c66c2493e0d50acf945430d9bf7accbbc83 Mon Sep 17 00:00:00 2001 From: root <287494524@qq.com> Date: Tue, 3 Sep 2019 10:38:23 +0800 Subject: [PATCH 02/45] errata for comment --- src/backend/vector/avx2/edwards.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 675797d..274dc62 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -153,7 +153,7 @@ impl ExtendedPoint { // Set tmp1 = ( S_9, S_6, S_6, S_9) // b < ( 1.6, 1.6, 1.6, 1.6) tmp1 = tmp0.shuffle(Shuffle::DBBD); - // Set tmp1 = ( S_8, S_5, S_8, S_5) + // Set tmp0 = ( S_8, S_5, S_8, S_5) // b < (2.33, 1.01, 2.33, 1.01) tmp0 = tmp0.shuffle(Shuffle::CACA); From 8da05f7e90b59b6dea6f72c4d4cad238647b1b60 Mon Sep 17 00:00:00 2001 From: root <287494524@qq.com> Date: Wed, 4 Sep 2019 12:38:02 +0800 Subject: [PATCH 03/45] errata and basepoint_odd_lookup_table test for better understanding --- docs/parallel-formulas.md | 2 +- src/backend/vector/avx2/edwards.rs | 22 +++++++++++++++++++++- src/backend/vector/avx2/mod.rs | 2 +- src/backend/vector/mod.rs | 2 +- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/parallel-formulas.md b/docs/parallel-formulas.md index 22f59cd..7f1e1c1 100644 --- a/docs/parallel-formulas.md +++ b/docs/parallel-formulas.md @@ -327,7 +327,7 @@ There are several directions for future improvement: [sandy2x]: https://eprint.iacr.org/2015/943.pdf [avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28 [hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf -[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/curve_models/index.html +[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html [bbjlp08]: https://eprint.iacr.org/2008/013 [cmo98]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf [intel]: https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 274dc62..7e7ad7a 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -47,6 +47,7 @@ use traits::Identity; use super::constants; use super::field::{FieldElement2625x4, Lanes, Shuffle}; +use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; /// A point on Curve25519, using parallel Edwards formulas for curve /// operations. @@ -188,7 +189,7 @@ impl From for CachedPoint { let mut x = P.0; x = x.blend(x.diff_sum(), Lanes::AB); - // x = (X1 - Y1, X2 + Y2, Z2, T2) = (S2 S3 Z2 T2) + // x = (Y2 - X2, Y2 + X2, Z2, T2) = (S2 S3 Z2 T2) x = x * (121666, 121666, 2 * 121666, 2 * 121665); // x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2) @@ -521,4 +522,23 @@ mod test { let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); doubling_test_helper(P); } + + #[test] + fn basepoint_odd_lookup_table_verify() { + use constants; + + let basepoint_odd_table = NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); + println!("basepoint_odd_lookup_table = {:?}", basepoint_odd_table); + + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + for (b_vec, base_vec) in table_B.0.iter().zip(basepoint_odd_table.0.iter()) { + let b_splits = b_vec.0.split(); + let base_splits = base_vec.0.split(); + + assert_eq!(base_splits[0], b_splits[0]); + assert_eq!(base_splits[1], b_splits[1]); + assert_eq!(base_splits[2], b_splits[2]); + assert_eq!(base_splits[3], b_splits[3]); + } + } } diff --git a/src/backend/vector/avx2/mod.rs b/src/backend/vector/avx2/mod.rs index 0b30085..a1a21eb 100644 --- a/src/backend/vector/avx2/mod.rs +++ b/src/backend/vector/avx2/mod.rs @@ -19,7 +19,7 @@ // missing). #![cfg_attr( all(feature = "nightly", feature = "stage2_build"), - doc(include = "../docs/avx2-notes.md") + doc(include = "../../../../docs/avx2-notes.md") )] pub(crate) mod field; diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 76d36ab..95b5446 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -19,7 +19,7 @@ // missing). #![cfg_attr( all(feature = "nightly", feature = "stage2_build"), - doc(include = "../docs/parallel-formulas.md") + doc(include = "../../../docs/parallel-formulas.md") )] #[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma", rustdoc)))] From 2d0c5323cbabc9a09473013411beec5da7aedcbe Mon Sep 17 00:00:00 2001 From: root <287494524@qq.com> Date: Wed, 4 Sep 2019 13:15:09 +0800 Subject: [PATCH 04/45] errata and basepoint_odd_lookup_table test for better understanding --- src/backend/vector/avx2/edwards.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 7e7ad7a..b2a3ba9 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -47,7 +47,6 @@ use traits::Identity; use super::constants; use super::field::{FieldElement2625x4, Lanes, Shuffle}; -use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; /// A point on Curve25519, using parallel Edwards formulas for curve /// operations. @@ -526,6 +525,7 @@ mod test { #[test] fn basepoint_odd_lookup_table_verify() { use constants; + use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; let basepoint_odd_table = NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); println!("basepoint_odd_lookup_table = {:?}", basepoint_odd_table); From 7e2aed394364f88541d482e0de9f560e0c1a016d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 10 Dec 2019 20:33:53 +0000 Subject: [PATCH 05/45] Fix typo of Pippenger's name. --- src/edwards.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edwards.rs b/src/edwards.rs index d72ec28..1a7d18b 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -758,7 +758,7 @@ impl EdwardsPoint { pub struct EdwardsBasepointTable(pub(crate) [LookupTable; 32]); impl EdwardsBasepointTable { - /// The computation uses Pippeneger's algorithm, as described on + /// The computation uses Pippenger's algorithm, as described on /// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with /// coefficients in \\([-8,8)\\), i.e., /// $$ From 4f29935c2cfb7825ac177a515030321f8e0b0339 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Dec 2019 02:21:48 +0000 Subject: [PATCH 06/45] Create macro for generating different sized LookupTables. --- src/window.rs | 67 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/src/window.rs b/src/window.rs index 3b01422..4afe63e 100644 --- a/src/window.rs +++ b/src/window.rs @@ -27,6 +27,9 @@ use backend::serial::curve_models::AffineNielsPoint; use zeroize::Zeroize; +macro_rules! impl_lookup_table { + (Name = $name:ident, Size = $size:expr, SizeNeg = $neg:expr, SizeRange = $range:expr, ConversionRange = $conv_range:expr) => { + /// A lookup table of precomputed multiples of a point \\(P\\), used to /// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\). /// @@ -37,19 +40,17 @@ use zeroize::Zeroize; /// only `pub(crate)` so that we can write hardcoded constants, so it's /// still technically possible. It would be nice to prevent direct /// access to the table. -/// -/// XXX make this generic with respect to table size #[derive(Copy, Clone)] -pub struct LookupTable(pub(crate) [T; 8]); +pub struct $name(pub(crate) [T; $size]); -impl LookupTable +impl $name where T: Identity + ConditionallySelectable + ConditionallyNegatable, { /// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time. pub fn select(&self, x: i8) -> T { - debug_assert!(x >= -8); - debug_assert!(x <= 8); + debug_assert!(x >= $neg); + debug_assert!(x as i16 <= $size as i16); // XXX We have to convert to i16s here for the radix-256 case.. this is wrong. // Compute xabs = |x| let xmask = x >> 7; @@ -57,9 +58,9 @@ where // Set t = 0 * P = identity let mut t = T::identity(); - for j in 1..9 { + for j in $range { // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. - let c = (xabs as u8).ct_eq(&(j as u8)); + let c = (xabs as u16).ct_eq(&(j as u16)); t.conditional_assign(&self.0[j - 1], c); } // Now t == |x| * P. @@ -72,48 +73,68 @@ where } } -impl Default for LookupTable { - fn default() -> LookupTable { - LookupTable([T::default(); 8]) +impl Default for $name { + fn default() -> $name { + $name([T::default(); $size]) } } -impl Debug for LookupTable { +impl Debug for $name { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "LookupTable({:?})", self.0) + write!(f, "{:?}(", stringify!($name))?; + + for x in self.0.iter() { + write!(f, "{:?}", x)?; + } + + write!(f, ")") } } -impl<'a> From<&'a EdwardsPoint> for LookupTable { +impl<'a> From<&'a EdwardsPoint> for $name { fn from(P: &'a EdwardsPoint) -> Self { - let mut points = [P.to_projective_niels(); 8]; - for j in 0..7 { + let mut points = [P.to_projective_niels(); $size]; + for j in $conv_range { points[j + 1] = (P + &points[j]).to_extended().to_projective_niels(); } - LookupTable(points) + $name(points) } } -impl<'a> From<&'a EdwardsPoint> for LookupTable { +impl<'a> From<&'a EdwardsPoint> for $name { fn from(P: &'a EdwardsPoint) -> Self { - let mut points = [P.to_affine_niels(); 8]; + let mut points = [P.to_affine_niels(); $size]; // XXX batch inversion would be good if perf mattered here - for j in 0..7 { + for j in $conv_range { points[j + 1] = (P + &points[j]).to_extended().to_affine_niels() } - LookupTable(points) + $name(points) } } -impl Zeroize for LookupTable +impl Zeroize for $name where T: Copy + Default + Zeroize { fn zeroize(&mut self) { - self.0.zeroize(); + for x in self.0.iter_mut() { + x.zeroize(); + } } } +}} // End macro_rules! impl_lookup_table + +// The first one has to be named "LookupTable" because it's used as a constructor for consts. +impl_lookup_table! {Name = LookupTable, Size = 8, SizeNeg = -8, SizeRange = 1 .. 9, ConversionRange = 0 .. 7} // radix-16 +impl_lookup_table! {Name = LookupTableRadix32, Size = 16, SizeNeg = -16, SizeRange = 1 .. 17, ConversionRange = 0 .. 15} // radix-32 +impl_lookup_table! {Name = LookupTableRadix64, Size = 32, SizeNeg = -32, SizeRange = 1 .. 33, ConversionRange = 0 .. 31} // radix-64 +impl_lookup_table! {Name = LookupTableRadix128, Size = 64, SizeNeg = -64, SizeRange = 1 .. 65, ConversionRange = 0 .. 63} // radix-128 +impl_lookup_table! {Name = LookupTableRadix256, Size = 128, SizeNeg = -128, SizeRange = 1 .. 129, ConversionRange = 0 .. 127} // radix-256 + +// For homogeneity we then alias it to "LookupTableRadix16". +pub type LookupTableRadix16 = LookupTable; + /// Holds odd multiples 1A, 3A, ..., 15A of a point A. #[derive(Copy, Clone)] pub(crate) struct NafLookupTable5(pub(crate) [T; 8]); From 383e65f6bd5df67079d40cd42e154fcb1c67216c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Dec 2019 12:54:52 +0000 Subject: [PATCH 07/45] Add a trait for implementing a basepoint table. --- src/traits.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/traits.rs b/src/traits.rs index b024c88..7fa269c 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -47,6 +47,21 @@ where } } +/// A precomputed table of basepoints, for optimising scalar multiplications. +pub trait BasepointTable { + /// The type of point contained within this table. + type Point; + + /// Generate a new precomputed basepoint table from the given basepoint. + fn create(basepoint: &Self::Point) -> Self; + + /// Retrieve the original basepoint from this table. + fn basepoint(&self) -> Self::Point; + + /// Multiply a `scalar` by this precomputed basepoint table, in constant time. + fn basepoint_mul(&self, scalar: &Scalar) -> Self::Point; +} + /// A trait for constant-time multiscalar multiplication without precomputation. pub trait MultiscalarMul { /// The type of point being multiplied, e.g., `RistrettoPoint`. From 8a9e09ba34943002b64b81970b110e9e75fc5466 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Dec 2019 21:32:30 +0000 Subject: [PATCH 08/45] Implement larger sizes of basepoint tables. This implements a macro for implementing the BasepointTable trait, and uses the macro to create basepoint table types. The default table still uses radix-16 representation and is ~30KB in size. The new table types, and their memory usage and additions required per basepoint multiplication are: * `EdwardsBasepointTableRadix64`: ~120KB, 43 additions * `EdwardsBasepointTableRadix128`: ~240KB, 37 additions * `EdwardsBasepointTableRadix256`: ~480KB, 32 additions --- src/edwards.rs | 195 +++++++++++++++++++++++++++++++++-------------- src/ristretto.rs | 1 + src/scalar.rs | 15 ++-- 3 files changed, 149 insertions(+), 62 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 998af8d..40b2b5e 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -117,11 +117,15 @@ use backend::serial::curve_models::CompletedPoint; use backend::serial::curve_models::ProjectiveNielsPoint; use backend::serial::curve_models::ProjectivePoint; -use window::LookupTable; +use window::LookupTableRadix16; +use window::LookupTableRadix64; +use window::LookupTableRadix128; +use window::LookupTableRadix256; #[allow(unused_imports)] use prelude::*; +use traits::BasepointTable; use traits::ValidityCheck; use traits::{Identity, IsIdentity}; @@ -743,56 +747,116 @@ impl EdwardsPoint { } } +macro_rules! impl_basepoint_table { + (Name = $name:ident, LookupTable = $table:ident, Point = $point:ty, Radix = $radix:expr, Additions = $adds:expr) => { + /// A precomputed table of multiples of a basepoint, for accelerating /// fixed-base scalar multiplication. One table, for the Ed25519 /// basepoint, is provided in the `constants` module. /// -/// The basepoint tables are reasonably large (30KB), so they should -/// probably be boxed. +/// The basepoint tables are reasonably large, so they should probably be boxed. +/// +/// The sizes for the tables and the number of additions required for one scalar +/// multiplication are as follows: +/// +/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A +/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`]) +/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A +/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A +/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A +/// +/// # Why 33 additions for radix-256? +/// +/// Normally, the radix-256 tables would allow for only 32 additions per scalar +/// multiplication. However, due to the fact that standardised definitions of +/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar +/// invariants, when converting such an unreduced scalar's representation to +/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last +/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of +/// the radix, is \\(w < 8\\), we can fold the final carry onto the last +/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so +/// $$ +/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8} +/// $$ +/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we +/// add the carry bit onto an additional coefficient. #[derive(Clone)] -pub struct EdwardsBasepointTable(pub(crate) [LookupTable; 32]); +pub struct $name(pub(crate) [$table; 32]); -impl EdwardsBasepointTable { - /// The computation uses Pippeneger's algorithm, as described on - /// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with - /// coefficients in \\([-8,8)\\), i.e., +impl BasepointTable for $name { + type Point = $point; + + /// Create a table of precomputed multiples of `basepoint`. + fn create(basepoint: &$point) -> $name { + // XXX use init_with + let mut table = $name([$table::default(); 32]); + let mut P = *basepoint; + for i in 0..32 { + // P = (2w)^i * B + table.0[i] = $table::from(&P); + P = P.mul_by_pow_2($radix + $radix); + } + table + } + + /// Get the basepoint for this table as an `EdwardsPoint`. + fn basepoint(&self) -> $point { + // self.0[0].select(1) = 1*(16^2)^0*B + // but as an `AffineNielsPoint`, so add identity to convert to extended. + (&<$point>::identity() + &self.0[0].select(1)).to_extended() + } + + /// The computation uses Pippeneger's algorithm, as described for the + /// specific case of radix-16 on page 13 of the Ed25519 paper. + /// + /// # Piggenger's Algorithm Generalised + /// + /// Write the scalar \\(a\\) in radix-\\(w\\), where \\(w\\) is a power of + /// 2, with coefficients in \\([\frac{-w}{2},\frac{w}{2})\\), i.e., /// $$ - /// a = a\_0 + a\_1 16\^1 + \cdots + a\_{63} 16\^{63}, + /// a = a\_0 + a\_1 w\^1 + \cdots + a\_{x} w\^{x}, /// $$ - /// with \\(-8 \leq a_i < 8\\), \\(-8 \leq a\_{63} \leq 8\\). Then + /// with /// $$ - /// a B = a\_0 B + a\_1 16\^1 B + \cdots + a\_{63} 16\^{63} B. + /// \frac{-w}{2} \leq a_i < \frac{w}{2}, \cdots, \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2} + /// $$ + /// and the number of additions, \\(x\\), is given by \\(x = \lceil \frac{256}{w} \rceil\\). + /// Then + /// $$ + /// a B = a\_0 B + a\_1 w\^1 B + \cdots + a\_{x-1} w\^{x-1} B. /// $$ /// Grouping even and odd coefficients gives /// $$ /// \begin{aligned} - /// a B = \quad a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B \\\\ - /// + a\_1 16\^1 B +& a\_3 16\^3 B + \cdots + a\_{63} 16\^{63} B \\\\ - /// = \quad(a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B) \\\\ - /// + 16(a\_1 16\^0 B +& a\_3 16\^2 B + \cdots + a\_{63} 16\^{62} B). \\\\ + /// a B = \quad a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B \\\\ + /// + a\_1 w\^1 B +& a\_3 w\^3 B + \cdots + a\_{x-1} w\^{x-1} B \\\\ + /// = \quad(a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B) \\\\ + /// + w(a\_1 w\^0 B +& a\_3 w\^2 B + \cdots + a\_{x-1} w\^{x-2} B). \\\\ /// \end{aligned} /// $$ /// For each \\(i = 0 \ldots 31\\), we create a lookup table of /// $$ - /// [16\^{2i} B, \ldots, 8\cdot16\^{2i} B], + /// [w\^{2i} B, \ldots, \frac{w}{2}\cdotw\^{2i} B], /// $$ - /// and use it to select \\( x \cdot 16\^{2i} \cdot B \\) in constant time. + /// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time. /// - /// The radix-\\(16\\) representation requires that the scalar is bounded + /// The radix-\\(w\\) representation requires that the scalar is bounded /// by \\(2\^{255}\\), which is always the case. - fn basepoint_mul(&self, scalar: &Scalar) -> EdwardsPoint { - let a = scalar.to_radix_16(); + /// + /// The above algorithm is trivially generalised to other powers-of-2 radices. + fn basepoint_mul(&self, scalar: &Scalar) -> $point { + let a = scalar.to_radix_2w($radix); let tables = &self.0; - let mut P = EdwardsPoint::identity(); + let mut P = <$point>::identity(); - for i in (0..64).filter(|x| x % 2 == 1) { + for i in (0..$adds).filter(|x| x % 2 == 1) { P = (&P + &tables[i/2].select(a[i])).to_extended(); } - P = P.mul_by_pow_2(4); + P = P.mul_by_pow_2($radix); - for i in (0..64).filter(|x| x % 2 == 0) { + for i in (0..$adds).filter(|x| x % 2 == 0) { P = (&P + &tables[i/2].select(a[i])).to_extended(); } @@ -800,49 +864,53 @@ impl EdwardsBasepointTable { } } -impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { - type Output = EdwardsPoint; +impl<'a, 'b> Mul<&'b Scalar> for &'a $name { + type Output = $point; /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by /// computing the multiple \\(aB\\) of this basepoint \\(B\\). - fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { + fn mul(self, scalar: &'b Scalar) -> $point { // delegate to a private function so that its documentation appears in internal docs self.basepoint_mul(scalar) } } -impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar { - type Output = EdwardsPoint; +impl<'a, 'b> Mul<&'a $name> for &'b Scalar { + type Output = $point; /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by /// computing the multiple \\(aB\\) of this basepoint \\(B\\). - fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> EdwardsPoint { + fn mul(self, basepoint_table: &'a $name) -> $point { basepoint_table * self } } -impl EdwardsBasepointTable { - /// Create a table of precomputed multiples of `basepoint`. - pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable { - // XXX use init_with - let mut table = EdwardsBasepointTable([LookupTable::default(); 32]); - let mut P = *basepoint; +impl Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{:?}([\n", stringify!($name))?; for i in 0..32 { - // P = (16^2)^i * B - table.0[i] = LookupTable::from(&P); - P = P.mul_by_pow_2(8); + write!(f, "\t{:?},\n", &self.0[i])?; } - table - } - - /// Get the basepoint for this table as an `EdwardsPoint`. - pub fn basepoint(&self) -> EdwardsPoint { - // self.0[0].select(1) = 1*(16^2)^0*B - // but as an `AffineNielsPoint`, so add identity to convert to extended. - (&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended() + write!(f, "])") } } +}} // End macro_rules! impl_basepoint_table + +// The number of additions required is ceil(256/w) where w is the radix representation. +impl_basepoint_table! {Name = EdwardsBasepointTable, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix64, LookupTable = LookupTableRadix64, Point = EdwardsPoint, Radix = 6, Additions = 43} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = LookupTableRadix128, Point = EdwardsPoint, Radix = 7, Additions = 37} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33} + +/// A type-alias for [`EdwardsBasepointTable`] because the latter is +/// used as a constructor in the `constants` module. +// +// Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable` +// first, because it's used as a constructor, and then provide a type alias for +// it. +pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable; + impl EdwardsPoint { /// Multiply by the cofactor: return \\([8]P\\). pub fn mul_by_cofactor(&self) -> EdwardsPoint { @@ -930,16 +998,6 @@ impl Debug for EdwardsPoint { } } -impl Debug for EdwardsBasepointTable { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "EdwardsBasepointTable([\n")?; - for i in 0..32 { - write!(f, "\t{:?},\n", &self.0[i])?; - } - write!(f, "])") - } -} - // ------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------ @@ -1148,6 +1206,29 @@ mod test { assert_eq!(bp2.compress(), BASE2_CMPRSSD); } + /// Test that all the basepoint table types compute the same results. + #[test] + fn basepoint_tables() { + let P = &constants::ED25519_BASEPOINT_POINT; + let a = A_SCALAR; + + let table_radix16 = EdwardsBasepointTableRadix16::create(&P); + let table_radix64 = EdwardsBasepointTableRadix64::create(&P); + let table_radix128 = EdwardsBasepointTableRadix128::create(&P); + let table_radix256 = EdwardsBasepointTableRadix256::create(&P); + + let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let aP16 = (&table_radix16 * &a).compress(); + let aP64 = (&table_radix64 * &a).compress(); + let aP128 = (&table_radix128 * &a).compress(); + let aP256 = (&table_radix256 * &a).compress(); + + assert_eq!(aP, aP16); + assert_eq!(aP16, aP64); + assert_eq!(aP64, aP128); + assert_eq!(aP128, aP256); + } + /// Check that converting to projective and then back to extended round-trips. #[test] fn basepoint_projective_extended_round_trip() { diff --git a/src/ristretto.rs b/src/ristretto.rs index c4b6170..380df18 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -185,6 +185,7 @@ use prelude::*; use scalar::Scalar; +use traits::BasepointTable; use traits::Identity; #[cfg(any(feature = "alloc", feature = "std"))] use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; diff --git a/src/scalar.rs b/src/scalar.rs index d365d25..3e70367 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -989,10 +989,11 @@ impl Scalar { /// Returns a size hint indicating how many entries of the return /// value of `to_radix_2w` are nonzero. pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { - debug_assert!(w >= 6); + debug_assert!(w == 4 || w >= 6); debug_assert!(w <= 8); let digits_count = match w { + 4 => (256 + w - 1)/w as usize, 6 => (256 + w - 1)/w as usize, 7 => (256 + w - 1)/w as usize, // See comment in to_radix_2w on handling the terminal carry. @@ -1000,7 +1001,7 @@ impl Scalar { _ => panic!("invalid radix parameter"), }; - debug_assert!(digits_count <= 43); + debug_assert!(digits_count <= 64); digits_count } @@ -1022,10 +1023,14 @@ impl Scalar { /// $$ /// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\). /// - pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 43] { - debug_assert!(w >= 6); + pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 64] { + debug_assert!(w == 4 || w >= 6); debug_assert!(w <= 8); + if w == 4 { + return self.to_radix_16(); + } + use byteorder::{ByteOrder, LittleEndian}; // Scalar formatted as four `u64`s with carry bit packed into the highest bit. @@ -1036,7 +1041,7 @@ impl Scalar { let window_mask: u64 = radix - 1; let mut carry = 0u64; - let mut digits = [0i8; 43]; + let mut digits = [0i8; 64]; let digits_count = (256 + w - 1)/w as usize; for i in 0..digits_count { // Construct a buffer of bits of the scalar, starting at `bit_offset`. From cfbcb6ca6167f2f90ffdd34394050e48715d1dd5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 30 Dec 2019 22:05:01 +0000 Subject: [PATCH 09/45] Implement conversions between basepoint table sizes. This is useful for programs/protocol which can do some heuristics or learning-based approach towards optimising the table size based on the number of uses of e.g. a public key, the second basepoint in a Pedersen commitment, etc., i.e. the first time a public key is used to verify a signature, the usual variable-time basepoint multiscalar multiplication is used, however after 1000 verifications, the table size is upgraded, and again after 10000 verifications, etc. --- src/edwards.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/edwards.rs b/src/edwards.rs index 40b2b5e..b64e4a3 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -911,6 +911,29 @@ impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = Looku // it. pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable; +macro_rules! impl_basepoint_table_conversions { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl<'a> From<&'a $lhs> for $rhs { + fn from(table: &'a $lhs) -> $rhs { + <$rhs>::create(&table.basepoint()) + } + } + + impl<'a> From<&'a $rhs> for $lhs { + fn from(table: &'a $rhs) -> $lhs { + <$lhs>::create(&table.basepoint()) + } + } + } +} + +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix64} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix128} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix256} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix128} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix256} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} + impl EdwardsPoint { /// Multiply by the cofactor: return \\([8]P\\). pub fn mul_by_cofactor(&self) -> EdwardsPoint { From c01bd780dca04602f2d3fc18d8cb1aacb1daf1f6 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 31 Dec 2019 00:12:20 +0000 Subject: [PATCH 10/45] Implement radix-32 precomputed scalar multiplication tables. --- src/edwards.rs | 14 +++++++++++++- src/scalar.rs | 8 ++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index b64e4a3..3f21e96 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -118,6 +118,7 @@ use backend::serial::curve_models::ProjectiveNielsPoint; use backend::serial::curve_models::ProjectivePoint; use window::LookupTableRadix16; +use window::LookupTableRadix32; use window::LookupTableRadix64; use window::LookupTableRadix128; use window::LookupTableRadix256; @@ -899,6 +900,7 @@ impl Debug for $name { // The number of additions required is ceil(256/w) where w is the radix representation. impl_basepoint_table! {Name = EdwardsBasepointTable, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix32, LookupTable = LookupTableRadix32, Point = EdwardsPoint, Radix = 5, Additions = 52} impl_basepoint_table! {Name = EdwardsBasepointTableRadix64, LookupTable = LookupTableRadix64, Point = EdwardsPoint, Radix = 6, Additions = 43} impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = LookupTableRadix128, Point = EdwardsPoint, Radix = 7, Additions = 37} impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33} @@ -927,11 +929,18 @@ macro_rules! impl_basepoint_table_conversions { } } +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix32} impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix64} impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix128} impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix256} + +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix64} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix128} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix256} + impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix128} impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix256} + impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} impl EdwardsPoint { @@ -1236,18 +1245,21 @@ mod test { let a = A_SCALAR; let table_radix16 = EdwardsBasepointTableRadix16::create(&P); + let table_radix32 = EdwardsBasepointTableRadix32::create(&P); let table_radix64 = EdwardsBasepointTableRadix64::create(&P); let table_radix128 = EdwardsBasepointTableRadix128::create(&P); let table_radix256 = EdwardsBasepointTableRadix256::create(&P); let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); let aP16 = (&table_radix16 * &a).compress(); + let aP32 = (&table_radix32 * &a).compress(); let aP64 = (&table_radix64 * &a).compress(); let aP128 = (&table_radix128 * &a).compress(); let aP256 = (&table_radix256 * &a).compress(); assert_eq!(aP, aP16); - assert_eq!(aP16, aP64); + assert_eq!(aP16, aP32); + assert_eq!(aP32, aP64); assert_eq!(aP64, aP128); assert_eq!(aP128, aP256); } diff --git a/src/scalar.rs b/src/scalar.rs index 3e70367..21b801c 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -994,6 +994,7 @@ impl Scalar { let digits_count = match w { 4 => (256 + w - 1)/w as usize, + 5 => (256 + w - 1)/w as usize, 6 => (256 + w - 1)/w as usize, 7 => (256 + w - 1)/w as usize, // See comment in to_radix_2w on handling the terminal carry. @@ -1005,14 +1006,13 @@ impl Scalar { digits_count } - /// Creates a representation of a Scalar in radix 64, 128 or 256 for use with the Pippenger algorithm. + /// Creates a representation of a Scalar in radix 32, 64, 128 or 256 for use with the Pippenger algorithm. /// For lower radix, use `to_radix_16`, which is used by the Straus multi-scalar multiplication. /// Higher radixes are not supported to save cache space. Radix 256 is near-optimal even for very /// large inputs. /// - /// Radix below 64 or above 256 is prohibited. + /// Radix below 32 or above 256 is prohibited. /// This method returns digits in a fixed-sized array, excess digits are zeroes. - /// The second returned value is the number of digits. /// /// ## Scalar representation /// @@ -1024,7 +1024,7 @@ impl Scalar { /// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\). /// pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 64] { - debug_assert!(w == 4 || w >= 6); + debug_assert!(w >= 4); debug_assert!(w <= 8); if w == 4 { From ca1f730790957c2ea938951def365895136d020d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 3 Jan 2020 23:56:30 +0000 Subject: [PATCH 11/45] Fix debug_assert! range in Scalar::to_radix_2w_size_hint(). --- src/scalar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scalar.rs b/src/scalar.rs index 21b801c..13a5ea6 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -989,7 +989,7 @@ impl Scalar { /// Returns a size hint indicating how many entries of the return /// value of `to_radix_2w` are nonzero. pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { - debug_assert!(w == 4 || w >= 6); + debug_assert!(w >= 4); debug_assert!(w <= 8); let digits_count = match w { From 1f8a19a7539217485613d9396a84dcc755f753b9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 7 Jan 2020 08:04:45 +0000 Subject: [PATCH 12/45] Fix an attempted overflow on absolute value computation for radix-256 tables. Found by the fuzzer in 4f5d2d4. --- src/window.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/window.rs b/src/window.rs index 4afe63e..adedac9 100644 --- a/src/window.rs +++ b/src/window.rs @@ -53,8 +53,8 @@ where debug_assert!(x as i16 <= $size as i16); // XXX We have to convert to i16s here for the radix-256 case.. this is wrong. // Compute xabs = |x| - let xmask = x >> 7; - let xabs = (x + xmask) ^ xmask; + let xmask = x as i16 >> 7; + let xabs = (x as i16 + xmask) ^ xmask; // Set t = 0 * P = identity let mut t = T::identity(); From e82910d215aeb4ba90d689f3253dac4f5a2e2d91 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 7 Jan 2020 08:06:27 +0000 Subject: [PATCH 13/45] Add test for basepoint table multiplication by unreduced scalar. --- src/edwards.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/edwards.rs b/src/edwards.rs index 3f21e96..09eaa56 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -1264,6 +1264,37 @@ mod test { assert_eq!(aP128, aP256); } + // Check a unreduced scalar multiplication by the basepoint tables. + #[test] + fn basepoint_tables_unreduced_scalar() { + let P = &constants::ED25519_BASEPOINT_POINT; + let a = Scalar::from_bits([ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ]); + + let table_radix16 = EdwardsBasepointTableRadix16::create(&P); + let table_radix32 = EdwardsBasepointTableRadix32::create(&P); + let table_radix64 = EdwardsBasepointTableRadix64::create(&P); + let table_radix128 = EdwardsBasepointTableRadix128::create(&P); + let table_radix256 = EdwardsBasepointTableRadix256::create(&P); + + let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let aP16 = (&table_radix16 * &a).compress(); + let aP32 = (&table_radix32 * &a).compress(); + let aP64 = (&table_radix64 * &a).compress(); + let aP128 = (&table_radix128 * &a).compress(); + let aP256 = (&table_radix256 * &a).compress(); + + assert_eq!(aP, aP16); + assert_eq!(aP16, aP32); + assert_eq!(aP32, aP64); + assert_eq!(aP64, aP128); + assert_eq!(aP128, aP256); + } + /// Check that converting to projective and then back to extended round-trips. #[test] fn basepoint_projective_extended_round_trip() { From c9fe6c5533b4a476c0d0e3846ebc2277ffe36f23 Mon Sep 17 00:00:00 2001 From: gedigi <19227040+gedigi@users.noreply.github.com> Date: Thu, 19 Mar 2020 14:16:06 -0700 Subject: [PATCH 14/45] implemented Zeroize for CompressedRistretto and RistrettoPoint --- src/ristretto.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/ristretto.rs b/src/ristretto.rs index c4b6170..0e8f742 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -200,6 +200,8 @@ use backend::serial::scalar_mul; ))] use backend::vector::scalar_mul; +use zeroize::Zeroize; + // ------------------------------------------------------------------------ // Compressed points // ------------------------------------------------------------------------ @@ -1078,6 +1080,25 @@ impl Debug for RistrettoPoint { } } +// ------------------------------------------------------------------------ +// Zeroize traits +// ------------------------------------------------------------------------ + +impl Zeroize for CompressedRistretto { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl Zeroize for RistrettoPoint { + fn zeroize(&mut self) { + self.0.X.zeroize(); + self.0.Y.zeroize(); + self.0.Z.zeroize(); + self.0.T.zeroize(); + } +} + // ------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------ From 6afd8ff212694669973043e4277f0938cebff24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 15 Jun 2020 07:14:45 -0400 Subject: [PATCH 15/45] Update sha2, digest to 0.9 --- Cargo.toml | 4 ++-- src/ristretto.rs | 4 ++-- src/scalar.rs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d73a932..d4fa2f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ features = ["nightly", "simd_backend"] travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"} [dev-dependencies] -sha2 = { version = "0.8", default-features = false } +sha2 = { version = "0.9", default-features = false } bincode = "1" criterion = "0.3.0" rand = "0.7" @@ -42,7 +42,7 @@ harness = false [dependencies] rand_core = { version = "0.5", default-features = false } byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] } -digest = { version = "0.8", default-features = false } +digest = { version = "0.9", default-features = false } subtle = { version = "^2.2.1", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } packed_simd = { version = "0.3", features = ["into_bits"], optional = true } diff --git a/src/ristretto.rs b/src/ristretto.rs index 977f52f..93d310f 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -689,7 +689,7 @@ impl RistrettoPoint { where D: Digest + Default { let mut hash = D::default(); - hash.input(input); + hash.update(input); RistrettoPoint::from_hash(hash) } @@ -702,7 +702,7 @@ impl RistrettoPoint { where D: Digest + Default { // dealing with generic arrays is clumsy, until const generics land - let output = hash.result(); + let output = hash.finalize(); let mut output_bytes = [0u8; 64]; output_bytes.copy_from_slice(&output.as_slice()); diff --git a/src/scalar.rs b/src/scalar.rs index 87f5da9..6ead65a 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -102,8 +102,8 @@ //! //! // Streaming data into a hash object //! let mut hasher = Sha512::default(); -//! hasher.input(b"Abolish "); -//! hasher.input(b"ICE"); +//! hasher.update(b"Abolish "); +//! hasher.update(b"ICE"); //! let a2 = Scalar::from_hash(hasher); //! //! assert_eq!(a, a2); @@ -588,7 +588,7 @@ impl Scalar { where D: Digest + Default { let mut hash = D::default(); - hash.input(input); + hash.update(input); Scalar::from_hash(hash) } @@ -630,7 +630,7 @@ impl Scalar { where D: Digest { let mut output = [0u8; 64]; - output.copy_from_slice(hash.result().as_slice()); + output.copy_from_slice(hash.finalize().as_slice()); Scalar::from_bytes_mod_order_wide(&output) } From 91a0faea35ee20f3b92470f88416ee6d4ccb15d9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 18 Aug 2020 00:44:47 +0000 Subject: [PATCH 16/45] Move CoC section from CONTRIBUTING.md to new file. This helps Github's UI show that we have one and autolink to it. --- CODE_OF_CONDUCT.md | 8 ++++++++ CONTRIBUTING.md | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a802fde --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,8 @@ +# Code of Conduct + +We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html), +with the following additional clauses: + +* We respect the rights to privacy and anonymity for contributors and people in + the community. If someone wishes to contribute under a pseudonym different to + their primary identity, that wish is to be respected by all contributors. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 86622d4..d4e0ff8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,12 +17,3 @@ ask @isislovecruft or @hdevalence. Some issues are easier than others. The `easy` label can be used to find the easy issues. If you want to work on an issue, please leave a comment so that we can assign it to you! - -# Code of Conduct - -We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html), -with the following additional clauses: - -* We respect the rights to privacy and anonymity for contributors and people in - the community. If someone wishes to contribute under a pseudonym different to - their primary identity, that wish is to be respected by all contributors. From 6d96eb7796d706a4f42394e14c87fe7db7a1b289 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 17 Aug 2020 18:20:26 -0700 Subject: [PATCH 17/45] Bump version to 3.0.0. --- CHANGELOG.md | 12 ++++++++++++ Cargo.toml | 2 +- README.md | 5 ++++- src/lib.rs | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84de2c..9e63ebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Entries are listed in reverse chronological order. +## 3.0.0 + +* Update the `digest` dependency to `0.9`. This requires a major version + because the `digest` traits are part of the public API, but there are + otherwise no changes to the API. + ## 2.1.0 * Make `Scalar::from_bits` a `const fn`, allowing its use in `const` contexts. @@ -25,6 +31,12 @@ Entries are listed in reverse chronological order. The only significant change is the data model change to the `serde` feature; besides the `rand_core` version bump, there are no other user-visible changes. +## 1.2.4 + +* Specify a semver bound for `clear_on_drop` rather than an exact version, + addressing an issue where changes to inline assembly in rustc prevented + `clear_on_drop` from working without an update. + ## 1.2.3 * Fix an issue identified by a Quarkslab audit (and Jack Grigg), where manually diff --git a/Cargo.toml b/Cargo.toml index d4fa2f0..c65b819 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update html_root_url # - update README if required by semver -version = "2.1.0" +version = "3.0.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/README.md b/README.md index e3363f5..0f35b5a 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,12 @@ make doc-internal To import `curve25519-dalek`, add the following to the dependencies section of your project's `Cargo.toml`: ```toml -curve25519-dalek = "2" +curve25519-dalek = "3" ``` +The `3.x` series has API almost entirely unchanged from the `2.x` series, +except that the `digest` version was updated. + The `2.x` series has API almost entirely unchanged from the `1.x` series, except that: diff --git a/src/lib.rs b/src/lib.rs index e1409a2..3d68c58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/2.1.0")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.0.0")] //! Note that docs will only build on nightly Rust until //! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732). From c2e394dd045e27ea4f26585d1b57e9b780aee6b8 Mon Sep 17 00:00:00 2001 From: Markus Zoppelt Date: Wed, 30 Sep 2020 12:59:10 +0200 Subject: [PATCH 18/45] bumped packed_simd to 0.3.4. resolves #333 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c65b819..7e1a524 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] digest = { version = "0.9", default-features = false } subtle = { version = "^2.2.1", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } -packed_simd = { version = "0.3", features = ["into_bits"], optional = true } +packed_simd = { package = "packed_simd_2", version = "*", git = "https://github.com/rust-lang/packed_simd", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } [features] From f27923bf8c1cf696063f92aee06217c3fd861ea1 Mon Sep 17 00:00:00 2001 From: Markus Zoppelt Date: Wed, 30 Sep 2020 15:17:18 +0200 Subject: [PATCH 19/45] adjusted dependency entry like to pick up latest pick up the latest packed_simd crate under an alternative name. see also: https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7e1a524..27d902a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] digest = { version = "0.9", default-features = false } subtle = { version = "^2.2.1", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } -packed_simd = { package = "packed_simd_2", version = "*", git = "https://github.com/rust-lang/packed_simd", features = ["into_bits"], optional = true } +packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } [features] From 45f3f53351102ba8c7a8b062b4306fe93b7d169a Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 30 Sep 2020 12:01:43 -0700 Subject: [PATCH 20/45] Add link to Cargo.toml with explanation of packed_simd renaming --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 27d902a..8420f4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,8 @@ byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] digest = { version = "0.9", default-features = false } subtle = { version = "^2.2.1", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } +# The original packed_simd package was orphaned, see +# https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } From 608f8cd594433e26179fafd587a3b0138b4afcdb Mon Sep 17 00:00:00 2001 From: Stephane Raux Date: Tue, 20 Oct 2020 17:54:06 -0700 Subject: [PATCH 21/45] Make crate feature alloc work with stable Rust `println!` was removed in the test as the corresponding test for `u32` does not have it. --- src/backend/serial/u64/scalar.rs | 1 - src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index 97069ad..cee69da 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -443,7 +443,6 @@ mod test { fn from_bytes_wide() { let bignum = [255u8; 64]; // 2^512 - 1 let reduced = Scalar52::from_bytes_wide(&bignum); - println!("{:?}", reduced); for i in 0..5 { assert!(reduced[i] == C[i]); } diff --git a/src/lib.rs b/src/lib.rs index 3d68c58..179e70a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![cfg_attr(feature = "nightly", feature(test))] -#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] #![cfg_attr(feature = "nightly", feature(external_doc))] #![cfg_attr(feature = "nightly", feature(doc_cfg))] #![cfg_attr(feature = "simd_backend", feature(stdsimd))] From 8aa1458941b77290cc9bbfb91880494a8d5172db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Wed, 21 Oct 2020 11:02:06 -0400 Subject: [PATCH 22/45] Implements an Elligator2 map for Curve25519 This implementation: - is agnostic on the hash used to pick a field element, even though SHA512 is commonly used, - follows https://tools.ietf.org/id/draft-irtf-cfrg-hash-to-curve-10.html closely - tests the outputs of the function using libsignal's implementation. --- Cargo.toml | 1 + src/backend/serial/u32/constants.rs | 4 ++ src/backend/serial/u64/constants.rs | 3 + src/edwards.rs | 87 +++++++++++++++++++++++++++++ src/montgomery.rs | 61 ++++++++++++++++++-- 5 files changed, 152 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8420f4d..6e5e44c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "mast sha2 = { version = "0.9", default-features = false } bincode = "1" criterion = "0.3.0" +hex = "0.4.2" rand = "0.7" [[bench]] diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 73f353f..49eb1b0 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -63,6 +63,10 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625([ pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); +/// `MONT_A` is a constant of Curve25519. (This is used internally within the Elligator map.) +pub(crate) const MONT_A: FieldElement2625 = + FieldElement2625([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// `L` is the order of base point, i.e. 2^252 + /// 27742317777372353535851937790883648493 pub(crate) const L: Scalar29 = Scalar29([ diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index fc8c6da..9d0c547 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -91,6 +91,9 @@ pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([ /// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = FieldElement51([121666, 0, 0, 0, 0]); +/// `MONT_A` is a constant of Curve25519. (This is used internally within the Elligator map.) +pub(crate) const MONT_A: FieldElement51 = FieldElement51([486662, 0, 0, 0, 0]); + /// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493 pub(crate) const L: Scalar52 = Scalar52([ 0x0002631a5cf5d3ed, diff --git a/src/edwards.rs b/src/edwards.rs index 1524dbd..61c3d91 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -100,6 +100,7 @@ use core::ops::{Add, Neg, Sub}; use core::ops::{AddAssign, SubAssign}; use core::ops::{Mul, MulAssign}; +use digest::{generic_array::typenum::U64, Digest}; use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -493,6 +494,31 @@ impl EdwardsPoint { s[31] ^= x.is_negative().unwrap_u8() << 7; CompressedEdwardsY(s) } + + /// Perform hashing to the group using the Elligator2 map + /// + /// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 + pub fn hash_from_bytes(bytes: &[u8]) -> EdwardsPoint + where + D: Digest + Default, + { + let mut hash = D::new(); + hash.update(bytes); + let h = hash.finalize(); + let mut res = [0u8; 32]; + res.copy_from_slice(&h[..32]); + + let sign_bit = (res[31] & 0x80) >> 7; + + let fe = FieldElement::from_bytes(&res); + + let M1 = crate::montgomery::elligator_map(&fe); + let E1_opt = M1.to_edwards(sign_bit); + + E1_opt + .expect("Montgomery conversion to Edwards point in Elligator failed") + .mul_by_cofactor() + } } // ------------------------------------------------------------------------ @@ -1432,4 +1458,65 @@ mod test { let bp: EdwardsPoint = bincode::deserialize(raw_bytes).unwrap(); assert_eq!(bp, constants::ED25519_BASEPOINT_POINT); } + + //////////////////////////////////////////////////////////// + // Signal tests from // + // https://github.com/signalapp/libsignal-protocol-c/ // + //////////////////////////////////////////////////////////// + + fn test_vectors() -> Vec> { + vec![ + vec![ + "214f306e1576f5a7577636fe303ca2c625b533319f52442b22a9fa3b7ede809f", + "c95becf0f93595174633b9d4d6bbbeb88e16fa257176f877ce426e1424626052", + ], + vec![ + "2eb10d432702ea7f79207da95d206f82d5a3b374f5f89f17a199531f78d3bea6", + "d8f8b508edffbb8b6dab0f602f86a9dd759f800fe18f782fdcac47c234883e7f", + ], + vec![ + "84cbe9accdd32b46f4a8ef51c85fd39d028711f77fb00e204a613fc235fd68b9", + "93c73e0289afd1d1fc9e4e78a505d5d1b2642fbdf91a1eff7d281930654b1453", + ], + vec![ + "c85165952490dc1839cb69012a3d9f2cc4b02343613263ab93a26dc89fd58267", + "43cbe8685fd3c90665b91835debb89ff1477f906f5170f38a192f6a199556537", + ], + vec![ + "26e7fc4a78d863b1a4ccb2ce0951fbcd021e106350730ee4157bacb4502e1b76", + "b6fc3d738c2c40719479b2f23818180cdafa72a14254d4016bbed8f0b788a835", + ], + vec![ + "1618c08ef0233f94f0f163f9435ec7457cd7a8cd4bb6b160315d15818c30f7a2", + "da0b703593b29dbcd28ebd6e7baea17b6f61971f3641cae774f6a5137a12294c", + ], + vec![ + "48b73039db6fcdcb6030c4a38e8be80b6390d8ae46890e77e623f87254ef149c", + "ca11b25acbc80566603eabeb9364ebd50e0306424c61049e1ce9385d9f349966", + ], + vec![ + "a744d582b3a34d14d311b7629da06d003045ae77cebceeb4e0e72734d63bd07d", + "fad25a5ea15d4541258af8785acaf697a886c1b872c793790e60a6837b1adbc0", + ], + vec![ + "80a6ff33494c471c5eff7efb9febfbcf30a946fe6535b3451cda79f2154a7095", + "57ac03913309b3f8cd3c3d4c49d878bb21f4d97dc74a1eaccbe5c601f7f06f47", + ], + vec![ + "f06fc939bc10551a0fd415aebf107ef0b9c4ee1ef9a164157bdd089127782617", + "785b2a6a00a5579cc9da1ff997ce8339b6f9fb46c6f10cf7a12ff2986341a6e0", + ], + ] + } + + #[test] + fn elligator_signal_test_vectors() { + for vector in test_vectors().iter() { + let input = hex::decode(vector[0]).unwrap(); + let output = hex::decode(vector[1]).unwrap(); + + let point = EdwardsPoint::hash_from_bytes::(&input); + assert_eq!(point.compress().to_bytes(), output[..]); + } + } } diff --git a/src/montgomery.rs b/src/montgomery.rs index c3676c2..3400ca9 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -50,7 +50,7 @@ use core::ops::{Mul, MulAssign}; -use constants::APLUS2_OVER_FOUR; +use constants::{APLUS2_OVER_FOUR, MONT_A}; use edwards::{CompressedEdwardsY, EdwardsPoint}; use field::FieldElement; use scalar::Scalar; @@ -58,8 +58,8 @@ use scalar::Scalar; use traits::Identity; use subtle::Choice; -use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; +use subtle::{ConditionallyNegatable, ConditionallySelectable}; use zeroize::Zeroize; @@ -156,6 +156,33 @@ impl MontgomeryPoint { } } +/// Perform the Elligator2 mapping to a Montgomery point +/// +/// See +/// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 +pub(crate) fn elligator_map(r_0: &FieldElement) -> MontgomeryPoint { + let minus_a = -&MONT_A; /* A = 486662 */ + let one = FieldElement::one(); + let d_1 = &one + &r_0.square2(); /* 2r^2 */ + + let d = &minus_a * &(d_1.invert()); /* A/(1+2r^2) */ + + let d_sq = &d.square(); + let au = &MONT_A * &d; + + let inner = &(d_sq + &au) + &one; + let eps = &d * &inner; /* eps = d^3 + Ad^2 + d */ + + let (eps_is_sq, _eps) = FieldElement::sqrt_ratio_i(&eps, &one); + + let zero = FieldElement::zero(); + let Atemp = FieldElement::conditional_select(&MONT_A, &zero, eps_is_sq); /* 0, or A if nonsquare*/ + let mut u = &d + &Atemp; /* d, or d+A if nonsquare */ + u.conditional_negate(!eps_is_sq); /* d, or -d-A if nonsquare */ + + MontgomeryPoint(u.to_bytes()) +} + /// A `ProjectivePoint` holds a point on the projective line /// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer /// line of the Montgomery curve. @@ -315,8 +342,9 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar { #[cfg(test)] mod test { - use constants; use super::*; + use constants; + use core::convert::TryInto; use rand_core::OsRng; @@ -396,8 +424,33 @@ mod test { let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); let expected = s * p_edwards; - let result = s * p_montgomery; + let result = s * p_montgomery; assert_eq!(result, expected.to_montgomery()) } + + const ELLIGATOR_CORRECT_OUTPUT: [u8; 32] = [ + 0x5f, 0x35, 0x20, 0x00, 0x1c, 0x6c, 0x99, 0x36, 0xa3, 0x12, 0x06, 0xaf, 0xe7, 0xc7, 0xac, + 0x22, 0x4e, 0x88, 0x61, 0x61, 0x9b, 0xf9, 0x88, 0x72, 0x44, 0x49, 0x15, 0x89, 0x9d, 0x95, + 0xf4, 0x6e, + ]; + + #[test] + #[cfg(feature = "std")] // Vec + fn montgomery_elligator_correct() { + let bytes: std::vec::Vec = (0u8..32u8).collect(); + let bits_in: [u8; 32] = (&bytes[..]).try_into().expect("Range invariant broken"); + + let fe = FieldElement::from_bytes(&bits_in); + let eg = elligator_map(&fe); + assert_eq!(eg.to_bytes(), ELLIGATOR_CORRECT_OUTPUT); + } + + #[test] + fn montgomery_elligator_zero_zero() { + let zero = [0u8; 32]; + let fe = FieldElement::from_bytes(&zero); + let eg = elligator_map(&fe); + assert_eq!(eg.to_bytes(), zero); + } } From e47a1809918be52718f6acb482ee6dd55a9e96eb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 7 Jan 2021 21:29:17 +0000 Subject: [PATCH 23/45] Bump curve25519-dalek to 3.0.1. --- CHANGELOG.md | 5 +++++ Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e63ebe..15de61e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Entries are listed in reverse chronological order. +## 3.0.1 + +* Update the optional `packed-simd` dependency to rely on a newer, + maintained version of the `packed-simd-2` crate. + ## 3.0.0 * Update the `digest` dependency to `0.9`. This requires a major version diff --git a/Cargo.toml b/Cargo.toml index 8420f4d..b58f3f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update html_root_url # - update README if required by semver -version = "3.0.0" +version = "3.0.1" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" From 64099e9adfb2a8749910bd7fdc98aada112b7f91 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 7 Jan 2021 21:31:57 +0000 Subject: [PATCH 24/45] Fix CHANGELOG so that we can note backported patches. --- CHANGELOG.md | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15de61e..f97d7e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,28 @@ # Changelog -Entries are listed in reverse chronological order. +Entries are listed in reverse chronological order per undeprecated +major series. -## 3.0.1 +## 3.x series + +### 3.0.1 * Update the optional `packed-simd` dependency to rely on a newer, maintained version of the `packed-simd-2` crate. -## 3.0.0 +### 3.0.0 * Update the `digest` dependency to `0.9`. This requires a major version because the `digest` traits are part of the public API, but there are otherwise no changes to the API. -## 2.1.0 +## 2.x series + +### 2.1.0 * Make `Scalar::from_bits` a `const fn`, allowing its use in `const` contexts. -## 2.0.0 +### 2.0.0 * Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin which caused points and scalars to be serialized with length fields rather @@ -36,13 +41,15 @@ Entries are listed in reverse chronological order. The only significant change is the data model change to the `serde` feature; besides the `rand_core` version bump, there are no other user-visible changes. -## 1.2.4 +## 1.x series + +### 1.2.4 * Specify a semver bound for `clear_on_drop` rather than an exact version, addressing an issue where changes to inline assembly in rustc prevented `clear_on_drop` from working without an update. -## 1.2.3 +### 1.2.3 * Fix an issue identified by a Quarkslab audit (and Jack Grigg), where manually constructing unreduced `Scalar` values, as needed for X/Ed25519, and then @@ -56,14 +63,14 @@ besides the `rand_core` version bump, there are no other user-visible changes. * Fix compilation on nightly broken due to changes to the `#[doc(include)]` path root (not quite correctly done in 1.2.2). -## 1.2.2 +### 1.2.2 * Fix a typo in an internal doc-comment. * Add the "crypto" tag to crate metadata. * Fix compilation on nightly broken due to changes to the `#[doc(include)]` path root. -## 1.2.1 +### 1.2.1 * Fix a bug in bucket index calculations in the Pippenger multiscalar algorithm for very large input sizes. @@ -72,7 +79,7 @@ besides the `rand_core` version bump, there are no other user-visible changes. * Ensure that that multiscalar and NAF computations work correctly on extremal `Scalar` values constructed via `from_bits`. -## 1.2.0 +### 1.2.0 * New multiscalar multiplication algorithm with better performance for large problem sizes. The backend algorithm is selected @@ -81,16 +88,16 @@ besides the `rand_core` version bump, there are no other user-visible changes. * Equality of Edwards points is now checked in projective coordinates. * Serde can now be used with `no_std`. -## 1.1.4 +### 1.1.4 * Fix typos in documentation comments. * Remove unnecessary `Default` bound on `Scalar::from_hash`. -## 1.1.3 +### 1.1.3 * Reverts the change in 1.1.0 to allow owned and borrowed RNGs, which caused a breakage due to a subtle interaction with ownership rules. (The `RngCore` change is retained). -## 1.1.2 +### 1.1.2 * Disabled KaTeX on `docs.rs` pending proper [support upstream](https://github.com/rust-lang/docs.rs/issues/302). @@ -98,7 +105,7 @@ besides the `rand_core` version bump, there are no other user-visible changes. * Fixed an issue related to `#[cfg(rustdoc)]` which prevented documenting multiple backends. -## 1.1.0 +### 1.1.0 * Adds support for precomputation for multiscalar multiplication. * Restructures the internal source tree into `serial` and `vector` backends (no change to external API). @@ -107,19 +114,19 @@ besides the `rand_core` version bump, there are no other user-visible changes. * Replaces the `rand` dependency with `rand_core`. * Generalizes trait bounds on `RistrettoPoint::random()` and `Scalar::random()` to allow owned and borrowed RNGs and to allow `RngCore` instead of `Rng`. -## 1.0.3 +### 1.0.3 * Adds `ConstantTimeEq` implementation for compressed points. -## 1.0.2 +### 1.0.2 * Fixes a typo in the naming of variables in Ristretto formulas (no change to functionality). -## 1.0.1 +### 1.0.1 * Depends on the stable `2.0` version of `subtle` instead of `2.0.0-pre.0`. -## 1.0.0 +### 1.0.0 Initial stable release. Yanked due to a dependency mistake (see above). From 7e320cd1d95bd9a1ea3c370e917ce0efcde63740 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 7 Jan 2021 21:33:06 +0000 Subject: [PATCH 25/45] Remove deprecated feature flags from .travis.yml. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc5f2dc..4b61db3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ env: - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u32_backend' # Tests the u64 backend - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' - # Tests the avx2 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std avx2_backend' + # Tests the simd backend + - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' # Tests serde support and default feature selection - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' # Tests building without std. We have to select a backend, so we select the one @@ -21,9 +21,9 @@ env: matrix: exclude: - # Test the avx2 backend only on nightly + # Test the simd backend only on nightly - rust: stable - env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std avx2_backend' + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' # Test no_std+alloc only on nightly - rust: stable env: TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' From 77ec9742120c7d2fec7003b992ab346fc6660c49 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 8 Jan 2021 00:33:37 +0000 Subject: [PATCH 26/45] Whitespace fixes for 3267a5d merge. --- docs/parallel-formulas.md | 2 +- src/backend/vector/avx2/edwards.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/parallel-formulas.md b/docs/parallel-formulas.md index 7f1e1c1..f84d1cc 100644 --- a/docs/parallel-formulas.md +++ b/docs/parallel-formulas.md @@ -327,7 +327,7 @@ There are several directions for future improvement: [sandy2x]: https://eprint.iacr.org/2015/943.pdf [avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28 [hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf -[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html +[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html [bbjlp08]: https://eprint.iacr.org/2008/013 [cmo98]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf [intel]: https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index b25a557..77af176 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -526,8 +526,8 @@ mod test { fn basepoint_odd_lookup_table_verify() { use constants; use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; - - let basepoint_odd_table = NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); + + let basepoint_odd_table = NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); println!("basepoint_odd_lookup_table = {:?}", basepoint_odd_table); let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; From 55e0db7cf625b54d67a503b485d19abd85738cf2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 8 Jan 2021 03:32:42 +0000 Subject: [PATCH 27/45] Bump curve25519-dalek version to 3.0.2. --- CHANGELOG.md | 22 ++++++++++++++++++++++ Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f97d7e1..90ac99b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ major series. ## 3.x series +### 3.0.2 + +* Fixes to make using alloc+no_std possible for stable Rust. + ### 3.0.1 * Update the optional `packed-simd` dependency to rely on a newer, @@ -18,6 +22,15 @@ major series. ## 2.x series +### 2.1.2 + +* Fixes to make using alloc+no_std possible for stable Rust. + +### 2.1.1 + +* Update the optional `packed-simd` dependency to rely on a newer, + maintained version of the `packed-simd-2` crate. + ### 2.1.0 * Make `Scalar::from_bits` a `const fn`, allowing its use in `const` contexts. @@ -43,6 +56,15 @@ besides the `rand_core` version bump, there are no other user-visible changes. ## 1.x series +### 1.2.6 + +* Fixes to make using alloc+no_std possible for stable Rust. + +### 1.2.5 + +* Update the optional `packed-simd` dependency to rely on a newer, + maintained version of the `packed-simd-2` crate. + ### 1.2.4 * Specify a semver bound for `clear_on_drop` rather than an exact version, diff --git a/Cargo.toml b/Cargo.toml index b58f3f8..3426071 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update html_root_url # - update README if required by semver -version = "3.0.1" +version = "3.0.2" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/src/lib.rs b/src/lib.rs index 179e70a..912b62a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.0.0")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.0.2")] //! Note that docs will only build on nightly Rust until //! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732). From d684e13f092a337779679d90560770857939d94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 27 Aug 2019 15:52:55 -0700 Subject: [PATCH 28/45] Add a fiat_u64_backend option to curve25519-dalek This uses https://github.com/calibra/rust-curve25519-fiat/ to implement a new 64bit serial backend for dalek. Co-authored-by: Zoe Parakevopoulou --- Cargo.toml | 3 + src/backend/mod.rs | 3 +- src/backend/serial/fiat/field.rs | 243 ++++++++++++++++++++++++++++ src/backend/serial/fiat/mod.rs | 28 ++++ src/backend/serial/mod.rs | 11 +- src/backend/serial/u64/constants.rs | 10 +- src/constants.rs | 6 +- src/field.rs | 10 ++ src/lib.rs | 4 +- src/scalar.rs | 7 + 10 files changed, 314 insertions(+), 11 deletions(-) create mode 100644 src/backend/serial/fiat/field.rs create mode 100644 src/backend/serial/fiat/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 3426071..0ceb29d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } +curve25519-fiat = { git="https://github.com/calibra/rust-curve25519-fiat.git", version = "0.1.0", optional = true} [features] nightly = ["subtle/nightly"] @@ -60,6 +61,8 @@ alloc = ["zeroize/alloc"] u32_backend = [] # The u64 backend uses u64s with u128 products. u64_backend = [] +# The fiat-u64 backend uses u64s with u128 products. +fiat_u64_backend = ["curve25519-fiat"] # The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. simd_backend = ["nightly", "u64_backend", "packed_simd"] # DEPRECATED: this is now an alias for `simd_backend` and may be removed diff --git a/src/backend/mod.rs b/src/backend/mod.rs index f761eaa..9c07816 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -36,11 +36,12 @@ #[cfg(not(any( feature = "u32_backend", feature = "u64_backend", + feature = "fiat_u64_backend", feature = "simd_backend", )))] compile_error!( "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend, simd_backend" + please enable one of: u32_backend, u64_backend, fiat_u64_backend, simd_backend" ); pub mod serial; diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat/field.rs new file mode 100644 index 0000000..a2f1a90 --- /dev/null +++ b/src/backend/serial/fiat/field.rs @@ -0,0 +1,243 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit +//! limbs with \\(128\\)-bit products. + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +use curve25519_fiat::curve25519_64::*; + +/// A `FieldElement51` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 64-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to +/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement51` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement51(pub(crate) [u64; 5]); + +impl Debug for FieldElement51 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement51({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement51 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 { + fn add_assign(&mut self, _rhs: &'b FieldElement51) { + let input = self.0; + fiat_25519_add(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + fiat_25519_add(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> SubAssign<&'b FieldElement51> for FieldElement51 { + fn sub_assign(&mut self, _rhs: &'b FieldElement51) { + let input = self.0; + fiat_25519_sub(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Sub<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn sub(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + fiat_25519_sub(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 { + fn mul_assign(&mut self, _rhs: &'b FieldElement51) { + let input = self.0; + fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0); + } +} + +impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0); + output + } +} + +impl<'a> Neg for &'a FieldElement51 { + type Output = FieldElement51; + fn neg(self) -> FieldElement51 { + let mut output = *self; + fiat_25519_opp(&mut output.0, &self.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl ConditionallySelectable for FieldElement51 { + fn conditional_select( + a: &FieldElement51, + b: &FieldElement51, + choice: Choice, + ) -> FieldElement51 { + let mut output = [0u64; 5]; + fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0); + FieldElement51(output) + } + + fn conditional_swap(a: &mut FieldElement51, b: &mut FieldElement51, choice: Choice) { + u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + } + + fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: Choice) { + self.0[0].conditional_assign(&_rhs.0[0], choice); + self.0[1].conditional_assign(&_rhs.0[1], choice); + self.0[2].conditional_assign(&_rhs.0[2], choice); + self.0[3].conditional_assign(&_rhs.0[3], choice); + self.0[4].conditional_assign(&_rhs.0[4], choice); + } +} + +impl FieldElement51 { + /// Construct zero. + pub fn zero() -> FieldElement51 { + FieldElement51([0, 0, 0, 0, 0]) + } + + /// Construct one. + pub fn one() -> FieldElement51 { + FieldElement51([1, 0, 0, 0, 0]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement51 { + FieldElement51([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]) + } + + /// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon). + #[inline(always)] + #[allow(dead_code)] // Need this to not complain about reduce not being used + fn reduce(mut limbs: [u64; 5]) -> FieldElement51 { + let input = limbs; + fiat_25519_carry(&mut limbs, &input); + FieldElement51(limbs) + } + + /// Load a `FieldElement51` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + /// + pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 { + let mut temp = [0u8; 32]; + temp.copy_from_slice(bytes); + temp[31] &= 127u8; + let mut output = [0u64; 5]; + fiat_25519_from_bytes(&mut output, &temp); + FieldElement51(output) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + let mut bytes = [0u8; 32]; + fiat_25519_to_bytes(&mut bytes, &self.0); + return bytes; + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, mut k: u32) -> FieldElement51 { + let mut output = *self; + loop { + let input = output.0; + fiat_25519_carry_square(&mut output.0, &input); + k -= 1; + if k == 0 { + return output; + } + } + } + + /// Returns the square of this field element. + pub fn square(&self) -> FieldElement51 { + let mut output = *self; + fiat_25519_carry_square(&mut output.0, &self.0); + output + } + + /// Returns 2 times the square of this field element. + pub fn square2(&self) -> FieldElement51 { + let mut output = *self; + let mut temp = *self; + // Void vs return type, measure cost of copying self + fiat_25519_carry_square(&mut temp.0, &self.0); + fiat_25519_add(&mut output.0, &temp.0, &temp.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} diff --git a/src/backend/serial/fiat/mod.rs b/src/backend/serial/fiat/mod.rs new file mode 100644 index 0000000..8c83062 --- /dev/null +++ b/src/backend/serial/fiat/mod.rs @@ -0,0 +1,28 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier. +//! +//! On x86_64, the idiom `(x as u128) * (y as u128)` lowers to `MUL` +//! instructions taking 64-bit inputs and producing 128-bit outputs. On +//! other platforms, this implementation is not recommended. +//! +//! On Haswell and newer, the BMI2 extension provides `MULX`, and on +//! Broadwell and newer, the ADX extension provides `ADCX` and `ADOX` +//! (allowing the CPU to compute two carry chains in parallel). These +//! will be used if available. + +#[path = "../u64/scalar.rs"] +pub mod scalar; + +pub mod field; + +#[path = "../u64/constants.rs"] +pub mod constants; diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index fc6b320..a4a03dd 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -22,10 +22,14 @@ //! Note: at this time the `u32` and `u64` backends cannot be built //! together. -#[cfg(not(any(feature = "u32_backend", feature = "u64_backend")))] +#[cfg(not(any( + feature = "u32_backend", + feature = "u64_backend", + feature = "fiat_u64_backend" +)))] compile_error!( "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend" + please enable one of: u32_backend, u64_backend, fiat_u64_backend" ); #[cfg(feature = "u32_backend")] @@ -34,6 +38,9 @@ pub mod u32; #[cfg(feature = "u64_backend")] pub mod u64; +#[cfg(feature = "fiat_u64_backend")] +pub mod fiat; + pub mod curve_models; #[cfg(not(all( diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index fc8c6da..0b2d50a 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -10,9 +10,9 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. +use super::field::FieldElement51; +use super::scalar::Scalar52; use backend::serial::curve_models::AffineNielsPoint; -use backend::serial::u64::field::FieldElement51; -use backend::serial::u64::scalar::Scalar52; use edwards::{EdwardsBasepointTable, EdwardsPoint}; use window::{LookupTable, NafLookupTable8}; @@ -22,7 +22,7 @@ pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ 2251799813685247, 2251799813685247, 2251799813685247, - 2251799813685247 + 2251799813685247, ]); /// Edwards `d` value, equal to `-121665/121666 mod p`. @@ -49,7 +49,7 @@ pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([ 1998550399581263, 496427632559748, 118527312129759, - 45110755273534 + 45110755273534, ]); /// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` @@ -58,7 +58,7 @@ pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([ 1572317787530805, 683053064812840, 317374165784489, - 1572899562415810 + 1572899562415810, ]); /// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. diff --git a/src/constants.rs b/src/constants.rs index e30d35e..5887c7a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -33,10 +33,12 @@ use ristretto::CompressedRistretto; use montgomery::MontgomeryPoint; use scalar::Scalar; -#[cfg(feature = "u64_backend")] -pub use backend::serial::u64::constants::*; +#[cfg(feature = "fiat_u64_backend")] +pub use backend::serial::fiat::constants::*; #[cfg(feature = "u32_backend")] pub use backend::serial::u32::constants::*; +#[cfg(feature = "u64_backend")] +pub use backend::serial::u64::constants::*; /// The Ed25519 basepoint, in `CompressedEdwardsY` format. /// diff --git a/src/field.rs b/src/field.rs index 54d048d..58127ec 100644 --- a/src/field.rs +++ b/src/field.rs @@ -32,6 +32,16 @@ use subtle::ConstantTimeEq; use constants; use backend; +#[cfg(feature = "fiat_u64_backend")] +pub use backend::serial::fiat::field::*; +/// A `FieldElement` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// The `FieldElement` type is an alias for one of the platform-specific +/// implementations. +#[cfg(feature = "fiat_u64_backend")] +pub type FieldElement = backend::serial::fiat::field::FieldElement51; + #[cfg(feature = "u64_backend")] pub use backend::serial::u64::field::*; /// A `FieldElement` represents an element of the field diff --git a/src/lib.rs b/src/lib.rs index 912b62a..3f46bd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ // This means that missing docs will still fail CI, but means we can use // README.md as the crate documentation. #![cfg_attr(feature = "nightly", deny(missing_docs))] - #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] #![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.0.2")] @@ -46,6 +45,9 @@ pub extern crate digest; extern crate rand_core; extern crate zeroize; +#[cfg(feature = "fiat_u64_backend")] +extern crate curve25519_fiat; + // Used for traits related to constant-time code. extern crate subtle; diff --git a/src/scalar.rs b/src/scalar.rs index 6ead65a..b7376ad 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -165,6 +165,13 @@ use zeroize::Zeroize; use backend; use constants; +/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. +/// +/// This is a type alias for one of the scalar types in the `backend` +/// module. +#[cfg(feature = "fiat_u64_backend")] +type UnpackedScalar = backend::serial::fiat::scalar::Scalar52; + /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. /// /// This is a type alias for one of the scalar types in the `backend` From 4ce680d3aaec5d48e62213dd1942dfd3464aaccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 17 Feb 2020 09:42:41 -0500 Subject: [PATCH 29/45] Update the fiat backend to use the fiat-crypto package https://crates.io/crates/fiat-crypto --- Cargo.toml | 4 ++-- src/backend/serial/fiat/field.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0ceb29d..124069c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } -curve25519-fiat = { git="https://github.com/calibra/rust-curve25519-fiat.git", version = "0.1.0", optional = true} +fiat-crypto = { version = "0.1.0", optional = true} [features] nightly = ["subtle/nightly"] @@ -62,7 +62,7 @@ u32_backend = [] # The u64 backend uses u64s with u128 products. u64_backend = [] # The fiat-u64 backend uses u64s with u128 products. -fiat_u64_backend = ["curve25519-fiat"] +fiat_u64_backend = ["fiat-crypto"] # The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. simd_backend = ["nightly", "u64_backend", "packed_simd"] # DEPRECATED: this is now an alias for `simd_backend` and may be removed diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat/field.rs index a2f1a90..25e3649 100644 --- a/src/backend/serial/fiat/field.rs +++ b/src/backend/serial/fiat/field.rs @@ -22,7 +22,7 @@ use subtle::ConditionallySelectable; use zeroize::Zeroize; -use curve25519_fiat::curve25519_64::*; +use fiat_crypto::curve25519_64::*; /// A `FieldElement51` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). diff --git a/src/lib.rs b/src/lib.rs index 3f46bd1..982d323 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ extern crate rand_core; extern crate zeroize; #[cfg(feature = "fiat_u64_backend")] -extern crate curve25519_fiat; +extern crate fiat_crypto; // Used for traits related to constant-time code. extern crate subtle; From a9e50eab363897a3599d774e6426c9590ea465d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 May 2020 15:04:18 -0400 Subject: [PATCH 30/45] implement conditional assign with fiat__25519_cmovznz_u64 --- src/backend/serial/fiat/field.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat/field.rs index 25e3649..dbb9fb0 100644 --- a/src/backend/serial/fiat/field.rs +++ b/src/backend/serial/fiat/field.rs @@ -141,11 +141,14 @@ impl ConditionallySelectable for FieldElement51 { } fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: Choice) { - self.0[0].conditional_assign(&_rhs.0[0], choice); - self.0[1].conditional_assign(&_rhs.0[1], choice); - self.0[2].conditional_assign(&_rhs.0[2], choice); - self.0[3].conditional_assign(&_rhs.0[3], choice); - self.0[4].conditional_assign(&_rhs.0[4], choice); + let mut output = [0u64; 5]; + let choicebit = choice.unwrap_u8() as fiat_25519_u1; + fiat_25519_cmovznz_u64(&mut output[0], choicebit, self.0[0], _rhs.0[0]); + fiat_25519_cmovznz_u64(&mut output[1], choicebit, self.0[1], _rhs.0[1]); + fiat_25519_cmovznz_u64(&mut output[2], choicebit, self.0[2], _rhs.0[2]); + fiat_25519_cmovznz_u64(&mut output[3], choicebit, self.0[3], _rhs.0[3]); + fiat_25519_cmovznz_u64(&mut output[4], choicebit, self.0[4], _rhs.0[4]); + *self = FieldElement51(output); } } From 3422872346ae88d812006dc4841e50279ba28832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 May 2020 14:41:02 -0400 Subject: [PATCH 31/45] bump fiat-crypto version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 124069c..be34e80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } -fiat-crypto = { version = "0.1.0", optional = true} +fiat-crypto = { version = "0.1.1", optional = true} [features] nightly = ["subtle/nightly"] From 756a921beefd8df3e7ec511bf36d2a2882568dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Fri, 29 May 2020 20:36:50 -0400 Subject: [PATCH 32/45] bump fiat-crypto version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index be34e80..239065c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } -fiat-crypto = { version = "0.1.1", optional = true} +fiat-crypto = { version = "0.1.5", optional = true} [features] nightly = ["subtle/nightly"] From ce2e3f6e69deddd400723866eaf8eb52e2f240b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 Jan 2021 09:32:54 -0800 Subject: [PATCH 33/45] bump fiat-crypto version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 239065c..44685e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } zeroize = { version = "1", default-features = false } -fiat-crypto = { version = "0.1.5", optional = true} +fiat-crypto = { version = "0.1.6", optional = true} [features] nightly = ["subtle/nightly"] From abd192245681d768c63f320aae9e7cbc0fe31495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 Jan 2021 13:20:55 -0800 Subject: [PATCH 34/45] Add a fiat_u32 backend based on fiat-crypto as well. Renames fiat backend directory to fiat_u64 and does the additional plumbing required to make fiat_{u32, u64}_backend equal alternatives. Adds a few comments. --- Cargo.toml | 4 +- src/backend/mod.rs | 3 +- src/backend/serial/fiat_u32/field.rs | 260 ++++++++++++++++++ src/backend/serial/fiat_u32/mod.rs | 26 ++ .../serial/{fiat => fiat_u64}/field.rs | 3 + src/backend/serial/{fiat => fiat_u64}/mod.rs | 0 src/backend/serial/mod.rs | 8 +- src/backend/serial/u32/constants.rs | 4 +- src/backend/serial/u64/constants.rs | 8 +- src/constants.rs | 8 +- src/field.rs | 9 +- src/lib.rs | 2 +- src/scalar.rs | 4 +- 13 files changed, 322 insertions(+), 17 deletions(-) create mode 100644 src/backend/serial/fiat_u32/field.rs create mode 100644 src/backend/serial/fiat_u32/mod.rs rename src/backend/serial/{fiat => fiat_u64}/field.rs (98%) rename src/backend/serial/{fiat => fiat_u64}/mod.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 44685e1..d33703f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,8 +61,10 @@ alloc = ["zeroize/alloc"] u32_backend = [] # The u64 backend uses u64s with u128 products. u64_backend = [] -# The fiat-u64 backend uses u64s with u128 products. +# fiat-u64 backend (with formally-verified field arith) uses u64s with u128 products. fiat_u64_backend = ["fiat-crypto"] +# fiat-u32 backend (with formally-verified field arith) uses u64s with u128 products. +fiat_u32_backend = ["fiat-crypto"] # The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. simd_backend = ["nightly", "u64_backend", "packed_simd"] # DEPRECATED: this is now an alias for `simd_backend` and may be removed diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 9c07816..2eef774 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -36,12 +36,13 @@ #[cfg(not(any( feature = "u32_backend", feature = "u64_backend", + feature = "fiat_u32_backend", feature = "fiat_u64_backend", feature = "simd_backend", )))] compile_error!( "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend, fiat_u64_backend, simd_backend" + please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend, simd_backend" ); pub mod serial; diff --git a/src/backend/serial/fiat_u32/field.rs b/src/backend/serial/fiat_u32/field.rs new file mode 100644 index 0000000..2864c95 --- /dev/null +++ b/src/backend/serial/fiat_u32/field.rs @@ -0,0 +1,260 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit +//! limbs with \\(64\\)-bit products. +//! +//! This code was originally derived from Adam Langley's Golang ed25519 +//! implementation, and was then rewritten to use unsigned limbs instead +//! of signed limbs. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +use fiat_crypto::curve25519_32::*; + +/// A `FieldElement2625` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 32-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{25.5}\\) as ten `u32`s. This means that a field +/// element \\(x\\) is represented as +/// $$ +/// x = \sum\_{i=0}\^9 x\_i 2\^{\lceil i \frac {51} 2 \rceil} +/// = x\_0 + x\_1 2\^{26} + x\_2 2\^{51} + x\_3 2\^{77} + \cdots + x\_9 2\^{230}; +/// $$ +/// the coefficients are alternately bounded by \\(2\^{25}\\) and +/// \\(2\^{26}\\). The limbs are allowed to grow between reductions up +/// to \\(2\^{25+b}\\) or \\(2\^{26+b}\\), where \\(b = 1.75\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement2625` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement2625(pub(crate) [u32; 10]); + +impl Debug for FieldElement2625 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement2625({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement2625 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 { + fn add_assign(&mut self, _rhs: &'b FieldElement2625) { + let input = self.0; + fiat_25519_add(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + fiat_25519_add(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 { + fn sub_assign(&mut self, _rhs: &'b FieldElement2625) { + let input = self.0; + fiat_25519_sub(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Sub<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn sub(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + fiat_25519_sub(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 { + fn mul_assign(&mut self, _rhs: &'b FieldElement2625) { + let input = self.0; + fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0); + } +} + +impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0); + output + } +} + +impl<'a> Neg for &'a FieldElement2625 { + type Output = FieldElement2625; + fn neg(self) -> FieldElement2625 { + let mut output = *self; + fiat_25519_opp(&mut output.0, &self.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl ConditionallySelectable for FieldElement2625 { + fn conditional_select( + a: &FieldElement2625, + b: &FieldElement2625, + choice: Choice, + ) -> FieldElement2625 { + let mut output = [0u32; 10]; + fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0); + FieldElement2625(output) + } + + fn conditional_assign(&mut self, other: &FieldElement2625, choice: Choice) { + let mut output = [0u32; 10]; + let choicebit = choice.unwrap_u8() as fiat_25519_u1; + fiat_25519_cmovznz_u32(&mut output[0], choicebit, self.0[0], other.0[0]); + fiat_25519_cmovznz_u32(&mut output[1], choicebit, self.0[1], other.0[1]); + fiat_25519_cmovznz_u32(&mut output[2], choicebit, self.0[2], other.0[2]); + fiat_25519_cmovznz_u32(&mut output[3], choicebit, self.0[3], other.0[3]); + fiat_25519_cmovznz_u32(&mut output[4], choicebit, self.0[4], other.0[4]); + fiat_25519_cmovznz_u32(&mut output[5], choicebit, self.0[5], other.0[5]); + fiat_25519_cmovznz_u32(&mut output[6], choicebit, self.0[6], other.0[6]); + fiat_25519_cmovznz_u32(&mut output[7], choicebit, self.0[7], other.0[7]); + fiat_25519_cmovznz_u32(&mut output[8], choicebit, self.0[8], other.0[8]); + fiat_25519_cmovznz_u32(&mut output[9], choicebit, self.0[9], other.0[9]); + *self = FieldElement2625(output); + } + + fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) { + u32::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u32::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u32::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u32::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u32::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + u32::conditional_swap(&mut a.0[5], &mut b.0[5], choice); + u32::conditional_swap(&mut a.0[6], &mut b.0[6], choice); + u32::conditional_swap(&mut a.0[7], &mut b.0[7], choice); + u32::conditional_swap(&mut a.0[8], &mut b.0[8], choice); + u32::conditional_swap(&mut a.0[9], &mut b.0[9], choice); + } +} + +impl FieldElement2625 { + /// Invert the sign of this field element + pub fn negate(&mut self) { + let neg = self.neg(); + self.0 = neg.0; + } + + /// Construct zero. + pub fn zero() -> FieldElement2625 { + FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + /// Construct one. + pub fn one() -> FieldElement2625 { + FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement2625 { + FieldElement2625([ + 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, + 0x3ffffff, 0x1ffffff, + ]) + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, k: u32) -> FieldElement2625 { + debug_assert!(k > 0); + let mut z = self.square(); + for _ in 1..k { + z = z.square(); + } + z + } + + /// Load a `FieldElement2625` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { + let mut temp = [0u8; 32]; + temp.copy_from_slice(data); + temp[31] &= 127u8; + let mut output = [0u32; 10]; + fiat_25519_from_bytes(&mut output, &temp); + FieldElement2625(output) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + let mut bytes = [0u8; 32]; + fiat_25519_to_bytes(&mut bytes, &self.0); + return bytes; + } + + /// Compute `self^2`. + pub fn square(&self) -> FieldElement2625 { + let mut output = *self; + fiat_25519_carry_square(&mut output.0, &self.0); + output + } + + /// Compute `2*self^2`. + pub fn square2(&self) -> FieldElement2625 { + let mut output = *self; + let mut temp = *self; + // Void vs return type, measure cost of copying self + fiat_25519_carry_square(&mut temp.0, &self.0); + fiat_25519_add(&mut output.0, &temp.0, &temp.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} diff --git a/src/backend/serial/fiat_u32/mod.rs b/src/backend/serial/fiat_u32/mod.rs new file mode 100644 index 0000000..974316e --- /dev/null +++ b/src/backend/serial/fiat_u32/mod.rs @@ -0,0 +1,26 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. +//! +//! This code is intended to be portable, but it requires that +//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result +//! is constant-time on the target platform. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) + +#[path = "../u32/scalar.rs"] +pub mod scalar; + +pub mod field; + +#[path = "../u32/constants.rs"] +pub mod constants; diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat_u64/field.rs similarity index 98% rename from src/backend/serial/fiat/field.rs rename to src/backend/serial/fiat_u64/field.rs index dbb9fb0..7e381b6 100644 --- a/src/backend/serial/fiat/field.rs +++ b/src/backend/serial/fiat_u64/field.rs @@ -10,6 +10,9 @@ //! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit //! limbs with \\(128\\)-bit products. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) use core::fmt::Debug; use core::ops::Neg; diff --git a/src/backend/serial/fiat/mod.rs b/src/backend/serial/fiat_u64/mod.rs similarity index 100% rename from src/backend/serial/fiat/mod.rs rename to src/backend/serial/fiat_u64/mod.rs diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index a4a03dd..a01d4a3 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -25,11 +25,12 @@ #[cfg(not(any( feature = "u32_backend", feature = "u64_backend", + feature = "fiat_u32_backend", feature = "fiat_u64_backend" )))] compile_error!( "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend, fiat_u64_backend" + please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend" ); #[cfg(feature = "u32_backend")] @@ -38,8 +39,11 @@ pub mod u32; #[cfg(feature = "u64_backend")] pub mod u64; +#[cfg(feature = "fiat_u32_backend")] +pub mod fiat_u32; + #[cfg(feature = "fiat_u64_backend")] -pub mod fiat; +pub mod fiat_u64; pub mod curve_models; diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 73f353f..7c381d4 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -13,8 +13,8 @@ //! lookup tables of pre-computed points. use backend::serial::curve_models::AffineNielsPoint; -use backend::serial::u32::field::FieldElement2625; -use backend::serial::u32::scalar::Scalar29; +use super::field::FieldElement2625; +use super::scalar::Scalar29; use edwards::{EdwardsBasepointTable, EdwardsPoint}; use window::{LookupTable, NafLookupTable8}; diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 0b2d50a..c941b20 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -10,9 +10,9 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. +use backend::serial::curve_models::AffineNielsPoint; use super::field::FieldElement51; use super::scalar::Scalar52; -use backend::serial::curve_models::AffineNielsPoint; use edwards::{EdwardsBasepointTable, EdwardsPoint}; use window::{LookupTable, NafLookupTable8}; @@ -22,7 +22,7 @@ pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ 2251799813685247, 2251799813685247, 2251799813685247, - 2251799813685247, + 2251799813685247 ]); /// Edwards `d` value, equal to `-121665/121666 mod p`. @@ -49,7 +49,7 @@ pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([ 1998550399581263, 496427632559748, 118527312129759, - 45110755273534, + 45110755273534 ]); /// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` @@ -58,7 +58,7 @@ pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([ 1572317787530805, 683053064812840, 317374165784489, - 1572899562415810, + 1572899562415810 ]); /// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. diff --git a/src/constants.rs b/src/constants.rs index 5887c7a..8831dda 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -33,12 +33,14 @@ use ristretto::CompressedRistretto; use montgomery::MontgomeryPoint; use scalar::Scalar; +#[cfg(feature = "fiat_u32_backend")] +pub use backend::serial::fiat_u32::constants::*; #[cfg(feature = "fiat_u64_backend")] -pub use backend::serial::fiat::constants::*; -#[cfg(feature = "u32_backend")] -pub use backend::serial::u32::constants::*; +pub use backend::serial::fiat_u64::constants::*; #[cfg(feature = "u64_backend")] pub use backend::serial::u64::constants::*; +#[cfg(feature = "u32_backend")] +pub use backend::serial::u32::constants::*; /// The Ed25519 basepoint, in `CompressedEdwardsY` format. /// diff --git a/src/field.rs b/src/field.rs index 58127ec..40dcf70 100644 --- a/src/field.rs +++ b/src/field.rs @@ -32,15 +32,20 @@ use subtle::ConstantTimeEq; use constants; use backend; +#[cfg(feature = "fiat_u32_backend")] +pub use backend::serial::fiat_u32::field::*; #[cfg(feature = "fiat_u64_backend")] -pub use backend::serial::fiat::field::*; +pub use backend::serial::fiat_u64::field::*; /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). /// /// The `FieldElement` type is an alias for one of the platform-specific /// implementations. +/// Using formally-verified field arithmetic from fiat-crypto +#[cfg(feature = "fiat_u32_backend")] +pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; #[cfg(feature = "fiat_u64_backend")] -pub type FieldElement = backend::serial::fiat::field::FieldElement51; +pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; #[cfg(feature = "u64_backend")] pub use backend::serial::u64::field::*; diff --git a/src/lib.rs b/src/lib.rs index 982d323..f353085 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ pub extern crate digest; extern crate rand_core; extern crate zeroize; -#[cfg(feature = "fiat_u64_backend")] +#[cfg(any(feature = "fiat_u64_backend", feature = "fiat_u32_backend"))] extern crate fiat_crypto; // Used for traits related to constant-time code. diff --git a/src/scalar.rs b/src/scalar.rs index b7376ad..b113906 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -169,8 +169,10 @@ use constants; /// /// This is a type alias for one of the scalar types in the `backend` /// module. +#[cfg(feature = "fiat_u32_backend")] +type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29; #[cfg(feature = "fiat_u64_backend")] -type UnpackedScalar = backend::serial::fiat::scalar::Scalar52; +type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52; /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. /// From e2651cceb64274d59d71e798ec18fdc6d8bf4edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 12 Jan 2021 13:46:04 -0800 Subject: [PATCH 35/45] Rename elligator_map -> elligator_encode leaves an obvious name open for the reverse mapping --- src/edwards.rs | 2 +- src/montgomery.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 61c3d91..cc62456 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -512,7 +512,7 @@ impl EdwardsPoint { let fe = FieldElement::from_bytes(&res); - let M1 = crate::montgomery::elligator_map(&fe); + let M1 = crate::montgomery::elligator_encode(&fe); let E1_opt = M1.to_edwards(sign_bit); E1_opt diff --git a/src/montgomery.rs b/src/montgomery.rs index 3400ca9..1c24ac6 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -160,7 +160,7 @@ impl MontgomeryPoint { /// /// See /// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 -pub(crate) fn elligator_map(r_0: &FieldElement) -> MontgomeryPoint { +pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint { let minus_a = -&MONT_A; /* A = 486662 */ let one = FieldElement::one(); let d_1 = &one + &r_0.square2(); /* 2r^2 */ @@ -442,7 +442,7 @@ mod test { let bits_in: [u8; 32] = (&bytes[..]).try_into().expect("Range invariant broken"); let fe = FieldElement::from_bytes(&bits_in); - let eg = elligator_map(&fe); + let eg = elligator_encode(&fe); assert_eq!(eg.to_bytes(), ELLIGATOR_CORRECT_OUTPUT); } @@ -450,7 +450,7 @@ mod test { fn montgomery_elligator_zero_zero() { let zero = [0u8; 32]; let fe = FieldElement::from_bytes(&zero); - let eg = elligator_map(&fe); + let eg = elligator_encode(&fe); assert_eq!(eg.to_bytes(), zero); } } From d1ed427af517cacf8dff8f8f950476a80c327194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 Jan 2021 13:39:48 -0800 Subject: [PATCH 36/45] add fiat backends to Travis tests --- .travis.yml | 4 ++++ Cargo.toml | 2 +- src/lib.rs | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b61db3..f2411e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,10 @@ env: - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u32_backend' # Tests the u64 backend - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' + # Tests the fiat_u32 backend + - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u32_backend' + # Tests the fiat_u64 backend + - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u64_backend' # Tests the simd backend - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' # Tests serde support and default feature selection diff --git a/Cargo.toml b/Cargo.toml index d33703f..e39b73a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ u32_backend = [] u64_backend = [] # fiat-u64 backend (with formally-verified field arith) uses u64s with u128 products. fiat_u64_backend = ["fiat-crypto"] -# fiat-u32 backend (with formally-verified field arith) uses u64s with u128 products. +# fiat-u32 backend (with formally-verified field arith) uses u32s with u64 products. fiat_u32_backend = ["fiat-crypto"] # The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. simd_backend = ["nightly", "u64_backend", "packed_simd"] diff --git a/src/lib.rs b/src/lib.rs index f353085..e15ffa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ // This means that missing docs will still fail CI, but means we can use // README.md as the crate documentation. #![cfg_attr(feature = "nightly", deny(missing_docs))] + #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] #![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.0.2")] From 08bf6ebf081e50da44e6245775c1ef97e89fa0ee Mon Sep 17 00:00:00 2001 From: zgfzgf <1901989065@qq.com> Date: Wed, 3 Feb 2021 17:46:01 +0800 Subject: [PATCH 37/45] fix build warning --- src/backend/serial/scalar_mul/variable_base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/src/backend/serial/scalar_mul/variable_base.rs index c69e48c..a4ff2ed 100644 --- a/src/backend/serial/scalar_mul/variable_base.rs +++ b/src/backend/serial/scalar_mul/variable_base.rs @@ -3,7 +3,7 @@ use traits::Identity; use scalar::Scalar; use edwards::EdwardsPoint; -use backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; +use backend::serial::curve_models::ProjectiveNielsPoint; use window::LookupTable; /// Perform constant-time, variable-base scalar multiplication. From 0154ebbfaf4069b5a49e34894b014838463ea7ee Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Wed, 10 Feb 2021 12:14:32 -0700 Subject: [PATCH 38/45] implement Zeroize trait on Ristretto curve point types This is helpful for hardening some of our cryptographic implementations that use Ristretto curve points --- Cargo.toml | 2 +- src/edwards.rs | 6 ++++-- src/ristretto.rs | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3426071..b20f0ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # The original packed_simd package was orphaned, see # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } -zeroize = { version = "1", default-features = false } +zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } [features] nightly = ["subtle/nightly"] diff --git a/src/edwards.rs b/src/edwards.rs index 1524dbd..19ce866 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -105,6 +105,8 @@ use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; +use zeroize::Zeroize; + use constants; use field::FieldElement; @@ -150,7 +152,7 @@ use backend::vector::scalar_mul; /// /// The first 255 bits of a `CompressedEdwardsY` represent the /// \\(y\\)-coordinate. The high bit of the 32nd byte gives the sign of \\(x\\). -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Zeroize)] pub struct CompressedEdwardsY(pub [u8; 32]); impl ConstantTimeEq for CompressedEdwardsY { @@ -307,7 +309,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY { // ------------------------------------------------------------------------ /// An `EdwardsPoint` represents a point on the Edwards form of Curve25519. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Zeroize)] #[allow(missing_docs)] pub struct EdwardsPoint { pub(crate) X: FieldElement, diff --git a/src/ristretto.rs b/src/ristretto.rs index 93d310f..55f5ffd 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -177,6 +177,8 @@ use subtle::ConditionallySelectable; use subtle::ConditionallyNegatable; use subtle::ConstantTimeEq; +use zeroize::Zeroize; + use edwards::EdwardsBasepointTable; use edwards::EdwardsPoint; @@ -208,7 +210,7 @@ use backend::vector::scalar_mul; /// /// The Ristretto encoding is canonical, so two points are equal if and /// only if their encodings are equal. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Zeroize)] pub struct CompressedRistretto(pub [u8; 32]); impl ConstantTimeEq for CompressedRistretto { @@ -434,7 +436,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto { /// operations on `RistrettoPoint`s are exactly as fast as operations on /// `EdwardsPoint`s. /// -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Zeroize)] pub struct RistrettoPoint(pub(crate) EdwardsPoint); impl RistrettoPoint { From 4a1fc3c66ee48044f134f66f93632a53cde7a596 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 25 Mar 2021 01:45:54 +0000 Subject: [PATCH 39/45] Implement Zeroize for points as the identity element. --- Cargo.toml | 2 +- src/edwards.rs | 26 ++++++++++++++++++++++++-- src/ristretto.rs | 11 +++-------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b20f0ad..3426071 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # The original packed_simd package was orphaned, see # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } -zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "1", default-features = false } [features] nightly = ["subtle/nightly"] diff --git a/src/edwards.rs b/src/edwards.rs index 19ce866..0db8727 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -152,7 +152,7 @@ use backend::vector::scalar_mul; /// /// The first 255 bits of a `CompressedEdwardsY` represent the /// \\(y\\)-coordinate. The high bit of the 32nd byte gives the sign of \\(x\\). -#[derive(Copy, Clone, Eq, PartialEq, Hash, Zeroize)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct CompressedEdwardsY(pub [u8; 32]); impl ConstantTimeEq for CompressedEdwardsY { @@ -309,7 +309,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY { // ------------------------------------------------------------------------ /// An `EdwardsPoint` represents a point on the Edwards form of Curve25519. -#[derive(Copy, Clone, Zeroize)] +#[derive(Copy, Clone)] #[allow(missing_docs)] pub struct EdwardsPoint { pub(crate) X: FieldElement, @@ -369,6 +369,28 @@ impl Default for EdwardsPoint { } } +// ------------------------------------------------------------------------ +// Zeroize implementations for wiping points from memory +// ------------------------------------------------------------------------ + +impl Zeroize for CompressedEdwardsY { + /// Reset this `CompressedEdwardsY` to the compressed form of the identity element. + fn zeroize(&mut self) { + self.0.zeroize(); + self.0[0] = 1; + } +} + +impl Zeroize for EdwardsPoint { + /// Reset this `CompressedEdwardsPoint` to the identity element. + fn zeroize(&mut self) { + self.X.zeroize(); + self.Y = FieldElement::one(); + self.Z = FieldElement::one(); + self.T.zeroize(); + } +} + // ------------------------------------------------------------------------ // Validity checks (for debugging, not CT) // ------------------------------------------------------------------------ diff --git a/src/ristretto.rs b/src/ristretto.rs index 5ef9551..8eb79f5 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -202,8 +202,6 @@ use backend::serial::scalar_mul; ))] use backend::vector::scalar_mul; -use zeroize::Zeroize; - // ------------------------------------------------------------------------ // Compressed points // ------------------------------------------------------------------------ @@ -212,7 +210,7 @@ use zeroize::Zeroize; /// /// The Ristretto encoding is canonical, so two points are equal if and /// only if their encodings are equal. -#[derive(Copy, Clone, Eq, PartialEq, Hash, Zeroize)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct CompressedRistretto(pub [u8; 32]); impl ConstantTimeEq for CompressedRistretto { @@ -438,7 +436,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto { /// operations on `RistrettoPoint`s are exactly as fast as operations on /// `EdwardsPoint`s. /// -#[derive(Copy, Clone, Zeroize)] +#[derive(Copy, Clone)] pub struct RistrettoPoint(pub(crate) EdwardsPoint); impl RistrettoPoint { @@ -1094,10 +1092,7 @@ impl Zeroize for CompressedRistretto { impl Zeroize for RistrettoPoint { fn zeroize(&mut self) { - self.0.X.zeroize(); - self.0.Y.zeroize(); - self.0.Z.zeroize(); - self.0.T.zeroize(); + self.0.zeroize(); } } From ab468cd24cae05ec2eba43618c45188560ff0d55 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 25 Mar 2021 02:29:37 +0000 Subject: [PATCH 40/45] Fix copyright years in some of the files I touched. --- src/edwards.rs | 5 +++-- src/montgomery.rs | 5 +++-- src/ristretto.rs | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 0db8727..ce3185e 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2020 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Group operations for Curve25519, in Edwards form. diff --git a/src/montgomery.rs b/src/montgomery.rs index c3676c2..c4b653f 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Scalar multiplication on the Montgomery form of Curve25519. diff --git a/src/ristretto.rs b/src/ristretto.rs index 8eb79f5..b9e3734 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2020 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence // We allow non snake_case names because coordinates in projective space are From 1491f0db364f8d8fc1072caff88967248c555ef5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 25 Mar 2021 04:10:55 +0000 Subject: [PATCH 41/45] Update copyright years. --- LICENSE | 3 +- src/backend/mod.rs | 5 +- src/backend/serial/curve_models/mod.rs | 5 +- src/backend/serial/mod.rs | 5 +- src/backend/serial/scalar_mul/mod.rs | 5 +- src/backend/serial/scalar_mul/straus.rs | 5 +- .../serial/scalar_mul/vartime_double_base.rs | 5 +- src/backend/serial/u32/constants.rs | 5 +- src/backend/serial/u32/field.rs | 7 +- src/backend/serial/u32/mod.rs | 5 +- src/backend/serial/u64/constants.rs | 5 +- src/backend/serial/u64/field.rs | 7 +- src/backend/serial/u64/mod.rs | 5 +- src/backend/vector/avx2/constants.rs | 5 +- src/backend/vector/avx2/edwards.rs | 5 +- src/backend/vector/avx2/field.rs | 7 +- src/backend/vector/avx2/mod.rs | 5 +- src/backend/vector/ifma/field.rs | 6 +- src/backend/vector/mod.rs | 5 +- src/backend/vector/scalar_mul/mod.rs | 5 +- src/backend/vector/scalar_mul/straus.rs | 5 +- .../vector/scalar_mul/vartime_double_base.rs | 6 +- src/constants.rs | 5 +- src/edwards.rs | 111 ------------------ src/field.rs | 3 +- src/lib.rs | 5 +- src/macros.rs | 5 +- src/prelude.rs | 11 ++ src/ristretto.rs | 18 --- src/scalar.rs | 3 +- src/traits.rs | 5 +- src/window.rs | 5 +- 32 files changed, 100 insertions(+), 187 deletions(-) diff --git a/LICENSE b/LICENSE index 2501697..ff34757 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2016-2019 Isis Agora Lovecruft, Henry de Valence. All rights reserved. +Copyright (c) 2016-2021 isis agora lovecruft. All rights reserved. +Copyright (c) 2016-2021 Henry de Valence. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/src/backend/mod.rs b/src/backend/mod.rs index f761eaa..a55a045 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Pluggable implementations for different architectures. diff --git a/src/backend/serial/curve_models/mod.rs b/src/backend/serial/curve_models/mod.rs index 5d5850f..9d10d92 100644 --- a/src/backend/serial/curve_models/mod.rs +++ b/src/backend/serial/curve_models/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Internal curve representations which are not part of the public API. diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index fc6b320..30d6546 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Serial implementations of field, scalar, point arithmetic. diff --git a/src/backend/serial/scalar_mul/mod.rs b/src/backend/serial/scalar_mul/mod.rs index 544725a..8bdad1f 100644 --- a/src/backend/serial/scalar_mul/mod.rs +++ b/src/backend/serial/scalar_mul/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Implementations of various scalar multiplication algorithms. diff --git a/src/backend/serial/scalar_mul/straus.rs b/src/backend/serial/scalar_mul/straus.rs index b63e162..a361df5 100644 --- a/src/backend/serial/scalar_mul/straus.rs +++ b/src/backend/serial/scalar_mul/straus.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Implementation of the interleaved window method, also known as Straus' method. diff --git a/src/backend/serial/scalar_mul/vartime_double_base.rs b/src/backend/serial/scalar_mul/vartime_double_base.rs index ef8c0ca..03517f9 100644 --- a/src/backend/serial/scalar_mul/vartime_double_base.rs +++ b/src/backend/serial/scalar_mul/vartime_double_base.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence #![allow(non_snake_case)] diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 49eb1b0..9ffb793 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! This module contains various constants (such as curve parameters diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index 603ed3f..c8f3e5e 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -1,11 +1,12 @@ -// -*- mode: rust; coding: utf-8; -*- +// -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit diff --git a/src/backend/serial/u32/mod.rs b/src/backend/serial/u32/mod.rs index e0f344f..401ce74 100644 --- a/src/backend/serial/u32/mod.rs +++ b/src/backend/serial/u32/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 9d0c547..c89a521 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. diff --git a/src/backend/serial/u64/field.rs b/src/backend/serial/u64/field.rs index 1cb7778..a73d4b5 100644 --- a/src/backend/serial/u64/field.rs +++ b/src/backend/serial/u64/field.rs @@ -1,11 +1,12 @@ -// -*- mode: rust; coding: utf-8; -*- +// -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit diff --git a/src/backend/serial/u64/mod.rs b/src/backend/serial/u64/mod.rs index d329a89..aa29eb6 100644 --- a/src/backend/serial/u64/mod.rs +++ b/src/backend/serial/u64/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2018 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier. diff --git a/src/backend/vector/avx2/constants.rs b/src/backend/vector/avx2/constants.rs index 73e5ba3..122068e 100644 --- a/src/backend/vector/avx2/constants.rs +++ b/src/backend/vector/avx2/constants.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! This module contains constants used by the AVX2 backend. diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 77af176..821d516 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Parallel Edwards Arithmetic for Curve25519. diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index edd1fa6..94a06ee 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -1,11 +1,12 @@ -// -*- mode: rust; coding: utf-8; -*- +// -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! An implementation of 4-way vectorized 32bit field arithmetic using diff --git a/src/backend/vector/avx2/mod.rs b/src/backend/vector/avx2/mod.rs index 175b7eb..527fdc1 100644 --- a/src/backend/vector/avx2/mod.rs +++ b/src/backend/vector/avx2/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence #![cfg_attr( diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index 5b7c092..a393b22 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -1,10 +1,12 @@ -// -*- mode: rust; coding: utf-8; -*- +// -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2018-2019 Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: +// - isis agora lovecruft // - Henry de Valence #![allow(non_snake_case)] diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 9726c71..29a6f65 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence // Conditionally include the notes if we're on nightly (so we can include docs at all). diff --git a/src/backend/vector/scalar_mul/mod.rs b/src/backend/vector/scalar_mul/mod.rs index 2fc1b18..36a7047 100644 --- a/src/backend/vector/scalar_mul/mod.rs +++ b/src/backend/vector/scalar_mul/mod.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence pub mod variable_base; diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 7206cf3..b6c02f9 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence #![allow(non_snake_case)] diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index d78e46d..3f7cc3e 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -1,12 +1,14 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence + #![allow(non_snake_case)] use backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; diff --git a/src/constants.rs b/src/constants.rs index e30d35e..c911ec2 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Various constants, such as the Ristretto and Ed25519 basepoints. diff --git a/src/edwards.rs b/src/edwards.rs index aff8260..c95128a 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -101,14 +101,11 @@ use core::ops::{Add, Neg, Sub}; use core::ops::{AddAssign, SubAssign}; use core::ops::{Mul, MulAssign}; -use digest::{generic_array::typenum::U64, Digest}; use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; -use zeroize::Zeroize; - use constants; use field::FieldElement; @@ -371,28 +368,6 @@ impl Default for EdwardsPoint { } } -// ------------------------------------------------------------------------ -// Zeroize implementations for wiping points from memory -// ------------------------------------------------------------------------ - -impl Zeroize for CompressedEdwardsY { - /// Reset this `CompressedEdwardsY` to the compressed form of the identity element. - fn zeroize(&mut self) { - self.0.zeroize(); - self.0[0] = 1; - } -} - -impl Zeroize for EdwardsPoint { - /// Reset this `CompressedEdwardsPoint` to the identity element. - fn zeroize(&mut self) { - self.X.zeroize(); - self.Y = FieldElement::one(); - self.Z = FieldElement::one(); - self.T.zeroize(); - } -} - // ------------------------------------------------------------------------ // Validity checks (for debugging, not CT) // ------------------------------------------------------------------------ @@ -519,31 +494,6 @@ impl EdwardsPoint { s[31] ^= x.is_negative().unwrap_u8() << 7; CompressedEdwardsY(s) } - - /// Perform hashing to the group using the Elligator2 map - /// - /// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 - pub fn hash_from_bytes(bytes: &[u8]) -> EdwardsPoint - where - D: Digest + Default, - { - let mut hash = D::new(); - hash.update(bytes); - let h = hash.finalize(); - let mut res = [0u8; 32]; - res.copy_from_slice(&h[..32]); - - let sign_bit = (res[31] & 0x80) >> 7; - - let fe = FieldElement::from_bytes(&res); - - let M1 = crate::montgomery::elligator_encode(&fe); - let E1_opt = M1.to_edwards(sign_bit); - - E1_opt - .expect("Montgomery conversion to Edwards point in Elligator failed") - .mul_by_cofactor() - } } // ------------------------------------------------------------------------ @@ -1483,65 +1433,4 @@ mod test { let bp: EdwardsPoint = bincode::deserialize(raw_bytes).unwrap(); assert_eq!(bp, constants::ED25519_BASEPOINT_POINT); } - - //////////////////////////////////////////////////////////// - // Signal tests from // - // https://github.com/signalapp/libsignal-protocol-c/ // - //////////////////////////////////////////////////////////// - - fn test_vectors() -> Vec> { - vec![ - vec![ - "214f306e1576f5a7577636fe303ca2c625b533319f52442b22a9fa3b7ede809f", - "c95becf0f93595174633b9d4d6bbbeb88e16fa257176f877ce426e1424626052", - ], - vec![ - "2eb10d432702ea7f79207da95d206f82d5a3b374f5f89f17a199531f78d3bea6", - "d8f8b508edffbb8b6dab0f602f86a9dd759f800fe18f782fdcac47c234883e7f", - ], - vec![ - "84cbe9accdd32b46f4a8ef51c85fd39d028711f77fb00e204a613fc235fd68b9", - "93c73e0289afd1d1fc9e4e78a505d5d1b2642fbdf91a1eff7d281930654b1453", - ], - vec![ - "c85165952490dc1839cb69012a3d9f2cc4b02343613263ab93a26dc89fd58267", - "43cbe8685fd3c90665b91835debb89ff1477f906f5170f38a192f6a199556537", - ], - vec![ - "26e7fc4a78d863b1a4ccb2ce0951fbcd021e106350730ee4157bacb4502e1b76", - "b6fc3d738c2c40719479b2f23818180cdafa72a14254d4016bbed8f0b788a835", - ], - vec![ - "1618c08ef0233f94f0f163f9435ec7457cd7a8cd4bb6b160315d15818c30f7a2", - "da0b703593b29dbcd28ebd6e7baea17b6f61971f3641cae774f6a5137a12294c", - ], - vec![ - "48b73039db6fcdcb6030c4a38e8be80b6390d8ae46890e77e623f87254ef149c", - "ca11b25acbc80566603eabeb9364ebd50e0306424c61049e1ce9385d9f349966", - ], - vec![ - "a744d582b3a34d14d311b7629da06d003045ae77cebceeb4e0e72734d63bd07d", - "fad25a5ea15d4541258af8785acaf697a886c1b872c793790e60a6837b1adbc0", - ], - vec![ - "80a6ff33494c471c5eff7efb9febfbcf30a946fe6535b3451cda79f2154a7095", - "57ac03913309b3f8cd3c3d4c49d878bb21f4d97dc74a1eaccbe5c601f7f06f47", - ], - vec![ - "f06fc939bc10551a0fd415aebf107ef0b9c4ee1ef9a164157bdd089127782617", - "785b2a6a00a5579cc9da1ff997ce8339b6f9fb46c6f10cf7a12ff2986341a6e0", - ], - ] - } - - #[test] - fn elligator_signal_test_vectors() { - for vector in test_vectors().iter() { - let input = hex::decode(vector[0]).unwrap(); - let output = hex::decode(vector[1]).unwrap(); - - let point = EdwardsPoint::hash_from_bytes::(&input); - assert_eq!(point.compress().to_bytes(), output[..]); - } - } } diff --git a/src/field.rs b/src/field.rs index 54d048d..cbac170 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1,7 +1,8 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis agora lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/lib.rs b/src/lib.rs index 912b62a..b4bfe1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence #![no_std] diff --git a/src/macros.rs b/src/macros.rs index 5985a5f..84a2ce1 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis agora lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Internal macros. diff --git a/src/prelude.rs b/src/prelude.rs index be2f600..5c0a611 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,3 +1,14 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + //! Crate-local prelude (for alloc-dependent features like `Vec`) // TODO: switch to alloc::prelude diff --git a/src/ristretto.rs b/src/ristretto.rs index b9e3734..d284b5b 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -178,8 +178,6 @@ use subtle::ConditionallySelectable; use subtle::ConditionallyNegatable; use subtle::ConstantTimeEq; -use zeroize::Zeroize; - use edwards::EdwardsBasepointTable; use edwards::EdwardsPoint; @@ -1081,22 +1079,6 @@ impl Debug for RistrettoPoint { } } -// ------------------------------------------------------------------------ -// Zeroize traits -// ------------------------------------------------------------------------ - -impl Zeroize for CompressedRistretto { - fn zeroize(&mut self) { - self.0.zeroize(); - } -} - -impl Zeroize for RistrettoPoint { - fn zeroize(&mut self) { - self.0.zeroize(); - } -} - // ------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------ diff --git a/src/scalar.rs b/src/scalar.rs index 6ead65a..ce38058 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -1,7 +1,8 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // Portions Copyright 2017 Brian Smith // See LICENSE for licensing information. // diff --git a/src/traits.rs b/src/traits.rs index b024c88..4e582b3 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Module for common traits. diff --git a/src/window.rs b/src/window.rs index 3b01422..e2cec0f 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,11 +1,12 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft // - Henry de Valence //! Code for fixed- and sliding-window functionality From d130b5f17eca75ec07dc3445d147f4bea4b49aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Fri, 26 Mar 2021 09:18:18 -0700 Subject: [PATCH 42/45] [benchmarks-only] Updates the benchmarks - removes usages fo the (deprecated) `bench_function_over_inputs` - introduces a few benchmark groups. --- benches/dalek_benchmarks.rs | 295 ++++++++++++++++++++---------------- 1 file changed, 165 insertions(+), 130 deletions(-) diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index 89e8e62..136d0e7 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -7,8 +7,10 @@ use rand::thread_rng; #[macro_use] extern crate criterion; +use criterion::measurement::Measurement; use criterion::BatchSize; use criterion::Criterion; +use criterion::{BenchmarkGroup, BenchmarkId}; extern crate curve25519_dalek; @@ -100,115 +102,136 @@ mod multiscalar_benches { (construct_scalars(n), construct_points(n)) } - fn consttime_multiscalar_mul(c: &mut Criterion) { - c.bench_function_over_inputs( - "Constant-time variable-base multiscalar multiplication", - |b, &&size| { - let points = construct_points(size); - // This is supposed to be constant-time, but we might as well - // rerandomize the scalars for every call just in case. - b.iter_batched( - || construct_scalars(size), - |scalars| EdwardsPoint::multiscalar_mul(&scalars, &points), - BatchSize::SmallInput, - ); - }, - &MULTISCALAR_SIZES, - ); + fn consttime_multiscalar_mul(c: &mut BenchmarkGroup) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Constant-time variable-base multiscalar multiplication", + *multiscalar_size, + ), + &multiscalar_size, + |b, &&size| { + let points = construct_points(size); + // This is supposed to be constant-time, but we might as well + // rerandomize the scalars for every call just in case. + b.iter_batched( + || construct_scalars(size), + |scalars| EdwardsPoint::multiscalar_mul(&scalars, &points), + BatchSize::SmallInput, + ); + }, + ); + } } - fn vartime_multiscalar_mul(c: &mut Criterion) { - c.bench_function_over_inputs( - "Variable-time variable-base multiscalar multiplication", - |b, &&size| { - let points = construct_points(size); - // Rerandomize the scalars for every call to prevent - // false timings from better caching (e.g., the CPU - // cache lifts exactly the right table entries for the - // benchmark into the highest cache levels). - b.iter_batched( - || construct_scalars(size), - |scalars| EdwardsPoint::vartime_multiscalar_mul(&scalars, &points), - BatchSize::SmallInput, - ); - }, - &MULTISCALAR_SIZES, - ); + fn vartime_multiscalar_mul(c: &mut BenchmarkGroup) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Variable-time variable-base multiscalar multiplication", + *multiscalar_size, + ), + &multiscalar_size, + |b, &&size| { + let points = construct_points(size); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). + b.iter_batched( + || construct_scalars(size), + |scalars| EdwardsPoint::vartime_multiscalar_mul(&scalars, &points), + BatchSize::SmallInput, + ); + }, + ); + } } - fn vartime_precomputed_pure_static(c: &mut Criterion) { - c.bench_function_over_inputs( - "Variable-time fixed-base multiscalar multiplication", - move |b, &&total_size| { - let static_size = total_size; + fn vartime_precomputed_pure_static(c: &mut BenchmarkGroup) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Variable-time fixed-base multiscalar multiplication", + &multiscalar_size, + ), + &multiscalar_size, + move |b, &&total_size| { + let static_size = total_size; - let static_points = construct_points(static_size); - let precomp = VartimeEdwardsPrecomputation::new(&static_points); - // Rerandomize the scalars for every call to prevent - // false timings from better caching (e.g., the CPU - // cache lifts exactly the right table entries for the - // benchmark into the highest cache levels). - b.iter_batched( - || construct_scalars(static_size), - |scalars| precomp.vartime_multiscalar_mul(&scalars), - BatchSize::SmallInput, - ); - }, - &MULTISCALAR_SIZES, - ); + let static_points = construct_points(static_size); + let precomp = VartimeEdwardsPrecomputation::new(&static_points); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). + b.iter_batched( + || construct_scalars(static_size), + |scalars| precomp.vartime_multiscalar_mul(&scalars), + BatchSize::SmallInput, + ); + }, + ); + } } - fn vartime_precomputed_helper(c: &mut Criterion, dynamic_fraction: f64) { - let label = format!( - "Variable-time mixed-base multiscalar multiplication ({:.0}pct dyn)", - 100.0 * dynamic_fraction, - ); - c.bench_function_over_inputs( - &label, - move |b, &&total_size| { - let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize; - let static_size = total_size - dynamic_size; + fn vartime_precomputed_helper( + c: &mut BenchmarkGroup, + dynamic_fraction: f64, + ) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Variable-time mixed-base multiscalar multiplication ({:.0}pct dyn)", + format!("({:.0}pct dyn)", 100.0 * dynamic_fraction), + ), + &multiscalar_size, + move |b, &&total_size| { + let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize; + let static_size = total_size - dynamic_size; - let static_points = construct_points(static_size); - let dynamic_points = construct_points(dynamic_size); - let precomp = VartimeEdwardsPrecomputation::new(&static_points); - // Rerandomize the scalars for every call to prevent - // false timings from better caching (e.g., the CPU - // cache lifts exactly the right table entries for the - // benchmark into the highest cache levels). Timings - // should be independent of points so we don't - // randomize them. - b.iter_batched( - || { - ( - construct_scalars(static_size), - construct_scalars(dynamic_size), - ) - }, - |(static_scalars, dynamic_scalars)| { - precomp.vartime_mixed_multiscalar_mul( - &static_scalars, - &dynamic_scalars, - &dynamic_points, - ) - }, - BatchSize::SmallInput, - ); - }, - &MULTISCALAR_SIZES, - ); + let static_points = construct_points(static_size); + let dynamic_points = construct_points(dynamic_size); + let precomp = VartimeEdwardsPrecomputation::new(&static_points); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). Timings + // should be independent of points so we don't + // randomize them. + b.iter_batched( + || { + ( + construct_scalars(static_size), + construct_scalars(dynamic_size), + ) + }, + |(static_scalars, dynamic_scalars)| { + precomp.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ) + }, + BatchSize::SmallInput, + ); + }, + ); + } } - fn vartime_precomputed_00_pct_dynamic(c: &mut Criterion) { - vartime_precomputed_helper(c, 0.0); - } + fn multiscalar_multiplications(c: &mut Criterion) { + let mut group: BenchmarkGroup<_> = c.benchmark_group("Multiscalar muls"); - fn vartime_precomputed_20_pct_dynamic(c: &mut Criterion) { - vartime_precomputed_helper(c, 0.2); - } + consttime_multiscalar_mul(&mut group); + vartime_multiscalar_mul(&mut group); + vartime_precomputed_pure_static(&mut group); - fn vartime_precomputed_50_pct_dynamic(c: &mut Criterion) { - vartime_precomputed_helper(c, 0.5); + let dynamic_fracs = [0.0, 0.2, 0.5]; + for frac in dynamic_fracs.iter() { + vartime_precomputed_helper(&mut group, *frac); + } + group.finish(); } criterion_group! { @@ -216,12 +239,7 @@ mod multiscalar_benches { // Lower the sample size to run the benchmarks faster config = Criterion::default().sample_size(15); targets = - consttime_multiscalar_mul, - vartime_multiscalar_mul, - vartime_precomputed_pure_static, - vartime_precomputed_00_pct_dynamic, - vartime_precomputed_20_pct_dynamic, - vartime_precomputed_50_pct_dynamic, + multiscalar_multiplications, } } @@ -243,18 +261,26 @@ mod ristretto_benches { }); } - fn double_and_compress_batch(c: &mut Criterion) { - c.bench_function_over_inputs( - "Batch Ristretto double-and-encode", - |b, &&size| { - let mut rng = OsRng; - let points: Vec = (0..size) - .map(|_| RistrettoPoint::random(&mut rng)) - .collect(); - b.iter(|| RistrettoPoint::double_and_compress_batch(&points)); - }, - &BATCH_SIZES, - ); + fn double_and_compress_batch(c: &mut BenchmarkGroup) { + for batch_size in &BATCH_SIZES { + c.bench_with_input( + BenchmarkId::new("Batch Ristretto double-and-encode", *batch_size), + &batch_size, + |b, &&size| { + let mut rng = OsRng; + let points: Vec = (0..size) + .map(|_| RistrettoPoint::random(&mut rng)) + .collect(); + b.iter(|| RistrettoPoint::double_and_compress_batch(&points)); + }, + ); + } + } + + fn double_and_compress_group(c: &mut Criterion) { + let mut group: BenchmarkGroup<_> = c.benchmark_group("double & compress batched"); + double_and_compress_batch(&mut group); + group.finish(); } criterion_group! { @@ -263,7 +289,7 @@ mod ristretto_benches { targets = compress, decompress, - double_and_compress_batch, + double_and_compress_group, } } @@ -295,19 +321,28 @@ mod scalar_benches { }); } - fn batch_scalar_inversion(c: &mut Criterion) { - c.bench_function_over_inputs( - "Batch scalar inversion", - |b, &&size| { - let mut rng = OsRng; - let scalars: Vec = (0..size).map(|_| Scalar::random(&mut rng)).collect(); - b.iter(|| { - let mut s = scalars.clone(); - Scalar::batch_invert(&mut s); - }); - }, - &BATCH_SIZES, - ); + fn batch_scalar_inversion(c: &mut BenchmarkGroup) { + for batch_size in &BATCH_SIZES { + c.bench_with_input( + BenchmarkId::new("Batch scalar inversion", *batch_size), + &batch_size, + |b, &&size| { + let mut rng = OsRng; + let scalars: Vec = + (0..size).map(|_| Scalar::random(&mut rng)).collect(); + b.iter(|| { + let mut s = scalars.clone(); + Scalar::batch_invert(&mut s); + }); + }, + ); + } + } + + fn batch_scalar_inversion_group(c: &mut Criterion) { + let mut group: BenchmarkGroup<_> = c.benchmark_group("batch scalar inversion"); + batch_scalar_inversion(&mut group); + group.finish(); } criterion_group! { @@ -315,7 +350,7 @@ mod scalar_benches { config = Criterion::default(); targets = scalar_inversion, - batch_scalar_inversion, + batch_scalar_inversion_group, } } From ee90202a58d355a54983ab71651481e028983ebf Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 13 Apr 2021 00:24:50 +0000 Subject: [PATCH 43/45] Trivial cleanups to Elligator2 encoding. cf. https://github.com/dalek-cryptography/curve25519-dalek/pull/336 --- src/backend/serial/u32/constants.rs | 12 ++++++++++-- src/backend/serial/u64/constants.rs | 16 ++++++++++++++-- src/montgomery.rs | 18 ++++++++++-------- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 9ffb793..5848539 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -64,10 +64,18 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625([ pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); -/// `MONT_A` is a constant of Curve25519. (This is used internally within the Elligator map.) -pub(crate) const MONT_A: FieldElement2625 = +/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation +/// for Curve25519 in its Montgomery form. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A: FieldElement2625 = FieldElement2625([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); +/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625([ + 66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, +]); + /// `L` is the order of base point, i.e. 2^252 + /// 27742317777372353535851937790883648493 pub(crate) const L: Scalar29 = Scalar29([ diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index c89a521..261ca6b 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -92,8 +92,20 @@ pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([ /// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = FieldElement51([121666, 0, 0, 0, 0]); -/// `MONT_A` is a constant of Curve25519. (This is used internally within the Elligator map.) -pub(crate) const MONT_A: FieldElement51 = FieldElement51([486662, 0, 0, 0, 0]); +/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation +/// for Curve25519 in its Montgomery form. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A: FieldElement51 = FieldElement51([486662, 0, 0, 0, 0]); + +/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51([ + 2251799813198567, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, +]); /// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493 pub(crate) const L: Scalar52 = Scalar52([ diff --git a/src/montgomery.rs b/src/montgomery.rs index 17b8677..de0f8b7 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -51,7 +51,7 @@ use core::ops::{Mul, MulAssign}; -use constants::{APLUS2_OVER_FOUR, MONT_A}; +use constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; use edwards::{CompressedEdwardsY, EdwardsPoint}; use field::FieldElement; use scalar::Scalar; @@ -157,19 +157,21 @@ impl MontgomeryPoint { } } -/// Perform the Elligator2 mapping to a Montgomery point +/// Perform the Elligator2 mapping to a Montgomery point. /// -/// See -/// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 +/// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 +// +// TODO Determine how much of the hash-to-group API should be exposed after the CFRG +// draft gets into a more polished/accepted state. +#[allow(unused)] pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint { - let minus_a = -&MONT_A; /* A = 486662 */ let one = FieldElement::one(); let d_1 = &one + &r_0.square2(); /* 2r^2 */ - let d = &minus_a * &(d_1.invert()); /* A/(1+2r^2) */ + let d = &MONTGOMERY_A_NEG * &(d_1.invert()); /* A/(1+2r^2) */ let d_sq = &d.square(); - let au = &MONT_A * &d; + let au = &MONTGOMERY_A * &d; let inner = &(d_sq + &au) + &one; let eps = &d * &inner; /* eps = d^3 + Ad^2 + d */ @@ -177,7 +179,7 @@ pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint { let (eps_is_sq, _eps) = FieldElement::sqrt_ratio_i(&eps, &one); let zero = FieldElement::zero(); - let Atemp = FieldElement::conditional_select(&MONT_A, &zero, eps_is_sq); /* 0, or A if nonsquare*/ + let Atemp = FieldElement::conditional_select(&MONTGOMERY_A, &zero, eps_is_sq); /* 0, or A if nonsquare*/ let mut u = &d + &Atemp; /* d, or d+A if nonsquare */ u.conditional_negate(!eps_is_sq); /* d, or -d-A if nonsquare */ From 0da8f08d6582cbc35af6ef1da0e7917d4f5ddfed Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 13 Apr 2021 01:24:06 +0000 Subject: [PATCH 44/45] Maintain legacy 3.x support for lookup tables. --- src/edwards.rs | 132 ++++++++++++++++++++++++++++++++++++++++++++--- src/ristretto.rs | 1 - 2 files changed, 124 insertions(+), 9 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index ba82da3..7c97ca4 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -118,6 +118,7 @@ use backend::serial::curve_models::CompletedPoint; use backend::serial::curve_models::ProjectiveNielsPoint; use backend::serial::curve_models::ProjectivePoint; +use window::LookupTable; use window::LookupTableRadix16; use window::LookupTableRadix32; use window::LookupTableRadix64; @@ -900,19 +901,134 @@ impl Debug for $name { }} // End macro_rules! impl_basepoint_table // The number of additions required is ceil(256/w) where w is the radix representation. -impl_basepoint_table! {Name = EdwardsBasepointTable, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix16, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64} impl_basepoint_table! {Name = EdwardsBasepointTableRadix32, LookupTable = LookupTableRadix32, Point = EdwardsPoint, Radix = 5, Additions = 52} impl_basepoint_table! {Name = EdwardsBasepointTableRadix64, LookupTable = LookupTableRadix64, Point = EdwardsPoint, Radix = 6, Additions = 43} impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = LookupTableRadix128, Point = EdwardsPoint, Radix = 7, Additions = 37} impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33} -/// A type-alias for [`EdwardsBasepointTable`] because the latter is -/// used as a constructor in the `constants` module. -// -// Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable` -// first, because it's used as a constructor, and then provide a type alias for -// it. -pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable; +// ------------------------------------------------------------------------------------- +// BEGIN legacy 3.x series code for backwards compatibility with BasepointTable trait +// ------------------------------------------------------------------------------------- + +/// A precomputed table of multiples of a basepoint, for accelerating +/// fixed-base scalar multiplication. One table, for the Ed25519 +/// basepoint, is provided in the `constants` module. +/// +/// The basepoint tables are reasonably large, so they should probably be boxed. +/// +/// The sizes for the tables and the number of additions required for one scalar +/// multiplication are as follows: +/// +/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A +/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`]) +/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A +/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A +/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A +/// +/// # Why 33 additions for radix-256? +/// +/// Normally, the radix-256 tables would allow for only 32 additions per scalar +/// multiplication. However, due to the fact that standardised definitions of +/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar +/// invariants, when converting such an unreduced scalar's representation to +/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last +/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of +/// the radix, is \\(w < 8\\), we can fold the final carry onto the last +/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so +/// $$ +/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8} +/// $$ +/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we +/// add the carry bit onto an additional coefficient. +#[derive(Clone)] +pub struct EdwardsBasepointTable(pub(crate) [LookupTable; 32]); + +impl EdwardsBasepointTable { + /// Create a table of precomputed multiples of `basepoint`. + #[allow(warnings)] + pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable { + Self(EdwardsBasepointTableRadix16::create(basepoint).0) + } + + /// The computation uses Pippenger's algorithm, as described on + /// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with + /// coefficients in \\([-8,8)\\), i.e., + /// $$ + /// a = a\_0 + a\_1 16\^1 + \cdots + a\_{63} 16\^{63}, + /// $$ + /// with \\(-8 \leq a_i < 8\\), \\(-8 \leq a\_{63} \leq 8\\). Then + /// $$ + /// a B = a\_0 B + a\_1 16\^1 B + \cdots + a\_{63} 16\^{63} B. + /// $$ + /// Grouping even and odd coefficients gives + /// $$ + /// \begin{aligned} + /// a B = \quad a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B \\\\ + /// + a\_1 16\^1 B +& a\_3 16\^3 B + \cdots + a\_{63} 16\^{63} B \\\\ + /// = \quad(a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B) \\\\ + /// + 16(a\_1 16\^0 B +& a\_3 16\^2 B + \cdots + a\_{63} 16\^{62} B). \\\\ + /// \end{aligned} + /// $$ + /// For each \\(i = 0 \ldots 31\\), we create a lookup table of + /// $$ + /// [16\^{2i} B, \ldots, 8\cdot16\^{2i} B], + /// $$ + /// and use it to select \\( x \cdot 16\^{2i} \cdot B \\) in constant time. + /// + /// The radix-\\(16\\) representation requires that the scalar is bounded + /// by \\(2\^{255}\\), which is always the case. + #[allow(warnings)] + pub fn basepoint_mul(&self, scalar: &Scalar) -> EdwardsPoint { + let a = scalar.to_radix_16(); + + let tables = &self.0; + let mut P = EdwardsPoint::identity(); + + for i in (0..64).filter(|x| x % 2 == 1) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P = P.mul_by_pow_2(4); + + for i in (0..64).filter(|x| x % 2 == 0) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P + } + + /// Get the basepoint for this table as an `EdwardsPoint`. + #[allow(warnings)] + pub fn basepoint(&self) -> EdwardsPoint { + (&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended() + } +} + +impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { + type Output = EdwardsPoint; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { + // delegate to a private function so that its documentation appears in internal docs + self.basepoint_mul(scalar) + } +} + +impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar { + type Output = EdwardsPoint; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> EdwardsPoint { + basepoint_table * self + } +} + +// ------------------------------------------------------------------------------------- +// END legacy 3.x series code for backwards compatibility with BasepointTable trait +// ------------------------------------------------------------------------------------- macro_rules! impl_basepoint_table_conversions { (LHS = $lhs:ty, RHS = $rhs:ty) => { diff --git a/src/ristretto.rs b/src/ristretto.rs index d5cceb2..d284b5b 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -186,7 +186,6 @@ use prelude::*; use scalar::Scalar; -use traits::BasepointTable; use traits::Identity; #[cfg(any(feature = "alloc", feature = "std"))] use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; From 2ea17d554a54066efb3bc4895bee92e5b2e1bd50 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 01:30:57 +0000 Subject: [PATCH 45/45] Update CHANGELOG and README; bump to 3.1.0. --- CHANGELOG.md | 15 +++++++++++++++ Cargo.toml | 2 +- README.md | 16 +++++++++++++--- src/lib.rs | 2 +- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90ac99b..1d42492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ major series. ## 3.x series +### 3.1.0 + +* Add support for the Elligator2 encoding for Edwards points. +* Add two optional formally-verified field arithmetic backends which + use the Fiat Crypto project's Rust code, which is generated from + proofs of functional correctness checked by the Coq theorem proving + system. +* Add support for additional sizes of precomputed tables for basepoint + scalar multiplication. +* Fix an unused import. +* Add support for using the `zeroize` traits with all point types. + Note that points are not automatically zeroized on Drop, but that + consumers of `curve25519-dalek` should call these methods manually + when needed. + ### 3.0.2 * Fixes to make using alloc+no_std possible for stable Rust. diff --git a/Cargo.toml b/Cargo.toml index 75e9af5..fb6f627 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update html_root_url # - update README if required by semver -version = "3.0.2" +version = "3.1.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/README.md b/README.md index 0f35b5a..19679f9 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,19 @@ your project's `Cargo.toml`: curve25519-dalek = "3" ``` -The `3.x` series has API almost entirely unchanged from the `2.x` series, -except that the `digest` version was updated. +The sole breaking change in the `3.x` series was an update to the `digest` +version, and in terms of non-breaking changes it includes: + +* support for using `alloc` instead of `std` on stable Rust, +* the Elligator2 encoding for Edwards points, +* a fix to use `packed_simd2`, +* various documentation fixes and improvements, +* support for configurably-sized, precomputed lookup tables for basepoint scalar + multiplication, +* two new formally-verified field arithmetic backends which use the Fiat Crypto + Rust code, which is generated from proofs of functional correctness checked by + the Coq theorem proving system, and +* support for explicitly calling the `zeroize` traits for all point types. The `2.x` series has API almost entirely unchanged from the `1.x` series, except that: @@ -58,7 +69,6 @@ except that: corrected, so that when the `2.x`-series `serde` implementation is used with `serde-bincode`, the derived serialization matches the usual X/Ed25519 formats; - * the `rand` version was updated. See `CHANGELOG.md` for more details. diff --git a/src/lib.rs b/src/lib.rs index f47130a..13f9393 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.0.2")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.1.0")] //! Note that docs will only build on nightly Rust until //! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732).