From af3c2b28210d6bdb307bb7c0e26ec6807d9bbb64 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 18 Dec 2017 13:58:37 -0800 Subject: [PATCH] Document readdition --- src/backend/avx2/mod.rs | 122 +++++++++++++++++++++++++++++++--------- 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/src/backend/avx2/mod.rs b/src/backend/avx2/mod.rs index 1b041e1..48dddb6 100644 --- a/src/backend/avx2/mod.rs +++ b/src/backend/avx2/mod.rs @@ -69,7 +69,8 @@ //! subtraction steps are done largely serially, using masking to handle //! the instruction divergence. //! -//! The remaining obstacle to parallelism is the multiplication by the curve constant \\(k = 2d\\). In the Curve25519 case, this is +//! The remaining obstacle to parallelism is the multiplication by the +//! curve constant \\(k = 2d\\). In the Curve25519 case, this is //! //! $$ k \equiv 2 \frac{-121665}{121666} \\ \equiv 16295367250680780974490674513165176452449235426866156013048779062215315747161 \pmod p. $$ //! @@ -133,25 +134,6 @@ //! vectorization must overcome the disadvantage of losing the \\( 64 //! \times 64 \rightarrow 128\\)-bit (serial) integer multiplier. //! -//! When used for constant-time variable-base scalar multiplication, -//! this strategy (using AVX2) gives a significant speedup over the -//! serial implementation (using the \\(64 \times 64\\) multiplier) of -//! approximately 1.6x for Skylake-X with `target_cpu=skylake` (using AVX2), of -//! approximately 1.8x for Skylake-X with `target_cpu=skylake-avx512` (using the extra -//! `ymm16..ymm31` registers from AVX512VL), and of approximately 1.0x -//! for Ryzen (which implements AVX2 at half rate). -//! -//! (Note: since testing this, the experimental `llvm50` Rust branch -//! used to compile the experimental `stdsimd` intrinsics have fallen -//! out of sync and it is no longer possible to compile for -//! `skylake-avx512`. This is why all of this branch is part of the -//! `yolocrypto` feature, pending upstream work.) -//! -//! However, since the relative cost of doubling and addition has -//! changed, the optimal tradeoffs for window size etc. in scalar -//! multiplication have probably also changed and should be -//! re-evaluated. -//! //! # Tweaked formulas //! //! After tweaking the formulas as described above, we obtain the @@ -187,7 +169,7 @@ //! S\_8 &\gets S\_4 \cdot 121666 \\\\ //! S\_9 &\gets S\_5 \cdot 121666 \\\\ //! S\_{10} &\gets S\_6 \cdot 2 \cdot 121666 \\\\ -//! S\_{11} &\gets S\_7 \cdot 2 \cdot 121665 +//! S\_{11} &\gets S\_7 \cdot -2 \cdot 121665 //! \end{aligned} //! $$ //! @@ -195,8 +177,8 @@ //! \begin{aligned} //! S\_{12} &\gets S\_9 - S\_8 \\\\ //! S\_{13} &\gets S\_9 + S\_8 \\\\ -//! S\_{15} &\gets S\_{10} - S\_{11} \\\\ -//! S\_{14} &\gets S\_{10} + S\_{11} +//! S\_{14} &\gets S\_{10} - S\_{11} \\\\ +//! S\_{15} &\gets S\_{10} + S\_{11} //! \end{aligned} //! $$ //! @@ -209,10 +191,76 @@ //! \end{aligned} //! $$ //! -//! to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = P\_1 + P\_2 \\). Notice that by multiplying -//! \\( S\_{11} \\) by \\(121665\\) instead of by \\(-121665\\), we save a negation; since we use -//! \\( S\_{11} \\) to compute \\( S\_{10} \pm S\_{11} \\), flipping the sign of \\( S\_{11} \\) -//! swaps \\( S\_{14} \\) and \\( S\_{15} \\). +//! to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = P\_1 + P\_2 \\). +//! +//! ## Readdition +//! +//! If the point \\( P_2 = (X\_2 : Y\_2 : Z\_2 : T\_2) \\) is fixed, we can precompute +//! +//! $$ +//! \begin{aligned} +//! S\_2 &\gets Y\_2 - X\_2 \\\\ +//! S\_3 &\gets Y\_2 + X\_2 +//! \end{aligned} +//! $$ +//! +//! $$ +//! \begin{aligned} +//! S\_2' &\gets S\_2 \cdot 121666 \\\\ +//! S\_3' &\gets S\_3 \cdot 121666 \\\\ +//! Z\_2' &\gets Z\_2 \cdot 2 \cdot 121666 \\\\ +//! T\_2' &\gets T\_2 \cdot -2 \cdot 121665 \\\\ +//! \end{aligned} +//! $$ +//! +//! to obtain the `CachedPoint` \\( (S\_2', S\_3', Z\_2', T\_2') \\). +//! This precomputation is essentially the same as that suggested in +//! ยง3.1 of HWCD, with the difference that the multiplication by the curve +//! constant \\( -121665 / 121666 \\) is spread over all four +//! coordinates, to allow a vectorized computation of four +//! multiplications of small constants instead of a serial computation +//! of multiplication by a large constant. +//! +//! To perform readdition of \\(P_1 = (X_1 : Y_1 : Z_1 : T_1) \\) and +//! \\(P_2 = (S\_2', S\_3', Z\_2', T\_2') \\), we compute +//! +//! $$ +//! \begin{aligned} +//! S\_0 &\gets Y\_1 - X\_1 \\\\ +//! S\_1 &\gets Y\_1 + X\_1 +//! \end{aligned} +//! $$ +//! +//! $$ +//! \begin{aligned} +//! S\_8 &\gets S\_0 S\_2' \\\\ +//! S\_9 &\gets S\_1 S\_3' \\\\ +//! S\_{10} &\gets Z\_1 Z\_2' \\\\ +//! S\_{11} &\gets T\_1 T\_2' +//! \end{aligned} +//! $$ +//! +//! $$ +//! \begin{aligned} +//! S\_{12} &\gets S\_9 - S\_8 \\\\ +//! S\_{13} &\gets S\_9 + S\_8 \\\\ +//! S\_{14} &\gets S\_{10} - S\_{11} \\\\ +//! S\_{15} &\gets S\_{10} + S\_{11} +//! \end{aligned} +//! $$ +//! +//! $$ +//! \begin{aligned} +//! X\_3 &\gets S\_{12} S\_{14} \\\\ +//! Y\_3 &\gets S\_{15} S\_{13} \\\\ +//! Z\_3 &\gets S\_{15} S\_{14} \\\\ +//! T\_3 &\gets S\_{12} S\_{13} +//! \end{aligned} +//! $$ +//! +//! to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = P\_1 + P\_2 \\). +//! +//! Compared to the addition formulas above, this saves \\( 1\mathbf D \\). //! //! ## Doubling //! @@ -349,6 +397,26 @@ //! as an `op + blend`, so hopefully this will improve as the AVX512 //! support in LLVM improves. //! +//! When used for constant-time variable-base scalar multiplication, +//! this strategy (using AVX2) gives a significant speedup over the +//! serial implementation (using the \\(64 \times 64\\) multiplier) of +//! approximately 1.6x for Skylake-X with `target_cpu=skylake` (using AVX2), of +//! approximately 1.8x for Skylake-X with `target_cpu=skylake-avx512` (using the extra +//! `ymm16..ymm31` registers from AVX512VL), and of approximately 1.0x +//! for Ryzen (which implements AVX2 at half rate). +//! +//! When used for variable-time double-base scalar multiplication \\( aA +//! + bB \\) for fixed \\(B\\) (as in, e.g., signature verification), +//! this strategy provides a 1.4x speedup on Skylake-X over the same +//! operation as implemented in `ed25519-donna`, the fastest +//! production-quality Ed25519 implementation. +//! +//! (Note: since testing this, the experimental `llvm50` Rust branch +//! used to compile the experimental `stdsimd` intrinsics have fallen +//! out of sync and it is no longer possible to compile for +//! `skylake-avx512`. This is why all of this branch is part of the +//! `yolocrypto` feature, pending upstream work.) +//! //! [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