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

libbitcoin / libbitcoin-system / 5894307386

17 Aug 2023 06:00PM UTC coverage: 80.943% (-1.9%) from 82.857%
5894307386

push

github

web-flow
Merge pull request #1368 from pmienk/master

Update copyright date range, regenerate artifacts.

9752 of 12048 relevant lines covered (80.94%)

4744998.68 hits per line

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

80.91
/include/bitcoin/system/impl/hash/sha/algorithm.ipp
1
/**
2
 * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS)
3
 *
4
 * This file is part of libbitcoin.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
#ifndef LIBBITCOIN_SYSTEM_HASH_SHA_ALGORITHM_IPP
20
#define LIBBITCOIN_SYSTEM_HASH_SHA_ALGORITHM_IPP
21

22
#include <utility>
23
#include <bitcoin/system/define.hpp>
24
#include <bitcoin/system/endian/endian.hpp>
25
#include <bitcoin/system/math/math.hpp>
26

27
// Based on:
28
// FIPS PUB 180-4 [Secure Hash Standard (SHS)].
29
// All aspects of FIPS180 are supported within the implmentation.
30
// nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
31

32
namespace libbitcoin {
33
namespace system {
34
namespace sha {
35

36
// Bogus warning suggests constexpr when declared consteval.
37
BC_PUSH_WARNING(USE_CONSTEXPR_FOR_FUNCTION)
38
BC_PUSH_WARNING(NO_UNGUARDED_POINTERS)
39
BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)
40
BC_PUSH_WARNING(NO_ARRAY_INDEXING)
41

42
// 4.1 Functions
43
// ---------------------------------------------------------------------------
44

45
TEMPLATE
46
INLINE constexpr auto CLASS::
3,756,440✔
47
parity(auto x, auto y, auto z) NOEXCEPT
48
{
49
    return f::xor_(f::xor_(x, y), z);
50
}
51

52
TEMPLATE
53
INLINE constexpr auto CLASS::
292,944,044✔
54
choice(auto x, auto y, auto z) NOEXCEPT
55
{
56
    // Normal form reduced.
57
    ////return (x & y) ^ (~x & z);
58
    return f::xor_(f::and_(x, f::xor_(y, z)), z);
59
}
60

61
TEMPLATE
62
INLINE constexpr auto CLASS::
292,944,044✔
63
majority(auto x, auto y, auto z) NOEXCEPT
64
{
65
    // Normal form reduced.
66
    ////return (x & y) ^ (x & z) ^ (y & z);
67
    return f::or_(f::and_(x, f::or_(y, z)), f::and_(y, z));
68
}
69

70
TEMPLATE
71
template <unsigned int A, unsigned int B, unsigned int C>
72
INLINE constexpr auto CLASS::
303,566,806✔
73
sigma(auto x) NOEXCEPT
74
{
75
    constexpr auto s = SHA::word_bits;
76
    return f::xor_(f::xor_(f::ror<A, s>(x), f::ror<B, s>(x)), f::shr<C, s>(x));
77
}
78

79
TEMPLATE
80
template <unsigned int A, unsigned int B, unsigned int C>
81
INLINE constexpr auto CLASS::
582,131,648✔
82
Sigma(auto x) NOEXCEPT
83
{
84
    // Specialized for non-vector destructive ror.
85
    // "Because the ror instruction is destructive (that is, it overwrites the
86
    // operand), implementing the above as written would involve a number of
87
    // source register copy operations. If, however, the expressions are
88
    // rewritten as... Then the number of register copies can be minimized."
89
    // intel.com/content/dam/www/public/us/en/documents/white-papers/
90
    // sha-256-implementations-paper.pdf
91
    // AVX optimal (sha256)
92
    //
93
    // Examples:
94
    // S0(a) = (a >>> 2) ^ (a >>> 13) ^ (a >>> 22)
95
    // S1(e) = (e >>> 6) ^ (e >>> 11) ^ (e >>> 25)
96
    // S0(a) = ((((a >>>  9) ^ a) >>> 11) ^ a) >>> 2
97
    // S1(e) = ((((e >>> 14) ^ e) >>>  5) ^ e) >>> 6
98
    //
99
    // Generalization:
100
    // S (n) = (n >>> x) ^ (n >>> y) ^ (n >>> z)
101
    // S'(n) = ((((n >>> X) ^ n) >>> Y) ^ n) >>> Z
102
    // X = z - y
103
    // Y = y - x
104
    // Z = x
105
    // S'(n) = ((((n >>> (z-y)) ^ n) >>> (y-x)) ^ n) >>> x
106
    ////return f::xor_(f::xor_(f::ror<A, s>(x), f::ror<B, s>(x)), f::ror<C, s>(x));
107

108
    // This Sigma refactoring reduces native processing time by ~10%.
109
    constexpr auto s = SHA::word_bits;
110
    return f::ror<A, s>(f::xor_(f::ror<B - A, s>(f::xor_(f::ror<C - B, s>(x), x)), x));
111
}
112

113
// Sigma dispatch.
114
// ---------------------------------------------------------------------------
115

116
TEMPLATE
117
INLINE constexpr auto CLASS::
6,483,600✔
118
sigma0(auto x) NOEXCEPT
119
{
120
    if constexpr (SHA::strength == 256)
121
        return sigma<7, 18, 3>(x);
122
    else
123
        return sigma<1, 8, 7>(x);
124
}
125

126
TEMPLATE
127
INLINE constexpr auto CLASS::
36,089,008✔
128
sigma1(auto x) NOEXCEPT
129
{
130
    if constexpr (SHA::strength == 256)
131
        return sigma<17, 19, 10>(x);
132
    else
133
        return sigma<19, 61, 6>(x);
134
}
135

136
TEMPLATE
137
INLINE constexpr auto CLASS::
291,065,824✔
138
Sigma0(auto x) NOEXCEPT
139
{
140
    if constexpr (SHA::strength == 256)
141
        return Sigma<2, 13, 22>(x);
142
    else
143
        return Sigma<28, 34, 39>(x);
144
}
145

146
TEMPLATE
147
INLINE constexpr auto CLASS::
291,065,824✔
148
Sigma1(auto x) NOEXCEPT
149
{
150
    if constexpr (SHA::strength == 256)
151
        return Sigma<6, 11, 25>(x);
152
    else
153
        return Sigma<14, 18, 41>(x);
154
}
155

156
// Rounds
157
// ---------------------------------------------------------------------------
158

159
TEMPLATE
160
template<size_t Round, typename Auto>
161
CONSTEVAL auto CLASS::
162
functor() NOEXCEPT
163
{
164
    using self = CLASS;
165
    constexpr auto fn = Round / K::columns;
166

167
    if constexpr (fn == 0u)
168
        return &self::template choice<Auto, Auto, Auto>;
169
    else if constexpr (fn == 1u)
170
        return &self::template parity<Auto, Auto, Auto>;
171
    else if constexpr (fn == 2u)
172
        return &self::template majority<Auto, Auto, Auto>;
173
    else if constexpr (fn == 3u)
174
        return &self::template parity<Auto, Auto, Auto>;
175
}
176

177
TEMPLATE
178
template<size_t Round>
179
INLINE constexpr void CLASS::
7,512,880✔
180
round(auto a, auto& b, auto c, auto d, auto& e, auto wk) NOEXCEPT
181
{
182
    constexpr auto s = SHA::word_bits;
183
    constexpr auto fn = functor<Round, decltype(a)>();
184
    e = /*a =*/ f::add<s>(f::add<s>(f::add<s>(f::rol<5, s>(a), fn(b, c, d)), e), wk);
