keccak-fast.c

Minimal SIMD keccak implementation
git clone git://git.finwo.net/lib/keccak-fast.c
Log | Files | Refs | README | LICENSE

commit 1d186f9effe31f695b67b5627edd4dc6e9d0da59
parent 4f8228dfa93cf459cf5af338e04bdacaddfa4110
Author: finwo <finwo@pm.me>
Date:   Sat, 10 Oct 2026 20:05:46 +0200

perm/unroll fixes for -O2 gcc on avx

Diffstat:
Msrc/backend/avx2.c | 72++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/backend/avx512.c | 71++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
2 files changed, 96 insertions(+), 47 deletions(-)

diff --git a/src/backend/avx2.c b/src/backend/avx2.c @@ -18,25 +18,41 @@ static const uint64_t RC[24] = { #define KF_ROL64(x, n) \ _mm256_or_si256(_mm256_slli_epi64((x), (n)), _mm256_srli_epi64((x), 64 - (n))) -__attribute__((target("avx2"))) +__attribute__((target("avx2"), always_inline)) static inline void kf_avx2_round_x4(__m256i v[25], uint64_t rc) { - __m256i c[5]; - __m256i d[5]; + __m256i c0, c1, c2, c3, c4; + __m256i d0, d1, d2, d3, d4; __m256i t, u; - for (int x = 0; x < 5; x++) { - c[x] = _mm256_xor_si256( - _mm256_xor_si256(v[x], v[x + 5]), - _mm256_xor_si256(_mm256_xor_si256(v[x + 10], v[x + 15]), v[x + 20])); - } - for (int x = 0; x < 5; x++) { - d[x] = _mm256_xor_si256(c[(x + 4) % 5], KF_ROL64(c[(x + 1) % 5], 1)); - } - for (int y = 0; y < 5; y++) { - for (int x = 0; x < 5; x++) { - v[x + 5 * y] = _mm256_xor_si256(v[x + 5 * y], d[x]); - } - } +#define KF_C(x) \ + _mm256_xor_si256(_mm256_xor_si256(v[x], v[(x) + 5]), \ + _mm256_xor_si256(_mm256_xor_si256(v[(x) + 10], v[(x) + 15]), \ + v[(x) + 20])) + c0 = KF_C(0); + c1 = KF_C(1); + c2 = KF_C(2); + c3 = KF_C(3); + c4 = KF_C(4); +#undef KF_C + + d0 = _mm256_xor_si256(c4, KF_ROL64(c1, 1)); + d1 = _mm256_xor_si256(c0, KF_ROL64(c2, 1)); + d2 = _mm256_xor_si256(c1, KF_ROL64(c3, 1)); + d3 = _mm256_xor_si256(c2, KF_ROL64(c4, 1)); + d4 = _mm256_xor_si256(c3, KF_ROL64(c0, 1)); + +#define KF_ADD(x, d) \ + v[(x)] = _mm256_xor_si256(v[(x)], (d)); \ + v[(x) + 5] = _mm256_xor_si256(v[(x) + 5], (d)); \ + v[(x) + 10] = _mm256_xor_si256(v[(x) + 10], (d)); \ + v[(x) + 15] = _mm256_xor_si256(v[(x) + 15], (d)); \ + v[(x) + 20] = _mm256_xor_si256(v[(x) + 20], (d)); + KF_ADD(0, d0) + KF_ADD(1, d1) + KF_ADD(2, d2) + KF_ADD(3, d3) + KF_ADD(4, d4) +#undef KF_ADD t = v[1]; #define KF_RHOPI4(dest, rot) \ @@ -71,14 +87,22 @@ static inline void kf_avx2_round_x4(__m256i v[25], uint64_t rc) { KF_RHOPI4(1, 44); #undef KF_RHOPI4 - for (int y = 0; y < 5; y++) { - __m256i row[5]; - for (int x = 0; x < 5; x++) row[x] = v[x + 5 * y]; - for (int x = 0; x < 5; x++) { - v[x + 5 * y] = _mm256_xor_si256( - row[x], _mm256_andnot_si256(row[(x + 1) % 5], row[(x + 2) % 5])); - } - } +#define KF_ROW(y) \ + do { \ + __m256i r0 = v[(y)], r1 = v[(y) + 1], r2 = v[(y) + 2], r3 = v[(y) + 3], \ + r4 = v[(y) + 4]; \ + v[(y)] = _mm256_xor_si256(r0, _mm256_andnot_si256(r1, r2)); \ + v[(y) + 1] = _mm256_xor_si256(r1, _mm256_andnot_si256(r2, r3)); \ + v[(y) + 2] = _mm256_xor_si256(r2, _mm256_andnot_si256(r3, r4)); \ + v[(y) + 3] = _mm256_xor_si256(r3, _mm256_andnot_si256(r4, r0)); \ + v[(y) + 4] = _mm256_xor_si256(r4, _mm256_andnot_si256(r0, r1)); \ + } while (0) + KF_ROW(0); + KF_ROW(5); + KF_ROW(10); + KF_ROW(15); + KF_ROW(20); +#undef KF_ROW v[0] = _mm256_xor_si256(v[0], _mm256_set1_epi64x((long long)rc)); } diff --git a/src/backend/avx512.c b/src/backend/avx512.c @@ -15,24 +15,41 @@ static const uint64_t RC[24] = { 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; -__attribute__((target("avx512f"))) +__attribute__((target("avx512f"), always_inline)) static inline void kf_avx512_round_x8(__m512i v[25], uint64_t rc) { - __m512i c[5]; - __m512i d[5]; + __m512i c0, c1, c2, c3, c4; + __m512i d0, d1, d2, d3, d4; __m512i t, u; - for (int x = 0; x < 5; x++) { - c[x] = _mm512_ternarylogic_epi64(v[x], v[x + 5], v[x + 10], 0x96); - c[x] = _mm512_ternarylogic_epi64(c[x], v[x + 15], v[x + 20], 0x96); - } - for (int x = 0; x < 5; x++) { - d[x] = _mm512_xor_si512(c[(x + 4) % 5], _mm512_rol_epi64(c[(x + 1) % 5], 1)); - } - for (int y = 0; y < 5; y++) { - for (int x = 0; x < 5; x++) { - v[x + 5 * y] = _mm512_xor_si512(v[x + 5 * y], d[x]); - } - } +#define KF_C(x) \ + _mm512_ternarylogic_epi64( \ + _mm512_ternarylogic_epi64(v[x], v[(x) + 5], v[(x) + 10], 0x96), \ + v[(x) + 15], v[(x) + 20], 0x96) + c0 = KF_C(0); + c1 = KF_C(1); + c2 = KF_C(2); + c3 = KF_C(3); + c4 = KF_C(4); +#undef KF_C + + d0 = _mm512_xor_si512(c4, _mm512_rol_epi64(c1, 1)); + d1 = _mm512_xor_si512(c0, _mm512_rol_epi64(c2, 1)); + d2 = _mm512_xor_si512(c1, _mm512_rol_epi64(c3, 1)); + d3 = _mm512_xor_si512(c2, _mm512_rol_epi64(c4, 1)); + d4 = _mm512_xor_si512(c3, _mm512_rol_epi64(c0, 1)); + +#define KF_ADD(x, d) \ + v[(x)] = _mm512_xor_si512(v[(x)], (d)); \ + v[(x) + 5] = _mm512_xor_si512(v[(x) + 5], (d)); \ + v[(x) + 10] = _mm512_xor_si512(v[(x) + 10], (d)); \ + v[(x) + 15] = _mm512_xor_si512(v[(x) + 15], (d)); \ + v[(x) + 20] = _mm512_xor_si512(v[(x) + 20], (d)); + KF_ADD(0, d0) + KF_ADD(1, d1) + KF_ADD(2, d2) + KF_ADD(3, d3) + KF_ADD(4, d4) +#undef KF_ADD t = v[1]; #define KF_RHOPI8(dest, rot) \ @@ -67,14 +84,22 @@ static inline void kf_avx512_round_x8(__m512i v[25], uint64_t rc) { KF_RHOPI8(1, 44); #undef KF_RHOPI8 - for (int y = 0; y < 5; y++) { - __m512i row[5]; - for (int x = 0; x < 5; x++) row[x] = v[x + 5 * y]; - for (int x = 0; x < 5; x++) { - v[x + 5 * y] = - _mm512_ternarylogic_epi64(row[x], row[(x + 1) % 5], row[(x + 2) % 5], 0xD2); - } - } +#define KF_ROW(y) \ + do { \ + __m512i r0 = v[(y)], r1 = v[(y) + 1], r2 = v[(y) + 2], r3 = v[(y) + 3], \ + r4 = v[(y) + 4]; \ + v[(y)] = _mm512_ternarylogic_epi64(r0, r1, r2, 0xD2); \ + v[(y) + 1] = _mm512_ternarylogic_epi64(r1, r2, r3, 0xD2); \ + v[(y) + 2] = _mm512_ternarylogic_epi64(r2, r3, r4, 0xD2); \ + v[(y) + 3] = _mm512_ternarylogic_epi64(r3, r4, r0, 0xD2); \ + v[(y) + 4] = _mm512_ternarylogic_epi64(r4, r0, r1, 0xD2); \ + } while (0) + KF_ROW(0); + KF_ROW(5); + KF_ROW(10); + KF_ROW(15); + KF_ROW(20); +#undef KF_ROW v[0] = _mm512_xor_si512(v[0], _mm512_set1_epi64((long long)rc)); }