/src/botan/src/lib/permutations/keccak_perm/keccak_perm.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
22 | | namespace Botan { |
23 | | |
24 | | Keccak_Permutation::Keccak_Permutation(size_t capacity, uint64_t custom_padding, uint8_t custom_padding_bit_len) : |
25 | 333 | m_capacity(capacity), |
26 | 333 | m_byterate((1600 - capacity) / 8), |
27 | 333 | m_custom_padding(custom_padding), |
28 | 333 | m_custom_padding_bit_len(custom_padding_bit_len), |
29 | 333 | m_S(25), // 1600 bit |
30 | 333 | m_S_inpos(0), |
31 | 333 | m_S_outpos(0) { |
32 | 333 | BOTAN_ARG_CHECK(capacity % 64 == 0, "capacity must be a multiple of 64"); |
33 | 333 | } |
34 | | |
35 | 0 | std::string Keccak_Permutation::provider() const { |
36 | 0 | #if defined(BOTAN_HAS_KECCAK_PERM_BMI2) |
37 | 0 | if(CPUID::has(CPUID::Feature::BMI)) { |
38 | 0 | return "bmi2"; |
39 | 0 | } |
40 | 0 | #endif |
41 | | |
42 | 0 | return "base"; |
43 | 0 | } |
44 | | |
45 | 0 | void Keccak_Permutation::clear() { |
46 | 0 | zeroise(m_S); |
47 | 0 | m_S_inpos = 0; |
48 | 0 | m_S_outpos = 0; |
49 | 0 | } |
50 | | |
51 | 160 | void Keccak_Permutation::absorb(std::span<const uint8_t> input) { |
52 | 160 | 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 | 320 | while(!input_slicer.empty()) { |
57 | 160 | const size_t to_take_this_round = std::min(input_slicer.remaining(), m_byterate - m_S_inpos); |
58 | 160 | 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 | 160 | for(; !input_this_round.empty() && m_S_inpos % 8; ++m_S_inpos) { |
62 | 0 | m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(input_this_round.take_byte()) << (8 * (m_S_inpos % 8)); |
63 | 0 | } |
64 | | |
65 | | // Process as many aligned 64-bit integer values as possible |
66 | 1.28k | for(; input_this_round.remaining() >= 8; m_S_inpos += 8) { |
67 | 1.12k | m_S[m_S_inpos / 8] ^= load_le<uint64_t>(input_this_round.take(8).data(), 0); |
68 | 1.12k | } |
69 | | |
70 | | // Read remaining output data, causing misalignment, if necessary |
71 | 320 | for(; !input_this_round.empty(); ++m_S_inpos) { |
72 | 160 | m_S[m_S_inpos / 8] ^= static_cast<uint64_t>(input_this_round.take_byte()) << (8 * (m_S_inpos % 8)); |
73 | 160 | } |
74 | | |
75 | | // We reached the end of a sponge state block... permute() and start over |
76 | 160 | if(m_S_inpos == m_byterate) { |
77 | 0 | permute(); |
78 | 0 | m_S_inpos = 0; |
79 | 0 | } |
80 | 160 | } |
81 | 160 | } |
82 | | |
83 | 160 | void Keccak_Permutation::squeeze(std::span<uint8_t> output) { |
84 | 160 | BufferStuffer output_stuffer(output); |
85 | | |
86 | | // Block-wise readout of the sponge state until enough bytes |
87 | | // were filled into the output buffer |
88 | 320 | while(!output_stuffer.full()) { |
89 | 160 | const size_t bytes_in_this_round = std::min(output_stuffer.remaining_capacity(), m_byterate - m_S_outpos); |
90 | 160 | 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 | 160 | for(; !output_this_round.full() && m_S_outpos % 8 != 0; ++m_S_outpos) { |
94 | 0 | output_this_round.next_byte() = static_cast<uint8_t>(m_S[m_S_outpos / 8] >> (8 * (m_S_outpos % 8))); |
95 | 0 | } |
96 | | |
97 | | // Read out as many aligned 64-bit integer values as possible |
98 | 1.28k | for(; output_this_round.remaining_capacity() >= 8; m_S_outpos += 8) { |
99 | 1.12k | store_le(m_S[m_S_outpos / 8], output_this_round.next(8).data()); |
100 | 1.12k | } |
101 | | |
102 | | // Read remaining output data, causing misalignment, if necessary |
103 | 320 | for(; !output_this_round.full(); ++m_S_outpos) { |
104 | 160 | output_this_round.next_byte() = static_cast<uint8_t>(m_S[m_S_outpos / 8] >> (8 * (m_S_outpos % 8))); |
105 | 160 | } |
106 | | |
107 | | // We reached the end of a sponge state block... permute() and start over |
108 | 160 | if(m_S_outpos == m_byterate) { |
109 | 0 | permute(); |
110 | 0 | m_S_outpos = 0; |
111 | 0 | } |
112 | 160 | } |
113 | 160 | } |
114 | | |
115 | 160 | void Keccak_Permutation::finish() { |
116 | | // append the first bit of the final padding after the custom padding |
117 | 160 | uint8_t init_pad = static_cast<uint8_t>(m_custom_padding | uint64_t(1) << m_custom_padding_bit_len); |
118 | 160 | 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 | 160 | m_S[(m_byterate / 8) - 1] ^= static_cast<uint64_t>(0x80) << 56; |
122 | | |
123 | 160 | permute(); |
124 | 160 | } |
125 | | |
126 | 160 | void Keccak_Permutation::permute() { |
127 | 160 | #if defined(BOTAN_HAS_KECCAK_PERM_BMI2) |
128 | 160 | if(CPUID::has(CPUID::Feature::BMI)) { |
129 | 160 | return permute_bmi2(); |
130 | 160 | } |
131 | 0 | #endif |
132 | | |
133 | 0 | static const uint64_t RC[24] = {0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000, |
134 | 0 | 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, |
135 | 0 | 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, |
136 | 0 | 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003, |
137 | 0 | 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A, |
138 | 0 | 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; |
139 | |
|
140 | 0 | uint64_t T[25]; |
141 | |
|
142 | 0 | for(size_t i = 0; i != 24; i += 2) { |
143 | 0 | Keccak_Permutation_round(T, m_S.data(), RC[i + 0]); |
144 | 0 | Keccak_Permutation_round(m_S.data(), T, RC[i + 1]); |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | | } // namespace Botan |