Coverage Report

Created: 2025-04-11 06:34

/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