15,025,760✔
185
    b = /*c =*/ f::rol<30, s>(b);
7,512,880✔
186

187
    // SHA-NI
188
    // Four rounds (total rounds 80/4).
189
    // First round is add(e, w), then sha1nexte(e, w).
190
    // fk is round-based enumeration implying f selection and k value.
191
    //     e1 = sha1nexte(e0, w);
192
    //     abcd = sha1rnds4(abcd, e0, fk);
193
    // NEON
194
    // f is implied by k in wk.
195
    //     e1 = vsha1h(vgetq_lane(abcd, 0);
196
    //     vsha1cq(abcd, e0, vaddq(w, k));
197
}
198

199
TEMPLATE
200
template<size_t Round>
201
INLINE constexpr void CLASS::
291,065,824✔
202
round(auto a, auto b, auto c, auto& d, auto e, auto f, auto g, auto& h,
203
    auto wk) NOEXCEPT
204
{
205
    // TODO: if open lanes, vectorize Sigma0 and Sigma1 (see Intel).
206
    constexpr auto s = SHA::word_bits;
207
    const auto t = f::add<s>(f::add<s>(f::add<s>(Sigma1(e), choice(e, f, g)), h), wk);
291,065,824✔
208
    d = /*e =*/    f::add<s>(d, t);
291,065,824✔
209
    h = /*a =*/    f::add<s>(f::add<s>(Sigma0(a), majority(a, b, c)), t);
291,065,824✔
210

211
    // Rounds can be cut in half and this round doubled (intel paper).
212
    // Avoids the need for a temporary variable and aligns with SHA-NI.
213
    // Removing the temporary eliminates 2x64 instructions from the assembly.
214
    // h = /*a =*/ SIGMA0(a) + SIGMA1(e) + majority(a, b, c) +
215
    //             choice(e, f, g) + (k + w) + h;
216
    // d = /*e =*/ SIGMA1(e) + choice(e, f, g) + (k + w) + h + d;
217
    //
218
    // Each call is 2 rounds, 4 rounds total.
219
    // s, w and k are 128 (4 words each, s1/s2 is 8 word state).
220
    // SHA-NI
221
    //     const auto value = add(w, k);
222
    //     abcd = sha256rnds2(abcd, efgh, value);
223
    //     efgh = sha256rnds2(efgh, abcd, shuffle(value));
224
    // NEON
225
    //     const auto value = vaddq(w, k);
226
    //     abcd = vsha256hq(abcd, efgh, value);
227
    //     efgh = vsha256h2q(efgh, abcd, value);
228
}
229

230
TEMPLATE
231
template <typename Word, size_t Lane>
232
INLINE constexpr auto CLASS::
233
extract(Word a) NOEXCEPT
234
{
235
    // Compress vectorization and non-vectorization require no extraction.
236
    static_assert(Lane == zero);
237
    return a;
238
}
239

240
TEMPLATE
241
template <typename Word, size_t Lane, typename xWord,
242
    if_not_same<Word, xWord>>
243
INLINE Word CLASS::
8,806,400✔
244
extract(xWord a) NOEXCEPT
245
{
246
    // Schedule vectorization (with compress non-vectorization), extract word.
247
    return get<Word, Lane>(a);
248
}
249

250
TEMPLATE
251
template<size_t Round, size_t Lane>
252
INLINE constexpr void CLASS::
298,578,704✔
253
round(auto& state, const auto& wk) NOEXCEPT
254
{
255
    using word = std::decay_t<decltype(state.front())>;
256

257
    if constexpr (SHA::strength == 160)
258
    {
259
        // msvc++ not inlined in x32 for vectorized state.
260
        BC_PUSH_WARNING(NOT_INLINED)
261
        round<Round>(
11,260,720✔
262
            state[(SHA::rounds + 0 - Round) % SHA::state_words],
7,512,880✔
263
            state[(SHA::rounds + 1 - Round) % SHA::state_words], // c->b
7,512,880✔
264
            state[(SHA::rounds + 2 - Round) % SHA::state_words],
7,512,880✔
265
            state[(SHA::rounds + 3 - Round) % SHA::state_words],
7,512,880✔
266
            state[(SHA::rounds + 4 - Round) % SHA::state_words], // a->e
3,747,840✔
267
            extract<word, Lane>(wk[Round]));
7,418,969✔
268
        BC_POP_WARNING()
269

270
        // SNA-NI/NEON
271
        // State packs in 128 (one state variable), reduces above to 1 out[].
272
        // Input value is 128 (w). Constants (k) statically initialized as 128.
273
    }
274
    else
275
    {
276
        // msvc++ not inlined in x32 for vectorized state.
277
        BC_PUSH_WARNING(NOT_INLINED)
278
        round<Round>(
296,124,384✔
279
            state[(SHA::rounds + 0 - Round) % SHA::state_words],
291,065,824✔
280
            state[(SHA::rounds + 1 - Round) % SHA::state_words],
291,065,824✔
281
            state[(SHA::rounds + 2 - Round) % SHA::state_words],
291,065,824✔
282
            state[(SHA::rounds + 3 - Round) % SHA::state_words], // e->d
291,065,824✔
283
            state[(SHA::rounds + 4 - Round) % SHA::state_words],
291,065,824✔
284
            state[(SHA::rounds + 5 - Round) % SHA::state_words],
291,065,824✔
285
            state[(SHA::rounds + 6 - Round) % SHA::state_words],
291,065,824✔
286
            state[(SHA::rounds + 7 - Round) % SHA::state_words], // a->h
5,058,560✔
287
            extract<word, Lane>(wk[Round]));
286,661,856✔
288
        BC_POP_WARNING()
289

290
        // SHA-NI/NEON
291
        // Each element is 128 (vs. 32), reduces above to 2 out[] (s0/s1).
292
        // Input value is 128 (w). Constants (k) statically initialized as 128.
293
    }
294
}
295

