• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 23446816579

23 Mar 2026 01:13PM UTC coverage: 89.438% (-2.5%) from 91.89%
23446816579

push

github

web-flow
Merge pull request #5438 from KaganCanSit/fix/pwdhash-tune-params-not-implemented

Handle Not_Implemented in pwdhash tune_params test

104900 of 117288 relevant lines covered (89.44%)

11914309.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.02
/src/lib/hash/whirlpool/whirlpool.cpp
1
/*
2
* Whirlpool
3
* (C) 1999-2007,2020,2026 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/whirlpool.h>
9

10
#include <botan/internal/bit_ops.h>
11
#include <botan/internal/buffer_slicer.h>
12
#include <botan/internal/loadstor.h>
13
#include <botan/internal/rotate.h>
14
#include <array>
15

16
#if defined(BOTAN_HAS_CPUID)
17
   #include <botan/internal/cpuid.h>
18
#endif
19

20
namespace Botan {
21

22
namespace {
23

24
// Derive the 256-byte S-box from the Whirlpool E and R mini-boxes
25
consteval std::array<uint8_t, 256> whirlpool_sbox() noexcept {
26
   constexpr uint8_t Ebox[16] = {1, 11, 9, 12, 13, 6, 15, 3, 14, 8, 7, 4, 10, 2, 5, 0};
27
   constexpr uint8_t Rbox[16] = {7, 12, 11, 13, 14, 4, 9, 15, 6, 3, 8, 10, 2, 5, 1, 0};
28

29
   // Derive the inverse of the E table
30
   uint8_t Eibox[16] = {};
31
   for(size_t i = 0; i != 16; ++i) {
32
      Eibox[Ebox[i]] = static_cast<uint8_t>(i);
33
   }
34

35
   std::array<uint8_t, 256> S = {};
36
   for(size_t i = 0; i != 256; ++i) {
37
      const uint8_t L = Ebox[i >> 4];
38
      const uint8_t R = Eibox[i & 0x0F];
39
      const uint8_t T = Rbox[L ^ R];
40
      S[i] = static_cast<uint8_t>((Ebox[L ^ T] << 4) | Eibox[R ^ T]);
41
   }
42
   return S;
43
}
44

45
// Combined S-box + MDS diffusion table
46
consteval std::array<uint64_t, 256> whirlpool_T_table(const std::array<uint8_t, 256>& S) noexcept {
47
   // MDS circulant matrix first row: [1, 1, 4, 1, 8, 5, 2, 9] over GF(2^8)
48
   constexpr uint64_t MDS = 0x0101040108050209;
49

50
   std::array<uint64_t, 256> T = {};
51
   for(size_t i = 0; i != 256; ++i) {
52
      T[i] = poly_mul<0x1D>(MDS, S[i]);
53
   }
54
   return T;
55
}
56

57
// Round constants are from the first 64 elements of the sbox
58
consteval std::array<uint64_t, 10> whirlpool_rc(const std::array<uint8_t, 256>& S) noexcept {
59
   std::array<uint64_t, 10> RC = {};
60
   for(size_t r = 0; r != 10; ++r) {
61
      RC[r] = load_be<uint64_t>(S.data(), r);
62
   }
63
   return RC;
64
}
65

66
constexpr auto WHIRL_S = whirlpool_sbox();
67
alignas(256) constexpr auto WHIRL_T = whirlpool_T_table(WHIRL_S);
68
constexpr auto WHIRL_RC = whirlpool_rc(WHIRL_S);
69

70
uint64_t whirl(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6, uint64_t x7) {
103,840✔
71
   const uint64_t s0 = WHIRL_T[get_byte<0>(x0)];
103,840✔
72
   const uint64_t s1 = WHIRL_T[get_byte<1>(x1)];
103,840✔
73
   const uint64_t s2 = WHIRL_T[get_byte<2>(x2)];
103,840✔
74
   const uint64_t s3 = WHIRL_T[get_byte<3>(x3)];
103,840✔
75
   const uint64_t s4 = WHIRL_T[get_byte<4>(x4)];
103,840✔
76
   const uint64_t s5 = WHIRL_T[get_byte<5>(x5)];
103,840✔
77
   const uint64_t s6 = WHIRL_T[get_byte<6>(x6)];
103,840✔
78
   const uint64_t s7 = WHIRL_T[get_byte<7>(x7)];
103,840✔
79

80
   return s0 ^ rotr<8>(s1) ^ rotr<16>(s2) ^ rotr<24>(s3) ^ rotr<32>(s4) ^ rotr<40>(s5) ^ rotr<48>(s6) ^ rotr<56>(s7);
103,840✔
81
}
82

83
}  // namespace
84

85
std::string Whirlpool::provider() const {
22✔
86
#if defined(BOTAN_HAS_WHIRLPOOL_AVX512)
87
   if(auto feat = CPUID::check(CPUID::Feature::AVX512)) {
22✔
88
      return *feat;
×
89
   }
×
90
#endif
91

92
#if defined(BOTAN_HAS_WHIRLPOOL_AVX2)
93
   if(auto feat = CPUID::check(CPUID::Feature::AVX2)) {
22✔
94
      return *feat;
22✔
95
   }
11✔
96
#endif
97

98
   return "base";
11✔
99
}
100

101
/*
102
* Whirlpool Compression Function
103
*/
104
void Whirlpool::compress_n(digest_type& digest, std::span<const uint8_t> input, size_t blocks) {
588✔
105
#if defined(BOTAN_HAS_WHIRLPOOL_AVX512)
106
   if(CPUID::has(CPUID::Feature::AVX512)) {
588✔
107
      return compress_n_avx512(digest, input, blocks);
404✔
108
   }
109
#endif
110

111
#if defined(BOTAN_HAS_WHIRLPOOL_AVX2)
112
   if(CPUID::has(CPUID::Feature::AVX2)) {
588✔
113
      return compress_n_avx2(digest, input, blocks);
404✔
114
   }
115
#endif
116

117
   BufferSlicer in(input);
184✔
118

119
   for(size_t i = 0; i != blocks; ++i) {
833✔
120
      const auto block = in.take(block_bytes);
649✔
121

122
      uint64_t K[11 * 8] = {0};
649✔
123

124
      K[0] = digest[0];
649✔
125
      K[1] = digest[1];
649✔
126
      K[2] = digest[2];
649✔
127
      K[3] = digest[3];
649✔
128
      K[4] = digest[4];
649✔
129
      K[5] = digest[5];
649✔
130
      K[6] = digest[6];
649✔
131
      K[7] = digest[7];
649✔
132

133
      // Whirlpool key schedule:
134
      for(size_t r = 1; r != 11; ++r) {
7,139✔
135
         const uint64_t PK0 = K[8 * (r - 1) + 0];
6,490✔
136
         const uint64_t PK1 = K[8 * (r - 1) + 1];
6,490✔
137
         const uint64_t PK2 = K[8 * (r - 1) + 2];
6,490✔
138
         const uint64_t PK3 = K[8 * (r - 1) + 3];
6,490✔
139
         const uint64_t PK4 = K[8 * (r - 1) + 4];
6,490✔
140
         const uint64_t PK5 = K[8 * (r - 1) + 5];
6,490✔
141
         const uint64_t PK6 = K[8 * (r - 1) + 6];
6,490✔
142
         const uint64_t PK7 = K[8 * (r - 1) + 7];
6,490✔
143

144
         K[8 * r + 0] = whirl(PK0, PK7, PK6, PK5, PK4, PK3, PK2, PK1) ^ WHIRL_RC[r - 1];
6,490✔
145
         K[8 * r + 1] = whirl(PK1, PK0, PK7, PK6, PK5, PK4, PK3, PK2);
6,490✔
146
         K[8 * r + 2] = whirl(PK2, PK1, PK0, PK7, PK6, PK5, PK4, PK3);
6,490✔
147
         K[8 * r + 3] = whirl(PK3, PK2, PK1, PK0, PK7, PK6, PK5, PK4);
6,490✔
148
         K[8 * r + 4] = whirl(PK4, PK3, PK2, PK1, PK0, PK7, PK6, PK5);
6,490✔
149
         K[8 * r + 5] = whirl(PK5, PK4, PK3, PK2, PK1, PK0, PK7, PK6);
6,490✔
150
         K[8 * r + 6] = whirl(PK6, PK5, PK4, PK3, PK2, PK1, PK0, PK7);
6,490✔
151
         K[8 * r + 7] = whirl(PK7, PK6, PK5, PK4, PK3, PK2, PK1, PK0);
6,490✔
152
      }
153

154
      uint64_t M[8] = {0};
649✔
155
      load_be(M, block.data(), 8);
649✔
156

157
      // First round (key masking)
158
      uint64_t B0 = M[0] ^ K[0];
649✔
159
      uint64_t B1 = M[1] ^ K[1];
649✔
160
      uint64_t B2 = M[2] ^ K[2];
649✔
161
      uint64_t B3 = M[3] ^ K[3];
649✔
162
      uint64_t B4 = M[4] ^ K[4];
649✔
163
      uint64_t B5 = M[5] ^ K[5];
649✔
164
      uint64_t B6 = M[6] ^ K[6];
649✔
165
      uint64_t B7 = M[7] ^ K[7];
649✔
166

167
      for(size_t r = 1; r != 11; ++r) {
7,139✔
168
         const uint64_t T0 = whirl(B0, B7, B6, B5, B4, B3, B2, B1) ^ K[8 * r + 0];
6,490✔
169
         const uint64_t T1 = whirl(B1, B0, B7, B6, B5, B4, B3, B2) ^ K[8 * r + 1];
6,490✔
170
         const uint64_t T2 = whirl(B2, B1, B0, B7, B6, B5, B4, B3) ^ K[8 * r + 2];
6,490✔
171
         const uint64_t T3 = whirl(B3, B2, B1, B0, B7, B6, B5, B4) ^ K[8 * r + 3];
6,490✔
172
         const uint64_t T4 = whirl(B4, B3, B2, B1, B0, B7, B6, B5) ^ K[8 * r + 4];
6,490✔
173
         const uint64_t T5 = whirl(B5, B4, B3, B2, B1, B0, B7, B6) ^ K[8 * r + 5];
6,490✔
174
         const uint64_t T6 = whirl(B6, B5, B4, B3, B2, B1, B0, B7) ^ K[8 * r + 6];
6,490✔
175
         const uint64_t T7 = whirl(B7, B6, B5, B4, B3, B2, B1, B0) ^ K[8 * r + 7];
6,490✔
176

177
         B0 = T0;
6,490✔
178
         B1 = T1;
6,490✔
179
         B2 = T2;
6,490✔
180
         B3 = T3;
6,490✔
181
         B4 = T4;
6,490✔
182
         B5 = T5;
6,490✔
183
         B6 = T6;
6,490✔
184
         B7 = T7;
6,490✔
185
      }
186

187
      digest[0] ^= B0 ^ M[0];
649✔
188
      digest[1] ^= B1 ^ M[1];
649✔
189
      digest[2] ^= B2 ^ M[2];
649✔
190
      digest[3] ^= B3 ^ M[3];
649✔
191
      digest[4] ^= B4 ^ M[4];
649✔
192
      digest[5] ^= B5 ^ M[5];
649✔
193
      digest[6] ^= B6 ^ M[6];
649✔
194
      digest[7] ^= B7 ^ M[7];
649✔
195
   }
196
}
197

198
void Whirlpool::init(digest_type& digest) {
474✔
199
   digest.resize(8);
474✔
200
   zeroise(digest);
896✔
201
}
52✔
202

203
std::unique_ptr<HashFunction> Whirlpool::new_object() const {
22✔
204
   return std::make_unique<Whirlpool>();
22✔
205
}
206

207
std::unique_ptr<HashFunction> Whirlpool::copy_state() const {
16✔
208
   return std::make_unique<Whirlpool>(*this);
16✔
209
}
210

211
void Whirlpool::add_data(std::span<const uint8_t> input) {
572✔
212
   m_md.update(input);
572✔
213
}
572✔
214

215
void Whirlpool::final_result(std::span<uint8_t> output) {
378✔
216
   m_md.final(output);
378✔
217
}
378✔
218

219
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc