Bitcoin Core Developers Standard: BIP-370 — PSBT Version 2

03.09.2026

Bitcoin Core Developers Standard: BIP-370 — PSBT Version 2

A scientific and technical paper.  Subject: PSBT v2 specification and differences from BIP-174. Original normative document: BIP-370, status  Final , author Ava Chow, created January 14, 2021.

Annotation

BIP-370 defines PSBT version 2—a representation format for unsigned or partially signed Bitcoin transactions, in which the transaction structure is decomposed into global, input, and output maps. The main result of the standard is the elimination of the monolithic field  PSBT_GLOBAL_UNSIGNED_TXcharacteristic of BIP-174 (PSBT v0): inputs and outputs are allowed to be added after the initial creation of the PSBT, but only within the scope of explicitly stated modification rights.

For a cryptanalyst, PSBT v2 is important not as a new cryptographic primitive, but as a protocol for ensuring the integrity of the context in which an ECDSA or Schnorr signature is generated. It reduces the risk of discrepancies between the transaction displayed to the signing device and the actual serialized construction, but does not replace independent verification of amounts, UTXOs, scripts, derivation paths, and SIGHASH coverage.

Terms and model

PSBT  (Partially Signed Bitcoin Transaction) is a portable metadata container that allows multiple entities to coordinate the construction and signing of a single transaction. It decouples the communication format from the final network serialization of a Bitcoin transaction.

TermMeaningCryptographic value
CreatorCreates a PSBT blank.Forms an initial context that is not yet a spending authorization.
ConstructorAdds PSBT v2 inputs and outputs.Modifies the message that will ultimately be hashed for signature; must honor mutability flags.
UpdaterComplements data, such as sequence.Provides information necessary for correct sighash and verification of spending conditions.
SignerVerifies PSBT and generates partial signatures.Associates a secret key with a specific transaction message.
ExtractorAssembles the final network transaction.Materializes a structure certified by completed signatures.

BIP-174 context

BIP-174 defined the basic binary PSBT format: a magic start  0x70736274ff, followed by a global map, input maps, and output maps. Each map is a sequence of key-value pairs, and a zero byte terminates the map.

In PSBT v0, the mandatory global field  PSBT_GLOBAL_UNSIGNED_TX contains the entire unsigned transaction. Therefore, the number and order of inputs/outputs are already hardcoded in the global serialization; metadata about a single element is distributed between this transaction and the corresponding local map.

A historical and practical example.  The original PSBT was implemented in Bitcoin Core as an interoperable format for hardware wallets, multi-signature, and CoinJoin processes. In such scenarios, a pre-committed transaction is convenient for signing, but inconvenient for interactive coin selection and the gradual addition of change outputs.

The reason for the appearance of v2

PSBT v2 moves transaction constructor fields from a single global transaction to specialized maps. This allows the constructor to add inputs and outputs, and the handler receives a local, complete description of each input or output.

This change does not make signatures mathematically stronger: the security of ECDSA/Schnorr remains based on the difficulty of the discrete logarithm on secp256k1. The standard changes the engineering trust boundary: who, at what stage, and which parts of the signed message are allowed to change.

Normative invariants

  • PSBT_GLOBAL_UNSIGNED_TX is prohibited in PSBT v2.
  • PSBT_GLOBAL_VERSION is required and must have a value of 2.
  • PSBT_GLOBAL_INPUT_COUNT and  PSBT_GLOBAL_OUTPUT_COUNT are mandatory; they determine the number of subsequent cards.
  • Each input must contain the identifier of the previous transaction and the index of the output being spent.
  • Each output must contain the sum and  scriptPubKey.
  • Unknown or version-incompatible fields should be treated as validation errors, not as “harmless” data.
PSBTv2 := magic || global-map || input-map[0..Nin-1] || output-map[0..Nout-1]
magic  := 0x70 0x73 0x62 0x74 0xff     # ASCII "psbt" + separator