296
TEMPLATE
297
template <size_t Lane>
298
constexpr void CLASS::
4,497,879✔
299
compress(auto& state, const auto& buffer) NOEXCEPT
300
{
301
    // SHA-NI/256: 64/4 = 16 quad rounds, 8/4 = 2 state elements.
302
    // This is a copy (state type varies due to vectorization).
303
    const auto start = state;
4,497,879✔
304

305
    round< 0, Lane>(state, buffer);
306
    round< 1, Lane>(state, buffer);
307
    round< 2, Lane>(state, buffer);
308
    round< 3, Lane>(state, buffer);
309
    round< 4, Lane>(state, buffer);
310
    round< 5, Lane>(state, buffer);
311
    round< 6, Lane>(state, buffer);
312
    round< 7, Lane>(state, buffer);
313
    round< 8, Lane>(state, buffer);
314
    round< 9, Lane>(state, buffer);
315
    round<10, Lane>(state, buffer);
316
    round<11, Lane>(state, buffer);
317
    round<12, Lane>(state, buffer);
318
    round<13, Lane>(state, buffer);
319
    round<14, Lane>(state, buffer);
320
    round<15, Lane>(state, buffer);
321

322
    round<16, Lane>(state, buffer);
323
    round<17, Lane>(state, buffer);
324
    round<18, Lane>(state, buffer);
325
    round<19, Lane>(state, buffer);
326
    round<20, Lane>(state, buffer);
327
    round<21, Lane>(state, buffer);
328
    round<22, Lane>(state, buffer);
329
    round<23, Lane>(state, buffer);
330
    round<24, Lane>(state, buffer);
331
    round<25, Lane>(state, buffer);
332
    round<26, Lane>(state, buffer);
333
    round<27, Lane>(state, buffer);
334
    round<28, Lane>(state, buffer);
335
    round<29, Lane>(state, buffer);
336
    round<30, Lane>(state, buffer);
337
    round<31, Lane>(state, buffer);
338

339
    round<32, Lane>(state, buffer);
340
    round<33, Lane>(state, buffer);
341
    round<34, Lane>(state, buffer);
342
    round<35, Lane>(state, buffer);
343
    round<36, Lane>(state, buffer);
344
    round<37, Lane>(state, buffer);
345
    round<38, Lane>(state, buffer);
346
    round<39, Lane>(state, buffer);
347
    round<40, Lane>(state, buffer);
348
    round<41, Lane>(state, buffer);
349
    round<42, Lane>(state, buffer);
350
    round<43, Lane>(state, buffer);
351
    round<44, Lane>(state, buffer);
352
    round<45, Lane>(state, buffer);
353
    round<46, Lane>(state, buffer);
354
    round<47, Lane>(state, buffer);
355

356
    round<48, Lane>(state, buffer);
357
    round<49, Lane>(state, buffer);
358
    round<50, Lane>(state, buffer);
359
    round<51, Lane>(state, buffer);
360
    round<52, Lane>(state, buffer);
361
    round<53, Lane>(state, buffer);
362
    round<54, Lane>(state, buffer);
363
    round<55, Lane>(state, buffer);
364
    round<56, Lane>(state, buffer);
365
    round<57, Lane>(state, buffer);
366
    round<58, Lane>(state, buffer);
367
    round<59, Lane>(state, buffer);
368
    round<60, Lane>(state, buffer);
369
    round<61, Lane>(state, buffer);
370
    round<62, Lane>(state, buffer);
371
    round<63, Lane>(state, buffer);
372

373
    if constexpr (SHA::rounds == 80)
374
    {
375
        round<64, Lane>(state, buffer);
376
        round<65, Lane>(state, buffer);
377
        round<66, Lane>(state, buffer);
378
        round<67, Lane>(state, buffer);
379
        round<68, Lane>(state, buffer);
380
        round<69, Lane>(state, buffer);
381
        round<70, Lane>(state, buffer);
382
        round<71, Lane>(state, buffer);
383
        round<72, Lane>(state, buffer);
384
        round<73, Lane>(state, buffer);
385
        round<74, Lane>(state, buffer);
386
        round<75, Lane>(state, buffer);
387
        round<76, Lane>(state, buffer);
388
        round<77, Lane>(state, buffer);
389
        round<78, Lane>(state, buffer);
390
        round<79, Lane>(state, buffer);
391
    }
392

393
    summarize(state, start);
394
}
4,497,879✔
395

396
TEMPLATE
397
template<size_t Round>
398
INLINE constexpr void CLASS::
137,883,302✔
399
prepare(auto& buffer) NOEXCEPT
400
{
401
    // K is added to schedule words because schedule is vectorizable.
402
    // K-adding is shifted -16, with last 16 added after scheduling.
403
    constexpr auto s = SHA::word_bits;
404

405
    if constexpr (SHA::strength == 160)
406
    {
407
        constexpr auto r03 = Round - 3;
408
        constexpr auto r08 = Round - 8;
409
        constexpr auto r14 = Round - 14;
410
        constexpr auto r16 = Round - 16;
411

412
        buffer[Round] = f::rol<1, s>(f::xor_(
3,061,308✔
413
            f::xor_(buffer[r16], buffer[r14]),
3,014,256✔
414
            f::xor_(buffer[r08], buffer[r03])));
2,964,276✔
415

416
        buffer[r16] = f::addc<K::get[r16], s>(buffer[r16]);
3,014,256✔
417

418
        // SHA-NI
419
        //     buffer[Round] = sha1msg2 // xor and rotl1
420
        //     (
421
        //         xor                // not using sha1msg1
422
        //         (
423
        //             sha1msg1       // xor (specialized)
424
        //             (
425
        //                 buffer[Round - 16],
426
        //                 buffer[Round - 14]
427
        //             ),
428
        //             buffer[Round -  8]
429
        //          ),
430
        //          buffer[Round -  3]
431
        //     );
432
        // NEON
433
        //     vsha1su1q/vsha1su0q
434
    }
435
    else
436
    {
437
        constexpr auto r02 = Round - 2;
438
        constexpr auto r07 = Round - 7;
439
        constexpr auto r15 = Round - 15;
440
        constexpr auto r16 = Round - 16;
441

442
        buffer[Round] = f::add<s>(
272,533,883✔
443
            f::add<s>(buffer[r16], sigma0(buffer[r15])),
269,726,016✔
444
            f::add<s>(buffer[r07], sigma1(buffer[r02])));
266,924,187✔
445

446
        buffer[r16] = f::addc<K::get[r16], s>(buffer[r16]);
134,869,046✔
447

448
        // Each word is 128, buffer goes from 64 to 16 words.
449
        // SHA-NI
450
        // buffer[Round] =
451
        //     sha256msg1(buffer[Round - 16], buffer[Round - 15]) +
452
        //     sha256msg2(buffer[Round -  7], buffer[Round -  2]);
453
        // NEON
454
        // Not sure about these indexes.
455
        // mijailovic.net/2018/06/06/sha256-armv8
456
        // buffer[Round] =
457
        //     vsha256su0q(buffer[Round - 13], buffer[Round - 9])
458
        //     vsha256su1q(buffer[Round - 13], buffer[Round - 5],
459
        //                 buffer[Round - 1]);
460
    }
461
}
462

