1#![allow(
2 unused,
3 reason = "APIs that allow switching cores in code are not exposed to the public API, yet"
4)]
5
6#[cfg(target_arch = "x86_64")]
7pub(crate) mod x86_64;
8
9use generic_array::{
10 ArrayLength, GenericArray,
11 sequence::GenericSequence,
12 typenum::{IsLessOrEqual, U1, U2},
13};
14
15#[cfg(feature = "portable-simd")]
16#[allow(unused_imports)]
17use core::simd::{Swizzle as _, num::SimdUint, u32x4, u32x8, u32x16};
18
19#[allow(
20 unused_imports,
21 reason = "rust-analyzer doesn't consider -Ctarget-feature, silencing warnings"
22)]
23use crate::{
24 Align64,
25 simd::{Compose, ConcatLo, ExtractU32x2, FlipTable16, Inverse, Swizzle},
26};
27
28macro_rules! quarter_words {
29 ($w:expr, $a:literal, $b:literal, $c:literal, $d:literal) => {
30 $w[$b] ^= $w[$a].wrapping_add($w[$d]).rotate_left(7);
31 $w[$c] ^= $w[$b].wrapping_add($w[$a]).rotate_left(9);
32 $w[$d] ^= $w[$c].wrapping_add($w[$b]).rotate_left(13);
33 $w[$a] ^= $w[$d].wrapping_add($w[$c]).rotate_left(18);
34 };
35}
36
37struct Pivot;
39
40impl Swizzle<16> for Pivot {
41 const INDEX: [usize; 16] = [0, 5, 10, 15, 4, 9, 14, 3, 12, 1, 6, 11, 8, 13, 2, 7];
42}
43
44#[allow(unused, reason = "rust-analyzer spam, actually used")]
46struct RoundShuffleAbdc;
47
48impl Swizzle<16> for RoundShuffleAbdc {
49 const INDEX: [usize; 16] = const {
50 let mut index = [0; 16];
51 let mut i = 0;
52 while i < 4 {
53 index[i] = i;
54 i += 1;
55 }
56 while i < 8 {
57 index[i] = 8 + (i + 1) % 4;
58 i += 1;
59 }
60 while i < 12 {
61 index[i] = 4 + (i + 3) % 4;
62 i += 1;
63 }
64 while i < 16 {
65 index[i] = 12 + (i + 2) % 4;
66 i += 1;
67 }
68 index
69 };
70}
71
72#[cfg(feature = "portable-simd")]
73impl core::simd::Swizzle<16> for Pivot {
74 const INDEX: [usize; 16] = <Self as Swizzle<16>>::INDEX;
75}
76
77pub trait BlockType: Clone + Copy {
79 unsafe fn read_from_ptr(ptr: *const Self) -> Self;
81 unsafe fn write_to_ptr(self, ptr: *mut Self);
83 fn xor_with(&mut self, other: Self);
85}
86
87#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
88impl BlockType for core::arch::x86_64::__m512i {
89 #[inline(always)]
90 unsafe fn read_from_ptr(ptr: *const Self) -> Self {
91 unsafe { core::ptr::read(ptr.cast()) }
92 }
93 #[inline(always)]
94 unsafe fn write_to_ptr(self, ptr: *mut Self) {
95 unsafe { core::ptr::write(ptr.cast(), self) }
96 }
97 #[inline(always)]
98 fn xor_with(&mut self, other: Self) {
99 use core::arch::x86_64::*;
100 unsafe {
101 *self = _mm512_xor_si512(*self, other);
102 }
103 }
104}
105
106#[cfg(target_arch = "x86_64")]
107impl BlockType for [core::arch::x86_64::__m256i; 2] {
108 #[inline(always)]
109 unsafe fn read_from_ptr(ptr: *const Self) -> Self {
110 unsafe { core::ptr::read(ptr) }
111 }
112 #[inline(always)]
113 unsafe fn write_to_ptr(self, ptr: *mut Self) {
114 unsafe { core::ptr::write(ptr, self) };
115 }
116 #[inline(always)]
117 fn xor_with(&mut self, other: Self) {
118 use core::arch::x86_64::*;
119 unsafe {
120 self[0] = _mm256_xor_si256(self[0], other[0]);
121 self[1] = _mm256_xor_si256(self[1], other[1]);
122 }
123 }
124}
125
126#[cfg(target_arch = "x86_64")]
127impl BlockType for [core::arch::x86_64::__m128i; 4] {
128 #[inline(always)]
129 unsafe fn read_from_ptr(ptr: *const Self) -> Self {
130 unsafe { core::ptr::read(ptr) }
131 }
132 #[inline(always)]
133 unsafe fn write_to_ptr(self, ptr: *mut Self) {
134 unsafe { core::ptr::write(ptr, self) };
135 }
136 #[inline(always)]
137 fn xor_with(&mut self, other: Self) {
138 use core::arch::x86_64::*;
139 unsafe {
140 self[0] = _mm_xor_si128(self[0], other[0]);
141 self[1] = _mm_xor_si128(self[1], other[1]);
142 self[2] = _mm_xor_si128(self[2], other[2]);
143 self[3] = _mm_xor_si128(self[3], other[3]);
144 }
145 }
146}
147
148impl BlockType for Align64<[u32; 16]> {
149 unsafe fn read_from_ptr(ptr: *const Self) -> Self {
150 unsafe { ptr.read() }
151 }
152 unsafe fn write_to_ptr(mut self, ptr: *mut Self) {
153 unsafe { ptr.write(self) }
154 }
155 fn xor_with(&mut self, other: Self) {
156 for i in 0..16 {
157 self.0[i] ^= other.0[i];
158 }
159 }
160}
161
162#[cfg(feature = "portable-simd")]
163impl BlockType for core::simd::u32x16 {
164 unsafe fn read_from_ptr(ptr: *const Self) -> Self {
165 unsafe { ptr.read() }
166 }
167 unsafe fn write_to_ptr(self, ptr: *mut Self) {
168 unsafe { ptr.write(self) }
169 }
170 fn xor_with(&mut self, other: Self) {
171 *self ^= other;
172 }
173}
174
175pub trait Salsa20 {
177 type Lanes: ArrayLength;
179 type Block: BlockType;
181
182 fn shuffle_in(_ptr: &mut Align64<[u32; 16]>) {}
184
185 fn shuffle_out(_ptr: &mut Align64<[u32; 16]>) {}
187
188 fn read(ptr: GenericArray<&Self::Block, Self::Lanes>) -> Self;
190 fn write(&self, ptr: GenericArray<&mut Self::Block, Self::Lanes>);
194 fn keystream<const ROUND_PAIRS: usize>(&mut self);
196}
197
198#[allow(unused, reason = "Currently unused, but handy for testing")]
200pub struct BlockScalar<Lanes: ArrayLength> {
201 w: GenericArray<[u32; 16], Lanes>,
202}
203
204impl<Lanes: ArrayLength> Salsa20 for BlockScalar<Lanes> {
205 type Lanes = Lanes;
206 type Block = Align64<[u32; 16]>;
207
208 #[cfg(target_endian = "big")]
209 fn shuffle_in(ptr: &mut Align64<[u32; 16]>) {
210 for i in 0..16 {
211 ptr.0[i] = ptr.0[i].swap_bytes();
212 }
213 }
214
215 #[cfg(target_endian = "big")]
216 fn shuffle_out(ptr: &mut Align64<[u32; 16]>) {
217 for i in 0..16 {
218 ptr.0[i] = ptr.0[i].swap_bytes();
219 }
220 }
221
222 #[inline(always)]
223 fn read(ptr: GenericArray<&Self::Block, Lanes>) -> Self {
224 Self {
225 w: GenericArray::generate(|i| **ptr[i]),
226 }
227 }
228
229 #[inline(always)]
230 fn write(&self, mut ptr: GenericArray<&mut Self::Block, Lanes>) {
231 for i in 0..Lanes::USIZE {
232 for j in 0..16 {
233 ptr[i][j] = self.w[i][j];
234 }
235 }
236 }
237
238 fn keystream<const ROUND_PAIRS: usize>(&mut self) {
239 let mut w = self.w.clone();
240
241 for _ in 0..ROUND_PAIRS {
242 for i in 0..Lanes::USIZE {
243 quarter_words!(w[i], 0, 4, 8, 12);
244 quarter_words!(w[i], 5, 9, 13, 1);
245 quarter_words!(w[i], 10, 14, 2, 6);
246 quarter_words!(w[i], 15, 3, 7, 11);
247
248 quarter_words!(w[i], 0, 1, 2, 3);
249 quarter_words!(w[i], 5, 6, 7, 4);
250 quarter_words!(w[i], 10, 11, 8, 9);
251 quarter_words!(w[i], 15, 12, 13, 14);
252 }
253 }
254
255 for i in 0..Lanes::USIZE {
256 for j in 0..16 {
257 self.w[i][j] = self.w[i][j].wrapping_add(w[i][j]);
258 }
259 }
260 }
261}
262
263#[cfg(feature = "portable-simd")]
264pub struct BlockPortableSimd {
266 a: u32x4,
267 b: u32x4,
268 c: u32x4,
269 d: u32x4,
270}
271
272#[cfg(feature = "portable-simd")]
273#[inline(always)]
274fn simd_rotate_left<const N: usize, const D: u32>(
275 x: core::simd::Simd<u32, N>,
276) -> core::simd::Simd<u32, N>
277where
278 core::simd::LaneCount<N>: core::simd::SupportedLaneCount,
279{
280 let shifted = x << D;
281 let shifted2 = x >> (32 - D);
282 shifted | shifted2
283}
284
285#[cfg(feature = "portable-simd")]
286impl Salsa20 for BlockPortableSimd {
287 type Lanes = U1;
288 type Block = u32x16;
289
290 #[inline(always)]
291 fn shuffle_in(ptr: &mut Align64<[u32; 16]>) {
292 let pivoted = Pivot::swizzle(u32x16::from_array(ptr.0));
293
294 #[cfg(target_endian = "big")]
295 let pivoted = pivoted.swap_bytes();
296
297 ptr.0 = *pivoted.as_array();
298 }
299
300 #[inline(always)]
301 fn shuffle_out(ptr: &mut Align64<[u32; 16]>) {
302 let pivoted = Inverse::<_, Pivot>::swizzle(u32x16::from_array(ptr.0));
303
304 #[cfg(target_endian = "big")]
305 let pivoted = pivoted.swap_bytes();
306
307 ptr.0 = *pivoted.as_array();
308 }
309
310 #[inline(always)]
311 fn read(ptr: GenericArray<&Self::Block, U1>) -> Self {
312 let a = ptr[0].extract::<0, 4>();
313 let b = ptr[0].extract::<4, 4>();
314 let d = ptr[0].extract::<8, 4>();
315 let c = ptr[0].extract::<12, 4>();
316
317 Self { a, b, c, d }
318 }
319
320 #[inline(always)]
321 fn write(&self, mut ptr: GenericArray<&mut Self::Block, U1>) {
322 use crate::simd::Identity;
323
324 let ab = Identity::<8>::concat_swizzle(self.a, self.b);
326 let dc = Identity::<8>::concat_swizzle(self.d, self.c);
327 let abdc = Identity::<16>::concat_swizzle(ab, dc);
328
329 *ptr[0] += abdc;
330 }
331
332 #[inline(always)]
333 fn keystream<const ROUND_PAIRS: usize>(&mut self) {
334 if ROUND_PAIRS == 0 {
335 return;
336 }
337
338 for _ in 0..(ROUND_PAIRS * 2) {
339 self.b ^= simd_rotate_left::<_, 7>(self.a + self.d);
340 self.c ^= simd_rotate_left::<_, 9>(self.b + self.a);
341 self.d ^= simd_rotate_left::<_, 13>(self.c + self.b);
342 self.a ^= simd_rotate_left::<_, 18>(self.d + self.c);
343
344 self.d = self.d.rotate_elements_left::<1>();
345 self.c = self.c.rotate_elements_left::<2>();
346 self.b = self.b.rotate_elements_left::<3>();
347 (self.b, self.d) = (self.d, self.b);
348 }
349 }
350}
351
352#[cfg(feature = "portable-simd")]
353pub struct BlockPortableSimd2 {
355 a: u32x8,
356 b: u32x8,
357 c: u32x8,
358 d: u32x8,
359}
360
361#[cfg(feature = "portable-simd")]
362impl Salsa20 for BlockPortableSimd2 {
363 type Lanes = U2;
364 type Block = u32x16;
365
366 #[inline(always)]
367 fn shuffle_in(ptr: &mut Align64<[u32; 16]>) {
368 BlockPortableSimd::shuffle_in(ptr);
369 }
370
371 #[inline(always)]
372 fn shuffle_out(ptr: &mut Align64<[u32; 16]>) {
373 BlockPortableSimd::shuffle_out(ptr);
374 }
375
376 #[inline(always)]
377 fn read(ptr: GenericArray<&Self::Block, U2>) -> Self {
378 let buffer0_ab = core::simd::simd_swizzle!(*ptr[0], [0, 1, 2, 3, 4, 5, 6, 7]);
379 let buffer0_dc = core::simd::simd_swizzle!(*ptr[0], [8, 9, 10, 11, 12, 13, 14, 15]);
380 let buffer1_ab = core::simd::simd_swizzle!(*ptr[1], [0, 1, 2, 3, 4, 5, 6, 7]);
381 let buffer1_dc = core::simd::simd_swizzle!(*ptr[1], [8, 9, 10, 11, 12, 13, 14, 15]);
382
383 let a = core::simd::simd_swizzle!(buffer0_ab, buffer1_ab, [0, 1, 2, 3, 8, 9, 10, 11]);
384 let b = core::simd::simd_swizzle!(buffer0_ab, buffer1_ab, [4, 5, 6, 7, 12, 13, 14, 15]);
385 let d = core::simd::simd_swizzle!(buffer0_dc, buffer1_dc, [0, 1, 2, 3, 8, 9, 10, 11]);
386 let c = core::simd::simd_swizzle!(buffer0_dc, buffer1_dc, [4, 5, 6, 7, 12, 13, 14, 15]);
387
388 Self { a, b, c, d }
389 }
390
391 #[inline(always)]
392 fn write(&self, mut ptr: GenericArray<&mut Self::Block, U2>) {
393 use crate::simd::Identity;
394
395 let a0b0 = core::simd::simd_swizzle!(self.a, self.b, [0, 1, 2, 3, 8, 9, 10, 11]);
399 let a1b1 = core::simd::simd_swizzle!(self.a, self.b, [4, 5, 6, 7, 12, 13, 14, 15]);
400 let d0c0 = core::simd::simd_swizzle!(self.d, self.c, [0, 1, 2, 3, 8, 9, 10, 11]);
401 let d1c1 = core::simd::simd_swizzle!(self.d, self.c, [4, 5, 6, 7, 12, 13, 14, 15]);
402
403 *ptr[0] += Identity::<16>::concat_swizzle(a0b0, d0c0);
404 *ptr[1] += Identity::<16>::concat_swizzle(a1b1, d1c1);
405 }
406
407 #[inline(always)]
408 fn keystream<const ROUND_PAIRS: usize>(&mut self) {
409 if ROUND_PAIRS == 0 {
410 return;
411 }
412
413 for _ in 0..(ROUND_PAIRS * 2) {
414 self.b ^= simd_rotate_left::<_, 7>(self.a + self.d);
415 self.c ^= simd_rotate_left::<_, 9>(self.b + self.a);
416 self.d ^= simd_rotate_left::<_, 13>(self.c + self.b);
417 self.a ^= simd_rotate_left::<_, 18>(self.d + self.c);
418
419 self.d = core::simd::simd_swizzle!(self.d, [1, 2, 3, 0, 5, 6, 7, 4]);
420 self.c = core::simd::simd_swizzle!(self.c, [2, 3, 0, 1, 6, 7, 4, 5]);
421 self.b = core::simd::simd_swizzle!(self.b, [3, 0, 1, 2, 7, 4, 5, 6]);
422 (self.b, self.d) = (self.d, self.b);
423 }
424 }
425}
426
427#[cfg(test)]
428#[allow(unused_imports)]
429mod tests {
430 use generic_array::{
431 GenericArray,
432 typenum::{U1, U4, U5, U10},
433 };
434 use salsa20::cipher::StreamCipherCore;
435 use sha2::digest::generic_array::GenericArray as RcGenericArray;
436
437 use super::*;
438
439 pub(crate) fn test_shuffle_in_out_identity<S: Salsa20>()
440 where
441 S::Block: BlockType,
442 {
443 fn lfsr(x: &mut u32) -> u32 {
444 *x = *x ^ (*x >> 2);
445 *x = *x ^ (*x >> 3);
446 *x = *x ^ (*x >> 5);
447 *x
448 }
449
450 let mut state = 0;
451
452 for _ in 0..5 {
453 let test_input = Align64(core::array::from_fn(|i| lfsr(&mut state) + i as u32));
454
455 let mut result = test_input.clone();
456 S::shuffle_in(&mut result);
457 S::shuffle_out(&mut result);
458 assert_eq!(result, test_input);
459 }
460 }
461
462 fn test_scalar_keystream_against_reference<
463 RoundPairs: ArrayLength,
464 const ROUND_PAIRS: usize,
465 >() {
466 type Reference<RoundPairs> = ::salsa20::SalsaCore<RoundPairs>;
467
468 let mut raw_state0 = [0u32; 16];
469 raw_state0[0] = u32::from_be_bytes([b'e', b'x', b'p', b'a']);
470 raw_state0[4 + 1] = u32::from_be_bytes([b'n', b'd', b' ', b'3']);
471 raw_state0[8 + 2] = u32::from_be_bytes([b'2', b'-', b'b', b'y']);
472 raw_state0[12 + 3] = u32::from_be_bytes([b't', b'e', b' ', b'k']);
473 let mut raw_state1 = raw_state0.clone();
474 raw_state1[1] = 0xff;
475
476 let mut feedback0 = raw_state0.clone();
477 let mut feedback1 = raw_state1.clone();
478 for _rep in 0..32 {
479 let mut reference_state = Reference::<RoundPairs>::from_raw_state(raw_state0);
480 let mut output = RcGenericArray::default();
481 reference_state.write_keystream_block(&mut output);
482 let mut expected0 = [0u32; 16];
483 for i in 0..16 {
484 expected0[i] = u32::from_le_bytes(output[i * 4..][..4].try_into().unwrap());
485 }
486 reference_state = Reference::<RoundPairs>::from_raw_state(raw_state1);
487 reference_state.write_keystream_block(&mut output);
488 let mut expected1 = [0u32; 16];
489 for i in 0..16 {
490 expected1[i] = u32::from_le_bytes(output[i * 4..][..4].try_into().unwrap());
491 }
492
493 let mut shuffled_state0 = Align64(raw_state0.clone());
494 BlockScalar::<U1>::shuffle_in(&mut shuffled_state0);
495
496 let mut state = BlockScalar::<U1>::read(GenericArray::from_array([&shuffled_state0]));
497 state.keystream::<ROUND_PAIRS>();
498 state.write(GenericArray::from_array([&mut shuffled_state0]));
499 BlockScalar::<U1>::shuffle_out(&mut shuffled_state0);
500
501 assert_eq!(*shuffled_state0, expected0);
502
503 shuffled_state0 = Align64(raw_state0.clone());
504 let mut shuffled_state1 = Align64(raw_state1.clone());
505 BlockScalar::<U1>::shuffle_in(&mut shuffled_state1);
506 let mut state = BlockScalar::<U2>::read(GenericArray::from_array([
507 &shuffled_state1,
508 &shuffled_state0,
509 ]));
510 state.keystream::<ROUND_PAIRS>();
511 state.write(GenericArray::from_array([
512 &mut shuffled_state1,
513 &mut shuffled_state0,
514 ]));
515 BlockScalar::<U2>::shuffle_out(&mut shuffled_state0);
516 BlockScalar::<U2>::shuffle_out(&mut shuffled_state1);
517
518 assert_eq!(*shuffled_state0, expected0);
519 assert_eq!(*shuffled_state1, expected1);
520
521 for i in 0..16 {
522 raw_state0[i] = feedback0[i].wrapping_add(expected0[i]);
523 raw_state1[i] = feedback1[i].wrapping_add(expected1[i]);
524 }
525 feedback0 = expected1;
526 feedback1 = expected0;
527 }
528 }
529
530 #[cfg(feature = "portable-simd")]
531 fn test_keystream_portable_simd<const ROUND_PAIRS: usize>() {
532 test_shuffle_in_out_identity::<BlockPortableSimd>();
533
534 let test_input: Align64<[u32; 16]> = Align64(core::array::from_fn(|i| i as u32));
535 let mut expected = test_input.clone();
536
537 let mut test_input_scalar_shuffled = test_input.clone();
538 BlockScalar::<U1>::shuffle_in(&mut test_input_scalar_shuffled);
539 let mut block =
540 BlockScalar::<U1>::read(GenericArray::from_array([&test_input_scalar_shuffled]));
541 block.keystream::<ROUND_PAIRS>();
542 block.write(GenericArray::from_array([&mut expected]));
543 BlockScalar::<U1>::shuffle_out(&mut expected);
544
545 let mut test_input_shuffled = test_input.clone();
546
547 BlockPortableSimd::shuffle_in(&mut test_input_shuffled);
548 let mut result = u32x16::from_array(*test_input_shuffled);
549
550 let mut block_v = BlockPortableSimd::read(GenericArray::from_array([&result]));
551 block_v.keystream::<ROUND_PAIRS>();
552 block_v.write(GenericArray::from_array([&mut result]));
553
554 let mut output = Align64(result.to_array());
555 BlockPortableSimd::shuffle_out(&mut output);
556
557 assert_eq!(output, expected);
558 }
559
560 #[cfg(feature = "portable-simd")]
561 fn test_keystream_portable_simd2<const ROUND_PAIRS: usize>() {
562 test_shuffle_in_out_identity::<BlockPortableSimd2>();
563
564 let test_input0: Align64<[u32; 16]> = Align64(core::array::from_fn(|i| i as u32));
565 let test_input1: Align64<[u32; 16]> = Align64(core::array::from_fn(|i| i as u32 + 16));
566 let mut expected0 = test_input0.clone();
567 let mut expected1 = test_input1.clone();
568
569 let mut test_input0_scalar_shuffled = test_input0.clone();
570 let mut test_input1_scalar_shuffled = test_input1.clone();
571 BlockScalar::<U1>::shuffle_in(&mut test_input0_scalar_shuffled);
572 BlockScalar::<U1>::shuffle_in(&mut test_input1_scalar_shuffled);
573
574 let mut block0 =
575 BlockScalar::<U1>::read(GenericArray::from_array([&test_input0_scalar_shuffled]));
576 let mut block1 =
577 BlockScalar::<U1>::read(GenericArray::from_array([&test_input1_scalar_shuffled]));
578 block0.keystream::<ROUND_PAIRS>();
579 block1.keystream::<ROUND_PAIRS>();
580 block0.write(GenericArray::from_array([&mut expected0]));
581 block1.write(GenericArray::from_array([&mut expected1]));
582 BlockScalar::<U1>::shuffle_out(&mut expected0);
583 BlockScalar::<U1>::shuffle_out(&mut expected1);
584
585 let mut test_input0_shuffled = test_input0.clone();
586 let mut test_input1_shuffled = test_input1.clone();
587 BlockPortableSimd2::shuffle_in(&mut test_input0_shuffled);
588 BlockPortableSimd2::shuffle_in(&mut test_input1_shuffled);
589
590 let mut result0 = u32x16::from_array(*test_input0_shuffled);
591 let mut result1 = u32x16::from_array(*test_input1_shuffled);
592
593 let mut block_v0 = BlockPortableSimd2::read(GenericArray::from_array([&result0, &result1]));
594 block_v0.keystream::<ROUND_PAIRS>();
595 block_v0.write(GenericArray::from_array([&mut result0, &mut result1]));
596
597 let mut output0 = Align64(result0.to_array());
598 let mut output1 = Align64(result1.to_array());
599
600 BlockPortableSimd2::shuffle_out(&mut output0);
601 BlockPortableSimd2::shuffle_out(&mut output1);
602
603 assert_eq!(output0, expected0);
604 assert_eq!(output1, expected1);
605 }
606
607 #[test]
608 fn test_scalar_keystream_against_reference_2() {
609 test_scalar_keystream_against_reference::<U1, 1>();
610 }
611
612 #[test]
613 fn test_scalar_keystream_against_reference_8() {
614 test_scalar_keystream_against_reference::<U4, 4>();
615 }
616
617 #[test]
618 fn test_scalar_keystream_against_reference_10() {
619 test_scalar_keystream_against_reference::<U5, 5>();
620 }
621
622 #[test]
623 fn test_scalar_keystream_against_reference_20() {
624 test_scalar_keystream_against_reference::<U10, 10>();
625 }
626
627 #[cfg(feature = "portable-simd")]
628 #[test]
629 fn test_keystream_portable_simd_0() {
630 test_keystream_portable_simd::<0>();
631 }
632
633 #[cfg(feature = "portable-simd")]
634 #[test]
635 fn test_keystream_portable_simd_2() {
636 test_keystream_portable_simd::<1>();
637 }
638
639 #[cfg(feature = "portable-simd")]
640 #[test]
641 fn test_keystream_portable_simd_8() {
642 test_keystream_portable_simd::<4>();
643 }
644
645 #[cfg(feature = "portable-simd")]
646 #[test]
647 fn test_keystream_portable_simd_10() {
648 test_keystream_portable_simd::<5>();
649 }
650
651 #[cfg(feature = "portable-simd")]
652 #[test]
653 fn test_keystream_portable_simd2_0() {
654 test_keystream_portable_simd2::<0>();
655 }
656
657 #[cfg(feature = "portable-simd")]
658 #[test]
659 fn test_keystream_portable_simd2_2() {
660 test_keystream_portable_simd2::<1>();
661 }
662
663 #[cfg(feature = "portable-simd")]
664 #[test]
665 fn test_keystream_portable_simd2_8() {
666 test_keystream_portable_simd2::<4>();
667 }
668
669 #[cfg(feature = "portable-simd")]
670 #[test]
671 fn test_keystream_portable_simd2_10() {
672 test_keystream_portable_simd2::<5>();
673 }
674}