An example of test vectors.  BIP-370 intentionally includes invalid samples: PSBT v0 with a version 2 field, PSBT v0 with v2 fields, and PSBT v2 without the required input counter, output counter, prevout TXID, or index. Such negative vectors are important for fuzzing and regression testing of parsers: accepting a hybrid object creates the risk of different interpretations by different participants.

Global Map v2

FieldCodeCodingNormative rolePractical example
Transaction version0x02signed int32 LEThe version of the Bitcoin transaction being created, not the PSBT version.For scripts using BIP-68/CSV, the constructor selects version no lower than 2.
Backup locktime0x03uint32 LEUsed if inputs do not require their own locktime.The wallet sets the anti-fee-sniping height as a fallback, but entering with a stricter CLTV changes the resulting rule.
Number of inputs0x04CompactSize uintDefines the number of input maps.The parser can limit memory allocation in advance and not “guess” the boundaries of the structure.
Number of outputs0x05CompactSize uintDefines the number of output maps.Allows you to interactively add a change before the signature starts, if enabled by the flag.
Mutability flags0x06uint8Explicitly set the permissibility of changing inputs/outputs and the presence of SIGHASH_SINGLE.After a regular signature without ANYONECANPAY, adding a new login is prohibited.
flags = b0 + 2*b1 + 4*b2
b0 = inputs_modifiable
b1 = outputs_modifiable
b2 = has_sighash_single

Flags are not a cryptographic signature in themselves. Their security value arises because, after adding a signature, the signer is required to adjust the flags to reflect the degree of freedom of change retained by the selected SIGHASH.

Entrance maps

FieldCodeCodingSemantics and example
Previous TXID0x0e32 bytesThe hash of the previous transaction. Together with the index, it uniquely defines the outpoint: for example, a hardware wallet checks it against a locally known UTXO.
Output Index0x0fuint32 LEOutput number in the transaction  Previous TXID. An index error may direct the signature to a different UTXO and must be detected before signing.
Sequence0x10uint32 LEIf absent, it is assumed  0xffffffff. In real contracts, sequence is involved in BIP-68 relative delays and affects locktime activation.
Time locktime0x11uint32 LE, >= 500000000Minimum Unix timestamp for entry. Example: emergency refund branch after calendar date.
Height locktime0x12uint32 LE, 0 < x < 500000000Minimum block height. Example: timelock in a vault or escrow structure, expressed in blocks.

Exit maps

FieldCodeCodingMeaning
Output Amount0x03int64 LEOutput amount in satoshi. In v2, this is a mandatory part of the output map.
Output Script0x04byte arrayscriptPubKey recipient; required in v2 and prohibited in v0.

Placing the amount and script in a single output map makes the output a self-contained unit of audit. For a secure user experience, the signer must display the address (or a meaningful description of the script), amount, fee, and the difference between a change output and an external payment; the presence of fields does not necessarily prove that the interface correctly recognized their purpose.

Locktime algorithm

The final value  nLockTime is derived from the fallback field and the input requirements. If no input specifies a requirement, is used  PSBT_GLOBAL_FALLBACK_LOCKTIME; if none, zero is used.

\[ L = \begin{cases} L_{fallback}, & R_t = \varnothing \land R_h = \varnothing,\\ \max(R_h), & \text{if the height type is valid for all bounding inputs},\\ \max(R_t), & \text{otherwise, if the time type is valid for all bounding inputs}. \end{cases} \]

where \(R_t\) is the set of time requirements, and \(R_h\) is the set of height requirements. When both types can be selected, BIP-370 dictates that the block height option be chosen.

Cryptanalytic meaning.  Locktime is part of the message being signed. If, after a signature is created, an added input changes the selected type or maximum locktime, the digest is changed and the existing signature no longer matches the transaction. Therefore, the constructor should not add such an input if signatures are present.

Identification v2

For unique identification, BIP-370 proposes reconstructing an unsigned transaction from v2 fields and calculating its TXID. The reconstruction inputs  nSequence are set to 0 and  nLockTime calculated using the standard algorithm.

