Botan 3.4.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/cpuid.h>
14#include <botan/internal/fmt.h>
15#include <botan/internal/keccak_perm_round.h>
16#include <botan/internal/loadstor.h>
17#include <botan/internal/stl_util.h>
18
19namespace Botan {
20
21Keccak_Permutation::Keccak_Permutation(size_t capacity, uint64_t custom_padding, uint8_t custom_padding_bit_len) :
22 m_capacity(capacity),
23 m_byterate((1600 - capacity) / 8),
24 m_custom_padding(custom_padding),
25 m_custom_padding_bit_len(custom_padding_bit_len),
26 m_S(25), // 1600 bit
27 m_S_inpos(0),
28 m_S_outpos(0) {
29 BOTAN_ARG_CHECK(capacity % 64 == 0, "capacity must be a multiple of 64");
30}
31
32std::string Keccak_Permutation::provider() const {
33#if defined(BOTAN_HAS_KECCAK_PERM_BMI2)
34 if(CPUID::has_bmi2()) {
35 return "bmi2";
36 }
37#endif
38
39 return "base";
40}
41
43 zeroise(m_S);
44 m_S_inpos = 0;
45 m_S_outpos = 0;
46}
47
48void Keccak_Permutation::absorb(std::span<const uint8_t> input) {
49 BufferSlicer input_slicer(input);
50
51 // Block-wise incorporation of the input data into the sponge state until
52 // all input bytes are processed
53 while(!input_slicer.empty()) {
54 const size_t to_take_this_round = std::min(input_slicer.remaining(), m_byterate - m_S_inpos);
55 BufferSlicer input_this_round(input_slicer.take(to_take_this_round));
56
57 // If necessary, try to get aligned with the sponge state's 64-bit integer array
58 for(; !input_this_round.empty() && m_S_inpos % 8; ++m_S_inpos) {
59 m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(input_this_round.take_byte()) << (8 * (m_S_inpos % 8));
60 }
61
62 // Process as many aligned 64-bit integer values as possible
63 for(; input_this_round.remaining() >= 8; m_S_inpos += 8) {
64 m_S[m_S_inpos / 8] ^= load_le<uint64_t>(input_this_round.take(8).data(), 0);
65 }
66
67 // Read remaining output data, causing misalignment, if necessary
68 for(; !input_this_round.empty(); ++m_S_inpos) {
69 m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(input_this_round.take_byte()) << (8 * (m_S_inpos % 8));
70 }
71
72 // We reached the end of a sponge state block... permute() and start over
73 if(m_S_inpos == m_byterate) {
74 permute();
75 m_S_inpos = 0;
76 }
77 }
78}
79
80void Keccak_Permutation::squeeze(std::span<uint8_t> output) {
81 BufferStuffer output_stuffer(output);
82
83 // Block-wise readout of the sponge state until enough bytes
84 // were filled into the output buffer
85 while(!output_stuffer.full()) {
86 const size_t bytes_in_this_round = std::min(output_stuffer.remaining_capacity(), m_byterate - m_S_outpos);
87 BufferStuffer output_this_round(output_stuffer.next(bytes_in_this_round));
88
89 // If necessary, try to get aligned with the sponge state's 64-bit integer array
90 for(; !output_this_round.full() && m_S_outpos % 8 != 0; ++m_S_outpos) {
91 output_this_round.next_byte() = static_cast<uint8_t>(m_S[m_S_outpos / 8] >> (8 * (m_S_outpos % 8)));
92 }
93
94 // Read out as many aligned 64-bit integer values as possible
95 for(; output_this_round.remaining_capacity() >= 8; m_S_outpos += 8) {
96 store_le(m_S[m_S_outpos / 8], output_this_round.next(8).data());
97 }
98
99 // Read remaining output data, causing misalignment, if necessary
100 for(; !output_this_round.full(); ++m_S_outpos) {
101 output_this_round.next_byte() = static_cast<uint8_t>(m_S[m_S_outpos / 8] >> (8 * (m_S_outpos % 8)));
102 }
103
104 // We reached the end of a sponge state block... permute() and start over
105 if(m_S_outpos == m_byterate) {
106 permute();
107 m_S_outpos = 0;
108 }
109 }
110}
111
113 // append the first bit of the final padding after the custom padding
114 uint8_t init_pad = static_cast<uint8_t>(m_custom_padding | uint64_t(1) << m_custom_padding_bit_len);
115 m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(init_pad) << (8 * (m_S_inpos % 8));
116
117 // final bit of the padding of the last block
118 m_S[(m_byterate / 8) - 1] ^= static_cast<uint64_t>(0x80) << 56;
119
120 permute();
121}
122
123void Keccak_Permutation::permute() {
124#if defined(BOTAN_HAS_KECCAK_PERM_BMI2)
125 if(CPUID::has_bmi2()) {
126 return permute_bmi2();
127 }
128#endif
129
130 static const uint64_t RC[24] = {0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
131 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
132 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
133 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
134 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
135 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008};
136
137 uint64_t T[25];
138
139 for(size_t i = 0; i != 24; i += 2) {
140 Keccak_Permutation_round(T, m_S.data(), RC[i + 0]);
141 Keccak_Permutation_round(m_S.data(), T, RC[i + 1]);
142 }
143}
144
145} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
size_t remaining() const
Definition stl_util.h:185
uint8_t take_byte()
Definition stl_util.h:176
bool empty() const
Definition stl_util.h:187
std::span< const uint8_t > take(const size_t count)
Definition stl_util.h:156
Helper class to ease in-place marshalling of concatenated fixed-length values.
Definition stl_util.h:200
constexpr size_t remaining_capacity() const
Definition stl_util.h:247
constexpr std::span< uint8_t > next(size_t bytes)
Definition stl_util.h:208
constexpr uint8_t & next_byte()
Definition stl_util.h:233
constexpr bool full() const
Definition stl_util.h:245
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.
FE_25519 T
Definition ge.cpp:34
void zeroise(std::vector< T, Alloc > &vec)
Definition secmem.h:108
constexpr auto store_le(ParamTs &&... params)
Definition loadstor.h:702
void Keccak_Permutation_round(uint64_t T[25], const uint64_t A[25], uint64_t RC)