From 4f6788c72d927dae82922891f8c483d62c5e451b Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 8 Nov 2017 15:31:02 -0800 Subject: [PATCH] First working version --- src/avx2/edwards.rs | 196 ++++++++++++++++++++++++++++++-------------- src/avx2/field.rs | 17 ++-- 2 files changed, 141 insertions(+), 72 deletions(-) diff --git a/src/avx2/edwards.rs b/src/avx2/edwards.rs index 85ff583..3ab6139 100644 --- a/src/avx2/edwards.rs +++ b/src/avx2/edwards.rs @@ -49,53 +49,86 @@ impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { 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 mut P: FieldElement32x4 = self.0; - let mut Q: FieldElement32x4 = other.0; - let mut t0: FieldElement32x4 = self.0; + let P: &FieldElement32x4 = &self.0; + let Q: &FieldElement32x4 = &other.0; + + let mut t0 = FieldElement32x4::zero(); + let mut t1 = FieldElement32x4::zero(); + + macro_rules! print_vec { + ($x:ident) => { + let splits = $x.split(); + println!("{}[0] = {:?}", stringify!($x), splits[0].to_bytes()); + println!("{}[1] = {:?}", stringify!($x), splits[1].to_bytes()); + println!("{}[2] = {:?}", stringify!($x), splits[2].to_bytes()); + println!("{}[3] = {:?}", stringify!($x), splits[3].to_bytes()); + } + } for i in 0..5 { t0.0[i] = _mm256_permute2x128_si256(P.0[i].into(), Q.0[i].into(), 32).into(); } //println!("t0 = (X1, Y1, X2, Y2)"); - //println!("t0 = {:?}\n", t0.split()); + //print_vec!(t0); + //println!(""); - let mut t1 = t0.diff_sum(); - //println!("t1 = (S1 S3 S2 S4)"); - //println!("t1 = {:?}\n", t1.split()); + t0.diff_sum(); + + //println!("t0 = (S0 S1 S2 S3)"); + //print_vec!(t0); + //println!(""); for i in 0..5 { - Q.0[i] = _mm256_permute2x128_si256(t1.0[i].into(), Q.0[i].into(), 49).into(); - t1.0[i] = _mm256_blend_epi32(t1.0[i].into(), P.0[i].into(), 0b11110000).into(); + 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(); } - //println!("Q = (S2 S4 Z2 T2)"); - //println!("Q = {:?}\n", Q.split()); - //println!("t1 = (S1 S3 Z1 T1)"); - //println!("t1 = {:?}\n", t1.split()); + //println!("t0 = (S2 S3 Z2 T2)"); + //print_vec!(t0); + //println!(""); - P = &t1 * &Q; - //println!("P = (S5 S6 S8 S7)"); - //println!("P = {:?}\n", P.split()); + //println!("t1 = (S0 S1 Z1 T1)"); + //print_vec!(t1); + //println!(""); + + let mut t2 = &t0 * &t1; + //println!("t2 = (S4 S5 S6 S7)"); + //print_vec!(t2); + //println!(""); - P.scale_by_curve_constants(); - //println!("P = (S5' S6' S10 S8)"); - //println!("P = {:?}\n", P.split()); + t2.scale_by_curve_constants(); + //println!("t2 = (S8 S9 S10 S11)"); + //print_vec!(t2); + //println!(""); + + for i in 0..5 { + let swapped = _mm256_shuffle_epi32(t2.0[i].into(), 0b10_11_00_01); + t2.0[i] = _mm256_blend_epi32(t2.0[i].into(), swapped, 0b11110000).into(); + } + //println!("t2 = (S8 S9 S11 S10)"); + //print_vec!(t2); + //println!(""); - Q = P.diff_sum(); - //println!("Q = (S11 S14 S12 S13)"); - //println!("Q = {:?}\n", Q.split()); + t2.diff_sum(); + //println!("t2 = (S12 S13 S14 S15)"); + //print_vec!(t2); + //println!(""); 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) -> (CBBC) + let c1 = u32x8::new(4,1,6,3,4,1,6,3); // (ABCD) -> (CBCB) for i in 0..5 { - t0.0[i] = _mm256_permutevar8x32_epi32(Q.0[i], c0); - t1.0[i] = _mm256_permutevar8x32_epi32(Q.0[i], c1); + t0.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c0); + t1.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c1); } //println!("t0 = (S11 S13 S13 S11)"); - //println!("t0 = {:?}\n", t0.split()); + //print_vec!(t0); + //println!(""); + //println!("t1 = (S12 S14 S14 S12)"); - //println!("t1 = {:?}\n", t1.split()); + //print_vec!(t1); + //println!(""); ExtendedPoint(&t0 * &t1) } @@ -112,25 +145,51 @@ mod test { let (X1, Y1, Z1, T1) = (P.X, P.Y, P.Z, P.T); let (X2, Y2, Z2, T2) = (Q.X, Q.Y, Q.Z, Q.T); + macro_rules! print_var { + ($x:ident) => { + println!("{} = {:?}", stringify!($x), $x.to_bytes()); + } + } + let S0 = &Y1 - &X1; // R1 let S1 = &Y1 + &X1; // R3 let S2 = &Y2 - &X2; // R2 let S3 = &Y2 + &X2; // R4 + print_var!(S0); + print_var!(S1); + print_var!(S2); + print_var!(S3); + println!(""); let S4 = &S0 * &S2; // R5 = R1 * R2 let S5 = &S1 * &S3; // R6 = R3 * R4 - let S6 = &T1 * &T2; // R7 - let S7 = &Z1 * &Z2; // R8 + let S6 = &Z1 * &Z2; // R8 + let S7 = &T1 * &T2; // R7 + print_var!(S4); + print_var!(S5); + print_var!(S6); + print_var!(S7); + println!(""); - let S8 = &S6 * &(-&FieldElement32([2*121665,0,0,0,0,0,0,0,0,0])); // R7 - let S9 = &S7 * &FieldElement32([2*121666,0,0,0,0,0,0,0,0,0]); // R8 - let S10 = &S4 * &FieldElement32([ 121666,0,0,0,0,0,0,0,0,0]); // R5 - let S11 = &S5 * &FieldElement32([ 121666,0,0,0,0,0,0,0,0,0]); // R6 + let S8 = &S4 * &FieldElement32([ 121666,0,0,0,0,0,0,0,0,0]); // R5 + let S9 = &S5 * &FieldElement32([ 121666,0,0,0,0,0,0,0,0,0]); // R6 + let S10 = &S6 * &FieldElement32([2*121666,0,0,0,0,0,0,0,0,0]); // R8 + let S11 = &S7 * &(-&FieldElement32([2*121665,0,0,0,0,0,0,0,0,0])); // R7 + print_var!(S8 ); + print_var!(S9 ); + print_var!(S10); + print_var!(S11); + println!(""); - let S12 = &S11 - &S10; // R1 - let S13 = &S11 + &S10; // R4 - let S14 = &S9 - &S8; // R2 - let S15 = &S9 + &S8; // R3 + let S12 = &S9 - &S8; // R1 + let S13 = &S9 + &S8; // R4 + let S14 = &S10 - &S11; // R2 + let S15 = &S10 + &S11; // R3 + print_var!(S12); + print_var!(S13); + print_var!(S14); + print_var!(S15); + println!(""); let X3 = &S12 * &S14; // R1 * R2 let Y3 = &S15 * &S13; // R3 * R4 @@ -140,8 +199,22 @@ mod test { edwards::ExtendedPoint{X: X3, Y: Y3, Z: Z3, T: T3} } + fn addition_test_helper(P: edwards::ExtendedPoint, Q: edwards::ExtendedPoint) { + let R1: edwards::ExtendedPoint = serial_add(P.into(), Q.into()).into(); + let R2: edwards::ExtendedPoint = (&ExtendedPoint::from(P) + &ExtendedPoint::from(Q)).into(); + println!("Testing point addition:"); + println!("P = {:?}", P); + println!("Q = {:?}", Q); + println!("(serial) R1 = {:?}", R1); + println!("(vector) R2 = {:?}", R2); + println!("P + Q = {:?}", &P + &Q); + assert_eq!(R1.compress(), (&P + &Q).compress()); + assert_eq!(R2.compress(), (&P + &Q).compress()); + println!("OK!\n"); + } + #[test] - fn serial_add_vs_edwards_extendedpoint() { + fn addition_vs_serial_add_vs_edwards_extendedpoint() { use constants; use scalar::Scalar; use edwards::Identity; @@ -149,41 +222,40 @@ mod test { println!("Testing id + id"); let P = edwards::ExtendedPoint::identity(); let Q = edwards::ExtendedPoint::identity(); - let R: edwards::ExtendedPoint = serial_add(P.into(), Q.into()).into(); - println!("P = {:?}", P); - println!("Q = {:?}", Q); - println!("R = {:?}", R); - println!("P + Q = {:?}", &P + &Q); - assert_eq!(R.compress(), (&P + &Q).compress()); + addition_test_helper(P, Q); println!("Testing id + B"); let P = edwards::ExtendedPoint::identity(); let Q = constants::ED25519_BASEPOINT_POINT; - let R: edwards::ExtendedPoint = serial_add(P.into(), Q.into()).into(); - println!("P = {:?}", P); - println!("Q = {:?}", Q); - println!("R = {:?}", R); - println!("P + Q = {:?}", &P + &Q); - assert_eq!(R.compress(), (&P + &Q).compress()); + addition_test_helper(P, Q); println!("Testing B + B"); let P = constants::ED25519_BASEPOINT_POINT; let Q = constants::ED25519_BASEPOINT_POINT; - let R: edwards::ExtendedPoint = serial_add(P.into(), Q.into()).into(); - println!("P = {:?}", P); - println!("Q = {:?}", Q); - println!("R = {:?}", R); - println!("P + Q = {:?}", &P + &Q); - assert_eq!(R.compress(), (&P + &Q).compress()); + addition_test_helper(P, Q); println!("Testing B + kB"); let P = constants::ED25519_BASEPOINT_POINT; let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from_u64(8475983829); - let R: edwards::ExtendedPoint = serial_add(P.into(), Q.into()).into(); - println!("P = {:?}", P); - println!("Q = {:?}", Q); - println!("R = {:?}", R); - println!("P + Q = {:?}", &P + &Q); - assert_eq!(R.compress(), (&P + &Q).compress()); + addition_test_helper(P, Q); } } + +#[cfg(all(test, feature = "bench"))] +mod bench { + use test::Bencher; + use super::*; + + use constants; + use scalar::Scalar; + + #[bench] + fn point_addition(b: &mut Bencher) { + let B = &constants::ED25519_BASEPOINT_TABLE; + let P = ExtendedPoint::from(B * &Scalar::from_u64(83973422)); + let Q = ExtendedPoint::from(B * &Scalar::from_u64(98932328)); + + b.iter(|| &P + &Q ); + } +} + diff --git a/src/avx2/field.rs b/src/avx2/field.rs index 15050c6..ba1b001 100644 --- a/src/avx2/field.rs +++ b/src/avx2/field.rs @@ -71,8 +71,8 @@ impl FieldElement32x4 { FieldElement32x4(buf) } - // Given `self = (A,B,C,D)`, compute `(B - A, B + A, D - C, D + C)`. - pub fn diff_sum(&self) -> FieldElement32x4 { + // Given `self = (A,B,C,D)`, set `self = (B - A, B + A, D - C, D + C)`. + pub fn diff_sum(&mut self) { /// (v0 v1 v2 v3 v4 v5 v6 v7) -> (v1 v0 v3 v2 v5 v4 v7 v6) #[inline(always)] fn alternate_32bit_lanes(v: u32x8) -> u32x8 { @@ -92,8 +92,6 @@ impl FieldElement32x4 { } } - let mut out = [u32x8::splat(0); 5]; - for i in 0..5 { let x = self.0[i]; let p = P_TIMES_2.0[i] ; @@ -103,10 +101,8 @@ impl FieldElement32x4 { let sum = x + x_shuf; let diff_sum = blend_alternating_32bit_lanes(diff, sum); - out[i] = diff_sum; + self.0[i] = diff_sum; } - - FieldElement32x4(out) } // Given `self = (A,B,C,D)`, compute `(B + A, B - A, D + C, D - C)`. @@ -415,9 +411,10 @@ mod test { let x2 = FieldElement32([10200, 10201, 10202, 10203, 10204, 10205, 10206, 10207, 10208, 10209]); let x3 = FieldElement32([10300, 10301, 10302, 10303, 10304, 10305, 10306, 10307, 10308, 10309]); - let vec = FieldElement32x4::new(&x0, &x1, &x2, &x3); + let mut vec = FieldElement32x4::new(&x0, &x1, &x2, &x3); + vec.diff_sum(); - let result = vec.diff_sum().split(); + let result = vec.split(); assert_eq!(result[0], &x1 - &x0); assert_eq!(result[1], &x1 + &x0); @@ -493,7 +490,7 @@ mod bench { #[bench] fn multiply(b: &mut Bencher) { - let vec = FieldElement32x4::splat(&FieldElement::zero()); + let vec = FieldElement32x4::splat(&FieldElement32::zero()); let vecprime = vec.clone(); b.iter(|| &vec * &vecprime );