Inside Bitcoin
Opening the selected file…
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) 2023-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#include <bip324.h>7#include <chainparams.h>8#include <crypto/chacha20.h>9#include <crypto/chacha20poly1305.h>10#include <crypto/hkdf_sha256_32.h>11#include <key.h>12#include <pubkey.h>13#include <random.h>14#include <span.h>15#include <support/cleanse.h>16#include <uint256.h>18#include <algorithm>19#include <cassert>20#include <cstddef>21#include <cstdint>22#include <iterator>23#include <string>25BIP324Cipher::BIP324Cipher(const CKey& key, std::span<const std::byte> ent32) noexcept26: m_key(key)27{28m_our_pubkey = m_key.EllSwiftCreate(ent32);29}31BIP324Cipher::BIP324Cipher(const CKey& key, const EllSwiftPubKey& pubkey) noexcept :32m_key(key), m_our_pubkey(pubkey) {}34void BIP324Cipher::Initialize(const EllSwiftPubKey& their_pubkey, bool initiator, bool self_decrypt) noexcept35{36// Determine salt (fixed string + network magic bytes)37const auto& message_header = Params().MessageStart();38std::string salt = std::string{"bitcoin_v2_shared_secret"} + std::string(std::begin(message_header), std::end(message_header));40// Perform ECDH to derive shared secret.41ECDHSecret ecdh_secret = m_key.ComputeBIP324ECDHSecret(their_pubkey, m_our_pubkey, initiator);43// Derive encryption keys from shared secret, and initialize stream ciphers and AEADs.44bool side = (initiator != self_decrypt);45CHKDF_HMAC_SHA256_L32 hkdf(UCharCast(ecdh_secret.data()), ecdh_secret.size(), salt);46std::array<std::byte, 32> hkdf_32_okm;47hkdf.Expand32("initiator_L", UCharCast(hkdf_32_okm.data()));48(side ? m_send_l_cipher : m_recv_l_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);49hkdf.Expand32("initiator_P", UCharCast(hkdf_32_okm.data()));50(side ? m_send_p_cipher : m_recv_p_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);51hkdf.Expand32("responder_L", UCharCast(hkdf_32_okm.data()));52(side ? m_recv_l_cipher : m_send_l_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);53hkdf.Expand32("responder_P", UCharCast(hkdf_32_okm.data()));54(side ? m_recv_p_cipher : m_send_p_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);56// Derive garbage terminators from shared secret.57hkdf.Expand32("garbage_terminators", UCharCast(hkdf_32_okm.data()));58std::copy(std::begin(hkdf_32_okm), std::begin(hkdf_32_okm) + GARBAGE_TERMINATOR_LEN,59(initiator ? m_send_garbage_terminator : m_recv_garbage_terminator).begin());60std::copy(std::end(hkdf_32_okm) - GARBAGE_TERMINATOR_LEN, std::end(hkdf_32_okm),61(initiator ? m_recv_garbage_terminator : m_send_garbage_terminator).begin());63// Derive session id from shared secret.64hkdf.Expand32("session_id", UCharCast(m_session_id.data()));66// Wipe all variables that contain information which could be used to re-derive encryption keys.67memory_cleanse(ecdh_secret.data(), ecdh_secret.size());68memory_cleanse(hkdf_32_okm.data(), sizeof(hkdf_32_okm));69memory_cleanse(&hkdf, sizeof(hkdf));70m_key = CKey();71}73void BIP324Cipher::Encrypt(std::span<const std::byte> contents, std::span<const std::byte> aad, bool ignore, std::span<std::byte> output) noexcept74{75assert(output.size() == contents.size() + EXPANSION);77// Encrypt length.78std::byte len[LENGTH_LEN];79len[0] = std::byte{(uint8_t)(contents.size() & 0xFF)};80len[1] = std::byte{(uint8_t)((contents.size() >> 8) & 0xFF)};81len[2] = std::byte{(uint8_t)((contents.size() >> 16) & 0xFF)};82m_send_l_cipher->Crypt(len, output.first(LENGTH_LEN));84// Encrypt plaintext.85std::byte header[HEADER_LEN] = {ignore ? IGNORE_BIT : std::byte{0}};86m_send_p_cipher->Encrypt(header, contents, aad, output.subspan(LENGTH_LEN));87}89uint32_t BIP324Cipher::DecryptLength(std::span<const std::byte> input) noexcept90{91assert(input.size() == LENGTH_LEN);93std::byte buf[LENGTH_LEN];94// Decrypt length95m_recv_l_cipher->Crypt(input, buf);96// Convert to number.97return uint32_t(buf[0]) + (uint32_t(buf[1]) << 8) + (uint32_t(buf[2]) << 16);98}100bool BIP324Cipher::Decrypt(std::span<const std::byte> input, std::span<const std::byte> aad, bool& ignore, std::span<std::byte> contents) noexcept101{102assert(input.size() + LENGTH_LEN == contents.size() + EXPANSION);104std::byte header[HEADER_LEN];105if (!m_recv_p_cipher->Decrypt(input, aad, header, contents)) return false;107ignore = (header[0] & IGNORE_BIT) == IGNORE_BIT;108return true;109}