463
TEMPLATE
464
INLINE constexpr void CLASS::
3,386,515✔
465
add_k(auto& buffer) NOEXCEPT
466
{
467
    // Add K to last 16 words.
468
    constexpr auto s = SHA::word_bits;
469
    constexpr auto r = SHA::rounds - array_count<words_t>;
470
    buffer[r + 0] = f::addc<K::get[r + 0], s>(buffer[r + 0]);
3,386,515✔
471
    buffer[r + 1] = f::addc<K::get[r + 1], s>(buffer[r + 1]);
3,386,515✔
472
    buffer[r + 2] = f::addc<K::get[r + 2], s>(buffer[r + 2]);
3,386,515✔
473
    buffer[r + 3] = f::addc<K::get[r + 3], s>(buffer[r + 3]);
3,386,515✔
474
    buffer[r + 4] = f::addc<K::get[r + 4], s>(buffer[r + 4]);
3,386,515✔
475
    buffer[r + 5] = f::addc<K::get[r + 5], s>(buffer[r + 5]);
3,386,515✔
476
    buffer[r + 6] = f::addc<K::get[r + 6], s>(buffer[r + 6]);
3,386,515✔
477
    buffer[r + 7] = f::addc<K::get[r + 7], s>(buffer[r + 7]);
3,386,515✔
478
    buffer[r + 8] = f::addc<K::get[r + 8], s>(buffer[r + 8]);
3,386,515✔
479
    buffer[r + 9] = f::addc<K::get[r + 9], s>(buffer[r + 9]);
3,386,515✔
480
    buffer[r + 10] = f::addc<K::get[r + 10], s>(buffer[r + 10]);
3,386,515✔
481
    buffer[r + 11] = f::addc<K::get[r + 11], s>(buffer[r + 11]);
3,386,515✔
482
    buffer[r + 12] = f::addc<K::get[r + 12], s>(buffer[r + 12]);
3,386,515✔
483
    buffer[r + 13] = f::addc<K::get[r + 13], s>(buffer[r + 13]);
3,386,515✔
484
    buffer[r + 14] = f::addc<K::get[r + 14], s>(buffer[r + 14]);
3,386,515✔
485
    buffer[r + 15] = f::addc<K::get[r + 15], s>(buffer[r + 15]);
2,740,610✔
486
}
528,668✔
487

488
TEMPLATE
489
INLINE constexpr void CLASS::
2,857,847✔
490
schedule_(auto& buffer) NOEXCEPT
491
{
492
    prepare<16>(buffer);
493
    prepare<17>(buffer);
494
    prepare<18>(buffer);
495
    prepare<19>(buffer);
496
    prepare<20>(buffer);
497
    prepare<21>(buffer);
498
    prepare<22>(buffer);
499
    prepare<23>(buffer);
500
    prepare<24>(buffer);
501
    prepare<25>(buffer);
502
    prepare<26>(buffer);
503
    prepare<27>(buffer);
504
    prepare<28>(buffer);
505
    prepare<29>(buffer);
506
    prepare<30>(buffer);
507
    prepare<31>(buffer);
508

509
    prepare<32>(buffer);
510
    prepare<33>(buffer);
511
    prepare<34>(buffer);
512
    prepare<35>(buffer);
513
    prepare<36>(buffer);
514
    prepare<37>(buffer);
515
    prepare<38>(buffer);
516
    prepare<39>(buffer);
517
    prepare<40>(buffer);
518
    prepare<41>(buffer);
519
    prepare<42>(buffer);
520
    prepare<43>(buffer);
521
    prepare<44>(buffer);
522
    prepare<45>(buffer);
523
    prepare<46>(buffer);
524
    prepare<47>(buffer);
525

526
    prepare<48>(buffer);
527
    prepare<49>(buffer);
528
    prepare<50>(buffer);
529
    prepare<51>(buffer);
530
    prepare<52>(buffer);
531
    prepare<53>(buffer);
532
    prepare<54>(buffer);
533
    prepare<55>(buffer);
534
    prepare<56>(buffer);
535
    prepare<57>(buffer);
536
    prepare<58>(buffer);
537
    prepare<59>(buffer);
538
    prepare<60>(buffer);
539
    prepare<61>(buffer);
540
    prepare<62>(buffer);
541
    prepare<63>(buffer);
542

543
    if constexpr (SHA::rounds == 80)
544
    {
545
        prepare<64>(buffer);
546
        prepare<65>(buffer);
547
        prepare<66>(buffer);
548
        prepare<67>(buffer);
549
        prepare<68>(buffer);
550
        prepare<69>(buffer);
551
        prepare<70>(buffer);
552
        prepare<71>(buffer);
553
        prepare<72>(buffer);
554
        prepare<73>(buffer);
555
        prepare<74>(buffer);
556
        prepare<75>(buffer);
557
        prepare<76>(buffer);
558
        prepare<77>(buffer);
559
        prepare<78>(buffer);
560
        prepare<79>(buffer);
561
    }
562

563
    add_k(buffer);
564
}
117,237✔
565

566
TEMPLATE
567
constexpr void CLASS::
3,377,549✔
568
schedule(auto& buffer) NOEXCEPT
569
{
570
    if (std::is_constant_evaluated())
3,377,549✔
571
    {
572
        schedule_(buffer);
573
    }
574
    else if constexpr (vectorization)
575
    {
576
        schedule_dispatch(buffer);
577
    }
578
    else
579
    {
580
        schedule_(buffer);
581
    }
582
}
3,377,549✔
583

584
TEMPLATE
585
INLINE constexpr void CLASS::
4,497,879✔
586
summarize(auto& out, const auto& in) NOEXCEPT
587
{
588
    constexpr auto s = SHA::word_bits;
589
    out[0] = f::add<s>(out[0], in[0]);
4,497,879✔
590
    out[1] = f::add<s>(out[1], in[1]);
4,497,879✔
591
    out[2] = f::add<s>(out[2], in[2]);
4,497,879✔
592
    out[3] = f::add<s>(out[3], in[3]);
4,497,879✔
593
    out[4] = f::add<s>(out[4], in[4]);
4,497,879✔
594

595
    if constexpr (SHA::strength != 160)
596
    {
597
        out[5] = f::add<s>(out[5], in[5]);
4,403,968✔
598
        out[6] = f::add<s>(out[6], in[6]);
4,403,968✔
599
        out[7] = f::add<s>(out[7], in[7]);
4,403,968✔
600
    }
601
}
602

603
TEMPLATE
604
INLINE constexpr void CLASS::
75✔
605
input(auto& buffer, const auto& state) NOEXCEPT
606
{
607
    // This is a double hash optimization.
608
    if (std::is_constant_evaluated())
×
609
    {
610
        buffer[0] = state[0];
×
611
        buffer[1] = state[1];
×
612
        buffer[2] = state[2];
×
613
        buffer[3] = state[3];
×
614
        buffer[4] = state[4];
×
615

616
        if constexpr (SHA::strength != 160)
617
        {
618
            buffer[5] = state[5];
×
619
            buffer[6] = state[6];
×
620
            buffer[7] = state[7];
×
621
        }
622
    }
623
    else
624
    {
625
        using word = array_element<decltype(state)>;
626
        array_cast<word, SHA::state_words>(buffer) = state;
338✔
627
    }
628
}
629

630
// 5.2 Parsing the Message
631
// ---------------------------------------------------------------------------
632
// big-endian I/O is conventional for SHA.
633

