A Bitcoin transaction does not send coins to an account. It creates transaction outputs containing values and spending conditions. A later input identifies an unspent output and supplies data intended to satisfy those conditions. Bitcoin Script is part of the rule system nodes use to determine whether that spend is valid.
The word โscriptโ can suggest a general programming environment. Bitcoin Script is narrower. It has no persistent application state, no network access, no filesystem, and no open-ended loop construct. It runs during transaction validation with tightly limited data and operations. Its purpose is to evaluate authorization and spending conditions, not to host arbitrary applications.
This guide was reviewed July 25, 2026 against Bitcoin Core 31.1, tag v31.1, commit 9be056a8a72b624dae9623b2f7bded92c2a21c91, relevant deployed BIPs, and tagged source, unit vectors, functional tests, and fuzz targets. Exact behavior depends on the script context, active consensus rules, verification flags, policy, and software version.
Outputs lock; inputs attempt to unlock
Every transaction output contains a value and a scriptPubKey. The scriptPubKey commits to or directly expresses the conditions under which the output may be spent.
A spending input references the prior output. Depending on the output type, the input can provide a scriptSig, witness data, or both. Validation combines the prior outputโs condition with the supplied spending data under rules selected by the output form and active script version.
โUnlocking scriptโ is common shorthand, but it can hide important structure. In SegWit and Taproot, the witness may contain signatures, public keys, scripts, control data, or stack arguments that are interpreted differently. The input does not alter the prior output; it presents evidence that the fixed condition is satisfied.
Stack execution
Bitcoin Script is stack based. Data pushes place byte arrays on a main stack. Opcodes consume items, transform or compare them, and push results. Some opcodes can move items to and from a separate alternate stack, but the alternate stack is local to one script evaluation and is cleared between separately evaluated scripts.
Execution is deterministic for the transaction, spent output, script, flags, and chain context supplied to the interpreter. Conditional opcodes can skip branches, but there are no unbounded loops. A script succeeds only if it avoids a failure condition and ends with the required truth result for its context.
Byte arrays can be interpreted as booleans, numbers, hashes, public keys, signatures, or opaque data. Those interpretations have encoding rules. The empty vector and โnegative zeroโ evaluate false. Non-minimal numbers, oversized elements, malformed signatures, or unexpected stack shapes can matter differently under consensus and policy.
Legacy script evaluation
In the base or legacy context, a node evaluates the inputโs scriptSig and the spent outputโs scriptPubKey sequentially on the same main stack. For pay-to-script-hash, or P2SH, BIP 16 adds another stage: a push-only scriptSig supplies a redeem script whose hash must match the scriptPubKey, and that redeem script is then evaluated using the restored stack.
Legacy signatures use the original signature-hash behavior. Historical rules and bug compatibility are part of consensus. A developer cannot replace them with a cleaner interpretation without changing which historical or future transactions validate.
Legacy does not mean โanything before SegWit is the same.โ Bare scripts, P2PKH, P2SH, timelocks, and multisignature patterns have distinct structures, and relay policy may reject forms that consensus would still allow in a block.
SegWit version 0 evaluation
BIP 141 introduced witness programs. A native witness output places a version and program directly in the scriptPubKey. A nested construction places a witness program inside a BIP 16 redeem script.
For P2WPKH, the witness must supply exactly a signature and public key corresponding to a 20-byte program. For P2WSH, the final witness element is a witness script whose SHA256 hash must match the 32-byte program; earlier witness elements become its initial stack.
SegWit version 0 uses the BIP 143 signature digest and consensus rules specific to witness execution. Witness data is serialized separately from the legacy transaction identifier, but upgraded nodes still validate it. Native witness spends require an empty scriptSig; nested witness spends require exactly one push of the witness-program redeem script.
Taproot key path and tapscript
A pay-to-Taproot output is a native SegWit version 1 output with a 32-byte program. BIP 341 defines key-path and script-path spending. P2SH-wrapped version 1 outputs are not Taproot spends.
A key-path spend validates a Schnorr signature against the output key. It does not execute a tapscript.
A script-path spend reveals a tapscript, control block, and Merkle path that prove the script was committed into the output key. BIP 342 defines the tapscript language and its signature-opcode behavior. Bitcoin Core represents key-path and tapscript validation as distinct signature versions.
Tapscript adds OP_CHECKSIGADD, disables OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY when they execute, and reserves designated OP_SUCCESSx values for future soft-fork upgrades. During tapscript validation, the interpreter scans for OP_SUCCESSx before ordinary parsing and resource checks; finding one makes the script succeed at consensus, while standard policy discourages spending such paths before they are assigned meaning.
Scripts, witnesses, and committed data
Several names describe different objects:
scriptPubKey: the spending condition stored in an output.scriptSig: input field used by legacy and P2SH constructions.- Redeem script: script revealed to satisfy a P2SH hash commitment.
- Witness: segregated per-input stack data introduced by SegWit.
- Witness script: final witness element whose hash satisfies a P2WSH program.
- Tapscript: script revealed in a Taproot script-path spend.
- Control block: Taproot data proving the leafโs commitment and reconstructing the output key.
The same byte sequence can be invalid, ignored, discouraged, or interpreted differently depending on where it appears. Naming the container and script version is necessary before describing behavior.
Signature checks and signature hashes
Signature opcodes do not merely ask whether a signature matches a key. They validate a signature over a context-specific digest of transaction data.
Legacy, SegWit version 0, and Taproot use different signature-message rules. Sighash modes can select which inputs and outputs are committed. SIGHASH_ALL, NONE, SINGLE, ANYONECANPAY, and Taprootโs SIGHASH_DEFAULT have precise version-specific semantics.
OP_CODESEPARATOR also differs by context. In legacy and witness-v0 execution, signature checking uses script code beginning after the most recently executed separator. Legacy hashing additionally removes matching signatures and omits remaining OP_CODESEPARATOR opcodes from the serialized script code; BIP 143 does not perform the legacy signature deletion and retains later separators. Tapscript instead commits to the entire tapleaf hash plus the opcode position of the last executed separator through the BIP 342 signature-message extension.
A valid cryptographic signature can still fail script validation because the public key encoding, signature encoding, sighash byte, stack position, or transaction context is wrong. Conversely, a script can fail before a signature operation runs.
Multisignature is also construction-specific. Legacy and SegWit v0 can use OP_CHECKMULTISIG, whose historical bug consumes one extra stack item. BIP 147โs active NULLDUMMY consensus rule requires that item to be empty. Tapscript disables the old multisignature opcodes and uses combinations such as OP_CHECKSIG and OP_CHECKSIGADD. Off-chain threshold or key-aggregation protocols are separate systems that may produce one on-chain signature.
Hashes, timelocks, and logical conditions
Hash opcodes let scripts compare a revealed preimage with a committed digest. They support constructions such as hashlocks, but the security of a construction depends on preimage entropy, disclosure, transaction structure, and surrounding conditions.
OP_CHECKLOCKTIMEVERIFY applies an absolute block-height or timestamp constraint through nLockTime and requires the spending input not to be final. OP_CHECKSEQUENCEVERIFY applies a relative block or time constraint through the input sequence field and requires transaction version 2 or later. Neither opcode creates a scheduler that broadcasts a transaction automatically.
Conditional and comparison opcodes allow multiple spending branches. A script can express โsignature A now, or signature B after a delay,โ but wallet coordination, key storage, fee management, and recovery remain outside Script itself.
Consensus rules versus standardness policy
Consensus rules determine whether a block is valid. Standardness and relay policy determine whether a node will accept an unconfirmed transaction into its mempool or relay it under local policy.
Bitcoin Core exposes verification flags used in different contexts. Some flags correspond to active consensus rules; others enforce standardness or discourage use of upgrade mechanisms before their meaning is known. The source comments explicitly warn that some encoding or upgrade-discouragement flags are not intended as mandatory block-validation rules.
A transaction can therefore be consensus-valid but nonstandard. It may be rejected from a nodeโs mempool yet accepted if included in a valid block. Policy is still operationally important: relying on nonstandard behavior can make broadcast and confirmation difficult.
Disabled, reserved, and upgrade opcodes
Some opcode byte values are globally disabled in base and witness-v0 script. Bitcoin Core rejects those bytes during decoding even when they appear in a conditional branch that would not execute. Their names can remain in the opcode enumeration for historical reasons; presence in script.h does not mean they are usable.
That behavior is distinct from opcodes that fail only when executed. For example, tapscriptโs OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY fail when reached but are ignored in an unexecuted branch. Reserved and invalid opcodes have their own context-specific behavior.
Some NOP opcodes were repurposed through soft forks, including the opcodes now used for absolute and relative timelocks. Policy can discourage remaining upgradeable NOPs so users do not rely on behavior that a future soft fork may narrow.
Tapscript uses a different upgrade mechanism. OP_SUCCESSx values intentionally succeed today at consensus, allowing a future soft fork to assign stricter meaning. Unknown tapleaf versions, unknown tapscript public-key types, and unknown witness versions are separate upgrade boundaries with separate policy flags. They must not be conflated with one another.
Resource and execution limits
Bitcoin validation limits resource use to reduce denial-of-service risk and keep validation bounded. In base and witness-v0 script, Bitcoin Core 31.1 enforces a 10,000-byte script limit, a 520-byte pushed-element limit, no more than 201 non-push operations per script, and no more than 1,000 combined main-stack and alternate-stack elements. P2WSH separately limits its revealed witness script to 10,000 bytes.
Tapscript deliberately does not use the 10,000-byte script limit or the 201 non-push-opcode limit; script size is instead bounded indirectly by transaction and block weight. If no OP_SUCCESSx is present, the 520-byte element limit remains, and the 1,000-item stack-plus-altstack limit also applies to the initial stack.
Tapscript signature opcodes use a per-input validation budget rather than the legacy block sigop accounting. The budget begins at 50 plus the serialized byte size of that inputโs full witness, including its compact-size prefix. Each executed OP_CHECKSIG, OP_CHECKSIGVERIFY, or OP_CHECKSIGADD with a non-empty signature consumes 50 units; crossing below zero fails the script.
These numbers should not be copied as one universal โScript limitโ table. A correct statement identifies the script version, whether the rule is consensus or policy, and the exact software or BIP source.
Common failure conditions
A spend can fail because:
- the committed script or key does not match the revealed data;
- stack underflow or overflow occurs;
- an opcode is disabled, reserved, or invalid for the script version;
- a signature, public key, number, or sighash type is malformed;
- a hash comparison or signature check returns false;
- a timelock condition is not satisfied;
- a branch is unbalanced or ends incorrectly;
- an element, script, control block, stack, or signature budget exceeds its applicable limit;
- the final stack result does not meet the contextโs success rule;
- witness or P2SH structure is malformed;
- an active consensus rule rejects the execution.
Bitcoin Core records script-error categories, but a user-facing RPC or wallet may present a higher-level message. Interface wording should not be mistaken for the complete consensus reason.
Why one interpreter function is not the protocol
Bitcoin Coreโs EvalScript is central, but Script behavior also depends on transaction serialization, spent-output lookup, signature hashing, verification flags, deployment state, chain context, consensus limits, witness-program recognition, Taproot commitment checks, and calling validation code.
Tests are equally important. Unit tests, JSON test vectors, functional tests, and fuzz targets exercise historical and edge behavior that prose can miss. Tests provide evidence for covered cases; they do not prove absence of defects.
When comparing implementations, pin an exact release or commit and reproduce the same vectors. A difference can be a policy choice, interface difference, test harness issue, or consensus bug. The category must be established before calling it a protocol disagreement.
Safe boundaries for โprogrammabilityโ
Bitcoin Script can compose signatures, hashes, timelocks, and logical branches into useful spending policies. It supports payment channels, recovery paths, escrows, atomic-swap components, and other protocols.
That does not make it equivalent to a general-purpose smart-contract virtual machine. Most application state and coordination live in transactions, wallets, communication protocols, and off-chain systems. Script evaluates a spend under bounded rules; it does not run continuously or maintain an autonomous application.
A precise description is: Bitcoin Script is a constrained, versioned validation language for transaction spending conditions.