
A research and practical article. Subject: a supported overview of PSBT practices, related BIPs, and wallet compatibility. Formulas are provided in LaTeX-compatible text format.
Abstract. Partially Signed Bitcoin Transaction (PSBT) is a format for exchanging transaction metadata and intermediate cryptographic signature artifacts between independent programs and devices. Its purpose is to decouple the construction, verification, signing, bundling, and extraction of Bitcoin transactions without transmitting private keys or requiring offline signers to have network access. This paper systematizes the architecture of PSBT, BIP174, BIP370, BIP371, BIP373, BIP375, and BIP376, interoperability practices, and cryptanalytic security boundaries.
Keywords: Bitcoin, PSBT, BIP174, BIP370, Taproot, Schnorr, MuSig2, ECDSA, UTXO, air-gapped signing, CoinJoin, cryptanalysis, secure implementation.
1. Subject and context
Bitcoin Optech describes PSBT as a format that allows wallets and other tools to communicate information about spendable UTXOs, outputs, and signatures before a transaction is ready to be broadcast. The base specification, PSBTv0, is published as BIP174, and PSBTv2 as BIP370; there is no version 1. This design eliminates dependency on a specific wallet’s internal format and enables cross-program and offline signing.
From a cryptanalytic perspective, PSBT does not weaken the discrete logarithmic security of secp256k1. It changes the trust boundary : the private key remains within the hardware or isolated signer, and the external environment supplies a strictly verifiable message and evidential contextual information. Consequently, the critical attack surface shifts from key extraction to payment intent spoofing, serialization errors, UTXO misinterpretation, nonce reuse, and implementation incompatibility.
Cryptanalytic fact. The strength of the ECDSA/Schnorr signature is based on the difficulty of the discrete logarithm problem in the secp256k1 point group: P = dG it is virtually impossible to recover the secret scalar given the public key d. However, repeating or predicting the nonce in ECDSA destroys key secrecy regardless of the PSBT: for two signatures with one, k the secret is recovered algebraically.
2. PSBT Data Model
A binary container begins with magic bytes 70 73 62 74 FF (ASCII psbt and a separator), followed by a global map, one map for each input, and one map for each output. Each map is a sequence of unique key-value pairs, terminated by a byte 0x00. The key includes the length, type, and additional key data; the value contains the length and payload.
<psbt> := <magic> <global-map> <input-map>* <output-map>* <magic> := 0x70 0x73 0x62 0x74 0xFF <global-map> := <keypair>* 0x00 <input-map> := <keypair>* 0x00 <output-map> := <keypair>* 0x00 <keypair> := <key> <value>
| Region | Purpose | Typical information | Practical example |
|---|---|---|---|
| Global map | General framework and parameters | Unsigned transaction v0 or transaction version, input/output counters and mutability flags v2; xpub; PSBT version | The CoinJoin coordinator creates a shared container; participants add to it without transmitting seeds. |
| Entrance map | Prove what exactly is being spent and collect signatures | UTXO, scriptPubKey, redeem/witness script, derivation path, sighash, partial and final signatures | The hardware wallet checks the amount and prevout script before signing a single input. |
| Exit map | Describe the generated UTXOs and the origin of the change | Sum/script in v2, derivation path, Taproot/MuSig2 data, utility extensions | The signer recognizes the change by its own fingerprint and BIP32 path to show the user only external payments. |
Parsing invariants
- Repeating the same full key within a map makes PSBT invalid; ambiguous “last value wins” is dangerous for different parsers.
- A compliant implementation should preserve unknown fields during re-serialization; this is the basis for extensibility, but not a reason to sign a semantically unclear payment.
- Each input must be associated with a prevout, amount, scriptPubKey, and the required script path; failure to do this verifies the external constructor as a potentially malicious data source.
3. Roles and protocol
BIP174 divides the process into roles. A single application can fulfill multiple roles, but logically separating them is useful for auditing: it shows at what stage data is created and who has permission to add, not change, it.
| Role | Permissible action | Security control | Historical and practical example |
|---|---|---|---|
| Creator | Creates a PSBT framework | Records inputs/outputs and empty cards | Bitcoin Core received initial RPCs for PSBT in release 0.17 (2018), making transaction construction a separate step. |
| Updater | Adds UTXO, scripts, paths | Should not replace the meaning of an already agreed upon transaction | utxoupdatepsbt can enrich the container with prevout data from the local node with txindex. |
| Signer | Adds only correct signatures | Checks UTXO, script hashes, sighash, addresses, amounts, and fees | An air-gapped hardware wallet receives PSBT via SD card or QR code, signs it inside a secure device, and returns only the signature. |
| Combiner | Combines equivalent PSBTs | Does not merge different underlying transactions; rejects conflicts of understood fields | In 2-of-3 multisig, two independent cosigners return containers with different partial signatures. |
| Finalizer | Builds final scriptSig/witness | Finalizes only inputs that satisfy the script policy | For P2WSH 2-of-3, builds a witness stack with a mandatory zero dummy element and two valid signatures. |
| Extractor | Extracts a network transaction | Requires finality of all inputs; may additionally validate the output | Since 2020, the Bitcoin Core GUI has included a PSBT signing and sending flow. |
The algebra of union expresses the expected commutativity of independent complements: Combine(f_A(PSBT), f_B(PSBT)) = f_A(f_B(PSBT)) = f_B(f_A(PSBT)). This is true only if the transaction object is shared and immutable and there are no conflicting values; therefore, union is not a cryptographic proof of agreement between the participants.
4. PSBTv0 and PSBTv2
| Property | PSBTv0 — BIP174 | PSBTv2 — BIP370 | Consequences for compatibility |
|---|---|---|---|
| Transaction representation | A mandatory global field of a complete unsigned transaction | A full unsigned transaction is excluded; the structure is defined by discrete fields | The v0 parser is not required to understand v2; the conversion should be done explicitly and tested. |
| PSBT version | The field is missing or equal to 0 | The version field is required and equal to 2 | “v1” is not a valid intermediate version; it cannot be used to mark a custom format. |
| Design | The transaction framework is fixed before signature | You can add inputs and outputs after creation | Convenient for interactive construction, CoinJoin and coordination protocols. |
| Input fields | Prevout is located in an unsigned transaction | Separate txid, index, sequence, and locktime fields | Implementations must strictly check for the inclusion of required v2 fields. |
| Output fields | Are in an unsigned transaction | Amount and scriptPubKey are separate entries | The signatory must re-display the final payment semantics to the person. |
PSBTv2 isn’t an “improved signature serialization,” but a different way to describe a transaction under construction. Its mutability flags are important for interactive protocols: the presence of an existing signature SIGHASH_SINGLE imposes a constraint that the input index corresponds to the output index, otherwise the signed commitment may change its meaning.
5. Related BIPs
| BIP | Region | Added data | Example of application |
|---|---|---|---|
| BIP174 | Basic format, PSBTv0 | Key-value maps, roles, UTXO, ECDSA partial signatures, proprietary fields | Offline 2-of-3 P2WSH storage where three organizations use different wallets. |
| BIP370 | PSBTv2 | Decomposed transaction structure, counters, mutability, locktime requirements | The coordinator adds the general structure, the participant adds its own input/output in the controlled protocol. |
| BIP371 | Taproot | Key-path and script-path Schnorr signatures, internal key, Merkle root, leaf scripts, x-only derivation | The taproot output consumes the key path with a single 64-byte Schnorr signature; the alternative script path expands the leaf and control block. |
| BIP373 | MuSig2 in PSBT | Participant key set, public nonce, partial MuSig2 signature | Joint aggregated signing of multiple keys for Taproot without publishing the traditional multisig script in the key path. |
| BIP375 | Sending Silent Payments | Global/input ECDH shares and DLEQ proofs, information about silent-payment output | The sender generates an output for silent payment, proving the correctness of the shared ECDH computations to the process participants. |
| BIP376 | Spending Silent Payments | Spend key path and 32-byte tweak for PSBTv2 | The recipient’s wallet provably finds a derivation context for spending the output sent to the silent-payment address. |
6. Cryptography and cryptanalysis
ECDSA and the dangers of nonce
For ECDSA over secp256k1 with secret key d, nonce k, message hash z and group order n the signature is:
R = kG
r = x(R) mod n
s = k^{-1}(z + rd) mod n
If one nonce k is used for two different hashes z_1 and z_2, signatures with the same r, and the secret key is calculated:
k = (z_1 - z_2)(s_1 - s_2)^{-1} mod n
d = (s_1 k - z_1)r^{-1} mod n
A historical class of Bitcoin incidents is associated specifically with poor nonce randomness or nonce repetition, including the Android SecureRandom vulnerability in 2013, which caused some mobile wallets to generate predictable ECDSA values. PSBT itself does not generate a nonce or cure a weak generator; the signer’s cryptographic module is required to use a deterministic nonce according to RFC 6979 or a valid secure generator, and auditing should verify uniqueness r in observed ECDSA signatures as an indicator of a catastrophic error.
Taproot, Schnorr, and Aggregation
In BIP340, a Schnorr signature is typically represented as a pair (R, s)where equality is checked:
sG = R + eP, e = H_challenge(R || P || m)
Schnorr’s linearity enables key aggregation and MuSig2, but introduces a new critical object: the nonce commitment and the public nonce of each participant. In practice, it is impossible to reuse a nonce between sessions, sign without a complete nonce protocol, or tamper with the participant list: an error could reveal a secret share or allow an attack on the aggregation’s correctness. BIP373 migrates the necessary transparent artifacts of MuSig2—the key list, public nonces, and partial signatures—to PSBT maps.
Commission and substitution of intention
For a transaction with inputs I and outputs, O the fee is:
fee = sum_{i in I} value_i - sum_{o in O} value_o
The classic attack on PSBT isn’t ECDSA cryptanalysis, but rather field substitution, which tricks the user into signing a different recipient script or an excessive fee. Therefore, the signing device must independently calculate amounts, fees, external addresses, and change based on verified UTXOs and its own key paths; displaying only “data from the coordinator” isn’t a validation.
7. Compatibility Practice
PSBT compatibility has four layers: container syntax, v0/v2 versions, supported script types, and application-specific extensions. The mere presence of PSBT import/export does not prove a wallet’s ability to sign Taproot, MuSig2, Silent Payments, or skip unknown fields without loss.
| Scenario | Minimum compatibility | Risk | Engineering measure |
|---|---|---|---|
| Cold wallet + desktop coordinator | BIP174 v0, SegWit UTXO, Base64 or file | Undisplayed commission/address, outdated firmware | Check the recipient’s device for the amount, fee-rate, change, and fingerprint; test on regtest/testnet. |
| 2-of-3 multisig | Unified script policy, derivation paths, partial signature merge | Key order confusion or incompatible witnessScript | Record the descriptor and check its fingerprint for all cosigners before creating addresses. |
| Taproot | BIP371 plus BIP340/341/342 for each signatory | Loss of control block/leaf data, lack of script path support | Perform separate tests of the key path and each crash leaf script. |
| MuSig2 | BIP373 and the agreed-upon BIP327 implementation | Nonce reuse, change of participant list, incomplete interactive session | Store session state atomically; destroy nonce after use; associate nonce with transaction and key list. |
| CoinJoin/PayJoin | Negotiated version, mutability flags, protocol rules | Adding unwanted inputs/outputs, deanonymization, changing fees | Check protocol invariants locally rather than treating the coordinator as a trusted party. |
A timeline compiled by Bitcoin Optech shows a gradual expansion of the ecosystem: initial support in Bitcoin Core arrived in 2018; in 2020, GUI streams were introduced, LND and C-Lightning developed PSBT for Lightning funding, Electrum replaced its partial format with PSBT, and JoinMarket added support. In 2021–2024, notable developments include Taproot fields, PSBTv2, watch-only support, BBQr QR encoding, descriptor tools, and MuSig2; in 2025–2026, testing of v2, Silent Payments, and improved signing device compatibility.
8. Verification algorithm
Below is a safe minimum for a signer. It doesn’t replace a full verification of Bitcoin Script and consensus, but it does include architectural checks that are crucial against PSBT substitution.
parse_strictly(psbt)
assert unique_keys_in_each_map(psbt)
assert supported_version(psbt.version)
for i, txin in enumerate(psbt.inputs):
prevout = verify_and_load_prevout(txin)
assert txin.txid_and_index_match(prevout)
assert scripts_commit_correctly(prevout, txin.redeem_script, txin.witness_script)
assert sighash_is_allowed(txin.sighash_type)
assert policy_matches_local_wallet(txin)
outputs = reconstruct_outputs(psbt)
fee = sum(input.value for input in psbt.inputs) - sum(output.value for output in outputs)
assert fee >= 0 and fee_rate_is_acceptable(fee)
show_external_outputs_and_fee_to_user(outputs, fee)
for mine in selected_local_keys:
sig = secure_sign(bound_sighash(psbt, mine))
psbt.add_partial_signature(mine.public_key, sig)
return psbt
An important property: “a partial signature is correct” is not the same as “the user has agreed to the payment intent.” The signature verifies the message; the purpose of the wallet interface and policy is to ensure that the message is constructed from clear and independently verified conditions.
9. Audit recommendations
- Reject duplicate keys, malformed CompactSize, invalid lengths, unknown versions, and conflicting fields when performing strict parsing.
- For legacy inputs, check the hash of the full non-witness UTXO transaction; for SegWit, check the amount and scriptPubKey of the witness UTXO, and if available, add the non-witness UTXO as an additional compatibility safeguard.
- Don’t remove unknown fields during round-trips; at the same time, block finalization if a critical extension or policy remains uninterpreted.
- Ensure that the PSBTs being merged describe the same underlying transaction/set of v2 invariants; do not silently select conflicting values.
- For Taproot and MuSig2, cover x-only keys, leaf hash, control block, key order, nonce state machine, and re-serialization with fuzzing tests.
- Store the derivation path and xpub as confidential metadata: they do not reveal the private key, but can deanonymize the wallet structure and address relationships.
- Use BIP174 test vectors, inter-wallet transfer unit tests, and end-to-end checks on regtest before updating firmware or protocol.
10. Final Provisions
PSBT is not a “pending transaction” format in the conventional sense, but a portable cryptographic protocol for coordination around an immutable, signable message. BIP174 defined its basic data map and role separation; BIP370 adapted it to interactive construction; BIP371 and BIP373 linked the container to Taproot and MuSig2; BIP375/BIP376 extend it to Silent Payments.
The key cryptanalytic conclusion is this: the security of PSBT is determined by more than just the inability to solve ECDLP. It requires correct implementation of signatures and nonces, hard-coding of UTXOs and scripts, fee/output verification on a trusted display, combining discipline, and testable interoperability. If these conditions are met, PSBT transforms disparate wallets, HSMs, and offline signers into a verifiable system for shared Bitcoin key management.
Sources
Bitcoin Optech Review: PSBT, BIP and Wallet Compatibility: https://treep.ru/bitcoin-optech-review-psbt-bip-and-wallet-compatibility/
- Bitcoin Optech. Partially signed bitcoin transactions : an overview of PSBT, BIP174/BIP370, and a historical timeline of integrations. https://bitcoinops.org/en/topics/psbt/
- Bitcoin Improvement Proposal 174. Partially Signed Bitcoin Transaction Format . Status: Final. https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
- Bitcoin Improvement Proposal 370. PSBT Version 2 . https://bitcoin.org/bip/370/
- Bitcoin Improvement Proposal 371. Taproot Fields for PSBT . https://bitcoin.org/bip/371/
- Bitcoin Improvement Proposal 373. MuSig2 PSBT Fields . https://bitcoin.org/bip/373/
- Bitcoin Improvement Proposal 375. Sending Silent Payments in PSBTs .
- Bitcoin Improvement Proposal 376. Spending Silent Payment outputs with PSBTs . https://bitcoin.org/bip/376/
- Bitcoin Improvement Proposals 340, 341, 342, 327; RFC 6979. Used for the Schnorr/Taproot/MuSig2 context and deterministic ECDSA nonce.