634
TEMPLATE
635
INLINE constexpr void CLASS::
3,275,204✔
636
input(buffer_t& buffer, const block_t& block) NOEXCEPT
637
{
638
    if (std::is_constant_evaluated())
1,620✔
639
    {
640
        constexpr auto size = SHA::word_bytes;
641
        from_big<0 * size>(buffer.at(0), block);
×
642
        from_big<1 * size>(buffer.at(1), block);
×
643
        from_big<2 * size>(buffer.at(2), block);
×
644
        from_big<3 * size>(buffer.at(3), block);
×
645
        from_big<4 * size>(buffer.at(4), block);
×
646
        from_big<5 * size>(buffer.at(5), block);
×
647
        from_big<6 * size>(buffer.at(6), block);
×
648
        from_big<7 * size>(buffer.at(7), block);
×
649
        from_big<8 * size>(buffer.at(8), block);
×
650
        from_big<9 * size>(buffer.at(9), block);
×
651
        from_big<10 * size>(buffer.at(10), block);
×
652
        from_big<11 * size>(buffer.at(11), block);
×
653
        from_big<12 * size>(buffer.at(12), block);
×
654
        from_big<13 * size>(buffer.at(13), block);
×
655
        from_big<14 * size>(buffer.at(14), block);
×
656
        from_big<15 * size>(buffer.at(15), block);
×
657
    }
658
    else if constexpr (bc::is_little_endian)
659
    {
660
        const auto& in = array_cast<word_t>(block);
1,620✔
661
        buffer[0] = native_from_big_end(in[0]);
2,748,509✔
662
        buffer[1] = native_from_big_end(in[1]);
1,620✔
663
        buffer[2] = native_from_big_end(in[2]);
1,620✔
664
        buffer[3] = native_from_big_end(in[3]);
1,620✔
665
        buffer[4] = native_from_big_end(in[4]);
1,620✔
666
        buffer[5] = native_from_big_end(in[5]);
1,620✔
667
        buffer[6] = native_from_big_end(in[6]);
1,620✔
668
        buffer[7] = native_from_big_end(in[7]);
1,620✔
669
        buffer[8] = native_from_big_end(in[8]);
1,620✔
670
        buffer[9] = native_from_big_end(in[9]);
1,620✔
671
        buffer[10] = native_from_big_end(in[10]);
1,620✔
672
        buffer[11] = native_from_big_end(in[11]);
1,620✔
673
        buffer[12] = native_from_big_end(in[12]);
1,620✔
674
        buffer[13] = native_from_big_end(in[13]);
1,620✔
675
        buffer[14] = native_from_big_end(in[14]);
1,620✔
676
        buffer[15] = native_from_big_end(in[15]);
3,240✔
677
    }
678
    else
679
    {
680
        array_cast<word_t, SHA::block_words>(buffer) =
681
            array_cast<word_t>(block);
682
    }
683
}
684

685
TEMPLATE
686
INLINE constexpr void CLASS::
100,789✔
687
input1(buffer_t& buffer, const half_t& half) NOEXCEPT
688
{
689
    using word = array_element<buffer_t>;
690

691
    if (std::is_constant_evaluated())
692
    {
693
        constexpr auto size = SHA::word_bytes;
694
        from_big<0 * size>(buffer.at(0), half);
695
        from_big<1 * size>(buffer.at(1), half);
696
        from_big<2 * size>(buffer.at(2), half);
697
        from_big<3 * size>(buffer.at(3), half);
698
        from_big<4 * size>(buffer.at(4), half);
699
        from_big<5 * size>(buffer.at(5), half);
700
        from_big<6 * size>(buffer.at(6), half);
701
        from_big<7 * size>(buffer.at(7), half);
702
    }
703
    else if constexpr (bc::is_little_endian)
704
    {
705
        const auto& in = array_cast<word>(half);
3✔
706
        buffer[0] = native_from_big_end(in[0]);
22✔
707
        buffer[1] = native_from_big_end(in[1]);
100,789✔
708
        buffer[2] = native_from_big_end(in[2]);
100,789✔
709
        buffer[3] = native_from_big_end(in[3]);
100,789✔
710
        buffer[4] = native_from_big_end(in[4]);
100,789✔
711
        buffer[5] = native_from_big_end(in[5]);
100,789✔
712
        buffer[6] = native_from_big_end(in[6]);
100,789✔
713
        buffer[7] = native_from_big_end(in[7]);
100,789✔
714
    }
715
    else
716
    {
717
        array_cast<word, SHA::chunk_words>(buffer) = array_cast<word>(half);
718
    }
719
}
720

721
TEMPLATE
722
INLINE constexpr void CLASS::
48✔
723
input2(buffer_t& buffer, const half_t& half) NOEXCEPT
724
{
725
    using word = array_element<buffer_t>;
726

727
    if (std::is_constant_evaluated())
728
    {
729
        constexpr auto size = SHA::word_bytes;
730
        from_big<0 * size>(buffer.at(8), half);
731
        from_big<1 * size>(buffer.at(9), half);
732
        from_big<2 * size>(buffer.at(10), half);
733
        from_big<3 * size>(buffer.at(11), half);
734
        from_big<4 * size>(buffer.at(12), half);
735
        from_big<5 * size>(buffer.at(13), half);
736
        from_big<6 * size>(buffer.at(14), half);
737
        from_big<7 * size>(buffer.at(15), half);
738
    }
739
    else if constexpr (bc::is_little_endian)
740
    {
741
        const auto& in = array_cast<word>(half);
3✔
742
        buffer[8] = native_from_big_end(in[0]);
15✔
743
        buffer[9] = native_from_big_end(in[1]);
48✔
744
        buffer[10] = native_from_big_end(in[2]);
48✔
745
        buffer[11] = native_from_big_end(in[3]);
48✔
746
        buffer[12] = native_from_big_end(in[4]);
48✔
747
        buffer[13] = native_from_big_end(in[5]);
48✔
748
        buffer[14] = native_from_big_end(in[6]);
48✔
749
        buffer[15] = native_from_big_end(in[7]);
48✔
750
    }
751
    else
752
    {
753
        array_cast<word, SHA::chunk_words, SHA::chunk_words>(buffer) =
754
            array_cast<word>(half);
755
    }
756
}
757

758
TEMPLATE
759
INLINE constexpr typename CLASS::digest_t CLASS::
2,406,713✔
760
output(const state_t& state) NOEXCEPT
761
{
762
    if (std::is_constant_evaluated())
32✔
763
    {
764
        digest_t digest{};
×
765

766
        constexpr auto size = SHA::word_bytes;
767
        to_big<0 * size>(digest, state.at(0));
×
768
        to_big<1 * size>(digest, state.at(1));
×
769
        to_big<2 * size>(digest, state.at(2));
×
770
        to_big<3 * size>(digest, state.at(3));
×
771
        to_big<4 * size>(digest, state.at(4));
×
772

773
        if constexpr (SHA::strength != 160)
774
        {
775
            to_big<5 * size>(digest, state.at(5));
×
776
            to_big<6 * size>(digest, state.at(6));
×
777
            to_big<7 * size>(digest, state.at(7));
×
778
        }
779

780
        return digest;
×
781
    }
782
    else if constexpr (bc::is_little_endian)
783
    {
784
        if constexpr (SHA::strength == 160)
785
        {
786
            return array_cast<byte_t>(state_t
7✔
787
            {
788
                native_to_big_end(state[0]),
7✔
789
                native_to_big_end(state[1]),
7✔
790
                native_to_big_end(state[2]),
7✔
791
                native_to_big_end(state[3]),
7✔
792
                native_to_big_end(state[4])
98✔
793
            });
794
        }
795
        else
796
        {
797
            return array_cast<byte_t>(state_t
304✔
798
            {
799
                native_to_big_end(state[0]),
1,000,314✔
800
                native_to_big_end(state[1]),
303✔
801
                native_to_big_end(state[2]),
303✔
802
                native_to_big_end(state[3]),
303✔
803
                native_to_big_end(state[4]),
303✔
804
                native_to_big_end(state[5]),
303✔
805
                native_to_big_end(state[6]),
303✔
806
                native_to_big_end(state[7])
2,304,087✔
807
            });
808
        }
809
    }
810
    else
811
    {
812
        return array_cast<byte_t>(state);
813
    }
814
}
815

