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

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

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

97.93
/src/lib/stream/chacha/chacha.cpp
1
/*
2
* ChaCha
3
* (C) 2014,2018,2023 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

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

10
#include <botan/exceptn.h>
11
#include <botan/internal/cpuid.h>
12
#include <botan/internal/fmt.h>
13
#include <botan/internal/loadstor.h>
14
#include <botan/internal/rotate.h>
15

16
namespace Botan {
17

18
namespace {
19

20
inline void chacha_quarter_round(uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d) {
2,216,096✔
21
   a += b;
2,216,096✔
22
   d ^= a;
2,216,096✔
23
   d = rotl<16>(d);
2,216,096✔
24
   c += d;
25
   b ^= c;
2,216,096✔
26
   b = rotl<12>(b);
2,216,096✔
27
   a += b;
2,216,096✔
28
   d ^= a;
2,216,096✔
29
   d = rotl<8>(d);
2,216,096✔
30
   c += d;
2,216,096✔
31
   b ^= c;
2,216,096✔
32
   b = rotl<7>(b);
2,216,096✔
33
}
2,216,096✔
34

35
/*
36
* Generate HChaCha cipher stream (for XChaCha IV setup)
37
*/
38
void hchacha(uint32_t output[8], const uint32_t input[16], size_t rounds) {
23,410✔
39
   BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds");
23,410✔
40

41
   uint32_t x00 = input[0], x01 = input[1], x02 = input[2], x03 = input[3], x04 = input[4], x05 = input[5],
23,410✔
42
            x06 = input[6], x07 = input[7], x08 = input[8], x09 = input[9], x10 = input[10], x11 = input[11],
23,410✔
43
            x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
23,410✔
44

45
   for(size_t i = 0; i != rounds / 2; ++i) {
257,510✔
46
      chacha_quarter_round(x00, x04, x08, x12);
234,100✔
47
      chacha_quarter_round(x01, x05, x09, x13);
234,100✔
48
      chacha_quarter_round(x02, x06, x10, x14);
234,100✔
49
      chacha_quarter_round(x03, x07, x11, x15);
234,100✔
50

51
      chacha_quarter_round(x00, x05, x10, x15);
234,100✔
52
      chacha_quarter_round(x01, x06, x11, x12);
234,100✔
53
      chacha_quarter_round(x02, x07, x08, x13);
234,100✔
54
      chacha_quarter_round(x03, x04, x09, x14);
234,100✔
55
   }
56

57
   output[0] = x00;
23,410✔
58
   output[1] = x01;
23,410✔
59
   output[2] = x02;
23,410✔
60
   output[3] = x03;
23,410✔
61
   output[4] = x12;
23,410✔
62
   output[5] = x13;
23,410✔
63
   output[6] = x14;
23,410✔
64
   output[7] = x15;
23,410✔
65
}
23,410✔
66

67
}
68

69
ChaCha::ChaCha(size_t rounds) : m_rounds(rounds) {
16,098✔
70
   BOTAN_ARG_CHECK(m_rounds == 8 || m_rounds == 12 || m_rounds == 20, "ChaCha only supports 8, 12 or 20 rounds");
16,098✔
71
}
16,098✔
72

73
size_t ChaCha::parallelism() {
89,110✔
74
#if defined(BOTAN_HAS_CHACHA_AVX512)
75
   if(CPUID::has_avx512())
89,110✔
76
      return 16;
77
#endif
78

79
#if defined(BOTAN_HAS_CHACHA_AVX2)
80
   if(CPUID::has_avx2())
89,110✔
81
      return 8;
88,460✔
82
#endif
83

84
   return 4;
85
}
86

87
std::string ChaCha::provider() const {
324✔
88
#if defined(BOTAN_HAS_CHACHA_AVX512)
89
   if(CPUID::has_avx512()) {
324✔
90
      return "avx512";
×
91
   }
92
#endif
93

94
#if defined(BOTAN_HAS_CHACHA_AVX2)
95
   if(CPUID::has_avx2()) {
324✔
96
      return "avx2";
108✔
97
   }
98
#endif
99

100
#if defined(BOTAN_HAS_CHACHA_SIMD32)
101
   if(CPUID::has_simd_32()) {
216✔
102
      return "simd32";
108✔
103
   }
104
#endif
105

106
   return "base";
108✔
107
}
108

