/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 <cstdint> | 
| 13 |  | #include <cstdlib> | 
| 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 | 15.4M |     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 |