From d62fc7caf1ae2533c6516d3c2c479ee89c3be693 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 7 Dec 2017 10:21:20 -0800 Subject: [PATCH] Rearrange signs to avoid a subtraction --- src/backend/avx2/edwards.rs | 12 +++++++----- src/backend/avx2/field.rs | 37 ++++++++++++------------------------- src/backend/avx2/mod.rs | 16 ++++++++++------ 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 49576b4..b720c9d 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -237,17 +237,19 @@ impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { // set t2 = (S0*S2 S1*S3 Z1*Z2 T1*T2) = (S4 S5 S6 S7) let mut t2 = &t0 * &t1; - // set t2 = (S8 S9 S10 S11) + //// set t2 = (S8 S9 S10 S11) + // set t2 = (121666*S4 121666*S5 2*121666*S6 2*121665*S7) + // = ( S8 S9 S10 -S11) t2.scale_by_curve_constants(); - // set t2 = (S8 S9 S11 S10) + // set t2 = (S8 S9 -S11 S10) t2.swap_CD(); - // set t2 = (S9-S8 S9+S8 S10-S11 S10+S11) = (S12 S13 S14 S15) + // set t2 = (S9-S8 S9+S8 S10+S11 S10-S11) = (S12 S13 S15 S14) t2.diff_sum(); - let c0 = u32x8::new(0,5,2,7,5,0,7,2); // (ABCD) -> (ADDA) - let c1 = u32x8::new(4,1,6,3,4,1,6,3); // (ABCD) -> (CBCB) + let c0 = u32x8::new(0,4,2,6,4,0,6,2); // (ABCD) -> (ACCA) + let c1 = u32x8::new(5,1,7,3,5,1,7,3); // (ABCD) -> (DBDB) // set t0 = (S12 S15 S15 S12) // set t1 = (S14 S13 S14 S13) diff --git a/src/backend/avx2/field.rs b/src/backend/avx2/field.rs index cd71d6a..2e44797 100644 --- a/src/backend/avx2/field.rs +++ b/src/backend/avx2/field.rs @@ -203,48 +203,35 @@ impl FieldElement32x4 { /// Let `self` \\(= (A, B, C, D) \\). /// /// Compute - /// $$( 121666A, 121666B, 2\cdot 121666C, -2\cdot 121665 D).$$ + /// $$( 121666A, 121666B, 2\cdot 121666C, 2\cdot 121665 D).$$ pub fn scale_by_curve_constants(&mut self) { let mut b = [u64x4::splat(0); 10]; let consts = u32x8::new(121666, 0, 121666, 0, 2*121666, 0, 2*121665, 0); - let low__p20 = u64x4::splat(0x3ffffed << 20); - let even_p20 = u64x4::splat(0x3ffffff << 20); - let odd__p20 = u64x4::splat(0x1ffffff << 20); unsafe { use stdsimd::vendor::_mm256_mul_epu32; use stdsimd::vendor::_mm256_blend_epi32; let (b0, b1) = unpack_pair(self.0[0]); - let b0 = _mm256_mul_epu32(b0, consts); // need a new binding since now - let b1 = _mm256_mul_epu32(b1, consts); // b0 has type u64x4 - b[0] = _mm256_blend_epi32(b0.into(), (low__p20 - b0).into(), 0b11_00_00_00).into(); - b[1] = _mm256_blend_epi32(b1.into(), (odd__p20 - b1).into(), 0b11_00_00_00).into(); + b[0] = _mm256_mul_epu32(b0, consts); + b[1] = _mm256_mul_epu32(b1, consts); let (b2, b3) = unpack_pair(self.0[1]); - let b2 = _mm256_mul_epu32(b2, consts); - let b3 = _mm256_mul_epu32(b3, consts); - b[2] = _mm256_blend_epi32(b2.into(), (even_p20 - b2).into(), 0b11_00_00_00).into(); - b[3] = _mm256_blend_epi32(b3.into(), (odd__p20 - b3).into(), 0b11_00_00_00).into(); + b[2] = _mm256_mul_epu32(b2, consts); + b[3] = _mm256_mul_epu32(b3, consts); let (b4, b5) = unpack_pair(self.0[2]); - let b4 = _mm256_mul_epu32(b4, consts); - let b5 = _mm256_mul_epu32(b5, consts); - b[4] = _mm256_blend_epi32(b4.into(), (even_p20 - b4).into(), 0b11_00_00_00).into(); - b[5] = _mm256_blend_epi32(b5.into(), (odd__p20 - b5).into(), 0b11_00_00_00).into(); + b[4] = _mm256_mul_epu32(b4, consts); + b[5] = _mm256_mul_epu32(b5, consts); let (b6, b7) = unpack_pair(self.0[3]); - let b6 = _mm256_mul_epu32(b6, consts); - let b7 = _mm256_mul_epu32(b7, consts); - b[6] = _mm256_blend_epi32(b6.into(), (even_p20 - b6).into(), 0b11_00_00_00).into(); - b[7] = _mm256_blend_epi32(b7.into(), (odd__p20 - b7).into(), 0b11_00_00_00).into(); + b[6] = _mm256_mul_epu32(b6, consts); + b[7] = _mm256_mul_epu32(b7, consts); let (b8, b9) = unpack_pair(self.0[4]); - let b8 = _mm256_mul_epu32(b8, consts); - let b9 = _mm256_mul_epu32(b9, consts); - b[8] = _mm256_blend_epi32(b8.into(), (even_p20 - b8).into(), 0b11_00_00_00).into(); - b[9] = _mm256_blend_epi32(b9.into(), (odd__p20 - b9).into(), 0b11_00_00_00).into(); + b[8] = _mm256_mul_epu32(b8, consts); + b[9] = _mm256_mul_epu32(b9, consts); } *self = FieldElement32x4::reduce64(b); @@ -539,7 +526,7 @@ mod test { assert_eq!(xs[0], FieldElement64([ 121666,0,0,0,0])); assert_eq!(xs[1], FieldElement64([ 121666,0,0,0,0])); assert_eq!(xs[2], FieldElement64([2*121666,0,0,0,0])); - assert_eq!(xs[3], -&FieldElement64([2*121665,0,0,0,0])); + assert_eq!(xs[3], FieldElement64([2*121665,0,0,0,0])); } #[test] diff --git a/src/backend/avx2/mod.rs b/src/backend/avx2/mod.rs index e9c3846..1b041e1 100644 --- a/src/backend/avx2/mod.rs +++ b/src/backend/avx2/mod.rs @@ -87,9 +87,9 @@ //! Hamburg. Ignoring the sign for the moment, since //! \\(2 \cdot 121666 < 2\^{18}\\), all these constants fit in 32 bits, //! so this can be done in parallel as a scaling by \\( (121666, 121666, -//! 2\cdot 121665, 2\cdot 121666) \\). To handle the sign, we use -//! masking to negate one of the field elements. +//! -2\cdot 121665, 2\cdot 121666) \\). //! +//! How do we handle the sign? //! Since we're primarily interested in Ristretto performance, not //! Curve25519 performance, we could alternately work on the //! \\(4\\)-isogenous "IsoEd25519" curve, which has \\(d = 121665\\). @@ -97,6 +97,7 @@ //! one field element by a 32-bit constant is not much easier than //! multiplying four field elements by 32-bit constants, and it would //! prevent accelerating Curve25519, so we don't make this choice. +//! Instead, we flip the sign later by swapping two intermediate variables (see below). //! //! The 4-wide formulas of the HWCD paper do not seem to have been //! implemented using SIMD before. The HWCD paper also describes and @@ -186,7 +187,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} //! $$ //! @@ -194,8 +195,8 @@ //! \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} +//! S\_{15} &\gets S\_{10} - S\_{11} \\\\ +//! S\_{14} &\gets S\_{10} + S\_{11} //! \end{aligned} //! $$ //! @@ -208,7 +209,10 @@ //! \end{aligned} //! $$ //! -//! to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = P\_1 + P\_2 \\). +//! 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} \\). //! //! ## Doubling //!