109
void ChaCha::chacha(uint8_t output[], size_t output_blocks, uint32_t state[16], size_t rounds) {
223,014✔
110
   BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds");
223,014✔
111

112
#if defined(BOTAN_HAS_CHACHA_AVX512)
113
   if(CPUID::has_avx512()) {
223,014✔
114
      while(output_blocks >= 16) {
×
115
         ChaCha::chacha_avx512_x16(output, state, rounds);
×
116
         output += 16 * 64;
×
117
         output_blocks -= 16;
×
118
      }
119
   }
120
#endif
121

122
#if defined(BOTAN_HAS_CHACHA_AVX2)
123
   if(CPUID::has_avx2()) {
223,014✔
124
      while(output_blocks >= 8) {
441,364✔
125
         ChaCha::chacha_avx2_x8(output, state, rounds);
220,682✔
126
         output += 8 * 64;
220,682✔
127
         output_blocks -= 8;
220,682✔
128
      }
129
   }
130
#endif
131

132
#if defined(BOTAN_HAS_CHACHA_SIMD32)
133
   if(CPUID::has_simd_32()) {
223,014✔
134
      while(output_blocks >= 4) {
223,014✔
135
         ChaCha::chacha_simd32_x4(output, state, rounds);
1,166✔
136
         output += 4 * 64;
1,166✔
137
         output_blocks -= 4;
1,166✔
138
      }
139
   }
140
#endif
141

142
   // TODO interleave rounds
143
   for(size_t i = 0; i != output_blocks; ++i) {
227,678✔
144
      uint32_t x00 = state[0], x01 = state[1], x02 = state[2], x03 = state[3], x04 = state[4], x05 = state[5],
4,664✔
145
               x06 = state[6], x07 = state[7], x08 = state[8], x09 = state[9], x10 = state[10], x11 = state[11],
4,664✔
146
               x12 = state[12], x13 = state[13], x14 = state[14], x15 = state[15];
4,664✔
147

148
      for(size_t r = 0; r != rounds / 2; ++r) {
47,576✔
149
         chacha_quarter_round(x00, x04, x08, x12);
42,912✔
150
         chacha_quarter_round(x01, x05, x09, x13);
42,912✔
151
         chacha_quarter_round(x02, x06, x10, x14);
42,912✔
152
         chacha_quarter_round(x03, x07, x11, x15);
42,912✔
153

154
         chacha_quarter_round(x00, x05, x10, x15);
42,912✔
155
         chacha_quarter_round(x01, x06, x11, x12);
42,912✔
156
         chacha_quarter_round(x02, x07, x08, x13);
42,912✔
157
         chacha_quarter_round(x03, x04, x09, x14);
42,912✔
158
      }
159

160
      x00 += state[0];
4,664✔
161
      x01 += state[1];
4,664✔
162
      x02 += state[2];
4,664✔
163
      x03 += state[3];
4,664✔
164
      x04 += state[4];
4,664✔
165
      x05 += state[5];
4,664✔
166
      x06 += state[6];
4,664✔
167
      x07 += state[7];
4,664✔
168
      x08 += state[8];
4,664✔
169
      x09 += state[9];
4,664✔
170
      x10 += state[10];
4,664✔
171
      x11 += state[11];
4,664✔
172
      x12 += state[12];
4,664✔
173
      x13 += state[13];
4,664✔
174
      x14 += state[14];
4,664✔
175
      x15 += state[15];
4,664✔
176

177
      store_le(x00, output + 64 * i + 4 * 0);
4,664✔
178
      store_le(x01, output + 64 * i + 4 * 1);
4,664✔
179
      store_le(x02, output + 64 * i + 4 * 2);
4,664✔
180
      store_le(x03, output + 64 * i + 4 * 3);
4,664✔
181
      store_le(x04, output + 64 * i + 4 * 4);
4,664✔
182
      store_le(x05, output + 64 * i + 4 * 5);
4,664✔
183
      store_le(x06, output + 64 * i + 4 * 6);
4,664✔
184
      store_le(x07, output + 64 * i + 4 * 7);
4,664✔
185
      store_le(x08, output + 64 * i + 4 * 8);
4,664✔
186
      store_le(x09, output + 64 * i + 4 * 9);
4,664✔
187
      store_le(x10, output + 64 * i + 4 * 10);
4,664✔
188
      store_le(x11, output + 64 * i + 4 * 11);
4,664✔
189
      store_le(x12, output + 64 * i + 4 * 12);
4,664✔
190
      store_le(x13, output + 64 * i + 4 * 13);
4,664✔
191
      store_le(x14, output + 64 * i + 4 * 14);
4,664✔
192
      store_le(x15, output + 64 * i + 4 * 15);
4,664✔
193

194
      state[12]++;
4,664✔
195
      state[13] += (state[12] == 0);
4,664✔
196
   }
197
}
223,014✔
198

