diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 50ca57d..49576b4 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -238,7 +238,7 @@ impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { let mut t2 = &t0 * &t1; // set t2 = (S8 S9 S10 S11) - t2.scale_by_curve_constants(true); + t2.scale_by_curve_constants(); // set t2 = (S8 S9 S11 S10) t2.swap_CD(); @@ -265,70 +265,12 @@ impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; - /// Uses a slight tweak of the parallel unified formulas of HWCD'08 + /// Implement subtraction by negating the point and adding. + /// + /// Empirically, this seems about the same cost as a custom subtraction impl (maybe because the + /// benefit is cancelled by increased code size?) fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint { - unsafe { - use stdsimd::vendor::_mm256_permute2x128_si256; - use stdsimd::vendor::_mm256_permutevar8x32_epi32; - use stdsimd::vendor::_mm256_blend_epi32; - use stdsimd::vendor::_mm256_shuffle_epi32; - - let P: &FieldElement32x4 = &self.0; - let Q: &FieldElement32x4 = &other.0; - - let mut t0 = FieldElement32x4::zero(); - let mut t1 = FieldElement32x4::zero(); - - // set t0 = (X1 Y1 X2 Y2) - for i in 0..5 { - t0.0[i] = _mm256_permute2x128_si256(P.0[i].into(), Q.0[i].into(), 32).into(); - } - - // Since we're subtracting instead of adding, we want to add the point (-X2 Y2 Z2 -T2). - // Set (X2' Y2' Z2' T2') = (-X2 Y2 Z2 -T2) - // - // so S2 = Y2 - X2' = Y2 - (-X2) = Y2 + X2 - // and S3 = Y2 + X2' = Y2 + (-X2) = Y2 - X2 - - // set t0 = (Y1-X1 Y1+X1 Y2-X2 Y2+X2) = (S0 S1 S3 S2) - t0.diff_sum(); - - // set t0 = (S0 S1 S2 S3) - t0.swap_CD(); - - // set t1 = (S0 S1 Z1 T1) - // set t0 = (S2 S3 Z2 T2) = (S2 S3 Z2' -T2') - for i in 0..5 { - t1.0[i] = _mm256_blend_epi32(t0.0[i].into(), P.0[i].into(), 0b11110000).into(); - t0.0[i] = _mm256_permute2x128_si256(t0.0[i].into(), Q.0[i].into(), 49).into(); - } - - // set t2 = (S0*S2 S1*S3 Z1*Z2 T1*T2 ) - // = (S0*S2 S1*S3 Z1*Z2' -T1*T2') = (S4 S5 S6 -S7) - let mut t2 = &t0 * &t1; - - // set t2 = (S8 S9 S10 S11) - t2.scale_by_curve_constants(false); - - // set t2 = (S8 S9 S11 S10) - t2.swap_CD(); - - // set t2 = (S9-S8 S9+S8 S10-S11 S10+S11) = (S12 S13 S14 S15) - 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) - - // set t0 = (S12 S15 S15 S12) - // set t1 = (S14 S13 S14 S13) - for i in 0..5 { - t0.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c0); - t1.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c1); - } - - // return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3) - ExtendedPoint(&t0 * &t1) - } + self + &(-other) } } @@ -647,7 +589,6 @@ pub mod vartime { if naf[i] > 0 { Q = &Q + &odd_multiple[( naf[i]/2) as usize]; } else if naf[i] < 0 { - // XXX impl Sub Q = &Q - &odd_multiple[(-naf[i]/2) as usize]; } } diff --git a/src/backend/avx2/field.rs b/src/backend/avx2/field.rs index b76d454..b6e6397 100644 --- a/src/backend/avx2/field.rs +++ b/src/backend/avx2/field.rs @@ -202,15 +202,9 @@ impl FieldElement32x4 { /// Let `self` \\(= (A, B, C, D) \\). /// - /// If `negate_121665 = true`, compute - /// + /// Compute /// $$( 121666A, 121666B, 2\cdot 121666C, -2\cdot 121665 D).$$ - /// - /// If `negate_121665 = false`, compute - /// - /// $$( 121666A, 121666B, 2\cdot 121666C, 2\cdot 121665 D).$$ - /// - pub fn scale_by_curve_constants(&mut self, negate_121665: bool) { + 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); @@ -225,57 +219,32 @@ impl FieldElement32x4 { 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 - if negate_121665 { - 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(); - } else { - b[0] = b0; - b[1] = b1; - } + 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 = _mm256_mul_epu32(b2, consts); let b3 = _mm256_mul_epu32(b3, consts); - if negate_121665 { - 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(); - } else { - b[2] = b2; - b[3] = b3; - } + 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 = _mm256_mul_epu32(b4, consts); let b5 = _mm256_mul_epu32(b5, consts); - if negate_121665 { - 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(); - } else { - b[4] = b4; - b[5] = b5; - } + 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 = _mm256_mul_epu32(b6, consts); let b7 = _mm256_mul_epu32(b7, consts); - if negate_121665 { - 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(); - } else { - b[6] = b6; - b[7] = b7; - } + 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 = _mm256_mul_epu32(b8, consts); let b9 = _mm256_mul_epu32(b9, consts); - if negate_121665 { - 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(); - } else { - b[8] = b8; - b[9] = b9; - } + 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); @@ -564,22 +533,13 @@ mod test { #[test] fn scale_by_curve_constants() { let mut x = FieldElement32x4::splat(&FieldElement64::one()); - x.scale_by_curve_constants(true); + x.scale_by_curve_constants(); let xs = x.split(); 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])); - - let mut y = FieldElement32x4::splat(&FieldElement64::one()); - y.scale_by_curve_constants(false); - - let ys = y.split(); - assert_eq!(ys[0], FieldElement64([ 121666,0,0,0,0])); - assert_eq!(ys[1], FieldElement64([ 121666,0,0,0,0])); - assert_eq!(ys[2], FieldElement64([2*121666,0,0,0,0])); - assert_eq!(ys[3], FieldElement64([2*121665,0,0,0,0])); } #[test]