
A scientific and technical paper. The subject of this study is an open repository bitcoin/bitcoin, which is an integration branch of Bitcoin Core. A version master is not equivalent to a stable release: signed release tags should be used for operation.
Annotation
Bitcoin Core is a complete Bitcoin node implementation that receives blocks and transactions from the peer-to-peer network, independently verifies them, and maintains local UTXO state. Its importance lies not only in the engineering implementation of the protocol: the software code specifies consensus predicates, meaning that an error at the boundary of cryptography, serialization, or state management potentially changes the history accepted by the network.
This article examines the structure of the source tree, the transaction lifecycle, the Script virtual machine, cryptographic mechanisms, and P2P processing. A central cryptanalytic fact: Bitcoin’s cryptographic strength does not eliminate the risk of consensus flaws; historically, coding flaws in ECDSA signatures and replay verification have created threats of malleability, denial of service, and inflation without breaking SHA-256 or the ECDLP solution.
Method and Limits
The analysis concerns the structure of the public repository tree: src, test, doc, depends, contrib, cmake, ci and share. Three levels are clearly distinguished: consensus rules, local node policy, and interface/wallet logic. This distinction is necessary: the mempool’s refusal to accept a transaction does not necessarily invalidate the block containing it.
Repository map
| Category | Purpose | Practical and cryptanalytic meaning |
|---|---|---|
src/ | Main C++ code of the node: consensus, primitives, Script, validation, net, wallet, RPC. | These are the paths that turn the bytes of a P2P message into an accept/reject decision for a block or transaction. |
src/consensus/ | Rules and constraints that are critical to ensure the same result on all nodes. | Special audit area: implementation discrepancies can cause a chain of events. |
src/script/ | Script interpreter, signature verification, sighash, standard templates. | The boundary between the stack-based unlocker and the ECDSA/Schnorr check. |
src/validation.*, src/txmempool.* | Block and transaction verification, UTXO, reorg, mempool. | Here, double spending is prevented and the conservation of the money supply is checked. |
src/net.*, src/net_processing.*, src/protocol.* | Transport, messaging, peer management and inventory handling. | Untrusted network data must be resource-limited prior to costly validation. |
src/primitives/ | Structures of transactions, blocks, headers and their serialization. | Byte canonicity affects txid, wtxid, hashing, and verification reproducibility. |
src/crypto/, src/secp256k1/ | Hash functions and the elliptic curve cryptographic library. | Isolating cryptographic code reduces the risk of implicit dependency on the inconsistent behavior of an external library. |
test/, src/test/, src/bench/, fuzz/ | Functional, unit, regression, performance and fuzzing tests. | Consensus regressions and DoS tasks must be reproducible as test vectors. |
depends/, cmake/, ci/ | Reproducible build, dependencies, cross-platform automation. | Reduce the risk of supply chain substitution and platform differences. |
doc/, contrib/, share/ | Documentation, helper utilities, resources, and localization. | Documents and test plans are important for verifying invariants that cannot be understood from a single function. |
Security model
A full node trusts neither the peer, nor the miner, nor its own mempool: validity arises only after deterministic application of the rules to the block and the current set of unspent outputs. Let the state be U, and the block be B; a valid transition has the form of a LaTeX block:
\[
U_{h+1} = \mathrm{ApplyBlock}(U_h, B_{h+1})
\quad ext{only if} \quad \mathrm{ConsensusValid}(B_{h+1}, U_h)=1.
\]
The key cost invariant for a typical transaction is expressed as:
\[
\sum_{i \in \mathrm{inputs}} v_i \ge \sum_{j \in \mathrm{outputs}} v_j,
\qquad f = \sum_i v_i - \sum_j v_j \ge 0.
\]
Coinbase has a separate constraint: the value created must not exceed the block subsidy plus the total fees. In the code, this isn’t an “accounting guideline,” but a consensus inflation barrier.
Transaction and UTXO
The transaction spends previously created UTXOs through links of the form outpoint = (txid, n) and creates new outputs. When verifying an input, the node verifies the existence of the output, its unspentness, the validity of the amount, the execution of the script predicate, the locking constraints, and the uniqueness of the inputs within the transaction.
A real-world example is CVE-2018-17144. A regression in duplicate input handling allowed some versions to incorrectly handle transactions with duplicate inputs in a block; the consequences ranged from DoS to potential inflation. This is a telling example: the attacker didn’t need to forge a signature or solve a discrete logarithm—it was enough to find a way to incorrectly apply the UTXO semantic invariant.
\[
orall i
ej:\; \mathrm{prevout}_i
e \mathrm{prevout}_j.
\]
This predicate must be checked before any irreversible change to the view state. The audit should separately trace the “check – mark as spent – rollback on error” processing, especially in block, reorg, and batch validation transactions.
Script as VM
Bitcoin Script is a deterministic, intentionally limited, general-purpose stack-based language without loops. The lock script scriptPubKey specifies the spend condition, and the unlock data comes from scriptSig a witness; the result of execution is a Boolean value at the top of the stack, subject to limits and validation flags.
Standard signature verification
OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Historically, this pattern corresponds to P2PKH: the provided public key is hashed, compared with the expected identifier, and then the signature is verified against the sighash message. The public key hash is not encryption; it hides the key until spent and associates the address with the Script condition.
Conceptual diagram of ECDSA signature over group order n:
\[
Q = dG, \qquad r = x(kG) mod n, \qquad s = k^{-1}(z + rd) mod n.
\]
\[
ext{Check:}\quad u_1=zs^{-1} mod n,\;u_2=rs^{-1} mod n,\;
r \equiv x(u_1G+u_2Q)\pmod n.
\]
Here d is the secret key, k is the one-time nonce, z and is the hash of the message being signed. Repeating the nonce for two different messages reveals the key:
\[
k = (z_1-z_2)(s_1-s_2)^{-1} mod n,
\qquad d = (s_1k-z_1)r^{-1} mod n.
\]
A cryptanalytic example. In the 2010s, nonce reuse or predictability in ECDSA across different implementations led to the extraction of private keys; this attack is not on secp256k1 as a mathematical problem, but on the randomness generator and signature implementation. In Bitcoin Core, cryptographic operations must rely on verifiable implementations and strict format handling, and private keys and nonces must not be allowed to appear in logs, dumps, or reused memory.
Canonicity and malleability
Before certain rules were strictly enforced by consensus, the same mathematically correct ECDSA proof could have multiple valid serializations. Since the signature is part of the transaction serialization, changing its representation could change txid the spent UTXOs without changing them—this is transaction malleability, not theft.
Historical fact: OpenSSL’s differences in signature format acceptance created the risk of consensus divergence; first, Bitcoin Core restricted non-standard DER encodings via its relay policy, then strict rules were enshrined by consensus, and signature verification was migrated to libsecp256k1. The lesson of cryptanalysis is that the mathematical equivalence of a signature is not the same as the equivalence of its byte serialization in distributed consensus.
Hashing and identifiers
In traditional notation, a transaction identifier is constructed as a double SHA-256 of serialized data, while SegWit distinguishes between identifiers with and without a witness. For analysis, it’s important to use the serialization required by the specific context:
\[
\mathrm{txid}=\mathrm{SHA256}(\mathrm{SHA256}(\mathrm{serialize}_{
eg witness}(tx))),
\]
\[
\mathrm{wtxid}=\mathrm{SHA256}(\mathrm{SHA256}(\mathrm{serialize}_{witness}(tx))).
\]
A researcher’s mistake in hashing “visual JSON” or hashing bytes in the wrong order does not prove a Core flaw: the precise format, endian representation of fields, and serialization rules are paramount. When constructing a test vector, it is necessary to preserve the original hex bytes, version, inputs, outputs, witness, sequence, and sighash type.
Network and untrusted input
The P2P subsystem accepts announcements and payloads of blocks, transactions, and service messages, but network availability does not create trust. The processor must limit the size, time, and number of objects, separate cheap pre-checking from expensive computations, and maintain correctness even when the data arrives in an arbitrary order.
A real-world example is handling orphan transactions. The vulnerability, disclosed as CVE-2024-52914, was related to the quadratic search for orphan transactions after accepting a new parent; specially crafted objects that were expensive to verify could stall a node for hours. This isn’t a cryptographic hack, but a typical cryptoengineering practice: an attacker exploits the asymmetry between the cost of creating a request and the cost of verifying it.
\[
T_{\mathrm{attacker}} \ll T_{\mathrm{validator}}
\quad \Rightarrow \quad
ext{limits, caching, and interruptible processing required.}
\]
Consensus and politics
| Layer | Question | Consequence of failure |
|---|---|---|
| Consensus | Can a block become part of a valid chain? | Differences in rules between nodes threaten a fork/chain split. |
| Mempool policy | Will an unconfirmed transaction be accepted and relayed by this node? | A transaction may not be propagated, remaining potentially valid in a block. |
| Wallet/RPC/UI | How to create, sign, and display an operation to the user? | The error is dangerous for the user, but does not in itself change the validity of the blocks. |
A practical analysis error is to transfer mempool policy to consensus or vice versa. For example, block transactions are verified according to consensus rules even if they haven’t undergone the standard mempool acceptance process.
Cryptographic surfaces
- ECDSA/Schnorr: signature validity, nonce, normalization and formatting.
- secp256k1: constant-time implementations of sensitive operations, correctness of scalars and points, absence of undefined behavior.
- SHA-256/RIPEMD-160: precise domain-specific serialization and hashing, protection against representation confusion.
- Script: flags, minimal coding rules, stack limits, witness and sighash.
- P2P: parsing untrusted bytes, resource accounting, anti-DoS, and message processing order.
- Build: Locking down dependencies, ensuring reproducibility and verifying origin.
Audit practice
An effective Bitcoin Core audit should begin not with searching for a “magic cryptographic attack,” but with formalizing invariants and constructing minimum reproducible vectors. Each hypothesis requires answers to four questions: which bytes the node receives, which checks are triggered, whether the UTXO state changes, and whether the result on a clean node matches that of an alternative, independent implementation.
# Иллюстративная последовательность разработчика
cmake -B build
cmake --build build -j
ctest --test-dir build --output-on-failure
build/test/functional/test_runner.py
For Script analysis, it’s more useful to add a test that captures a specific boundary property: DER form, minimal numeric representation, NULLDUMMY, locktime, witness commitment, or prevout duplication. For the P2P layer, parser fuzzing and load tests that measure the upper bound of CPU/RAM per untrusted object are appropriate.
Conclusions
Bitcoin Core is more than just a client and wallet, but an executable specification of a significant portion of the network’s rules: it integrates cryptographic verification, Script, UTXO transitions, block validation, and network security into a single deterministic pipeline. Its source code demonstrates a fundamental principle of distributed systems cryptanalysis: even with the strength of SHA-256 and secp256k1, security can be compromised by invariant errors, serialization errors, resource management errors, or implementation mismatches.
Resources for WordPress
Bitcoin Core Source Code: https://cryptoinside.ru/bitcoin-core-source-code/
- Bitcoin Core repository: github.com/bitcoin/bitcoin .
- Bitcoin Core Onboarding, Architecture: bitcoincore.academy/architecture.html .
- Bitcoin Core Onboarding, Transaction Validation: bitcoincore.academy/transaction-validation.html .
- Bitcoin Core Onboarding, Consensus Bugs: bitcoincore.academy/consensus-bugs.html .
- Bitcoin Core disclosure CVE-2024-52914: bitcoincore.org .