816
// 5.1 Padding the Message
817
// ---------------------------------------------------------------------------
818

819
TEMPLATE
820
template<size_t Blocks>
821
CONSTEVAL typename CLASS::buffer_t CLASS::
822
scheduled_pad() NOEXCEPT
823
{
824
    // This precomputed padding is limited to one word of counter.
825
    static_assert(Blocks <= maximum<word_t> / byte_bits);
826

827
    // See comments in accumulator regarding padding endianness.
828
    constexpr auto index = sub1(array_count<words_t>);
829
    constexpr auto bytes = safe_multiply(Blocks, array_count<block_t>);
830

831
    buffer_t out{};
832
    out.front() = bit_hi<word_t>;
833
    out.at(index) = possible_narrow_cast<word_t>(to_bits(bytes));
834
    schedule(out);
835
    return out;
836
}
837

838
TEMPLATE
839
CONSTEVAL typename CLASS::chunk_t CLASS::
840
chunk_pad() NOEXCEPT
841
{
842
    // See comments in accumulator regarding padding endianness.
843
    constexpr auto bytes = possible_narrow_cast<word_t>(array_count<half_t>);
844

845
    chunk_t out{};
846
    out.front() = bit_hi<word_t>;
847
    out.back() = to_bits(bytes);
848
    return out;
849
}
850

851
TEMPLATE
852
CONSTEVAL typename CLASS::pad_t CLASS::
853
stream_pad() NOEXCEPT
854
{
855
    // See comments in accumulator regarding padding endianness.
856
    pad_t out{};
857
    out.front() = bit_hi<word_t>;
858
    return out;
859
}
860

861
TEMPLATE
862
template<size_t Blocks>
863
constexpr void CLASS::
1,000,298✔
864
schedule_n(buffer_t& buffer) NOEXCEPT
865
{
866
    // Scheduled padding for n whole blocks.
867
    // This will compile in 4*64 (sha256) or 4*128 (sha512) bytes for each
868
    // unique size of blocks array hashed by callers (by template expansion).
869
    // and one for each that is cached for block vectors in schedule_n().
870
    constexpr auto pad = scheduled_pad<Blocks>();
1,000,298✔
871
    buffer = pad;
1,000,298✔
872
}
1,000,298✔
873

874
TEMPLATE
875
constexpr void CLASS::
1,397✔
876
schedule_n(buffer_t& buffer, size_t blocks) NOEXCEPT
877
{
878
    // This optimization is saves ~30% in message scheduling for one out of
879
    // N blocks: (N + 70%)/(N + 100%). So the proportional benefit decreases
880
    // exponentially with increasing N. For arbitrary data lengths this will
881
    // benefit 1/64 hashes on average. All array-sized n-block hashes have
882
    // precomputed schedules - this benefits only finalized chunk hashing.
883
    // Testing shows a 5% performance improvement for 128 byte chunk hashes.
884
    // Accumulator passes all write() of more than one block here.
885
    if constexpr (caching)
886
    {
887
        switch (blocks)
1,389✔
888
        {
889
            case 1: schedule_n<1>(buffer); return;
2✔
890
            case 2: schedule_n<2>(buffer); return;
189✔
891
            case 3: schedule_n<3>(buffer); return;
2✔
892
            case 4: schedule_n<4>(buffer); return;
1✔
893
            default:
1,195✔
894
            {
895
                pad_n(buffer, blocks);
1,195✔
896
                schedule(buffer);
1,195✔
897
                return;
1,195✔
898
            }
899
        }
900
    }
901
    else
902
    {
903
        pad_n(buffer, blocks);
8✔
904
        schedule(buffer);
8✔
905
        return;
4✔
906
    }
907
}
908

909
TEMPLATE
910
constexpr void CLASS::
1,000,093✔
911
schedule_1(buffer_t& buffer) NOEXCEPT
912
{
913
    // This ensures single block padding is always prescheduled.
914
    schedule_n<one>(buffer);
1,000,093✔
915
}
916

917
TEMPLATE
918
constexpr void CLASS::
101,094✔
919
pad_half(buffer_t& buffer) NOEXCEPT
920
{
921
    // Pad for any half block, unscheduled buffer.
922
    constexpr auto pad = chunk_pad();
101,094✔
923

924
    if (std::is_constant_evaluated())
925
    {
926
        buffer.at(8) = pad.at(0);
927
        buffer.at(9) = pad.at(1);
928
        buffer.at(10) = pad.at(2);
929
        buffer.at(11) = pad.at(3);
930
        buffer.at(12) = pad.at(4);
931
        buffer.at(13) = pad.at(5);
932
        buffer.at(14) = pad.at(6);
933
        buffer.at(15) = pad.at(7);
934
    }
935
    else
936
    {
937
        array_cast<word_t, SHA::chunk_words, SHA::chunk_words>(buffer) = pad;
101,094✔
938
    }
939
}
101,094✔
940

941
TEMPLATE
942
constexpr void CLASS::
1,203✔
943
pad_n(buffer_t& buffer, count_t blocks) NOEXCEPT
944
{
945
    // Pad any number of whole blocks, unscheduled buffer.
946
    constexpr auto pad = stream_pad();
1,203✔
947
    const auto bits = to_bits(blocks * array_count<block_t>);
×
948

949
    if (std::is_constant_evaluated())
950
    {
951
        buffer.at(0)  = pad.at(0);
952
        buffer.at(1)  = pad.at(1);
953
        buffer.at(2)  = pad.at(2);
954
        buffer.at(3)  = pad.at(3);
955
        buffer.at(4)  = pad.at(4);
956
        buffer.at(5)  = pad.at(5);
957
        buffer.at(6)  = pad.at(6);
958
        buffer.at(7)  = pad.at(7);
959
        buffer.at(8)  = pad.at(8);
960
        buffer.at(9)  = pad.at(9);
961
        buffer.at(10) = pad.at(10);
962
        buffer.at(11) = pad.at(11);
963
        buffer.at(12) = pad.at(12);
964
        buffer.at(13) = pad.at(13);
965
        buffer.at(14) = hi_word<word_t>(bits);
966
        buffer.at(15) = lo_word<word_t>(bits);
967
    }
968
    else
969
    {
970
        array_cast<word_t, array_count<pad_t>>(buffer) = pad;
1,203✔
971

972
        // Split count into hi/low words and assign end of padded buffer.
973
        buffer[14] = hi_word<word_t>(bits);
1,203✔
974
        buffer[15] = lo_word<word_t>(bits);
1,203✔
975
    }
976
}
1,203✔
977

