fuzz coverage

Coverage Report

Created: 2025-06-01 19:34

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