199
/*
200
* Combine cipher stream with message
201
*/
202
void ChaCha::cipher_bytes(const uint8_t in[], uint8_t out[], size_t length) {
288,241✔
203
   assert_key_material_set();
288,241✔
204

205
   while(length >= m_buffer.size() - m_position) {
576,455✔
206
      const size_t available = m_buffer.size() - m_position;
5,346✔
207

208
      xor_buf(out, in, &m_buffer[m_position], available);
5,346✔
209
      chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
5,346✔
210

211
      length -= available;
5,346✔
212
      in += available;
5,346✔
213
      out += available;
5,346✔
214
      m_position = 0;
5,346✔
215
   }
216

217
   xor_buf(out, in, &m_buffer[m_position], length);
282,868✔
218

219
   m_position += length;
282,868✔
220
}
282,868✔
221

222
void ChaCha::generate_keystream(uint8_t out[], size_t length) {
157,775✔
223
   assert_key_material_set();
157,775✔
224

225
   while(length >= m_buffer.size() - m_position) {
333,491✔
226
      const size_t available = m_buffer.size() - m_position;
17,941✔
227

228
      // TODO: this could write directly to the output buffer
229
      // instead of bouncing it through m_buffer first
230
      copy_mem(out, &m_buffer[m_position], available);
17,941✔
231
      chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
17,941✔
232

233
      length -= available;
17,941✔
234
      out += available;
17,941✔
235
      m_position = 0;
17,941✔
236
   }
237

238
   copy_mem(out, &m_buffer[m_position], length);
157,775✔
239

240
   m_position += length;
157,775✔
241
}
157,775✔
242

243
void ChaCha::initialize_state() {
198,836✔
244
   static const uint32_t TAU[] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
198,836✔
245

246
   static const uint32_t SIGMA[] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
198,836✔
247

248
   m_state[4] = m_key[0];
198,836✔
249
   m_state[5] = m_key[1];
198,836✔
250
   m_state[6] = m_key[2];
198,836✔
251
   m_state[7] = m_key[3];
198,836✔
252

253
   if(m_key.size() == 4) {
198,836✔
254
      m_state[0] = TAU[0];
210✔
255
      m_state[1] = TAU[1];
210✔
256
      m_state[2] = TAU[2];
210✔
257
      m_state[3] = TAU[3];
210✔
258

259
      m_state[8] = m_key[0];
210✔
260
      m_state[9] = m_key[1];
210✔
261
      m_state[10] = m_key[2];
210✔
262
      m_state[11] = m_key[3];
210✔
263
   } else {
264
      m_state[0] = SIGMA[0];
198,626✔
265
      m_state[1] = SIGMA[1];
198,626✔
266
      m_state[2] = SIGMA[2];
198,626✔
267
      m_state[3] = SIGMA[3];
198,626✔
268

269
      m_state[8] = m_key[4];
198,626✔
270
      m_state[9] = m_key[5];
198,626✔
271
      m_state[10] = m_key[6];
198,626✔
272
      m_state[11] = m_key[7];
198,626✔
273
   }
274

275
   m_state[12] = 0;
198,836✔
276
   m_state[13] = 0;
198,836✔
277
   m_state[14] = 0;
198,836✔
278
   m_state[15] = 0;
198,836✔
279

280
   m_position = 0;
198,836✔
281
}
198,836✔
282

283
bool ChaCha::has_keying_material() const { return !m_state.empty(); }
659,033✔
284

285
size_t ChaCha::buffer_size() const { return 64; }
324✔
286

