Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-03-24 13:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/crypto/chacha20.h
Line
Count
Source
1
// Copyright (c) 2017-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#ifndef BITCOIN_CRYPTO_CHACHA20_H
6
#define BITCOIN_CRYPTO_CHACHA20_H
7
8
#include <array>
9
#include <cstddef>
10
#include <cstdint>
11
#include <span>
12
#include <utility>
13
14
// classes for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein
15
// https://cr.yp.to/chacha/chacha-20080128.pdf.
16
//
17
// The 128-bit input is here implemented as a 96-bit nonce and a 32-bit block
18
// counter, as in RFC8439 Section 2.3. When the 32-bit block counter overflows
19
// the first 32-bit part of the nonce is automatically incremented, making it
20
// conceptually compatible with variants that use a 64/64 split instead.
21
22
/** ChaCha20 cipher that only operates on multiples of 64 bytes. */
23
class ChaCha20Aligned
24
{
25
private:
26
    uint32_t input[12];
27
28
public:
29
    /** Expected key length in constructor and SetKey. */
30
    static constexpr unsigned KEYLEN{32};
31
32
    /** Block size (inputs/outputs to Keystream / Crypt should be multiples of this). */
33
    static constexpr unsigned BLOCKLEN{64};
34
35
    /** For safety, disallow initialization without key. */
36
    ChaCha20Aligned() noexcept = delete;
37
38
    /** Initialize a cipher with specified 32-byte key. */
39
    ChaCha20Aligned(std::span<const std::byte> key) noexcept;
40
41
    /** Destructor to clean up private memory. */
42
    ~ChaCha20Aligned();
43
44
    /** Set 32-byte key, and seek to nonce 0 and block position 0. */
45
    void SetKey(std::span<const std::byte> key) noexcept;
46
47
    /** Type for 96-bit nonces used by the Set function below.
48
     *
49
     * The first field corresponds to the LE32-encoded first 4 bytes of the nonce, also referred
50
     * to as the '32-bit fixed-common part' in Example 2.8.2 of RFC8439.
51
     *
52
     * The second field corresponds to the LE64-encoded last 8 bytes of the nonce.
53
     *
54
     */
55
    using Nonce96 = std::pair<uint32_t, uint64_t>;
56
57
    /** Set the 96-bit nonce and 32-bit block counter.
58
     *
59
     * Block_counter selects a position to seek to (to byte BLOCKLEN*block_counter). After 256 GiB,
60
     * the block counter overflows, and nonce.first is incremented.
61
     */
62
    void Seek(Nonce96 nonce, uint32_t block_counter) noexcept;
63
64
    /** outputs the keystream into out, whose length must be a multiple of BLOCKLEN. */
65
    void Keystream(std::span<std::byte> out) noexcept;
66
67
    /** en/deciphers the message <input> and write the result into <output>
68
     *
69
     * The size of input and output must be equal, and be a multiple of BLOCKLEN.
70
     */
71
    void Crypt(std::span<const std::byte> input, std::span<std::byte> output) noexcept;
72
};
73
74
/** Unrestricted ChaCha20 cipher. */
75
class ChaCha20
76
{
77
private:
78
    ChaCha20Aligned m_aligned;
79
    std::array<std::byte, ChaCha20Aligned::BLOCKLEN> m_buffer;
80
    unsigned m_bufleft{0};
81
82
public:
83
    /** Expected key length in constructor and SetKey. */
84
    static constexpr unsigned KEYLEN = ChaCha20Aligned::KEYLEN;
85
86
    /** For safety, disallow initialization without key. */
87
    ChaCha20() noexcept = delete;
88
89
    /** Initialize a cipher with specified 32-byte key. */
90
0
    ChaCha20(std::span<const std::byte> key) noexcept : m_aligned(key) {}
91
92
    /** Destructor to clean up private memory. */
93
    ~ChaCha20();
94
95
    /** Set 32-byte key, and seek to nonce 0 and block position 0. */
96
    void SetKey(std::span<const std::byte> key) noexcept;
97
98
    /** 96-bit nonce type. */
99
    using Nonce96 = ChaCha20Aligned::Nonce96;
100
101
    /** Set the 96-bit nonce and 32-bit block counter. See ChaCha20Aligned::Seek. */
102
    void Seek(Nonce96 nonce, uint32_t block_counter) noexcept
103
0
    {
104
0
        m_aligned.Seek(nonce, block_counter);
105
0
        m_bufleft = 0;
106
0
    }
107
108
    /** en/deciphers the message <in_bytes> and write the result into <out_bytes>
109
     *
110
     * The size of in_bytes and out_bytes must be equal.
111
     */
112
    void Crypt(std::span<const std::byte> in_bytes, std::span<std::byte> out_bytes) noexcept;
113
114
    /** outputs the keystream to out. */
115
    void Keystream(std::span<std::byte> out) noexcept;
116
};
117
118
/** Forward-secure ChaCha20
119
 *
120
 * This implements a stream cipher that automatically transitions to a new stream with a new key
121
 * and new nonce after a predefined number of encryptions or decryptions.
122
 *
123
 * See BIP324 for details.
124
 */
125
class FSChaCha20
126
{
127
private:
128
    /** Internal stream cipher. */
129
    ChaCha20 m_chacha20;
130
131
    /** The number of encryptions/decryptions before a rekey happens. */
132
    const uint32_t m_rekey_interval;
133
134
    /** The number of encryptions/decryptions since the last rekey. */
135
    uint32_t m_chunk_counter{0};
136
137
    /** The number of rekey operations that have happened. */
138
    uint64_t m_rekey_counter{0};
139
140
public:
141
    /** Length of keys expected by the constructor. */
142
    static constexpr unsigned KEYLEN = 32;
143
144
    // No copy or move to protect the secret.
145
    FSChaCha20(const FSChaCha20&) = delete;
146
    FSChaCha20(FSChaCha20&&) = delete;
147
    FSChaCha20& operator=(const FSChaCha20&) = delete;
148
    FSChaCha20& operator=(FSChaCha20&&) = delete;
149
150
    /** Construct an FSChaCha20 cipher that rekeys every rekey_interval Crypt() calls. */
151
    FSChaCha20(std::span<const std::byte> key, uint32_t rekey_interval) noexcept;
152
153
    /** Encrypt or decrypt a chunk. */
154
    void Crypt(std::span<const std::byte> input, std::span<std::byte> output) noexcept;
155
};
156
157
#endif // BITCOIN_CRYPTO_CHACHA20_H