diff --git a/src/backend/vector/ifma/edwards.rs b/src/backend/vector/ifma/edwards.rs new file mode 100644 index 0000000..65f7c39 --- /dev/null +++ b/src/backend/vector/ifma/edwards.rs @@ -0,0 +1,136 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +use traits::Identity; + +use std::ops::Add; + +use edwards; + +use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle}; + +#[derive(Copy, Clone, Debug)] +pub struct ExtendedPoint(pub(super) F51x4Unreduced); + +#[derive(Copy, Clone, Debug)] +pub struct CachedPoint(pub(super) F51x4Reduced); + +impl From for ExtendedPoint { + fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { + ExtendedPoint(F51x4Unreduced::new(&P.X, &P.Y, &P.Z, &P.T)) + } +} + +impl From for edwards::EdwardsPoint { + fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { + let tmp = P.0.split(); + edwards::EdwardsPoint { + X: tmp[0], + Y: tmp[1], + Z: tmp[2], + T: tmp[3], + } + } +} + +impl From for CachedPoint { + fn from(P: ExtendedPoint) -> CachedPoint { + let mut x = P.0; + + x = x.blend(&x.diff_sum(), Lanes::AB); + x = &F51x4Reduced::from(x) * (121666, 121666, 2 * 121666, 2 * 121665); + x = x.blend(&x.negate_lazy(), Lanes::D); + + CachedPoint(F51x4Reduced::from(x)) + } +} + +impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Add an `ExtendedPoint` and a `CachedPoint`. + fn add(self, other: &'b CachedPoint) -> ExtendedPoint { + let mut tmp = self.0; + + tmp = tmp.blend(&tmp.diff_sum(), Lanes::AB); + // tmp = (Y1-X1 Y1+X1 Z1 T1) = (S0 S1 Z1 T1) + + tmp = &F51x4Reduced::from(tmp) * &other.0; + // tmp = (S0*S2' S1*S3' Z1*Z2' T1*T2') = (S8 S9 S10 S11) + + tmp = tmp.shuffle(Shuffle::ABDC); + // tmp = (S8 S9 S11 S10) + + let tmp = F51x4Reduced::from(tmp.diff_sum()); + // tmp = (S9-S8 S9+S8 S10-S11 S10+S11) = (S12 S13 S14 S15) + + let t0 = tmp.shuffle(Shuffle::ADDA); + // t0 = (S12 S15 S15 S12) + let t1 = tmp.shuffle(Shuffle::CBCB); + // t1 = (S14 S13 S14 S13) + + // Return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3) + ExtendedPoint(&t0 * &t1) + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn addition_test_helper(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) { + // Test the serial implementation of the parallel addition formulas + //let R_serial: edwards::EdwardsPoint = serial_add(P.into(), Q.into()).into(); + + // Test the vector implementation of the parallel readdition formulas + let cached_Q = CachedPoint::from(ExtendedPoint::from(Q)); + let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into(); + //et S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &cached_Q).into(); + + println!("Testing point addition:"); + println!("P = {:?}", P); + println!("Q = {:?}", Q); + println!("cached Q = {:?}", cached_Q); + println!("R = P + Q = {:?}", &P + &Q); + //println!("R_serial = {:?}", R_serial); + println!("R_vector = {:?}", R_vector); + //println!("S = P - Q = {:?}", &P - &Q); + //println!("S_vector = {:?}", S_vector); + //assert_eq!(R_serial.compress(), (&P + &Q).compress()); + assert_eq!(R_vector.compress(), (&P + &Q).compress()); + //assert_eq!(S_vector.compress(), (&P - &Q).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing id +- id"); + let P = edwards::EdwardsPoint::identity(); + let Q = edwards::EdwardsPoint::identity(); + addition_test_helper(P, Q); + + println!("Testing id +- B"); + let P = edwards::EdwardsPoint::identity(); + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- B"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- kB"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + addition_test_helper(P, Q); + } +} diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index be26a21..307f807 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -30,12 +30,18 @@ pub struct F51x4Reduced(pub(crate) [u64x4; 5]); #[derive(Copy, Clone)] pub enum Lanes { + D, AB, + AC, } #[derive(Copy, Clone)] pub enum Shuffle { AAAA, + BADC, + ADDA, + CBCB, + ABDC, } #[inline(always)] @@ -45,6 +51,10 @@ fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { match control { Shuffle::AAAA => perm(x.into_bits(), 0b00_00_00_00).into_bits(), + Shuffle::BADC => perm(x.into_bits(), 0b10_11_00_01).into_bits(), + Shuffle::ADDA => perm(x.into_bits(), 0b00_11_11_00).into_bits(), + Shuffle::CBCB => perm(x.into_bits(), 0b01_10_01_10).into_bits(), + Shuffle::ABDC => perm(x.into_bits(), 0b10_11_01_00).into_bits(), } } } @@ -55,7 +65,9 @@ fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { use core::arch::x86_64::_mm256_blend_epi32 as blend; match control { + Lanes::D => blend(x.into_bits(), y.into_bits(), 0b11_00_00_00).into_bits(), Lanes::AB => blend(x.into_bits(), y.into_bits(), 0b00_00_11_11).into_bits(), + Lanes::AC => blend(x.into_bits(), y.into_bits(), 0b00_11_00_11).into_bits(), } } } @@ -110,6 +122,29 @@ impl F51x4Unreduced { ] } + #[inline] + pub fn diff_sum(&self) -> F51x4Unreduced { + // tmp1 = (B, A, D, C) + let tmp1 = self.shuffle(Shuffle::BADC); + // tmp2 = (-A, B, -C, D) + let tmp2 = self.blend(&self.negate_lazy(), Lanes::AC); + // (B - A, B + A, D - C, D + C) + tmp1 + tmp2 + } + + #[inline] + pub fn negate_lazy(&self) -> F51x4Unreduced { + let lo = u64x4::splat(36028797018963664u64); + let hi = u64x4::splat(36028797018963952u64); + F51x4Unreduced([ + lo - self.0[0], + hi - self.0[1], + hi - self.0[2], + hi - self.0[3], + hi - self.0[4], + ]) + } + #[inline] pub fn shuffle(&self, control: Shuffle) -> F51x4Unreduced { F51x4Unreduced([ @@ -189,6 +224,20 @@ impl From for F51x4Reduced { } } +impl Add for F51x4Unreduced { + type Output = F51x4Unreduced; + #[inline] + fn add(self, rhs: F51x4Unreduced) -> F51x4Unreduced { + F51x4Unreduced([ + self.0[0] + rhs.0[0], + self.0[1] + rhs.0[1], + self.0[2] + rhs.0[2], + self.0[3] + rhs.0[3], + self.0[4] + rhs.0[4], + ]) + } +} + impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { type Output = F51x4Unreduced; #[inline] diff --git a/src/backend/vector/ifma/mod.rs b/src/backend/vector/ifma/mod.rs index e066ddd..8a77ed3 100644 --- a/src/backend/vector/ifma/mod.rs +++ b/src/backend/vector/ifma/mod.rs @@ -9,3 +9,5 @@ pub mod field; +pub mod edwards; +