Coverage Report

Created: 2025-11-16 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/block/noekeon/noekeon.cpp
Line
Count
Source
1
/*
2
* Noekeon
3
* (C) 1999-2008 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/internal/noekeon.h>
9
10
#include <botan/internal/loadstor.h>
11
#include <botan/internal/rotate.h>
12
13
#if defined(BOTAN_HAS_CPUID)
14
   #include <botan/internal/cpuid.h>
15
#endif
16
17
namespace Botan {
18
19
namespace {
20
21
/*
22
* Noekeon's Theta Operation
23
*/
24
0
inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3, const uint32_t EK[4]) {
25
0
   uint32_t T = A0 ^ A2;
26
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
27
0
   A1 ^= T;
28
0
   A3 ^= T;
29
30
0
   A0 ^= EK[0];
31
0
   A1 ^= EK[1];
32
0
   A2 ^= EK[2];
33
0
   A3 ^= EK[3];
34
35
0
   T = A1 ^ A3;
36
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
37
0
   A0 ^= T;
38
0
   A2 ^= T;
39
0
}
40
41
/*
42
* Theta With Null Key
43
*/
44
0
inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) {
45
0
   uint32_t T = A0 ^ A2;
46
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
47
0
   A1 ^= T;
48
0
   A3 ^= T;
49
50
0
   T = A1 ^ A3;
51
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
52
0
   A0 ^= T;
53
0
   A2 ^= T;
54
0
}
55
56
/*
57
* Noekeon's Gamma S-Box Layer
58
*/
59
0
inline void gamma(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) {
60
0
   A1 ^= ~(A2 | A3);
61
0
   A0 ^= A2 & A1;
62
63
0
   uint32_t T = A3;
64
0
   A3 = A0;
65
0
   A0 = T;
66
67
0
   A2 ^= A0 ^ A1 ^ A3;
68
69
0
   A1 ^= ~(A2 | A3);
70
0
   A0 ^= A2 & A1;
71
0
}
72
73
}  // namespace
74
75
0
size_t Noekeon::parallelism() const {
76
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
77
0
   if(CPUID::has(CPUID::Feature::SIMD_4X32)) {
78
0
      return 4;
79
0
   }
80
0
#endif
81
82
0
   return 1;
83
0
}
84
85
0
std::string Noekeon::provider() const {
86
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
87
0
   if(auto feat = CPUID::check(CPUID::Feature::SIMD_4X32)) {
88
0
      return *feat;
89
0
   }
90
0
#endif
91
92
0
   return "base";
93
0
}
94
95
/*
96
* Noekeon Round Constants
97
*/
98
const uint8_t Noekeon::RC[] = {
99
   0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4};
100
101
/*
102
* Noekeon Encryption
103
*/
104
0
void Noekeon::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
105
0
   assert_key_material_set();
106
107
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
108
0
   if(CPUID::has(CPUID::Feature::SIMD_4X32)) {
109
0
      while(blocks >= 4) {
110
0
         simd_encrypt_4(in, out);
111
0
         in += 4 * BLOCK_SIZE;
112
0
         out += 4 * BLOCK_SIZE;
113
0
         blocks -= 4;
114
0
      }
115
0
   }
116
0
#endif
117
118
0
   for(size_t i = 0; i != blocks; ++i) {
119
0
      uint32_t A0 = load_be<uint32_t>(in, 0);
120
0
      uint32_t A1 = load_be<uint32_t>(in, 1);
121
0
      uint32_t A2 = load_be<uint32_t>(in, 2);
122
0
      uint32_t A3 = load_be<uint32_t>(in, 3);
123
124
0
      for(size_t j = 0; j != 16; ++j) {
125
0
         A0 ^= RC[j];
126
0
         theta(A0, A1, A2, A3, m_EK.data());
127
128
0
         A1 = rotl<1>(A1);
129
0
         A2 = rotl<5>(A2);
130
0
         A3 = rotl<2>(A3);
131
132
0
         gamma(A0, A1, A2, A3);
133
134
0
         A1 = rotr<1>(A1);
135
0
         A2 = rotr<5>(A2);
136
0
         A3 = rotr<2>(A3);
137
0
      }
138
139
0
      A0 ^= RC[16];
140
0
      theta(A0, A1, A2, A3, m_EK.data());
141
142
0
      store_be(out, A0, A1, A2, A3);
143
144
0
      in += BLOCK_SIZE;
145
0
      out += BLOCK_SIZE;
146
0
   }
