native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
crypto_constant.h
1// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
2#pragma once
3#include "constant_lanes.h"
4
5namespace native::detail::arm_constant {
6 constexpr std::uint8_t aes_product(std::uint8_t a, std::uint8_t b) noexcept {
7 unsigned product = 0;
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));
11 }
12 return static_cast<std::uint8_t>(product);
13 }
14
15 constexpr std::uint8_t aes_inverse(std::uint8_t a) noexcept {
16 // a^254 in GF(2^8); this also maps zero to zero.
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);
21 }
22 return result;
23 }
24
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));
28 else {
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);
31 }
32 }
33
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]);
39 }
40 return pack<V>(result);
41 }
42
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]);
50 }
51 return pack<V>(result);
52 }
53
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);
60 }
61
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;
70 }
71 return pack<V>(a);
72 }
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]});
76 }
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)});
81 }
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]};
97 }
98 return pack<V>(Second ? y : x);
99 }
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])});
103 }
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]);
108 return pack<V>(a);
109 }
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]);
115 return pack<V>(a);
116 }
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]);
121 return pack<V>(a);
122 }
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])});
126 }
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]});
130 }
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];
134 return pack<V>(a);
135 }
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)});
139 }
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)});
143 }
144}