287
/*
288
* ChaCha Key Schedule
289
*/
290
void ChaCha::key_schedule(const uint8_t key[], size_t length) {
89,110✔
291
   m_key.resize(length / 4);
89,110✔
292
   load_le<uint32_t>(m_key.data(), key, m_key.size());
89,110✔
293

294
   m_state.resize(16);
89,110✔
295

296
   const size_t chacha_block = 64;
89,110✔
297
   m_buffer.resize(parallelism() * chacha_block);
89,110✔
298

299
   set_iv(nullptr, 0);
89,110✔
300
}
89,110✔
301

302
size_t ChaCha::default_iv_length() const { return 24; }
648✔
303

304
Key_Length_Specification ChaCha::key_spec() const { return Key_Length_Specification(16, 32, 16); }
89,759✔
305

306
std::unique_ptr<StreamCipher> ChaCha::new_object() const { return std::make_unique<ChaCha>(m_rounds); }
324✔
307

308
bool ChaCha::valid_iv_length(size_t iv_len) const {
200,133✔
309
   return (iv_len == 0 || iv_len == 8 || iv_len == 12 || iv_len == 24);
973✔
310
}
311

312
void ChaCha::set_iv_bytes(const uint8_t iv[], size_t length) {
199,481✔
313
   assert_key_material_set();
199,481✔
314

315
   if(!valid_iv_length(length))
199,160✔
316
      throw Invalid_IV_Length(name(), length);
648✔
317

318
   initialize_state();
198,836✔
319

320
   if(length == 0) {
198,836✔
321
      // Treat zero length IV same as an all-zero IV
322
      m_state[14] = 0;
89,113✔
323
      m_state[15] = 0;
89,113✔
324
   } else if(length == 8) {
109,723✔
325
      m_state[14] = load_le<uint32_t>(iv, 0);
310✔
326
      m_state[15] = load_le<uint32_t>(iv, 1);
310✔
327
   } else if(length == 12) {
109,413✔
328
      m_state[13] = load_le<uint32_t>(iv, 0);
86,003✔
329
      m_state[14] = load_le<uint32_t>(iv, 1);
86,003✔
330
      m_state[15] = load_le<uint32_t>(iv, 2);
86,003✔
331
   } else if(length == 24) {
23,410✔
332
      m_state[12] = load_le<uint32_t>(iv, 0);
23,410✔
333
      m_state[13] = load_le<uint32_t>(iv, 1);
23,410✔
334
      m_state[14] = load_le<uint32_t>(iv, 2);
23,410✔
335
      m_state[15] = load_le<uint32_t>(iv, 3);
23,410✔
336

337
      secure_vector<uint32_t> hc(8);
23,410✔
338
      hchacha(hc.data(), m_state.data(), m_rounds);
23,410✔
339

340
      m_state[4] = hc[0];
23,410✔
341
      m_state[5] = hc[1];
23,410✔
342
      m_state[6] = hc[2];
23,410✔
343
      m_state[7] = hc[3];
23,410✔
344
      m_state[8] = hc[4];
23,410✔
345
      m_state[9] = hc[5];
23,410✔
346
      m_state[10] = hc[6];
23,410✔
347
      m_state[11] = hc[7];
23,410✔
348
      m_state[12] = 0;
23,410✔
349
      m_state[13] = 0;
23,410✔
350
      m_state[14] = load_le<uint32_t>(iv, 4);
23,410✔
351
      m_state[15] = load_le<uint32_t>(iv, 5);
23,410✔
352
   }
23,410✔
353

354
   chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
198,836✔
355
   m_position = 0;
198,836✔
356
}
198,836✔
357

358
void ChaCha::clear() {
3,474✔
359
   zap(m_key);
3,474✔
360
   zap(m_state);
3,474✔
361
   zap(m_buffer);
3,474✔
362
   m_position = 0;
3,474✔
363
}
3,474✔
364

365
std::string ChaCha::name() const { return fmt("ChaCha({})", m_rounds); }
7,315✔
366

367
void ChaCha::seek(uint64_t offset) {
1,215✔
368
   assert_key_material_set();
1,215✔
369

370
   // Find the block offset
371
   const uint64_t counter = offset / 64;
891✔
372

373
   uint8_t out[8];
891✔
374

375
   store_le(counter, out);
891✔
376

377
   m_state[12] = load_le<uint32_t>(out, 0);
891✔
378
   m_state[13] += load_le<uint32_t>(out, 1);
891✔
379

380
   chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
891✔
381
   m_position = offset % 64;
891✔
382
}
891✔
383
}
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

© 2025 Coveralls, Inc