Coverage Report

Created: 2025-11-16 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/block/shacal2/shacal2.cpp
Line
Count
Source
1
/*
2
* SHACAL-2
3
* (C) 2017,2020 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/internal/shacal2.h>
9
10
#include <botan/internal/bit_ops.h>
11
#include <botan/internal/loadstor.h>
12
#include <botan/internal/rotate.h>
13
14
#if defined(BOTAN_HAS_CPUID)
15
   #include <botan/internal/cpuid.h>
16
#endif
17
18
namespace Botan {
19
20
namespace {
21
22
inline void SHACAL2_Fwd(
23
0
   uint32_t A, uint32_t B, uint32_t C, uint32_t& D, uint32_t E, uint32_t F, uint32_t G, uint32_t& H, uint32_t RK) {
24
0
   const uint32_t A_rho = rho<2, 13, 22>(A);
25
0
   const uint32_t E_rho = rho<6, 11, 25>(E);
26
27
0
   H += E_rho + choose(E, F, G) + RK;
28
0
   D += H;
29
0
   H += A_rho + majority(A, B, C);
30
0
}
31
32
inline void SHACAL2_Rev(
33
0
   uint32_t A, uint32_t B, uint32_t C, uint32_t& D, uint32_t E, uint32_t F, uint32_t G, uint32_t& H, uint32_t RK) {
34
0
   const uint32_t A_rho = rho<2, 13, 22>(A);
35
0
   const uint32_t E_rho = rho<6, 11, 25>(E);
36
37
0
   H -= A_rho + majority(A, B, C);
38
0
   D -= H;
39
0
   H -= E_rho + choose(E, F, G) + RK;
40
0
}
41
42
}  // namespace
43
44
/*
45
* SHACAL2 Encryption
46
*/
47
0
void SHACAL2::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
48
0
   assert_key_material_set();
49
50
0
#if defined(BOTAN_HAS_SHACAL2_AVX512)
51
0
   if(CPUID::has(CPUID::Feature::AVX512)) {
52
0
      size_t consumed = avx512_encrypt_blocks(in, out, blocks);
53
0
      in += consumed * BLOCK_SIZE;
54
0
      out += consumed * BLOCK_SIZE;
55
0
      blocks -= consumed;
56
0
   }
57
0
#endif
58
59
0
#if defined(BOTAN_HAS_SHACAL2_X86)
60
0
   if(CPUID::has(CPUID::Feature::SHA)) {
61
0
      return x86_encrypt_blocks(in, out, blocks);
62
0
   }
63
0
#endif
64
65
#if defined(BOTAN_HAS_SHACAL2_ARMV8)
66
   if(CPUID::has(CPUID::Feature::SHA2)) {
67
      return armv8_encrypt_blocks(in, out, blocks);
68
   }
69
#endif
70
71
0
#if defined(BOTAN_HAS_SHACAL2_AVX2)
72
0
   if(CPUID::has(CPUID::Feature::AVX2)) {
73
0
      while(blocks >= 8) {
74
0
         avx2_encrypt_8(in, out);
75
0
         in += 8 * BLOCK_SIZE;
76
0
         out += 8 * BLOCK_SIZE;
77
0
         blocks -= 8;
78
0
      }
79
0
   }
80
0
#endif
81
82
0
#if defined(BOTAN_HAS_SHACAL2_SIMD)
83
0
   if(CPUID::has(CPUID::Feature::SIMD_4X32)) {
84
0
      while(blocks >= 4) {
85
0
         simd_encrypt_4(in, out);
86
0
         in += 4 * BLOCK_SIZE;
87
0
         out += 4 * BLOCK_SIZE;
88
0
         blocks -= 4;
89
0
      }
90
0
   }