978
// Hashing.
979
// ---------------------------------------------------------------------------
980
// No hash(state_t) optimizations for sha160 (requires chunk_t/half_t).
981

982
TEMPLATE
983
template <size_t Size>
984
constexpr typename CLASS::digest_t CLASS::
11✔
985
hash(const ablocks_t<Size>& blocks) NOEXCEPT
986
{
987
    buffer_t buffer{};
11✔
988
    auto state = H::get;
11✔
989
    iterate(state, blocks);
990
    schedule_n<Size>(buffer);
11✔
991
    compress(state, buffer);
11✔
992
    return output(state);
11✔
993
}
994

995
TEMPLATE
996
typename CLASS::digest_t CLASS::
27✔
997
hash(iblocks_t&& blocks) NOEXCEPT
998
{
999
    // Save block count, as iterable decrements.
1000
    const auto count = blocks.size();
21✔
1001

1002
    buffer_t buffer{};
27✔
1003
    auto state = H::get;
27✔
1004
    iterate(state, blocks);
1005
    schedule_n(buffer, count);
23✔
1006
    compress(state, buffer);
27✔
1007
    return output(state);
27✔
1008
}
1009

1010
TEMPLATE
1011
constexpr typename CLASS::digest_t CLASS::
1,000,022✔
1012
hash(const block_t& block) NOEXCEPT
1013
{
1014
    buffer_t buffer{};
1,000,022✔
1015
    auto state = H::get;
1,000,022✔
1016
    input(buffer, block);
1017
    schedule(buffer);
1,000,022✔
1018
    compress(state, buffer);
1,000,022✔
1019
    schedule_1(buffer);
1020
    compress(state, buffer);
1,000,022✔
1021
    return output(state);
1,000,022✔
1022
}
1023

1024
TEMPLATE
1025
constexpr typename CLASS::digest_t CLASS::
279✔
1026
hash(const state_t& state) NOEXCEPT
1027
{
1028
    static_assert(is_same_type<state_t, chunk_t>);
1029

1030
    buffer_t buffer{};
279✔
1031
    auto state2 = H::get;
279✔
1032
    input(buffer, state);
1033
    pad_half(buffer);
279✔
1034
    schedule(buffer);
279✔
1035
    compress(state2, buffer);
279✔
1036
    return output(state2);
279✔
1037
}
1038

1039
TEMPLATE
1040
constexpr typename CLASS::digest_t CLASS::
100,734✔
1041
hash(const half_t& half) NOEXCEPT
1042
{
1043
    buffer_t buffer{};
100,734✔
1044
    auto state = H::get;
100,734✔
1045
    input1(buffer, half);
1046
    pad_half(buffer);
100,734✔
1047
    schedule(buffer);
100,734✔
1048
    compress(state, buffer);
100,734✔
1049
    return output(state);
100,734✔
1050
}
1051

1052
TEMPLATE
1053
constexpr typename CLASS::digest_t CLASS::
4✔
1054
hash(const half_t& left, const half_t& right) NOEXCEPT
1055
{
1056
    buffer_t buffer{};
4✔
1057
    auto state = H::get;
4✔
1058
    input1(buffer, left);
1059
    input2(buffer, right);
1060
    schedule(buffer);
4✔
1061
    compress(state, buffer);
4✔
1062
    schedule_1(buffer);
1063
    compress(state, buffer);
4✔
1064
    return output(state);
4✔
1065
}
1066

1067
// Double Hashing.
1068
// ---------------------------------------------------------------------------
1069
// No double_hash optimizations for sha160 (requires chunk_t/half_t).
1070

1071
TEMPLATE
1072
template <size_t Size>
1073
constexpr typename CLASS::digest_t CLASS::
×
1074
double_hash(const ablocks_t<Size>& blocks) NOEXCEPT
1075
{
1076
    static_assert(is_same_type<state_t, chunk_t>);
1077

1078
    buffer_t buffer{};
×
1079
    auto state = H::get;
×
1080
    iterate(state, blocks);
1081
    schedule_n<Size>(buffer);
×
1082
    compress(state, buffer);
×
1083

1084
    // Second hash
1085
    input(buffer, state);
1086
    pad_half(buffer);
×
1087
    schedule(buffer);
×
1088
    state = H::get;
×
1089
    compress(state, buffer);
×
1090
    return output(state);
×
1091
}
1092

1093
TEMPLATE
1094
typename CLASS::digest_t CLASS::
×
1095
double_hash(iblocks_t&& blocks) NOEXCEPT
1096
{
1097
    static_assert(is_same_type<state_t, chunk_t>);
1098

1099
    // Save block count, as iterable decrements.
1100
    const auto count = blocks.size();
×
1101

1102
    buffer_t buffer{};
×
1103
    auto state = H::get;
×
1104
    iterate(state, blocks);
1105
    schedule_n(buffer, count);
×
1106
    compress(state, buffer);
×
1107

1108
    // Second hash
1109
    input(buffer, state);
1110
    pad_half(buffer);
×
1111
    schedule(buffer);
×
1112
    state = H::get;
×
1113
    compress(state, buffer);
×
1114
    return output(state);
×
1115
}
1116

1117
TEMPLATE
1118
constexpr typename CLASS::digest_t CLASS::
23✔
1119
double_hash(const block_t& block) NOEXCEPT
1120
{
1121
    static_assert(is_same_type<state_t, chunk_t>);
1122

1123
    buffer_t buffer{};
23✔
1124

1125
    auto state = H::get;
23✔
1126
    input(buffer, block);
1127
    schedule(buffer);
23✔
1128
    compress(state, buffer);
23✔
1129
    schedule_1(buffer);
1130
    compress(state, buffer);
23✔
1131

1132
    // Second hash
1133
    input(buffer, state);
1134
    pad_half(buffer);
23✔
1135
    schedule(buffer);
23✔
1136
    state = H::get;
23✔
1137
    compress(state, buffer);
23✔
1138
    return output(state);
23✔
1139
}
1140

1141
TEMPLATE
1142
constexpr typename CLASS::digest_t CLASS::
7✔
1143
double_hash(const half_t& half) NOEXCEPT
1144
{
1145
    static_assert(is_same_type<state_t, chunk_t>);
1146

1147
    buffer_t buffer{};
7✔
1148
    auto state = H::get;
7✔
1149
    input1(buffer, half);
1150
    pad_half(buffer);
7✔
1151
    schedule(buffer);
7✔
1152
    compress(state, buffer);
7✔
1153

1154
    // Second hash
1155
    input(buffer, state);
1156
    pad_half(buffer);
7✔
1157
    schedule(buffer);
7✔
1158
    state = H::get;
7✔
1159
    compress(state, buffer);
7✔
1160
    return output(state);
7✔
1161
}
1162

