Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2017-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5// Based on the public domain implementation 'merged' by D. J. Bernstein6// See https://cr.yp.to/chacha.html.8#include <crypto/common.h>9#include <crypto/chacha20.h>10#include <support/cleanse.h>12#include <algorithm>13#include <bit>14#include <cassert>16#define QUARTERROUND(a,b,c,d) \17a += b; d = std::rotl(d ^ a, 16); \18c += d; b = std::rotl(b ^ c, 12); \19a += b; d = std::rotl(d ^ a, 8); \20c += d; b = std::rotl(b ^ c, 7);22#define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)24void ChaCha20Aligned::SetKey(std::span<const std::byte> key) noexcept25{26assert(key.size() == KEYLEN);27input[0] = ReadLE32(key.data() + 0);28input[1] = ReadLE32(key.data() + 4);29input[2] = ReadLE32(key.data() + 8);30input[3] = ReadLE32(key.data() + 12);31input[4] = ReadLE32(key.data() + 16);32input[5] = ReadLE32(key.data() + 20);33input[6] = ReadLE32(key.data() + 24);34input[7] = ReadLE32(key.data() + 28);35input[8] = 0;36input[9] = 0;37input[10] = 0;38input[11] = 0;39}41ChaCha20Aligned::~ChaCha20Aligned()42{43memory_cleanse(input, sizeof(input));44}46ChaCha20Aligned::ChaCha20Aligned(std::span<const std::byte> key) noexcept47{48SetKey(key);49}51void ChaCha20Aligned::Seek(Nonce96 nonce, uint32_t block_counter) noexcept52{53input[8] = block_counter;54input[9] = nonce.first;55input[10] = nonce.second;56input[11] = nonce.second >> 32;57}59inline void ChaCha20Aligned::Keystream(std::span<std::byte> output) noexcept60{61std::byte* c = output.data();62size_t blocks = output.size() / BLOCKLEN;63assert(blocks * BLOCKLEN == output.size());65uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;66uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;68if (!blocks) return;70j4 = input[0];71j5 = input[1];72j6 = input[2];73j7 = input[3];74j8 = input[4];75j9 = input[5];76j10 = input[6];77j11 = input[7];78j12 = input[8];79j13 = input[9];80j14 = input[10];81j15 = input[11];83for (;;) {84x0 = 0x61707865;85x1 = 0x3320646e;86x2 = 0x79622d32;87x3 = 0x6b206574;88x4 = j4;89x5 = j5;90x6 = j6;91x7 = j7;92x8 = j8;93x9 = j9;94x10 = j10;95x11 = j11;96x12 = j12;97x13 = j13;98x14 = j14;99x15 = j15;101// The 20 inner ChaCha20 rounds are unrolled here for performance.102REPEAT10(103QUARTERROUND( x0, x4, x8,x12);104QUARTERROUND( x1, x5, x9,x13);105QUARTERROUND( x2, x6,x10,x14);106QUARTERROUND( x3, x7,x11,x15);107QUARTERROUND( x0, x5,x10,x15);108QUARTERROUND( x1, x6,x11,x12);109QUARTERROUND( x2, x7, x8,x13);110QUARTERROUND( x3, x4, x9,x14);111);113x0 += 0x61707865;114x1 += 0x3320646e;115x2 += 0x79622d32;116x3 += 0x6b206574;117x4 += j4;118x5 += j5;119x6 += j6;120x7 += j7;121x8 += j8;122x9 += j9;123x10 += j10;124x11 += j11;125x12 += j12;126x13 += j13;127x14 += j14;128x15 += j15;130++j12;131if (!j12) ++j13;133WriteLE32(c + 0, x0);134WriteLE32(c + 4, x1);135WriteLE32(c + 8, x2);136WriteLE32(c + 12, x3);137WriteLE32(c + 16, x4);138WriteLE32(c + 20, x5);139WriteLE32(c + 24, x6);140WriteLE32(c + 28, x7);141WriteLE32(c + 32, x8);142WriteLE32(c + 36, x9);143WriteLE32(c + 40, x10);144WriteLE32(c + 44, x11);145WriteLE32(c + 48, x12);146WriteLE32(c + 52, x13);147WriteLE32(c + 56, x14);148WriteLE32(c + 60, x15);150if (blocks == 1) {151input[8] = j12;152input[9] = j13;153return;154}155blocks -= 1;156c += BLOCKLEN;157}158}160inline void ChaCha20Aligned::Crypt(std::span<const std::byte> in_bytes, std::span<std::byte> out_bytes) noexcept161{162assert(in_bytes.size() == out_bytes.size());163const std::byte* m = in_bytes.data();164std::byte* c = out_bytes.data();165size_t blocks = out_bytes.size() / BLOCKLEN;166assert(blocks * BLOCKLEN == out_bytes.size());168uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;169uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;171if (!blocks) return;173j4 = input[0];174j5 = input[1];175j6 = input[2];176j7 = input[3];177j8 = input[4];178j9 = input[5];179j10 = input[6];180j11 = input[7];181j12 = input[8];182j13 = input[9];183j14 = input[10];184j15 = input[11];186for (;;) {187x0 = 0x61707865;188x1 = 0x3320646e;189x2 = 0x79622d32;190x3 = 0x6b206574;191x4 = j4;192x5 = j5;193x6 = j6;194x7 = j7;195x8 = j8;196x9 = j9;197x10 = j10;198x11 = j11;199x12 = j12;200x13 = j13;201x14 = j14;202x15 = j15;204// The 20 inner ChaCha20 rounds are unrolled here for performance.205REPEAT10(206QUARTERROUND( x0, x4, x8,x12);207QUARTERROUND( x1, x5, x9,x13);208QUARTERROUND( x2, x6,x10,x14);209QUARTERROUND( x3, x7,x11,x15);210QUARTERROUND( x0, x5,x10,x15);211QUARTERROUND( x1, x6,x11,x12);212QUARTERROUND( x2, x7, x8,x13);213QUARTERROUND( x3, x4, x9,x14);214);216x0 += 0x61707865;217x1 += 0x3320646e;218x2 += 0x79622d32;219x3 += 0x6b206574;220x4 += j4;221x5 += j5;222x6 += j6;223x7 += j7;224x8 += j8;225x9 += j9;226x10 += j10;227x11 += j11;228x12 += j12;229x13 += j13;230x14 += j14;231x15 += j15;233x0 ^= ReadLE32(m + 0);234x1 ^= ReadLE32(m + 4);235x2 ^= ReadLE32(m + 8);236x3 ^= ReadLE32(m + 12);237x4 ^= ReadLE32(m + 16);238x5 ^= ReadLE32(m + 20);239x6 ^= ReadLE32(m + 24);240x7 ^= ReadLE32(m + 28);241x8 ^= ReadLE32(m + 32);242x9 ^= ReadLE32(m + 36);243x10 ^= ReadLE32(m + 40);244x11 ^= ReadLE32(m + 44);245x12 ^= ReadLE32(m + 48);246x13 ^= ReadLE32(m + 52);247x14 ^= ReadLE32(m + 56);248x15 ^= ReadLE32(m + 60);250++j12;
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.