91
0
#endif
92
93
0
   for(size_t i = 0; i != blocks; ++i) {
94
0
      uint32_t A = load_be<uint32_t>(in, 0);
95
0
      uint32_t B = load_be<uint32_t>(in, 1);
96
0
      uint32_t C = load_be<uint32_t>(in, 2);
97
0
      uint32_t D = load_be<uint32_t>(in, 3);
98
0
      uint32_t E = load_be<uint32_t>(in, 4);
99
0
      uint32_t F = load_be<uint32_t>(in, 5);
100
0
      uint32_t G = load_be<uint32_t>(in, 6);
101
0
      uint32_t H = load_be<uint32_t>(in, 7);
102
103
0
      for(size_t r = 0; r != 64; r += 8) {
104
0
         SHACAL2_Fwd(A, B, C, D, E, F, G, H, m_RK[r + 0]);
105
0
         SHACAL2_Fwd(H, A, B, C, D, E, F, G, m_RK[r + 1]);
106
0
         SHACAL2_Fwd(G, H, A, B, C, D, E, F, m_RK[r + 2]);
107
0
         SHACAL2_Fwd(F, G, H, A, B, C, D, E, m_RK[r + 3]);
108
0
         SHACAL2_Fwd(E, F, G, H, A, B, C, D, m_RK[r + 4]);
109
0
         SHACAL2_Fwd(D, E, F, G, H, A, B, C, m_RK[r + 5]);
110
0
         SHACAL2_Fwd(C, D, E, F, G, H, A, B, m_RK[r + 6]);
111
0
         SHACAL2_Fwd(B, C, D, E, F, G, H, A, m_RK[r + 7]);
112
0
      }
113
114
0
      store_be(out, A, B, C, D, E, F, G, H);
115
116
0
      in += BLOCK_SIZE;
117
0
      out += BLOCK_SIZE;
118
0
   }
119
0
}
120
121
/*
122
* SHACAL2 Encryption
123
*/
124
0
void SHACAL2::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
125
0
   assert_key_material_set();
126
127
0
#if defined(BOTAN_HAS_SHACAL2_AVX512)
128
0
   if(CPUID::has(CPUID::Feature::AVX512)) {
129
0
      size_t consumed = avx512_decrypt_blocks(in, out, blocks);
130
0
      in += consumed * BLOCK_SIZE;
131
0
      out += consumed * BLOCK_SIZE;
132
0
      blocks -= consumed;
133
0
   }
134
0
#endif
135
136
0
#if defined(BOTAN_HAS_SHACAL2_AVX2)
137
0
   if(CPUID::has(CPUID::Feature::AVX2)) {
138
0
      while(blocks >= 8) {
139
0
         avx2_decrypt_8(in, out);
140
0
         in += 8 * BLOCK_SIZE;
141
0
         out += 8 * BLOCK_SIZE;
142
0
         blocks -= 8;
143
0
      }
144
0
   }
145
0
#endif
146
147
0
#if defined(BOTAN_HAS_SHACAL2_SIMD)
148
0
   if(CPUID::has(CPUID::Feature::SIMD_4X32)) {
149
0
      while(blocks >= 4) {
150
0
         simd_decrypt_4(in, out);
151
0
         in += 4 * BLOCK_SIZE;
152
0
         out += 4 * BLOCK_SIZE;
153
0
         blocks -= 4;
154
0
      }
155
0
   }
156
0
#endif
157
158
0
   for(size_t i = 0; i != blocks; ++i) {
159
0
      uint32_t A = load_be<uint32_t>(in, 0);
160
0
      uint32_t B = load_be<uint32_t>(in, 1);
161
0
      uint32_t C = load_be<uint32_t>(in, 2);
162
0
      uint32_t D = load_be<uint32_t>(in, 3);
163
0
      uint32_t E = load_be<uint32_t>(in, 4);
164
0
      uint32_t F = load_be<uint32_t>(in, 5);
165
0
      uint32_t G = load_be<uint32_t>(in, 6);
166
0
      uint32_t H = load_be<uint32_t>(in, 7);
167
168
0
      for(size_t r = 0; r != 64; r += 8) {
169
0
         SHACAL2_Rev(B, C, D, E, F, G, H, A, m_RK[63 - r]);
170
0
         SHACAL2_Rev(C, D, E, F, G, H, A, B, m_RK[62 - r]);
171
0
         SHACAL2_Rev(D, E, F, G, H, A, B, C, m_RK[61 - r]);
172
0
         SHACAL2_Rev(E, F, G, H, A, B, C, D, m_RK[60 - r]);
173
0
         SHACAL2_Rev(F, G, H, A, B, C, D, E, m_RK[59 - r]);
174
0
         SHACAL2_Rev(G, H, A, B, C, D, E, F, m_RK[58 - r]);
175
0
         SHACAL2_Rev(H, A, B, C, D, E, F, G, m_RK[57 - r]);
176
0
         SHACAL2_Rev(A, B, C, D, E, F, G, H, m_RK[56 - r]);
177
0
      }
178
179
0
      store_be(out, A, B, C, D, E, F, G, H);
180
181
0
      in += BLOCK_SIZE;
182
0
      out += BLOCK_SIZE;
183
0
   }
