polyval/backend/intrinsics/
x86.rs1#![allow(unsafe_op_in_unsafe_fn)]
22
23use super::ExpandedKey;
24use crate::{Block, ParBlocks, field_element::FieldElement};
25
26#[cfg(target_arch = "x86")]
27use core::arch::x86::*;
28#[cfg(target_arch = "x86_64")]
29use core::arch::x86_64::*;
30
31const P1: u64 = 0xC200000000000000;
33
34cpufeatures::new!(clmul, "avx", "pclmulqdq");
35pub(crate) use clmul::InitToken;
36
37type ByteArray = [u8; 16];
39
40impl FieldElement {
41 #[target_feature(enable = "sse2")]
42 #[inline]
43 unsafe fn from_m128i(reg: __m128i) -> Self {
44 let mut out = ByteArray::default();
45 _mm_storeu_si128(out.as_mut_ptr().cast(), reg);
46 out.into()
47 }
48
49 #[target_feature(enable = "sse2")]
50 #[inline]
51 unsafe fn to_m128i(self) -> __m128i {
52 load_bytes(&self.into())
53 }
54}
55
56#[target_feature(enable = "sse2")]
61#[inline]
62unsafe fn load_bytes(bytes: &ByteArray) -> __m128i {
63 _mm_loadu_si128(bytes.as_ptr().cast())
64}
65
66#[target_feature(enable = "avx", enable = "pclmulqdq")]
71#[inline]
72pub(super) unsafe fn proc_block(
73 key: &ExpandedKey,
74 acc: FieldElement,
75 block: &Block,
76) -> FieldElement {
77 let data = load_bytes(&block.0);
78
79 let y = _mm_xor_si128(acc.to_m128i(), data);
81
82 FieldElement::from_m128i(gf128_mul_rf(y, key.h1.to_m128i(), key.d1.to_m128i()))
84}
85
86#[target_feature(enable = "avx", enable = "pclmulqdq")]
90#[inline]
91pub(super) unsafe fn proc_par_blocks(
92 key: &ExpandedKey,
93 acc: FieldElement,
94 par_blocks: &ParBlocks,
95) -> FieldElement {
96 let m0 = load_bytes(&par_blocks[0].0);
98 let m1 = load_bytes(&par_blocks[1].0);
99 let m2 = load_bytes(&par_blocks[2].0);
100 let m3 = load_bytes(&par_blocks[3].0);
101
102 let y0 = _mm_xor_si128(acc.to_m128i(), m0);
104
105 let (r0, f0) = rf_mul_unreduced(y0, key.h4.to_m128i(), key.d4.to_m128i());
107 let (r1, f1) = rf_mul_unreduced(m1, key.h3.to_m128i(), key.d3.to_m128i());
108 let (r2, f2) = rf_mul_unreduced(m2, key.h2.to_m128i(), key.d2.to_m128i());
109 let (r3, f3) = rf_mul_unreduced(m3, key.h1.to_m128i(), key.d1.to_m128i());
110
111 let r = _mm_xor_si128(_mm_xor_si128(r0, r1), _mm_xor_si128(r2, r3));
113 let f = _mm_xor_si128(_mm_xor_si128(f0, f1), _mm_xor_si128(f2, f3));
114
115 FieldElement::from_m128i(reduce_rf(r, f))
117}
118
119#[target_feature(enable = "avx", enable = "pclmulqdq")]
124pub(super) unsafe fn expand_key(h: &[u8; 16]) -> ExpandedKey {
125 let h1 = load_bytes(h);
126 let d1 = compute_d(h1);
127
128 let h2 = gf128_mul_rf(h1, h1, d1);
130 let d2 = compute_d(h2);
131
132 let h3 = gf128_mul_rf(h2, h1, d1);
133 let d3 = compute_d(h3);
134
135 let h4 = gf128_mul_rf(h2, h2, d2);
136 let d4 = compute_d(h4);
137
138 ExpandedKey {
139 h1: FieldElement::from_m128i(h1),
140 d1: FieldElement::from_m128i(d1),
141 h2: FieldElement::from_m128i(h2),
142 d2: FieldElement::from_m128i(d2),
143 h3: FieldElement::from_m128i(h3),
144 d3: FieldElement::from_m128i(d3),
145 h4: FieldElement::from_m128i(h4),
146 d4: FieldElement::from_m128i(d4),
147 }
148}
149
150#[target_feature(enable = "avx", enable = "pclmulqdq")]
154#[inline]
155unsafe fn compute_d(h: __m128i) -> __m128i {
156 #[allow(clippy::cast_possible_wrap)]
158 let p = _mm_set_epi64x(P1 as i64, 0);
159
160 let h_swap = _mm_shuffle_epi32(h, 0x4e);
162
163 let t = _mm_clmulepi64_si128(h, p, 0x10);
165
166 _mm_xor_si128(h_swap, t)
168}
169
170#[target_feature(enable = "avx", enable = "pclmulqdq")]
178#[inline]
179unsafe fn rf_mul_unreduced(m: __m128i, h: __m128i, d: __m128i) -> (__m128i, __m128i) {
180 let r0 = _mm_clmulepi64_si128(m, d, 0x10); let r1 = _mm_clmulepi64_si128(m, h, 0x11); let r = _mm_xor_si128(r0, r1);
184
185 let f0 = _mm_clmulepi64_si128(m, d, 0x00); let f1 = _mm_clmulepi64_si128(m, h, 0x01); let f = _mm_xor_si128(f0, f1);
189
190 (r, f)
191}
192
193#[target_feature(enable = "avx", enable = "pclmulqdq")]
197#[inline]
198unsafe fn reduce_rf(r: __m128i, f: __m128i) -> __m128i {
199 #[allow(clippy::cast_possible_wrap)]
201 let p1 = _mm_set_epi64x(0, P1 as i64);
202
203 let f1 = _mm_srli_si128(f, 8);
205
206 let f0_shifted = _mm_slli_si128(f, 8);
208
209 let p1_f0 = _mm_clmulepi64_si128(f, p1, 0x00);
211
212 let result = _mm_xor_si128(r, f1);
214 let result = _mm_xor_si128(result, f0_shifted);
215 _mm_xor_si128(result, p1_f0)
216}
217
218#[target_feature(enable = "avx", enable = "pclmulqdq")]
220#[inline]
221unsafe fn gf128_mul_rf(m: __m128i, h: __m128i, d: __m128i) -> __m128i {
222 let (r, f) = rf_mul_unreduced(m, h, d);
223 reduce_rf(r, f)
224}