Botan 3.10.0
Crypto and TLS for C&
blake2s.cpp
Go to the documentation of this file.
1/*
2 * BLAKE2s
3 * (C) 2023, 2025 Richard Huveneers
4 * (C) 2025 Kagan Can Sit
5 * (C) 2025 René Meusel, Rohde & Schwarz Cybersecurity
6 *
7 * Based on the RFC7693 reference implementation
8 *
9 * Botan is released under the Simplified BSD License (see license.txt)
10 */
11
12#include <botan/internal/blake2s.h>
13
14#include <botan/exceptn.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/loadstor.h>
17#include <botan/internal/rotate.h>
18#include <botan/internal/stl_util.h>
19
20namespace Botan {
21
22namespace {
23
24// Initialization Vector.
25
26constexpr std::array<uint32_t, 8> blake2s_iv{
27 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19};
28
29// Mixing function G.
30
31template <uint8_t a, uint8_t b, uint8_t c, uint8_t d>
32 requires(a < 16 && b < 16 && c < 16 && d < 16)
33constexpr void B2S_G(uint32_t x, uint32_t y, std::span<uint32_t, 16> v) {
34 v[a] = v[a] + v[b] + x;
35 v[d] = rotr<16>(v[d] ^ v[a]);
36 v[c] = v[c] + v[d];
37 v[b] = rotr<12>(v[b] ^ v[c]);
38 v[a] = v[a] + v[b] + y;
39 v[d] = rotr<8>(v[d] ^ v[a]);
40 v[c] = v[c] + v[d];
41 v[b] = rotr<7>(v[b] ^ v[c]);
42}
43
44} // namespace
45
46std::string BLAKE2s::name() const {
47 return fmt("BLAKE2s({})", m_outlen << 3);
48}
49
50// BLAKE2s is specified as a message authentication code. For that, the
51// key would need to be zero-padded and incorporated into the initial hash
52// state. See RFC 7693 Section 3.3 and Appendix D.2 `blake2s_init()`.
53void BLAKE2s::state_init(size_t outlen) {
54 m_h = blake2s_iv; // state, "param block"
55 m_h[0] ^= 0x01010000 ^ outlen;
56
57 m_bytes_processed = 0;
58 m_outlen = outlen;
59 m_buffer.clear();
60}
61
62// Compression function. "last" flag indicates last block.
63void BLAKE2s::compress(bool last, std::span<const uint8_t> buf) {
64 BOTAN_ASSERT_NOMSG(buf.size() == block_size);
65 constexpr std::array<std::array<uint8_t, 16>, 10> sigma{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
66 {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
67 {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
68 {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
69 {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
70 {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
71 {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
72 {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
73 {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
74 {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}}};
75
76 // init work variables
77 std::array<uint32_t, 16> v = concat(m_h, blake2s_iv);
78
79 v[12] ^= static_cast<uint32_t>(m_bytes_processed);
80 v[13] ^= static_cast<uint32_t>(m_bytes_processed >> 32);
81 if(last) { // last block flag set ?
82 v[14] = ~v[14];
83 }
84
85 const auto m = load_le<std::array<uint32_t, 16>>(buf); // get little-endian words
86
87 for(const auto& perm : sigma) { // ten rounds
88 B2S_G<0, 4, 8, 12>(m[perm[0]], m[perm[1]], v);
89 B2S_G<1, 5, 9, 13>(m[perm[2]], m[perm[3]], v);
90 B2S_G<2, 6, 10, 14>(m[perm[4]], m[perm[5]], v);
91 B2S_G<3, 7, 11, 15>(m[perm[6]], m[perm[7]], v);
92 B2S_G<0, 5, 10, 15>(m[perm[8]], m[perm[9]], v);
93 B2S_G<1, 6, 11, 12>(m[perm[10]], m[perm[11]], v);
94 B2S_G<2, 7, 8, 13>(m[perm[12]], m[perm[13]], v);
95 B2S_G<3, 4, 9, 14>(m[perm[14]], m[perm[15]], v);
96 }
97
98 for(size_t i = 0; i < 8; ++i) {
99 m_h[i] ^= v[i] ^ v[i + 8];
100 }
101}
102
103/*
104 * Clear memory of sensitive data
105 */
107 state_init(m_outlen);
108}
109
110void BLAKE2s::add_data(std::span<const uint8_t> input) {
111 BufferSlicer in(input);
112
113 while(!in.empty()) {
114 if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
115 m_bytes_processed += block_size;
116 compress(false, *one_block);
117 }
118
119 if(m_buffer.in_alignment()) {
120 while(const auto aligned_block = m_buffer.next_aligned_block_to_process(in)) {
121 m_bytes_processed += block_size;
122 compress(false, *aligned_block);
123 }
124 }
125 }
126}
127
128void BLAKE2s::final_result(std::span<uint8_t> out) {
129 m_bytes_processed += m_buffer.elements_in_buffer();
130
131 m_buffer.fill_up_with_zeros();
132 compress(true, m_buffer.consume());
133
134 // little endian convert and store
135 copy_out_le(out.first(output_length()), m_h);
136
137 clear();
138}
139
140std::unique_ptr<HashFunction> BLAKE2s::copy_state() const {
141 return std::make_unique<BLAKE2s>(*this);
142}
143
144/*
145 * BLAKE2s Constructor
146 */
147BLAKE2s::BLAKE2s(size_t output_bits) {
148 if(output_bits == 0 || output_bits > 256 || output_bits % 8 != 0) {
149 throw Invalid_Argument("Bad output bits size for BLAKE2s");
150 }
151 state_init(output_bits >> 3);
152}
153
157
158} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
std::optional< std::span< const uint8_t > > next_aligned_block_to_process(BufferSlicer &slicer) const
std::optional< std::span< const T > > handle_unaligned_data(BufferSlicer &slicer)
void clear() override
Definition blake2s.cpp:106
std::unique_ptr< HashFunction > copy_state() const override
Definition blake2s.cpp:140
~BLAKE2s() override
Definition blake2s.cpp:154
BLAKE2s(size_t output_bits=256)
Definition blake2s.cpp:147
std::string name() const override
Definition blake2s.cpp:46
size_t output_length() const override
Definition blake2s.h:36
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
void copy_out_le(std::span< uint8_t > out, const InR &in)
Definition loadstor.h:789
BOTAN_FORCE_INLINE constexpr T rotr(T input)
Definition rotate.h:35
void secure_scrub_memory(void *ptr, size_t n)
Definition mem_utils.cpp:24
constexpr auto concat(Rs &&... ranges)
Definition stl_util.h:254
BOTAN_FORCE_INLINE constexpr T sigma(T x)
Definition rotate.h:45
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495