\[ \mathrm{PSBTv2\_ID} = \mathrm{TXID}\left(\mathrm{Serialize}(T^{*})\right),\qquad T^{*}.\mathrm{sequence}_i=0. \]

In traditional Bitcoin notation: \(\mathrm{TXID}(T)=\mathrm{SHA256}(\mathrm{SHA256}(\mathrm{Serialize}(T)))\), and the displayed hex representation is usually written in big-endian order.

Sequence normalization eliminates the variability that an updater or combiner can introduce without changing the underlying PSBT structure. It is the identifier of the coordination object, not a replacement for the final TXID of the extracted transaction.

Signatures and SIGHASH

A Bitcoin signature verifies not the “entire PSBT file,” but rather a hashed message pre-image generated according to the rules of a specific input type and SIGHASH. For classic ECDSA on secp256k1, the following relation is verified:

\[ Q=dG,\qquad s \equiv k^{-1}(z+rd)\pmod n, \]

where \(d\) is the private key, \(Q\) is the public key, \(G\) is the base point, \(k\) is a one-time nonce, \(z\) is the integer from the digest of the message being signed, \(r,s\) are the signature components, \(n\) is the group order.

PSBT v2 does not change this equation. It standardizes the object’s lifecycle up to the point where signer evaluates  z, and ties permitted further modifications to the semantics of  SIGHASH_ALL,  SIGHASH_NONE,  SIGHASH_SINGLE and the modifier  ANYONECANPAY.

Subscription semanticsFlags requirement v2Why is this important?
Signature without ANYONECANPAYAfter signature  Inputs Modifiable = 0.Such a signature typically covers a set of inputs; adding/removing an input changes the message being signed.
Signature without SIGHASH_NONEAfter signature  Outputs Modifiable = 0.The signature is committed to outputs in a volume dependent on SIGHASH.
SIGHASH_SINGLEHas SIGHASH_SINGLE = 1.The index correspondence between the input and output element is preserved; the designer must carefully maintain pairs.

Cryptanalytic fact

A well-known classic ECDSA risk is nonce reuse. If two signatures with the same key use the same \(k\), then given \((r,s_1,z_1)\) and \((r,s_2,z_2)\) the private key can be recovered:

\[ k \equiv (z_1-z_2)(s_1-s_2)^{-1}\pmod n,\qquad d \equiv (s_1k-z_1)r^{-1}\pmod n. \]

Historically, vulnerabilities due to poor entropy or nonce reuse have led to the compromise of ECDSA keys in various systems, including the famous PlayStation 3 case. In Bitcoin, such an error would directly result in the loss of control over the UTXO. BIP-370 does not prevent nonce reuse: this threat is mitigated by deterministic nonce generation, isolated signers, and ECDSA/Schnorr implementation auditing.

However, v2 mitigates another, protocol-specific class of risks: structure ambiguity, field substitution during interprocess communication, and erroneous continuation of modifications after signatures have been created. In other words, cryptographic strength protects the key, and strong PSBT invariants protect the correctness of the message authenticated by that key.

Roles and transitions

PhasePermissible actionSecurity controlExample
CreatorCreate v2 with 0 inputs/outputs.Set version to 2; when passing to the constructor, set flags and transaction version >= 2.The online coordinator creates the CoinJoin framework without access to the keys.
ConstructorAdd input/output cards.Check permission bits, counters, locktime compatibility, SIGHASH_SINGLE pairs.The wallet adds change after selecting the UTXO before signing.
UpdaterSet sequence.Avoid incompatibility with relative locks and wallet policy.The service sets the sequence for the RBF or CSV branch.
SignerCreate a partial signature.Check outputs, fees, prevouts, and scripts; then narrow down modifiable flags.Air-gapped hardware wallet signs only after screen confirmation.
ExtractorAssemble a network-serialized transaction.Only completed inputs; locktime is calculated strictly according to BIP-370.The coordinator publishes the completed multisig transaction to the network.

v0 and v2

