Botan 3.9.0
Crypto and TLS for C&
simd_2x64.h
Go to the documentation of this file.
1/*
2* (C) 2022,2025 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#ifndef BOTAN_SIMD_2X64_H_
8#define BOTAN_SIMD_2X64_H_
9
10#include <botan/compiler.h>
11#include <botan/types.h>
12#include <botan/internal/isa_extn.h>
13#include <botan/internal/target_info.h>
14
15#if defined(BOTAN_TARGET_ARCH_SUPPORTS_SSSE3)
16 #include <emmintrin.h>
17 #include <tmmintrin.h>
18 #define BOTAN_SIMD_USE_SSSE3
19#endif
20
21namespace Botan {
22
23// NOLINTBEGIN(portability-simd-intrinsics)
24
25class SIMD_2x64 final {
26 public:
27 SIMD_2x64& operator=(const SIMD_2x64& other) = default;
28 SIMD_2x64(const SIMD_2x64& other) = default;
29
30 SIMD_2x64& operator=(SIMD_2x64&& other) = default;
31 SIMD_2x64(SIMD_2x64&& other) = default;
32
33 ~SIMD_2x64() = default;
34
35 // zero initialized
36 SIMD_2x64() : m_simd(_mm_setzero_si128()) {}
37
38 static SIMD_2x64 load_le(const void* in) {
39 return SIMD_2x64(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
40 }
41
42 static SIMD_2x64 load_be(const void* in) { return SIMD_2x64::load_le(in).bswap(); }
43
44 SIMD_2x64 BOTAN_FN_ISA_SIMD_2X64 bswap() const {
45 const auto idx = _mm_set_epi8(8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7);
46 return SIMD_2x64(_mm_shuffle_epi8(m_simd, idx));
47 }
48
49 void store_le(uint64_t out[2]) const { this->store_le(reinterpret_cast<uint8_t*>(out)); }
50
51 void store_le(uint8_t out[]) const { _mm_storeu_si128(reinterpret_cast<__m128i*>(out), m_simd); }
52
53 SIMD_2x64 operator+(const SIMD_2x64& other) const {
54 SIMD_2x64 retval(*this);
55 retval += other;
56 return retval;
57 }
58
59 SIMD_2x64 operator^(const SIMD_2x64& other) const {
60 SIMD_2x64 retval(*this);
61 retval ^= other;
62 return retval;
63 }
64
65 void operator+=(const SIMD_2x64& other) { m_simd = _mm_add_epi64(m_simd, other.m_simd); }
66
67 void operator^=(const SIMD_2x64& other) { m_simd = _mm_xor_si128(m_simd, other.m_simd); }
68
69 template <size_t ROT>
70 BOTAN_FN_ISA_SIMD_2X64 SIMD_2x64 rotr() const
71 requires(ROT > 0 && ROT < 64)
72 {
73 if constexpr(ROT == 8) {
74 auto tab = _mm_setr_epi8(1, 2, 3, 4, 5, 6, 7, 0, 9, 10, 11, 12, 13, 14, 15, 8);
75 return SIMD_2x64(_mm_shuffle_epi8(m_simd, tab));
76 } else if constexpr(ROT == 16) {
77 auto tab = _mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9);
78 return SIMD_2x64(_mm_shuffle_epi8(m_simd, tab));
79 } else if constexpr(ROT == 24) {
80 auto tab = _mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10);
81 return SIMD_2x64(_mm_shuffle_epi8(m_simd, tab));
82 } else if constexpr(ROT == 32) {
83 auto tab = _mm_setr_epi8(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
84 return SIMD_2x64(_mm_shuffle_epi8(m_simd, tab));
85 } else {
86 return SIMD_2x64(_mm_or_si128(_mm_srli_epi64(m_simd, static_cast<int>(ROT)),
87 _mm_slli_epi64(m_simd, static_cast<int>(64 - ROT))));
88 }
89 }
90
91 template <size_t ROT>
92 SIMD_2x64 rotl() const {
93 return this->rotr<64 - ROT>();
94 }
95
96 template <int SHIFT>
97 SIMD_2x64 shr() const noexcept {
98 return SIMD_2x64(_mm_srli_epi64(m_simd, SHIFT));
99 }
100
101 static SIMD_2x64 BOTAN_FN_ISA_SIMD_2X64 alignr8(const SIMD_2x64& a, const SIMD_2x64& b) {
102 return SIMD_2x64(_mm_alignr_epi8(a.m_simd, b.m_simd, 8));
103 }
104
105 // Argon2 specific operation
106 static void twist(SIMD_2x64& B0, SIMD_2x64& B1, SIMD_2x64& C0, SIMD_2x64& C1, SIMD_2x64& D0, SIMD_2x64& D1) {
107 auto T0 = SIMD_2x64::alignr8(B1, B0);
108 auto T1 = SIMD_2x64::alignr8(B0, B1);
109 B0 = T0;
110 B1 = T1;
111
112 T0 = C0;
113 C0 = C1;
114 C1 = T0;
115
116 T0 = SIMD_2x64::alignr8(D0, D1);
117 T1 = SIMD_2x64::alignr8(D1, D0);
118 D0 = T0;
119 D1 = T1;
120 }
121
122 // Argon2 specific operation
123 static void untwist(SIMD_2x64& B0, SIMD_2x64& B1, SIMD_2x64& C0, SIMD_2x64& C1, SIMD_2x64& D0, SIMD_2x64& D1) {
124 auto T0 = SIMD_2x64::alignr8(B0, B1);
125 auto T1 = SIMD_2x64::alignr8(B1, B0);
126 B0 = T0;
127 B1 = T1;
128
129 T0 = C0;
130 C0 = C1;
131 C1 = T0;
132
133 T0 = SIMD_2x64::alignr8(D1, D0);
134 T1 = SIMD_2x64::alignr8(D0, D1);
135 D0 = T0;
136 D1 = T1;
137 }
138
139 // Argon2 specific operation
141 const __m128i m = _mm_mul_epu32(x.m_simd, y.m_simd);
142 return SIMD_2x64(_mm_add_epi64(m, m));
143 }
144
145 explicit SIMD_2x64(__m128i x) : m_simd(x) {}
146
147 private:
148 __m128i m_simd;
149};
150
151// NOLINTEND(portability-simd-intrinsics)
152
153} // namespace Botan
154
155#endif
void operator+=(const SIMD_2x64 &other)
Definition simd_2x64.h:65
void operator^=(const SIMD_2x64 &other)
Definition simd_2x64.h:67
SIMD_2x64 & operator=(const SIMD_2x64 &other)=default
SIMD_2x64(const SIMD_2x64 &other)=default
SIMD_2x64(SIMD_2x64 &&other)=default
static void untwist(SIMD_2x64 &B0, SIMD_2x64 &B1, SIMD_2x64 &C0, SIMD_2x64 &C1, SIMD_2x64 &D0, SIMD_2x64 &D1)
Definition simd_2x64.h:123
SIMD_2x64 operator^(const SIMD_2x64 &other) const
Definition simd_2x64.h:59
void store_le(uint8_t out[]) const
Definition simd_2x64.h:51
static void twist(SIMD_2x64 &B0, SIMD_2x64 &B1, SIMD_2x64 &C0, SIMD_2x64 &C1, SIMD_2x64 &D0, SIMD_2x64 &D1)
Definition simd_2x64.h:106
~SIMD_2x64()=default
static SIMD_2x64 load_le(const void *in)
Definition simd_2x64.h:38
static SIMD_2x64 load_be(const void *in)
Definition simd_2x64.h:42
void store_le(uint64_t out[2]) const
Definition simd_2x64.h:49
SIMD_2x64 shr() const noexcept
Definition simd_2x64.h:97
SIMD_2x64(__m128i x)
Definition simd_2x64.h:145
SIMD_2x64 & operator=(SIMD_2x64 &&other)=default
static SIMD_2x64 mul2_32(SIMD_2x64 x, SIMD_2x64 y)
Definition simd_2x64.h:140
SIMD_2x64 rotl() const
Definition simd_2x64.h:92
static SIMD_2x64 BOTAN_FN_ISA_SIMD_2X64 alignr8(const SIMD_2x64 &a, const SIMD_2x64 &b)
Definition simd_2x64.h:101
SIMD_2x64 BOTAN_FN_ISA_SIMD_2X64 bswap() const
Definition simd_2x64.h:44
SIMD_2x64 operator+(const SIMD_2x64 &other) const
Definition simd_2x64.h:53
BOTAN_FN_ISA_SIMD_2X64 SIMD_2x64 rotr() const
Definition simd_2x64.h:70