1163
TEMPLATE
1164
constexpr typename CLASS::digest_t CLASS::
44✔
1165
double_hash(const half_t& left, const half_t& right) NOEXCEPT
1166
{
1167
    static_assert(is_same_type<state_t, chunk_t>);
1168

1169
    buffer_t buffer{};
44✔
1170
    auto state = H::get;
44✔
1171
    input1(buffer, left);
1172
    input2(buffer, right);
1173
    schedule(buffer);
44✔
1174
    compress(state, buffer);
44✔
1175
    schedule_1(buffer);
1176
    compress(state, buffer);
44✔
1177

1178
    // Second hash
1179
    input(buffer, state);
1180
    pad_half(buffer);
44✔
1181
    schedule(buffer);
44✔
1182
    state = H::get;
44✔
1183
    compress(state, buffer);
44✔
1184
    return output(state);
44✔
1185
}
1186

1187
// Block iteration.
1188
// ------------------------------------------------------------------------
1189

1190
TEMPLATE
1191
template <size_t Size>
1192
INLINE constexpr void CLASS::
11✔
1193
iterate(state_t& state, const ablocks_t<Size>& blocks) NOEXCEPT
1194
{
1195
    if (std::is_constant_evaluated())
11✔
1196
    {
1197
        iterate_(state, blocks);
1198
    }
1199
    else if constexpr (vectorization)
1200
    {
1201
        iterate_dispatch(state, blocks);
1202
    }
1203
    else
1204
    {
1205
        iterate_(state, blocks);
1206
    }
1207
}
1208

1209
TEMPLATE
1210
INLINE void CLASS::
720✔
1211
iterate(state_t& state, iblocks_t& blocks) NOEXCEPT
1212
{
1213
    if constexpr (vectorization)
1214
    {
1215
        iterate_dispatch(state, blocks);
1216
    }
1217
    else
1218
    {
1219
        iterate_(state, blocks);
1220
    }
1221
}
1222

1223
TEMPLATE
1224
template <size_t Size>
1225
INLINE constexpr void CLASS::
11✔
1226
iterate_(state_t& state, const ablocks_t<Size>& blocks) NOEXCEPT
1227
{
1228
    buffer_t buffer{};
11✔
1229
    for (auto& block: blocks)
33✔
1230
    {
1231
        input(buffer, block);
1232
        schedule(buffer);
22✔
1233
        compress(state, buffer);
22✔
1234
    }
1235
}
11✔
1236

1237
TEMPLATE
1238
INLINE void CLASS::
731✔
1239
iterate_(state_t& state, iblocks_t& blocks) NOEXCEPT
1240
{
1241
    buffer_t buffer{};
722✔
1242
    for (auto& block: blocks)
236,701✔
1243
    {
1244
        input(buffer, block);
1245
        schedule(buffer);
118,784✔
1246
        compress(state, buffer);
118,784✔
1247
    }
1248
}
1249

1250

1251
// Merkle Hashing (sha256/512).
1252
// ------------------------------------------------------------------------
1253
// No merkle_hash optimizations for sha160 (double_hash requires half_t).
1254

1255
TEMPLATE
1256
VCONSTEXPR typename CLASS::digest_t CLASS::
27✔
1257
merkle_root(digests_t&& digests) NOEXCEPT
1258
{
1259
    static_assert(is_same_type<state_t, chunk_t>);
1260

1261
    if (is_zero(digests.size()))
27✔
1262
        return {};
4✔
1263

1264
    while (!is_one(digests.size()))
47✔
1265
    {
1266
        if (is_odd(digests.size()))
24✔
1267
            digests.push_back(digests.back());
6✔
1268

1269
        merkle_hash(digests);
24✔
1270
    }
1271

1272
    return std::move(digests.front());
23✔
1273
}
1274

1275
TEMPLATE
1276
VCONSTEXPR typename CLASS::digests_t& CLASS::
28✔
1277
merkle_hash(digests_t& digests) NOEXCEPT
1278
{
1279
    static_assert(is_same_type<state_t, chunk_t>);
1280

1281
    if (std::is_constant_evaluated())
28✔
1282
    {
1283
        merkle_hash_(digests);
×
1284
    }
1285
    else if constexpr (vectorization)
1286
    {
1287
        merkle_hash_dispatch(digests);
1288
    }
1289
    else
1290
    {
1291
        merkle_hash_(digests);
1292
    }
1293

1294
    return digests;
28✔
1295
};
1296

1297
TEMPLATE
1298
VCONSTEXPR void CLASS::
28✔
1299
merkle_hash_(digests_t& digests, size_t offset) NOEXCEPT
1300
{
1301
    const auto blocks = to_half(digests.size());
1302
    for (auto i = offset, j = offset * two; i < blocks; ++i, j += two)
70✔
1303
        digests[i] = double_hash(digests[j], digests[add1(j)]);
42✔
1304

1305
    digests.resize(blocks);
28✔
1306
}
28✔
1307

1308
// Streaming (unfinalized).
1309
// ---------------------------------------------------------------------------
1310

1311
TEMPLATE
1312
void CLASS::
704✔
1313
accumulate(state_t& state, iblocks_t&& blocks) NOEXCEPT
1314
{
1315
    iterate(state, blocks);
1316
}
704✔
1317

1318
TEMPLATE
1319
constexpr void CLASS::
2,156,353✔
1320
accumulate(state_t& state, const block_t& block) NOEXCEPT
1321
{
1322
    buffer_t buffer{};
2,156,353✔
1323
    input(buffer, block);
1324
    schedule(buffer);
2,156,353✔
1325
    compress(state, buffer);
2,156,353✔
1326
}
2,156,353✔
1327

1328
TEMPLATE
1329
constexpr typename CLASS::digest_t CLASS::
1,370✔
1330
finalize(state_t& state, size_t blocks) NOEXCEPT
1331
{
1332
    buffer_t buffer{};
1,370✔
1333
    schedule_n(buffer, blocks);
1,370✔
1334
    compress(state, buffer);
1,370✔
1335
    return output(state);
1,370✔
1336
}
1337

1338
TEMPLATE
1339
constexpr typename CLASS::digest_t CLASS::
×
1340
finalize_double(state_t& state, size_t blocks) NOEXCEPT
1341
{
1342
    // The state out parameter is updated for first hash.
1343
    buffer_t buffer{};
×
1344
    schedule_n(buffer, blocks);
×
1345
    compress(state, buffer);
×
1346

1347
    // Second hash
1348
    input(buffer, state);
1349
    pad_half(buffer);
×
1350
    schedule(buffer);
×
1351
    auto state2 = H::get;
×
1352
    compress(state2, buffer);
×
1353
    return output(state2);
×
1354
}
1355

1356
TEMPLATE
1357
constexpr typename CLASS::digest_t CLASS::
1,304,192✔
1358
normalize(const state_t& state) NOEXCEPT
1359
{
1360
    return output(state);
1,304,192✔
1361
}
1362

1363
BC_POP_WARNING()
1364
BC_POP_WARNING()
1365
BC_POP_WARNING()
1366
BC_POP_WARNING()
1367

1368
} // namespace sha
1369
} // namespace system
1370
} // namespace libbitcoin
1371

1372
#endif
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