3#include "constant_lanes.h"
5namespace native::detail::arm_constant {
6 constexpr std::uint8_t aes_product(std::uint8_t a, std::uint8_t b)
noexcept {
8 for (
unsigned bit = 0; bit < 8; ++bit) {
9 if (b & (1u << bit)) product ^= a;
10 a =
static_cast<std::uint8_t
>((a << 1) ^ ((a & 0x80) ? 0x11b : 0));
12 return static_cast<std::uint8_t
>(product);
15 constexpr std::uint8_t aes_inverse(std::uint8_t a)
noexcept {
17 auto result = std::uint8_t{1};
18 for (
unsigned exponent = 254; exponent; exponent >>= 1) {
19 if (exponent & 1) result = aes_product(result, a);
20 a = aes_product(a, a);
25 template<
bool Inverse>
constexpr std::uint8_t aes_substitute(std::uint8_t a)
noexcept {
26 if constexpr (Inverse)
27 return aes_inverse(
static_cast<std::uint8_t
>(std::rotl(a, 1) ^ std::rotl(a, 3) ^ std::rotl(a, 6) ^ 5));
29 auto x = aes_inverse(a);
30 return static_cast<std::uint8_t
>(x ^ std::rotl(x, 1) ^ std::rotl(x, 2) ^ std::rotl(x, 3) ^ std::rotl(x, 4) ^ 0x63);
34 template<
bool Inverse,
class V>
constexpr V aes_round(V state, V key)
noexcept {
35 auto a = lanes(state), k = lanes(key), result = a;
36 for (
unsigned col = 0; col < 4; ++col)
for (
unsigned row = 0; row < 4; ++row) {
37 unsigned source = 4 * ((col + (Inverse ? 4 - row : row)) % 4) + row;
38 result[4 * col + row] = aes_substitute<Inverse>(a[source] ^ k[source]);
40 return pack<V>(result);
43 template<
bool Inverse,
class V>
constexpr V aes_mix(V state)
noexcept {
44 auto a = lanes(state), result = a;
45 constexpr std::uint8_t coefficients[2][4]{{2, 3, 1, 1}, {14, 11, 13, 9}};
46 for (
unsigned col = 0; col < 4; ++col)
for (
unsigned row = 0; row < 4; ++row) {
47 result[4 * col + row] = 0;
48 for (
unsigned term = 0; term < 4; ++term)
49 result[4 * col + row] ^= aes_product(a[4 * col + term], coefficients[Inverse][(term + 4 - row) % 4]);
51 return pack<V>(result);
54 template<
class R,
unsigned Offset,
class V>
constexpr R pmull_bytes(V a, V b)
noexcept {
55 auto x = lanes(a), y = lanes(b);
56 std::array<std::uint16_t, 8> result{};
57 for (
unsigned i = 0; i < 8; ++i)
for (
unsigned bit = 0; bit < 8; ++bit)
58 if ((y[i + Offset] >> bit) & 1) result[i] ^=
static_cast<std::uint16_t
>(x[i + Offset]) << bit;
59 return pack<R>(result);
62 template<
class T>
constexpr T choose(T a, T b, T c)
noexcept {
return c ^ (a & (b ^ c)); }
63 template<
class T>
constexpr T majority(T a, T b, T c)
noexcept {
return (a & b) | (c & (a | b)); }
64 template<
int Mode,
class V>
constexpr V sha1_rounds(V state, std::uint32_t e, V message)
noexcept {
65 auto a = lanes(state), w = lanes(message);
66 for (
unsigned i = 0; i < 4; ++i) {
67 auto f = Mode == 0 ? choose(a[1], a[2], a[3]) : Mode == 1 ? a[1] ^ a[2] ^ a[3] : majority(a[1], a[2], a[3]);
68 auto next = std::rotl(a[0], 5) + f + e + w[i];
69 e = a[3]; a[3] = a[2]; a[2] = std::rotl(a[1], 30); a[1] = a[0]; a[0] = next;
73 template<
class V>
constexpr V sha1su0(V x, V y, V z)
noexcept {
74 auto a = lanes(x), b = lanes(y), c = lanes(z);
75 return pack<V>(std::array{a[0] ^ a[2] ^ c[0], a[1] ^ a[3] ^ c[1], a[2] ^ b[0] ^ c[2], a[3] ^ b[1] ^ c[3]});
77 template<
class V>
constexpr V sha1su1(V x, V y)
noexcept {
78 auto a = lanes(x), b = lanes(y);
79 auto first = std::rotl(a[0] ^ b[1], 1);
80 return pack<V>(std::array{first, std::rotl(a[1] ^ b[2], 1), std::rotl(a[2] ^ b[3], 1), std::rotl(a[3] ^ first, 1)});
82 constexpr std::uint32_t small0(std::uint32_t x)
noexcept {
return std::rotr(x, 7) ^ std::rotr(x, 18) ^ (x >> 3); }
83 constexpr std::uint32_t small1(std::uint32_t x)
noexcept {
return std::rotr(x, 17) ^ std::rotr(x, 19) ^ (x >> 10); }
84 constexpr std::uint64_t small0(std::uint64_t x)
noexcept {
return std::rotr(x, 1) ^ std::rotr(x, 8) ^ (x >> 7); }
85 constexpr std::uint64_t small1(std::uint64_t x)
noexcept {
return std::rotr(x, 19) ^ std::rotr(x, 61) ^ (x >> 6); }
86 constexpr std::uint32_t big0(std::uint32_t x)
noexcept {
return std::rotr(x, 2) ^ std::rotr(x, 13) ^ std::rotr(x, 22); }
87 constexpr std::uint32_t big1(std::uint32_t x)
noexcept {
return std::rotr(x, 6) ^ std::rotr(x, 11) ^ std::rotr(x, 25); }
88 constexpr std::uint64_t big0(std::uint64_t x)
noexcept {
return std::rotr(x, 28) ^ std::rotr(x, 34) ^ std::rotr(x, 39); }
89 constexpr std::uint64_t big1(std::uint64_t x)
noexcept {
return std::rotr(x, 14) ^ std::rotr(x, 18) ^ std::rotr(x, 41); }
90 template<
bool Second,
class V>
constexpr V sha256_rounds(V first, V second, V message)
noexcept {
91 auto x = lanes(Second ? second : first), y = lanes(Second ? first : second), w = lanes(message);
92 for (
unsigned i = 0; i < 4; ++i) {
93 auto t = y[3] + big1(y[0]) + choose(y[0], y[1], y[2]) + w[i];
94 auto next = t + big0(x[0]) + majority(x[0], x[1], x[2]);
95 y = {x[3] + t, y[0], y[1], y[2]};
96 x = {next, x[0], x[1], x[2]};
98 return pack<V>(Second ? y : x);
100 template<
class V>
constexpr V sha256su0(V x, V y)
noexcept {
101 auto a = lanes(x), b = lanes(y);
102 return pack<V>(std::array{a[0] + small0(a[1]), a[1] + small0(a[2]), a[2] + small0(a[3]), a[3] + small0(b[0])});
104 template<
class V>
constexpr V sha256su1(V x, V y, V z)
noexcept {
105 auto a = lanes(x), b = lanes(y), c = lanes(z);
106 a[0] += b[1] + small1(c[2]); a[1] += b[2] + small1(c[3]);
107 a[2] += b[3] + small1(a[0]); a[3] += c[0] + small1(a[1]);
110 template<
class V>
constexpr V sha512h(V x, V y, V z)
noexcept {
111 auto a = lanes(x), b = lanes(y), c = lanes(z);
112 a[1] += big1(c[1]) + choose(c[1], b[0], b[1]);
113 auto e = a[1] + c[0];
114 a[0] += big1(e) + choose(e, c[1], b[0]);
117 template<
class V>
constexpr V sha512h2(V x, V y, V z)
noexcept {
118 auto a = lanes(x), b = lanes(y), c = lanes(z);
119 a[1] += big0(c[0]) + majority(c[0], c[1], b[0]);
120 a[0] += big0(a[1]) + majority(a[1], c[0], c[1]);
123 template<
class V>
constexpr V sha512su0(V x, V y)
noexcept {
124 auto a = lanes(x), b = lanes(y);
125 return pack<V>(std::array{a[0] + small0(a[1]), a[1] + small0(b[0])});
127 template<
class V>
constexpr V sha512su1(V x, V y, V z)
noexcept {
128 auto a = lanes(x), b = lanes(y), c = lanes(z);
129 return pack<V>(std::array{a[0] + small1(b[0]) + c[0], a[1] + small1(b[1]) + c[1]});
131 template<
bool Clear,
class V>
constexpr V logical(V x, V y, V z)
noexcept {
132 auto a = lanes(x), b = lanes(y), c = lanes(z);
133 for (
unsigned i = 0; i < V::lanes; ++i) a[i] = Clear ? a[i] ^ (b[i] & ~c[i]) : a[i] ^ b[i] ^ c[i];
136 template<
class V>
constexpr V rax1(V x, V y)
noexcept {
137 auto a = lanes(x), b = lanes(y);
138 return pack<V>(std::array{a[0] ^ std::rotl(b[0], 1), a[1] ^ std::rotl(b[1], 1)});
140 template<
unsigned Rotate,
class V>
constexpr V xar(V x, V y)
noexcept {
141 auto a = lanes(x), b = lanes(y);
142 return pack<V>(std::array{std::rotr(a[0] ^ b[0], Rotate), std::rotr(a[1] ^ b[1], Rotate)});