147
0
}
148
149
/*
150
* Noekeon Encryption
151
*/
152
0
void Noekeon::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
153
0
   assert_key_material_set();
154
155
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
156
0
   if(CPUID::has(CPUID::Feature::SIMD_4X32)) {
157
0
      while(blocks >= 4) {
158
0
         simd_decrypt_4(in, out);
159
0
         in += 4 * BLOCK_SIZE;
160
0
         out += 4 * BLOCK_SIZE;
161
0
         blocks -= 4;
162
0
      }
163
0
   }
164
0
#endif
165
166
0
   for(size_t i = 0; i != blocks; ++i) {
167
0
      uint32_t A0 = load_be<uint32_t>(in, 0);
168
0
      uint32_t A1 = load_be<uint32_t>(in, 1);
169
0
      uint32_t A2 = load_be<uint32_t>(in, 2);
170
0
      uint32_t A3 = load_be<uint32_t>(in, 3);
171
172
0
      for(size_t j = 16; j != 0; --j) {
173
0
         theta(A0, A1, A2, A3, m_DK.data());
174
0
         A0 ^= RC[j];
175
176
0
         A1 = rotl<1>(A1);
177
0
         A2 = rotl<5>(A2);
178
0
         A3 = rotl<2>(A3);
179
180
0
         gamma(A0, A1, A2, A3);
181
182
0
         A1 = rotr<1>(A1);
183
0
         A2 = rotr<5>(A2);
184
0
         A3 = rotr<2>(A3);
185
0
      }
186
187
0
      theta(A0, A1, A2, A3, m_DK.data());
188
0
      A0 ^= RC[0];
189
190
0
      store_be(out, A0, A1, A2, A3);
191
192
0
      in += BLOCK_SIZE;
193
0
      out += BLOCK_SIZE;
194
0
   }
195
0
}
196
197
0
bool Noekeon::has_keying_material() const {
198
0
   return !m_EK.empty();
199
0
}
200
201
/*
202
* Noekeon Key Schedule
203
*/
204
0
void Noekeon::key_schedule(std::span<const uint8_t> key) {
205
0
   uint32_t A0 = load_be<uint32_t>(key.data(), 0);
206
0
   uint32_t A1 = load_be<uint32_t>(key.data(), 1);
207
0
   uint32_t A2 = load_be<uint32_t>(key.data(), 2);
208
0
   uint32_t A3 = load_be<uint32_t>(key.data(), 3);
209
210
0
   for(size_t i = 0; i != 16; ++i) {
211
0
      A0 ^= RC[i];
212
0
      theta(A0, A1, A2, A3);
213
214
0
      A1 = rotl<1>(A1);
215
0
      A2 = rotl<5>(A2);
216
0
      A3 = rotl<2>(A3);
217
218
0
      gamma(A0, A1, A2, A3);
219
220
0
      A1 = rotr<1>(A1);
221
0
      A2 = rotr<5>(A2);
222
0
      A3 = rotr<2>(A3);
223
0
   }
224
225
0
   A0 ^= RC[16];
226
227
0
   m_DK.resize(4);
228
0
   m_DK[0] = A0;
229
0
   m_DK[1] = A1;
230
0
   m_DK[2] = A2;
231
0
   m_DK[3] = A3;
232
233
0
   theta(A0, A1, A2, A3);
234
235
0
   m_EK.resize(4);
236
0
   m_EK[0] = A0;
237
0
   m_EK[1] = A1;
238
0
   m_EK[2] = A2;
239
0
   m_EK[3] = A3;
240
0
}
241
242
/*
243
* Clear memory of sensitive data
244
*/
245
0
void Noekeon::clear() {
246
0
   zap(m_EK);
247
0
   zap(m_DK);
248
0
}
249
250
}  // namespace Botan