PropertyPSBT v0 — BIP-174PSBT v2 — BIP-370
Basic structureGlobal unsigned transaction plus metadata maps.The cards fully describe the transaction structure.
PSBT_GLOBAL_UNSIGNED_TXRequired.Prohibited.
PSBT versionImplicit v0 by default or explicit version.The version field is required and equal to 2.
Adding inputs/outputsAlmost impossible without rebuilding the global transaction.Allowed with appropriate flags.
Number of cardsFollows from unsigned transaction.Explicitly set by global counters.
Input/Output DescriptionSplit between unsigned transaction and card.Localized in input/output map.
CompatibilityIs not v2.Intentionally incompatible with v0, but convertible by reconstructing unsigned transaction.

Compatibility and migration

The key-value format and general organization of maps are identical between the versions, so the existing deserializer is conceptually extended to support new fields. However, semantic compatibility is intentionally absent: PSBT v0 and PSBT v2 should not be mixed, as the global unsigned transaction was removed from v2.

Converting v2 to v0 is possible: the implementation constructs an unsigned transaction from the v2 fields and places it in  PSBT_GLOBAL_UNSIGNED_TX. Reverse migration requires extracting the version, prevouts, sequence, amounts, and scripts from the v0 transaction and distributing them across maps, preserving the relevant BIP-174 metadata.

Testing and auditing

For implementation, it’s not enough to check “a valid PSBT is successfully signed.” Failures are required: required fields are missing, v0 contains a v2 key, v2 contains an unsigned transaction, the declared counts don’t match the number of cards, unknown flags are active, and adding an input changes the locktime after signing.

def validate_v2(psbt):
    assert psbt.global_map.version == 2
    assert not psbt.global_map.has_unsigned_tx
    assert len(psbt.inputs) == psbt.global_map.input_count
    assert len(psbt.outputs) == psbt.global_map.output_count
    for i in psbt.inputs:
        assert i.previous_txid is not None and i.output_index is not None
    for o in psbt.outputs:
        assert o.amount is not None and o.script_pubkey is not None
    validate_locktime_compatibility(psbt)
    validate_modifiability_vs_signatures(psbt)

A practical example:  When auditing a multisig wallet, the test should create a valid PSBT, allow one participant to sign  SIGHASH_ALL, and then attempt to add an input and an external output. A correct implementation should reject both modifications, since the signer should have removed the corresponding modification permissions.

Limitations of the standard

BIP-370 does not validate the existence of UTXOs in the blockchain, does not confirm the economic viability of the fee, does not determine a trusted source  witness_utxonon_witness_utxo and does not guarantee the absence of a malicious change output. These properties are verified by the wallet, full node, hardware signer, and application policies.

The standard also does not protect against key compromise, side-channel attacks, malicious firmware, or incorrect transaction display to the user. Its scope is the canonical representation and controlled evolution of a partially signed transaction.

Conclusion

BIP-370 formalizes PSBT v2 as a more modular model for cooperative Bitcoin transaction construction. Its key contributions include the migration of structured data to maps, explicit counters, and controlled mutability consistent with SIGHASH semantics.

For cryptographic practice, this exemplifies an important principle: the security of a digital signature is determined not only by the strength of the elliptic curve and the secrecy of the nonce, but also by the precision of the protocol that defines the message being signed. PSBT v2 does not replace cryptanalysis of signature implementations, but it significantly improves the verifiability and discipline of transaction workflows.

Normative sources

Regulatory Standard Bitcoin Core Developers: BIP-370 – PSBT Version 2:  https://alpinvest.ru/regulatory-standard-bitcoin-core-developers-bip-370-psbt-version-2/

  1. A. Chow.  BIP 370: PSBT Version 2 . Bitcoin Improvement Proposals, Final status, 2021.  GitHub .
  2. A. Chow.  BIP 174: Partially Signed Bitcoin Transaction Format . Bitcoin Improvement Proposals, 2017.  GitHub .
  3. Bitcoin Core.  PSBT Howto ; description of workflow Creator—Updater—Signer—Finalizer—Extractor.  GitHub .
  4. Bitcoin Core PR #21283.  Implement BIP 370 PSBTv2 .  GitHub .