Rearrange signs to avoid a subtraction

This commit is contained in:
Henry de Valence 2017-12-07 10:21:20 -08:00
parent 7d2d87441b
commit d62fc7caf1
3 changed files with 29 additions and 36 deletions

View file

@ -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) // set t2 = (S0*S2 S1*S3 Z1*Z2 T1*T2) = (S4 S5 S6 S7)
let mut t2 = &t0 * &t1; 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(); t2.scale_by_curve_constants();
// set t2 = (S8 S9 S11 S10) // set t2 = (S8 S9 -S11 S10)
t2.swap_CD(); 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(); t2.diff_sum();
let c0 = u32x8::new(0,5,2,7,5,0,7,2); // (ABCD) -> (ADDA) let c0 = u32x8::new(0,4,2,6,4,0,6,2); // (ABCD) -> (ACCA)
let c1 = u32x8::new(4,1,6,3,4,1,6,3); // (ABCD) -> (CBCB) let c1 = u32x8::new(5,1,7,3,5,1,7,3); // (ABCD) -> (DBDB)
// set t0 = (S12 S15 S15 S12) // set t0 = (S12 S15 S15 S12)
// set t1 = (S14 S13 S14 S13) // set t1 = (S14 S13 S14 S13)

View file

@ -203,48 +203,35 @@ impl FieldElement32x4 {
/// Let `self` \\(= (A, B, C, D) \\). /// Let `self` \\(= (A, B, C, D) \\).
/// ///
/// Compute /// 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) { pub fn scale_by_curve_constants(&mut self) {
let mut b = [u64x4::splat(0); 10]; let mut b = [u64x4::splat(0); 10];
let consts = u32x8::new(121666, 0, 121666, 0, 2*121666, 0, 2*121665, 0); 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 { unsafe {
use stdsimd::vendor::_mm256_mul_epu32; use stdsimd::vendor::_mm256_mul_epu32;
use stdsimd::vendor::_mm256_blend_epi32; use stdsimd::vendor::_mm256_blend_epi32;
let (b0, b1) = unpack_pair(self.0[0]); let (b0, b1) = unpack_pair(self.0[0]);
let b0 = _mm256_mul_epu32(b0, consts); // need a new binding since now b[0] = _mm256_mul_epu32(b0, consts);
let b1 = _mm256_mul_epu32(b1, consts); // b0 has type u64x4 b[1] = _mm256_mul_epu32(b1, consts);
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();
let (b2, b3) = unpack_pair(self.0[1]); let (b2, b3) = unpack_pair(self.0[1]);
let b2 = _mm256_mul_epu32(b2, consts); b[2] = _mm256_mul_epu32(b2, consts);
let b3 = _mm256_mul_epu32(b3, consts); b[3] = _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();
let (b4, b5) = unpack_pair(self.0[2]); let (b4, b5) = unpack_pair(self.0[2]);
let b4 = _mm256_mul_epu32(b4, consts); b[4] = _mm256_mul_epu32(b4, consts);
let b5 = _mm256_mul_epu32(b5, consts); b[5] = _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();
let (b6, b7) = unpack_pair(self.0[3]); let (b6, b7) = unpack_pair(self.0[3]);
let b6 = _mm256_mul_epu32(b6, consts); b[6] = _mm256_mul_epu32(b6, consts);
let b7 = _mm256_mul_epu32(b7, consts); b[7] = _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();
let (b8, b9) = unpack_pair(self.0[4]); let (b8, b9) = unpack_pair(self.0[4]);
let b8 = _mm256_mul_epu32(b8, consts); b[8] = _mm256_mul_epu32(b8, consts);
let b9 = _mm256_mul_epu32(b9, consts); b[9] = _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();
} }
*self = FieldElement32x4::reduce64(b); *self = FieldElement32x4::reduce64(b);
@ -539,7 +526,7 @@ mod test {
assert_eq!(xs[0], FieldElement64([ 121666,0,0,0,0])); assert_eq!(xs[0], FieldElement64([ 121666,0,0,0,0]));
assert_eq!(xs[1], 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[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] #[test]

View file

@ -87,9 +87,9 @@
//! Hamburg. Ignoring the sign for the moment, since //! Hamburg. Ignoring the sign for the moment, since
//! \\(2 \cdot 121666 < 2\^{18}\\), all these constants fit in 32 bits, //! \\(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, //! 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 //! -2\cdot 121665, 2\cdot 121666) \\).
//! masking to negate one of the field elements.
//! //!
//! How do we handle the sign?
//! Since we're primarily interested in Ristretto performance, not //! Since we're primarily interested in Ristretto performance, not
//! Curve25519 performance, we could alternately work on the //! Curve25519 performance, we could alternately work on the
//! \\(4\\)-isogenous "IsoEd25519" curve, which has \\(d = 121665\\). //! \\(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 //! one field element by a 32-bit constant is not much easier than
//! multiplying four field elements by 32-bit constants, and it would //! multiplying four field elements by 32-bit constants, and it would
//! prevent accelerating Curve25519, so we don't make this choice. //! 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 //! The 4-wide formulas of the HWCD paper do not seem to have been
//! implemented using SIMD before. The HWCD paper also describes and //! implemented using SIMD before. The HWCD paper also describes and
@ -186,7 +187,7 @@
//! S\_8 &\gets S\_4 \cdot 121666 \\\\ //! S\_8 &\gets S\_4 \cdot 121666 \\\\
//! S\_9 &\gets S\_5 \cdot 121666 \\\\ //! S\_9 &\gets S\_5 \cdot 121666 \\\\
//! S\_{10} &\gets S\_6 \cdot 2 \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} //! \end{aligned}
//! $$ //! $$
//! //!
@ -194,8 +195,8 @@
//! \begin{aligned} //! \begin{aligned}
//! S\_{12} &\gets S\_9 - S\_8 \\\\ //! S\_{12} &\gets S\_9 - S\_8 \\\\
//! S\_{13} &\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} //! \end{aligned}
//! $$ //! $$
//! //!
@ -208,7 +209,10 @@
//! \end{aligned} //! \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 //! ## Doubling
//! //!