184
0
}
185
186
0
bool SHACAL2::has_keying_material() const {
187
0
   return !m_RK.empty();
188
0
}
189
190
/*
191
* SHACAL2 Key Schedule
192
*/
193
0
void SHACAL2::key_schedule(std::span<const uint8_t> key) {
194
0
   const uint32_t RC[64] = {
195
0
      0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
196
0
      0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
197
0
      0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
198
0
      0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
199
0
      0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
200
0
      0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
201
0
      0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
202
0
      0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2};
203
204
0
   if(m_RK.empty()) {
205
0
      m_RK.resize(64);
206
0
   } else {
207
0
      clear_mem(m_RK.data(), m_RK.size());
208
0
   }
209
210
0
   load_be(m_RK.data(), key.data(), key.size() / 4);
211
212
0
   for(size_t i = 16; i != 64; ++i) {
213
0
      const uint32_t sigma0_15 = sigma<7, 18, 3>(m_RK[i - 15]);
214
0
      const uint32_t sigma1_2 = sigma<17, 19, 10>(m_RK[i - 2]);
215
0
      m_RK[i] = m_RK[i - 16] + sigma0_15 + m_RK[i - 7] + sigma1_2;
216
0
   }
217
218
0
   for(size_t i = 0; i != 64; ++i) {
219
0
      m_RK[i] += RC[i];
220
0
   }
221
0
}
222
223
0
size_t SHACAL2::parallelism() const {
224
0
#if defined(BOTAN_HAS_SHACAL2_AVX512)
225
0
   if(CPUID::has(CPUID::Feature::AVX512)) {
226
0
      return 16;
227
0
   }
228
0
#endif
229
230
0
#if defined(BOTAN_HAS_SHACAL2_X86)
231
0
   if(CPUID::has(CPUID::Feature::SHA)) {
232
0
      return 2;
233
0
   }
234
0
#endif
235
236
#if defined(BOTAN_HAS_SHACAL2_ARMV8)
237
   if(CPUID::has(CPUID::Feature::SHA2)) {
238
      return 2;
239
   }
240
#endif
241
242
0
#if defined(BOTAN_HAS_SHACAL2_AVX2)
243
0
   if(CPUID::has(CPUID::Feature::AVX2)) {
244
0
      return 8;
245
0
   }
246
0
#endif
247
248
0
#if defined(BOTAN_HAS_SHACAL2_SIMD)
249
0
   if(CPUID::has(CPUID::Feature::SIMD_4X32)) {
250
0
      return 4;
251
0
   }
252
0
#endif
253
254
0
   return 1;
255
0
}
256
257
0
std::string SHACAL2::provider() const {
258
0
#if defined(BOTAN_HAS_SHACAL2_AVX512)
259
0
   if(auto feat = CPUID::check(CPUID::Feature::AVX512)) {
260
0
      return *feat;
261
0
   }
262
0
#endif
263
264
0
#if defined(BOTAN_HAS_SHACAL2_X86)
265
0
   if(auto feat = CPUID::check(CPUID::Feature::SHA)) {
266
0
      return *feat;
267
0
   }
268
0
#endif
269
270
#if defined(BOTAN_HAS_SHACAL2_ARMV8)
271
   if(auto feat = CPUID::check(CPUID::Feature::SHA2)) {
272
      return *feat;
273
   }
274
#endif
275
276
0
#if defined(BOTAN_HAS_SHACAL2_AVX2)
277
0
   if(auto feat = CPUID::check(CPUID::Feature::AVX2)) {
278
0
      return *feat;
279
0
   }
280
0
#endif
281
282
0
#if defined(BOTAN_HAS_SHACAL2_SIMD)
283
0
   if(auto feat = CPUID::check(CPUID::Feature::SIMD_4X32)) {
284
0
      return *feat;
285
0
   }
286
0
#endif
287
288
0
   return "base";
289
0
}
290
291
/*
292
* Clear memory of sensitive data
293
*/
294
0
void SHACAL2::clear() {
295
0
   zap(m_RK);
296
0
}
297
298
}  // namespace Botan