Skip to content

Commit 9d7387f

Browse files
authored
Merge pull request #9 from hanickadot/feature/pre-nist-keccak
Feature/pre nist keccak
2 parents 2ca97bf + e496026 commit 9d7387f

File tree

8 files changed

+889
-78
lines changed

8 files changed

+889
-78
lines changed

include/cthash/sha3/common.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef CTHASH_SHA3_COMMON_HPP
22
#define CTHASH_SHA3_COMMON_HPP
33

4-
#include "keccak.hpp"
4+
#include "keccak-base.hpp"
55
#include "../hasher.hpp"
66
#include "../internal/bit.hpp"
77
#include "../internal/convert.hpp"
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#ifndef CTHASH_SHA3_KECCAK_BASE_HPP
2+
#define CTHASH_SHA3_KECCAK_BASE_HPP
3+
4+
#include <array>
5+
#include <bit>
6+
#include <span>
7+
#include <type_traits>
8+
#include <utility>
9+
#include <concepts>
10+
#include <cstdint>
11+
12+
namespace cthash::keccak {
13+
14+
// inspired by tiny-keccak (https://github.com/debris/tiny-keccak from Marek Kotewicz)
15+
16+
static constexpr auto rho = std::array<uint8_t, 24>{1u, 3u, 6u, 10u, 15u, 21u, 28u, 36u, 45u, 55u, 2u, 14u, 27u, 41u, 56u, 8u, 25u, 43u, 62u, 18u, 39u, 61u, 20u, 44u};
17+
18+
static constexpr auto pi = std::array<uint8_t, 24>{10u, 7u, 11u, 17u, 18u, 3u, 5u, 16u, 8u, 21u, 24u, 4u, 15u, 23u, 19u, 13u, 12u, 2u, 20u, 14u, 22u, 9u, 6u, 1u};
19+
20+
static constexpr auto rc = std::array<uint64_t, 24>{0x1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
21+
22+
struct state_1600: std::array<uint64_t, (5u * 5u)> { };
23+
24+
struct state_1600_ref: std::span<uint64_t, (5u * 5u)> {
25+
using super = std::span<uint64_t, (5u * 5u)>;
26+
using super::super;
27+
};
28+
29+
[[gnu::always_inline, gnu::flatten]] constexpr void theta(state_1600_ref state) noexcept {
30+
// xor of columns
31+
const auto b = std::array<uint64_t, 5>{
32+
state[0] xor state[5] xor state[10] xor state[15] xor state[20],
33+
state[1] xor state[6] xor state[11] xor state[16] xor state[21],
34+
state[2] xor state[7] xor state[12] xor state[17] xor state[22],
35+
state[3] xor state[8] xor state[13] xor state[18] xor state[23],
36+
state[4] xor state[9] xor state[14] xor state[19] xor state[24],
37+
};
38+
39+
const auto tmp = std::array<uint64_t, 5>{
40+
b[4] xor std::rotl(b[1], 1),
41+
b[0] xor std::rotl(b[2], 1),
42+
b[1] xor std::rotl(b[3], 1),
43+
b[2] xor std::rotl(b[4], 1),
44+
b[3] xor std::rotl(b[0], 1),
45+
};
46+
47+
[&]<size_t... Idx>(std::index_sequence<Idx...>) {
48+
((state[Idx] ^= tmp[Idx % 5u]), ...);
49+
}(std::make_index_sequence<25>());
50+
}
51+
52+
[[gnu::always_inline, gnu::flatten]] constexpr void rho_pi(state_1600_ref state) noexcept {
53+
uint64_t tmp = state[1];
54+
55+
[&]<size_t... Idx>(std::index_sequence<Idx...>) {
56+
((state[pi[Idx]] = std::rotl(std::exchange(tmp, state[pi[Idx]]), rho[Idx])), ...);
57+
}(std::make_index_sequence<24>());
58+
}
59+
60+
[[gnu::always_inline, gnu::flatten]] constexpr void chi(state_1600_ref state) noexcept {
61+
constexpr auto chi_helper = [](std::span<uint64_t, 5> row) {
62+
const auto b = std::array<uint64_t, 5>{row[0], row[1], row[2], row[3], row[4]};
63+
64+
row[0] = b[0] xor ((~b[1]) bitand b[2]);
65+
row[1] = b[1] xor ((~b[2]) bitand b[3]);
66+
row[2] = b[2] xor ((~b[3]) bitand b[4]);
67+
row[3] = b[3] xor ((~b[4]) bitand b[0]);
68+
row[4] = b[4] xor ((~b[0]) bitand b[1]);
69+
};
70+
71+
chi_helper(state.subspan<0>().first<5>());
72+
chi_helper(state.subspan<5>().first<5>());
73+
chi_helper(state.subspan<10>().first<5>());
74+
chi_helper(state.subspan<15>().first<5>());
75+
chi_helper(state.subspan<20>().first<5>());
76+
}
77+
78+
[[gnu::flatten]] constexpr void keccak_f(state_1600 & state) noexcept {
79+
// rounds
80+
for (int i = 0; i != 24; ++i) {
81+
// theta (xor each column together)
82+
theta(state);
83+
rho_pi(state);
84+
chi(state);
85+
state[0] ^= rc[static_cast<size_t>(i)];
86+
}
87+
}
88+
89+
} // namespace cthash::keccak
90+
91+
#endif

include/cthash/sha3/keccak.hpp

Lines changed: 31 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,47 @@
11
#ifndef CTHASH_SHA3_KECCAK_HPP
22
#define CTHASH_SHA3_KECCAK_HPP
33

4-
#include <array>
5-
#include <bit>
6-
#include <span>
7-
#include <type_traits>
8-
#include <utility>
9-
#include <concepts>
10-
#include <cstdint>
4+
#include "common.hpp"
115

12-
namespace cthash::keccak {
6+
namespace cthash {
137

14-
// inspired by tiny-keccak (https://github.com/debris/tiny-keccak from Marek Kotewicz)
8+
template <unsigned N> struct prenist_keccak_config {
9+
static constexpr size_t digest_length_bit = N;
10+
static constexpr size_t capacity_bit = digest_length_bit * 2u;
11+
static constexpr size_t rate_bit = 1600u - capacity_bit;
1512

16-
static constexpr auto rho = std::array<uint8_t, 24>{1u, 3u, 6u, 10u, 15u, 21u, 28u, 36u, 45u, 55u, 2u, 14u, 27u, 41u, 56u, 8u, 25u, 43u, 62u, 18u, 39u, 61u, 20u, 44u};
17-
18-
static constexpr auto pi = std::array<uint8_t, 24>{10u, 7u, 11u, 17u, 18u, 3u, 5u, 16u, 8u, 21u, 24u, 4u, 15u, 23u, 19u, 13u, 12u, 2u, 20u, 14u, 22u, 9u, 6u, 1u};
19-
20-
static constexpr auto rc = std::array<uint64_t, 24>{0x1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
21-
22-
struct state_1600: std::array<uint64_t, (5u * 5u)> { };
23-
24-
struct state_1600_ref: std::span<uint64_t, (5u * 5u)> {
25-
using super = std::span<uint64_t, (5u * 5u)>;
26-
using super::super;
13+
// Keccak (pre-NIST) domain bit = 0x01
14+
static constexpr auto suffix = keccak_suffix(0, 0x00);
2715
};
2816

29-
[[gnu::always_inline, gnu::flatten]] constexpr void theta(state_1600_ref state) noexcept {
30-
// xor of columns
31-
const auto b = std::array<uint64_t, 5>{
32-
state[0] xor state[5] xor state[10] xor state[15] xor state[20],
33-
state[1] xor state[6] xor state[11] xor state[16] xor state[21],
34-
state[2] xor state[7] xor state[12] xor state[17] xor state[22],
35-
state[3] xor state[8] xor state[13] xor state[18] xor state[23],
36-
state[4] xor state[9] xor state[14] xor state[19] xor state[24],
37-
};
38-
39-
const auto tmp = std::array<uint64_t, 5>{
40-
b[4] xor std::rotl(b[1], 1),
41-
b[0] xor std::rotl(b[2], 1),
42-
b[1] xor std::rotl(b[3], 1),
43-
b[2] xor std::rotl(b[4], 1),
44-
b[3] xor std::rotl(b[0], 1),
45-
};
17+
static_assert((prenist_keccak_config<256>::capacity_bit + prenist_keccak_config<256>::rate_bit) == 1600u);
4618

47-
[&]<size_t... Idx>(std::index_sequence<Idx...>) {
48-
((state[Idx] ^= tmp[Idx % 5u]), ...);
49-
}(std::make_index_sequence<25>());
50-
}
19+
using keccak_256 = cthash::keccak_hasher<prenist_keccak_config<256>>;
20+
using keccak_256_value = tagged_hash_value<prenist_keccak_config<256>>;
21+
using keccak_384 = cthash::keccak_hasher<prenist_keccak_config<384>>;
22+
using keccak_384_value = tagged_hash_value<prenist_keccak_config<384>>;
23+
using keccak_512 = cthash::keccak_hasher<prenist_keccak_config<512>>;
24+
using keccak_512_value = tagged_hash_value<prenist_keccak_config<512>>;
5125

52-
[[gnu::always_inline, gnu::flatten]] constexpr void rho_pi(state_1600_ref state) noexcept {
53-
uint64_t tmp = state[1];
26+
namespace literals {
5427

55-
[&]<size_t... Idx>(std::index_sequence<Idx...>) {
56-
((state[pi[Idx]] = std::rotl(std::exchange(tmp, state[pi[Idx]]), rho[Idx])), ...);
57-
}(std::make_index_sequence<24>());
58-
}
59-
60-
[[gnu::always_inline, gnu::flatten]] constexpr void chi(state_1600_ref state) noexcept {
61-
constexpr auto chi_helper = [](std::span<uint64_t, 5> row) {
62-
const auto b = std::array<uint64_t, 5>{row[0], row[1], row[2], row[3], row[4]};
63-
64-
row[0] = b[0] xor ((~b[1]) bitand b[2]);
65-
row[1] = b[1] xor ((~b[2]) bitand b[3]);
66-
row[2] = b[2] xor ((~b[3]) bitand b[4]);
67-
row[3] = b[3] xor ((~b[4]) bitand b[0]);
68-
row[4] = b[4] xor ((~b[0]) bitand b[1]);
69-
};
28+
template <fixed_string Value>
29+
consteval auto operator""_keccak_256() {
30+
return keccak_256_value(Value);
31+
}
7032

71-
chi_helper(state.subspan<0>().first<5>());
72-
chi_helper(state.subspan<5>().first<5>());
73-
chi_helper(state.subspan<10>().first<5>());
74-
chi_helper(state.subspan<15>().first<5>());
75-
chi_helper(state.subspan<20>().first<5>());
76-
}
33+
template <fixed_string Value>
34+
consteval auto operator""_keccak_384() {
35+
return keccak_384_value(Value);
36+
}
7737

78-
[[gnu::flatten]] constexpr void keccak_f(state_1600 & state) noexcept {
79-
// rounds
80-
for (int i = 0; i != 24; ++i) {
81-
// theta (xor each column together)
82-
theta(state);
83-
rho_pi(state);
84-
chi(state);
85-
state[0] ^= rc[static_cast<size_t>(i)];
38+
template <fixed_string Value>
39+
consteval auto operator""_keccak_512() {
40+
return keccak_512_value(Value);
8641
}
87-
}
8842

89-
} // namespace cthash::keccak
43+
} // namespace literals
44+
45+
} // namespace cthash
9046

91-
#endif
47+
#endif

tests/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ add_executable(test-runner
1414
sha3/sha3-384.cpp
1515
sha3/sha3-224.cpp
1616
sha3/sha3-256.cpp
17+
sha3/keccak-256.cpp
18+
sha3/keccak-384.cpp
19+
sha3/keccak-512.cpp
1720
sha3/shake256.cpp
1821
sha3/shake128.cpp
1922
sha3/sha3-512.cpp

tests/keccak.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
#include "internal/support.hpp"
2-
#include <cthash/sha3/keccak.hpp>
31
#include <catch2/benchmark/catch_benchmark.hpp>
42
#include <catch2/catch_test_macros.hpp>
3+
#include "internal/support.hpp"
4+
#include <cthash/sha3/keccak-base.hpp>
55

66
TEST_CASE("keccakF") {
77
auto s = cthash::keccak::state_1600{};

0 commit comments

Comments
 (0)