Botan 3.9.0
Crypto and TLS for C&
keccak_perm.cpp
Go to the documentation of this file.
1/*
2* Keccak Permutation
3* (C) 2010,2016 Jack Lloyd
4* (C) 2023 Falko Strenzke
5* (C) 2023 René Meusel - Rohde & Schwarz Cybersecurity
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9
10#include <botan/internal/keccak_perm.h>
11
12#include <botan/exceptn.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/keccak_perm_round.h>
15#include <botan/internal/loadstor.h>
16#include <botan/internal/stl_util.h>
17
18#if defined(BOTAN_HAS_CPUID)
19 #include <botan/internal/cpuid.h>
20#endif
21
22namespace Botan {
23
24Keccak_Permutation::Keccak_Permutation(size_t capacity, uint64_t custom_padding, uint8_t custom_padding_bit_len) :
25 m_capacity(capacity),
26 m_byterate((1600 - capacity) / 8),
27 m_custom_padding(custom_padding),
28 m_custom_padding_bit_len(custom_padding_bit_len),
29 m_S(25), // 1600 bit
30 m_S_inpos(0),
31 m_S_outpos(0) {
32 BOTAN_ARG_CHECK(capacity % 64 == 0, "capacity must be a multiple of 64");
33}
34
35std::string Keccak_Permutation::provider() const {
36#if defined(BOTAN_HAS_KECCAK_PERM_BMI2)
37 if(auto feat = CPUID::check(CPUID::Feature::BMI)) {
38 return *feat;
39 }
40#endif
41
42 return "base";
43}
44
46 zeroise(m_S);
47 m_S_inpos = 0;
48 m_S_outpos = 0;
49}
50
51void Keccak_Permutation::absorb(std::span<const uint8_t> input) {
52 BufferSlicer input_slicer(input);
53
54 // Block-wise incorporation of the input data into the sponge state until
55 // all input bytes are processed
56 while(!input_slicer.empty()) {
57 const size_t to_take_this_round = std::min(input_slicer.remaining(), m_byterate - m_S_inpos);
58 BufferSlicer input_this_round(input_slicer.take(to_take_this_round));
59
60 // If necessary, try to get aligned with the sponge state's 64-bit integer array
61 for(; !input_this_round.empty() && m_S_inpos % 8 > 0; ++m_S_inpos) {
62 m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(input_this_round.take_byte()) << (8 * (m_S_inpos % 8));
63 }
64
65 // Process as many aligned 64-bit integer values as possible
66 for(; input_this_round.remaining() >= 8; m_S_inpos += 8) {
67 m_S[m_S_inpos / 8] ^= load_le<uint64_t>(input_this_round.take(8).data(), 0);
68 }
69
70 // Read remaining output data, causing misalignment, if necessary
71 for(; !input_this_round.empty(); ++m_S_inpos) {
72 m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(input_this_round.take_byte()) << (8 * (m_S_inpos % 8));
73 }
74
75 // We reached the end of a sponge state block... permute() and start over
76 if(m_S_inpos == m_byterate) {
77 permute();
78 m_S_inpos = 0;
79 }
80 }
81}
82
83void Keccak_Permutation::squeeze(std::span<uint8_t> output) {
84 BufferStuffer output_stuffer(output);
85
86 // Block-wise readout of the sponge state until enough bytes
87 // were filled into the output buffer
88 while(!output_stuffer.full()) {
89 const size_t bytes_in_this_round = std::min(output_stuffer.remaining_capacity(), m_byterate - m_S_outpos);
90 BufferStuffer output_this_round(output_stuffer.next(bytes_in_this_round));
91
92 // If necessary, try to get aligned with the sponge state's 64-bit integer array
93 for(; !output_this_round.full() && m_S_outpos % 8 != 0; ++m_S_outpos) {
94 output_this_round.next_byte() = static_cast<uint8_t>(m_S[m_S_outpos / 8] >> (8 * (m_S_outpos % 8)));
95 }
96
97 // Read out as many aligned 64-bit integer values as possible
98 for(; output_this_round.remaining_capacity() >= 8; m_S_outpos += 8) {
99 store_le(m_S[m_S_outpos / 8], output_this_round.next(8).data());
100 }
101
102 // Read remaining output data, causing misalignment, if necessary
103 for(; !output_this_round.full(); ++m_S_outpos) {
104 output_this_round.next_byte() = static_cast<uint8_t>(m_S[m_S_outpos / 8] >> (8 * (m_S_outpos % 8)));
105 }
106
107 // We reached the end of a sponge state block... permute() and start over
108 if(m_S_outpos == m_byterate) {
109 permute();
110 m_S_outpos = 0;
111 }
112 }
113}
114
116 // append the first bit of the final padding after the custom padding
117 uint8_t init_pad = static_cast<uint8_t>(m_custom_padding | uint64_t(1) << m_custom_padding_bit_len);
118 m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(init_pad) << (8 * (m_S_inpos % 8));
119
120 // final bit of the padding of the last block
121 m_S[(m_byterate / 8) - 1] ^= static_cast<uint64_t>(0x80) << 56;
122
123 permute();
124}
125
126void Keccak_Permutation::permute() {
127#if defined(BOTAN_HAS_KECCAK_PERM_BMI2)
129 return permute_bmi2();
130 }
131#endif
132
133 static const uint64_t RC[24] = {0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
134 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
135 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
136 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
137 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
138 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008};
139
140 uint64_t T[25];
141
142 for(size_t i = 0; i != 24; i += 2) {
143 Keccak_Permutation_round(T, m_S.data(), RC[i + 0]);
144 Keccak_Permutation_round(m_S.data(), T, RC[i + 1]);
145 }
146}
147
148} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
size_t remaining() const
Definition stl_util.h:119
uint8_t take_byte()
Definition stl_util.h:110
bool empty() const
Definition stl_util.h:121
std::span< const uint8_t > take(const size_t count)
Definition stl_util.h:90
Helper class to ease in-place marshalling of concatenated fixed-length values.
Definition stl_util.h:134
constexpr size_t remaining_capacity() const
Definition stl_util.h:181
constexpr std::span< uint8_t > next(size_t bytes)
Definition stl_util.h:142
constexpr uint8_t & next_byte()
Definition stl_util.h:167
constexpr bool full() const
Definition stl_util.h:179
static std::optional< std::string > check(CPUID::Feature feat)
Definition cpuid.h:67
static bool has(CPUID::Feature feat)
Definition cpuid.h:94
void squeeze(std::span< uint8_t > output)
Expand output data from the current Keccak state.
Keccak_Permutation(size_t capacity_bits, uint64_t custom_padding, uint8_t custom_padding_bit_len)
Instantiate a Keccak permutation.
std::string provider() const
void absorb(std::span< const uint8_t > input)
Absorb input data into the Keccak sponge.
size_t capacity() const
Definition keccak_perm.h:51
void finish()
Add final padding (as provided in the constructor) and permute.
void zeroise(std::vector< T, Alloc > &vec)
Definition secmem.h:125
constexpr auto store_le(ParamTs &&... params)
Definition loadstor.h:736
void Keccak_Permutation_round(uint64_t T[25], const uint64_t A[25], uint64_t RC)
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495