mirror of
https://github.com/bitcoin/bips.git
synced 2026-05-11 16:51:51 +00:00
510 lines
20 KiB
Plaintext
510 lines
20 KiB
Plaintext
<pre>
|
|
BIP: 322
|
|
Layer: Applications
|
|
Title: Generic Signed Message Format
|
|
Authors: Karl-Johan Alm <karljohan-alm@garage.co.jp>
|
|
Deputies: guggero <gugger@gmail.com>
|
|
Status: Complete
|
|
Type: Specification
|
|
Assigned: 2018-09-10
|
|
License: CC0-1.0
|
|
Discussion: 2018-03-14: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-March/015818.html
|
|
2019-07-23: https://github.com/bitcoin/bitcoin/pull/16440
|
|
2022-01-13: https://github.com/bitcoin/bitcoin/pull/24058
|
|
2022-08-06: https://bitcointalk.org/index.php?topic=5408898.0
|
|
2024-05-04: https://groups.google.com/g/bitcoindev/c/RCi1Exs0ZvQ/m/vp6Xo36aBwAJ
|
|
2025-05-10: https://bitcoin.stackexchange.com/questions/126277/where-can-i-use-bip322-to-sign-a-message-to-verify-a-multisig-address
|
|
2026-04-20: https://groups.google.com/g/bitcoindev/c/qd6BNz9gxCk/m/k1fHq4RKAQAJ
|
|
Version: 1.0.0
|
|
</pre>
|
|
|
|
== Abstract ==
|
|
|
|
A standard for interoperable signed messages based on the Bitcoin Script format, either for proving
|
|
fund availability, or committing to a message as the intended recipient of funds sent to the invoice
|
|
address.
|
|
|
|
== Motivation ==
|
|
|
|
The current message signing standard only works for P2PKH (1...) invoice addresses. We propose to
|
|
extend and generalize the standard by using a Bitcoin Script based approach. This ensures that any
|
|
coins, no matter what script they are controlled by, can in-principle be signed for. For easy
|
|
interoperability with existing signing hardware, we also define a signature message format which
|
|
resembles a Bitcoin transaction (except that it contains an invalid input, so it cannot be spent on
|
|
any real network).
|
|
|
|
The Proof of Funds variant allows demonstrating control of a set of UTXOs.
|
|
The list of UTXOs may or may not be related to the address being signed with (the
|
|
<code>message_challenge</code>).
|
|
But in any case, the UTXO list does not aim to prove completeness (e.g. it does NOT mean:
|
|
"these are all UTXOs that exist for an address") nor that they are unspent (e.g. a
|
|
validator must consult the blockchain to verify that).
|
|
|
|
Additionally, the current message signature format uses ECDSA signatures which do not commit to the
|
|
public key, meaning that they do not actually prove knowledge of any secret keys. (Indeed, valid
|
|
signatures can be tweaked by 3rd parties to become valid signatures on certain related keys.)
|
|
|
|
Ultimately no message signing protocol can actually prove control of funds, both because a signature
|
|
is obsolete as soon as it is created, and because the possessor of a secret key may be willing to
|
|
sign messages on others' behalf even if it would not sign actual transactions. No message signing
|
|
protocol can fix these limitations.
|
|
|
|
Finally, this BIP only addresses the use case where a signer shows they will be able to control
|
|
funds sent to the invoice address. Proving that a signer sent a prior transaction is not possible
|
|
using this BIP.
|
|
|
|
== Terminology ==
|
|
|
|
In the context of this BIP, whenever the word "signature" or similar is used, it refers to the
|
|
output of the signing process described below and, depending on the script type of the
|
|
<code>message_challenge</code>, is either a full transaction input witness stack, a full
|
|
transaction, or a PSBT packet that can be validated against a Bitcoin Script Interpreter. Such a
|
|
"signature" may or may not contain an actual cryptographic (ECDSA or Schnorr) signature, depending
|
|
on what is required to satisfy the script corresponding to the <code>message_challenge</code>.
|
|
|
|
== Types of Signatures ==
|
|
|
|
This BIP specifies three formats for signing messages: ''legacy'', ''simple'' and ''full''.
|
|
Additionally, a variant of the ''full'' format can be used to demonstrate control over a set of
|
|
UTXOs.
|
|
|
|
{| class="wikitable"
|
|
|- style="font-weight:bold;"
|
|
!
|
|
! Compatible script types
|
|
! Signature prefix
|
|
! Signature format
|
|
|-
|
|
| Legacy
|
|
| <code>P2PKH</code>, <code>P2SH-P2WPKH</code><sup>1</sup>, <code>P2WPKH</code><sup>1</sup>
|
|
| n/a
|
|
| compact, public key recoverable ECDSA signature, base64-encoded
|
|
|-
|
|
| Simple
|
|
| <code>P2WPKH</code>, <code>P2WSH</code><sup>2</sup>, <code>P2TR</code><sup>2</sup> <br/>
|
|
| <code>smp</code>
|
|
| witness stack, consensus encoded and base64-encoded
|
|
|-
|
|
| Full
|
|
| <code>all</code>
|
|
| <code>ful</code>
|
|
| full <code>to_sign</code> transaction, consensus and base64-encoded
|
|
|-
|
|
| Full (Proof of Funds)
|
|
| <code>all</code>
|
|
| <code>pof</code>
|
|
| full finalized PSBT of the <code>to_sign</code> transaction, consensus and base64-encoded
|
|
|}
|
|
|
|
<sup>1</sup>: Possible on a technical level but should NOT be used anymore in the context of this
|
|
BIP.<br/>
|
|
<sup>2</sup>: Excluding time lock scripts.
|
|
|
|
Signers must prefix the signature with the variant that was used to create the signature.
|
|
To support backward compatibility with implementations of this BIP before it was finalized, a
|
|
verifier might assume the ''simple'' variant in the absence of a prefix.
|
|
|
|
=== Legacy ===
|
|
|
|
New proofs should use the new format for all invoice address formats, including P2PKH.
|
|
|
|
The legacy format MAY be used, but must be restricted to the legacy P2PKH invoice address format.
|
|
|
|
=== Simple ===
|
|
|
|
A ''simple'' signature consists of a witness stack, consensus encoded as a vector of vectors of
|
|
bytes, and base64-encoded, prefixed by the variant (<code>smp</code>). Validators should construct
|
|
<code>to_spend</code> and <code>to_sign</code> as defined below, with default values for all fields
|
|
except that
|
|
|
|
<ul>
|
|
<li>
|
|
<code>message_hash</code> is a BIP340-tagged hash of the message, as specified below
|
|
</li>
|
|
<li>
|
|
<code>message_challenge</code> in <code>to_spend</code> is set to the scriptPubKey being signed
|
|
with
|
|
</li>
|
|
<li>
|
|
<code>message_signature</code> in <code>to_sign</code> is set to the provided simple signature.
|
|
</li>
|
|
</ul>
|
|
|
|
and then proceed as they would for a full signature.
|
|
|
|
=== Full ===
|
|
|
|
Full signatures follow an analogous specification to the BIP-325 challenges and solutions used by
|
|
Signet.
|
|
|
|
Let there be two virtual transactions <code>to_spend</code> and <code>to_sign</code>.
|
|
|
|
The <code>to_spend</code> transaction is:
|
|
|
|
nVersion = 0
|
|
nLockTime = 0
|
|
vin[0].prevout.hash = 0000...000
|
|
vin[0].prevout.n = 0xFFFFFFFF
|
|
vin[0].nSequence = 0
|
|
vin[0].scriptSig = OP_0 PUSH32[ message_hash ]
|
|
vin[0].scriptWitness = []
|
|
vout[0].nValue = 0
|
|
vout[0].scriptPubKey = message_challenge
|
|
|
|
where <code>message_hash</code> is a BIP340-tagged hash of the message, i.e. sha256_tag(m), where
|
|
tag = <code>BIP0322-signed-message</code> and <code>m</code> is the message as is without length
|
|
prefix or null terminator, and <code>message_challenge</code> is the to be proven (public) key
|
|
script.
|
|
|
|
The <code>to_sign</code> transaction is:
|
|
|
|
nVersion = 0 or (FULL format only) as appropriate (e.g. 2, for time locks)
|
|
nLockTime = 0 or (FULL format only) as appropriate (for time locks)
|
|
vin[0].prevout.hash = to_spend.txid
|
|
vin[0].prevout.n = 0
|
|
vin[0].nSequence = 0 or (FULL format only) as appropriate (for time locks)
|
|
vin[0].scriptSig = [] or (FULL format only) as appropriate (for non segwit-native transactions)
|
|
vin[0].scriptWitness = message_signature
|
|
vout[0].nValue = 0
|
|
vout[0].scriptPubKey = OP_RETURN
|
|
|
|
A ''full'' signature consists of the variant-prefixed (<code>ful</code>) base64-encoding of the
|
|
<code>to_sign</code> transaction in standard network serialisation once it has been signed.
|
|
|
|
=== Full (Proof of Funds) ===
|
|
|
|
A signer may construct a proof of funds, demonstrating control of a set of UTXOs, by constructing a
|
|
full signature as above, with the following modifications.
|
|
|
|
<ul>
|
|
<li>
|
|
The <code>to_spend</code> transaction is represented as a finalized PSBT instead of a raw
|
|
transaction (see [[bip-0174.mediawiki#input-finalizer|BIP-0174]] for details on the finalization
|
|
process).
|
|
</li>
|
|
<li>
|
|
All outputs that the signer wishes to demonstrate control of are included as additional inputs of
|
|
<code>to_sign</code>, and their witness and scriptSig data should be set as though these outputs
|
|
were actually being spent.
|
|
</li>
|
|
<li>
|
|
The Non-Witness or Witness UTXO fields (as appropriate for the type) of each additional input must
|
|
be set to the corresponding UTXO.
|
|
</li>
|
|
<li>
|
|
As an optimization for large sets of Non-Witness UTXOs that spend outputs from the same
|
|
transaction, the Non-Witness UTXO field may be omitted for any input that spends an output from
|
|
the same transaction as an input earlier in the list.
|
|
</li>
|
|
</ul>
|
|
|
|
A ''full Proof of Funds'' signature consists of the variant-prefixed (<code>pof</code>)
|
|
base64-encoding of the finalized PSBT once it has been signed.
|
|
|
|
Unlike an ordinary signature, validators of a proof of funds need access to the current UTXO set, to
|
|
learn that the claimed inputs exist on the blockchain and remain unspent.
|
|
An offline validator therefore can only attest to the cryptographic validity of the additional
|
|
inputs' witness stack, but not its blockchain state.
|
|
An attested list of UTXOs can also never prove that there don't exist more UTXOs for a certain
|
|
address.
|
|
|
|
== Detailed Specification ==
|
|
|
|
For all signature types, except legacy, the <code>to_spend</code> and <code>to_sign</code>
|
|
transactions must be valid transactions which pass all consensus checks, except of course that the
|
|
output with prevout <code>000...000:FFFFFFFF</code> does not exist.
|
|
|
|
=== Verification ===
|
|
|
|
A validator is given as input an address ''A'' (which may be omitted in a proof-of-funds), signature
|
|
''s'' and message ''m'', and outputs one of three states
|
|
|
|
<ul>
|
|
<li>
|
|
''valid at time T and age S'' indicates that the signature has set timelocks but is otherwise
|
|
valid
|
|
</li>
|
|
<li>
|
|
''inconclusive'' means the validator was unable to check the scripts
|
|
</li>
|
|
<li>
|
|
''invalid'' means that some check failed
|
|
</li>
|
|
</ul>
|
|
|
|
==== Verification Process ====
|
|
|
|
Validation consists of the following steps:
|
|
|
|
# Basic validation
|
|
## Compute the transaction <code>to_spend</code> from ''m'' and ''A''
|
|
## Decode ''s'' as the transaction <code>to_sign</code>
|
|
## If ''s'' was a full transaction or PSBT, confirm all fields are set as specified above; in particular that
|
|
##* <code>to_sign</code> has at least one input and its first input spends the output of </code>to_spend</code>
|
|
##* <code>to_sign</code> with more than one input has an appropriate Witness UTXO or Non-Witness UTXO for each input
|
|
##** If (based on the input type) a Non-Witness UTXO is required but not provided, check if the first input with the same transaction ID has a Non-Witness UTXO set and use that; fail validation if no such Non-Witness UTXO can be found
|
|
##* <code>to_sign</code> has exactly one output, as specified above
|
|
## Confirm that the two transactions together satisfy all consensus rules, except for <code>to_spend</code>'s missing input, and except that ''nSequence'' of <code>to_sign</code>'s first input and ''nLockTime'' of <code>to_sign</code> are not checked.
|
|
# (Optional) If the validator does not have a full script interpreter, it should check that it understands all scripts being satisfied. If not, it should stop here and output ''inconclusive''.
|
|
# Check the '''required rules''':
|
|
## All signatures must use the SIGHASH_ALL flag.
|
|
## The use of <code>CODESEPARATOR</code> or <code>FindAndDelete</code> is forbidden.
|
|
## <code>LOW_S</code>, <code>STRICTENC</code> and <code>NULLFAIL</code>: valid ECDSA signatures must be strictly DER-encoded and have a low-S value; invalid ECDSA signature must be the empty push
|
|
## <code>MINIMALDATA</code>: all pushes must be minimally encoded
|
|
## <code>CLEANSTACK</code>: require that only a single stack element remains after evaluation
|
|
## <code>MINIMALIF</code>: the argument of <code>IF</code>/<code>NOTIF</code> must be exactly 0x01 or empty push
|
|
## If any of the above steps failed, the validator should stop and output the ''invalid'' state.
|
|
# Check the '''upgradeable rules'''
|
|
## The version of <code>to_sign</code> must be 0 or 2.
|
|
## The use of NOPs reserved for upgrades is forbidden.
|
|
## The use of Segwit versions greater than 1 are forbidden.
|
|
## If any of the above steps failed, the validator should stop and output the ''inconclusive'' state.
|
|
# Let ''T'' by the nLockTime of <code>to_sign</code> and ''S'' be the nSequence of the first input of <code>to_sign</code>. Output the state ''valid at time T and age S''.
|
|
|
|
=== Signing ===
|
|
|
|
Signers who control an address ''A'' who wish to sign a message ''m'' act as follows:
|
|
|
|
<ol>
|
|
<li>
|
|
They construct <code>to_spend</code> and <code>to_sign</code> as specified above, using the
|
|
scriptPubKey of ''A'' for <code>message_challenge</code> and tagged hash of ''m'' as
|
|
<code>message_hash</code>.
|
|
</li>
|
|
<li>
|
|
Optionally, they may set nVersion/nLockTime of <code>to_sign</code> or nSequence of its first
|
|
input.
|
|
</li>
|
|
<li>
|
|
Optionally, they may add any additional inputs to <code>to_sign</code> that they wish to prove
|
|
control of.
|
|
</li>
|
|
<li>
|
|
They satisfy <code>to_sign</code> as they would any other transaction.
|
|
</li>
|
|
</ol>
|
|
|
|
They then encode their signature, choosing either ''simple'', ''full'' or ''full-pof'' as follows:
|
|
|
|
<ul>
|
|
<li>
|
|
If they added no inputs to <code>to_sign</code>, left nVersion, nSequence and nLockTime at 0, and
|
|
''A'' is a "native" Segwit address (P2WPKH, P2WSH, P2TR), then they may base64-encode
|
|
<code>message_signature</code> with <code>smp</code> as prefix.
|
|
</li>
|
|
<li>
|
|
If they added no inputs to <code>to_sign</code>, they may base64-encode <code>to_sign</code> with
|
|
<code>ful</code> as prefix.
|
|
</li>
|
|
<li>
|
|
Otherwise, they must base64-encode the finalized PSBT of <code>to_sign</code> with
|
|
<code>pof</code> as prefix.
|
|
</li>
|
|
</ul>
|
|
|
|
=== PSBT-based signing ===
|
|
|
|
A valid witness stack for a multisig address must be constructed by coordinating different signers
|
|
to produce a partial signature each.
|
|
The coordination procedure is not specified by this BIP, but due to the use of PSBTs it should
|
|
closely resemble the coordination of signing a multisig transaction for publishing to the network.
|
|
|
|
The main difference is a new global PSBT field and the way a signer presents the transaction signing
|
|
request to the user. The new global type is defined as follows:
|
|
|
|
{| class="wikitable"
|
|
! Name
|
|
! <tt><keytype></tt>
|
|
! <tt><keydata></tt>
|
|
! <tt><keydata></tt> Description
|
|
! <tt><valuedata></tt>
|
|
! <tt><valuedata></tt> Description
|
|
! Versions Requiring Inclusion
|
|
! Versions Requiring Exclusion
|
|
! Versions Allowing Inclusion
|
|
|-
|
|
| Generic Signed Message
|
|
| <tt>PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE = 0x09</tt>
|
|
| None
|
|
| No key data
|
|
| <tt><bytes message></tt>
|
|
| The UTF-8 encoded message to be signed.
|
|
|
|
|
|
|
|
| 0, 2
|
|
|}
|
|
|
|
=== PSBT creator ===
|
|
|
|
The '''transaction creator''' of a BIP-0322 PSBT must follow these steps:
|
|
|
|
<ol>
|
|
<li>
|
|
They construct <code>to_spend</code> and <code>to_sign</code> as specified above, using the
|
|
scriptPubKey of ''A'' for <code>message_challenge</code> and tagged hash of ''m'' as
|
|
<code>message_hash</code>.
|
|
</li>
|
|
<li>
|
|
Optionally, they may set nVersion/nLockTime of <code>to_sign</code> or nSequence of its first
|
|
input.
|
|
</li>
|
|
<li>
|
|
Optionally, they may add any additional inputs to <code>to_sign</code> that they wish to prove
|
|
control of.
|
|
</li>
|
|
<li>
|
|
They set the appropriate <code>witness_utxo</code> and <code>non_witness_utxo</code> fields of the
|
|
first input, using the <code>to_spend</code> transaction as a <code>non_witness_utxo</code> or
|
|
the first output of the <code>to_spend</code> transaction as <code>witness_utxo</code>.
|
|
</li>
|
|
<li>
|
|
They set the appropriate <code>witness_utxo</code> and <code>non_witness_utxo</code> fields of
|
|
each additional input.
|
|
</li>
|
|
<li>
|
|
They set the appropriate PSBT input and global fields as required by the signers(s) to produce a
|
|
partial signature.
|
|
</li>
|
|
<li>
|
|
They set the <code>PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE</code> field, using the full UTF-8 encoded
|
|
message as the <code>valuedata</code>.
|
|
<ol>
|
|
<li>
|
|
There is no specified maximum length of an input's <code>valuedata</code> or a PSBT as a whole in
|
|
[[bip-0174.mediawiki|BIP-0174]], but different signers might impose safety limits. It is
|
|
recommended to use a maximum length of a few kilobytes to maximize compatibility. Very large
|
|
messages should be committed to by hash instead.
|
|
</li>
|
|
</ol>
|
|
</li>
|
|
</ol>
|
|
|
|
=== PSBT signer ===
|
|
|
|
A '''transaction signer''' of a BIP-0322 PSBT must follow these steps:
|
|
|
|
<ol>
|
|
<li>
|
|
They decode the base64-encoded PSBT as specified in [[bip-0174.mediawiki|BIP-0174]].
|
|
</li>
|
|
<li>
|
|
If they detect the following properties (all must be true, otherwise this is NOT a BIP-0322 PSBT
|
|
and they should treat it as an ordinary PSBT):
|
|
<ol>
|
|
<li>
|
|
The PSBT has the <code>PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE</code> field set. Extract and use as
|
|
<code>message</code> in the next steps.
|
|
</li>
|
|
<li>
|
|
The first PSBT input has either a <code>witness_utxo</code> or a <code>non_witness_utxo</code>
|
|
field set and the <code>scriptPubKey</code> can be extracted, then use as
|
|
<code>message_challenge</code> in the next steps.
|
|
</li>
|
|
<li>
|
|
The first PSBT input has <code>prevout.n = 0</code>.
|
|
</li>
|
|
<li>
|
|
The first PSBT input has <code>prevout.hash = to_spend.txid</code> where
|
|
<code>to_spend.txid</code> is constructed using the rules described above using the
|
|
<code>message</code> and <code>message_challenge</code> from the previous steps.
|
|
</li>
|
|
<li>
|
|
The PSBT's unsigned transaction has a single output with a value of <code>0</code> and the
|
|
<code>scriptPubKey</code> set to <code>OP_RETURN</code> (<code>0x6a</code>).
|
|
</li>
|
|
</ol>
|
|
</li>
|
|
<li>
|
|
If all of the above steps are true, the signer must inform the user about the message they are
|
|
signing and the address they are signing for.
|
|
<ol>
|
|
<li>
|
|
Even though the message being signed is a transaction, the user interaction (e.g. the steps and
|
|
messages shown on a hardware signing device's screen) should resemble the steps to sign a legacy
|
|
message, not the steps for signing a transaction.
|
|
</li>
|
|
<li>
|
|
Example: Instead of showing "spending 0 satoshi from address <challenge_address>" the
|
|
device should show "signing message <message> for address <challenge_address>".
|
|
</li>
|
|
</ol>
|
|
</li>
|
|
<li>
|
|
Upon user approval, the signer adds a partial signature for each input it is capable of signing.
|
|
</li>
|
|
</ol>
|
|
|
|
=== PSBT finalizer ===
|
|
|
|
A '''transaction finalizer''' of a BIP-0322 PSBT must follow these steps:
|
|
|
|
<ol>
|
|
<li>
|
|
They decode the base64-encoded PSBT as specified in [[bip-0174.mediawiki|BIP-0174]].
|
|
</li>
|
|
<li>
|
|
They finalize the PSBT as specified in [[bip-0174.mediawiki#input-finalizer|BIP-0174]].
|
|
</li>
|
|
<li>
|
|
They then encode the signature following the same steps as described in
|
|
[[bip-0322.mediawiki#signing|Signing]] above.
|
|
</li>
|
|
</ol>
|
|
|
|
== Compatibility ==
|
|
|
|
This specification is backwards compatible with the legacy signmessage/verifymessage specification
|
|
through the special case as described above.
|
|
To support backward compatibility with implementations of this BIP before it was finalized, a
|
|
verifier might assume the ''simple' variant in the absence of a prefix.
|
|
|
|
== Reference implementation ==
|
|
|
|
<ul>
|
|
<li>
|
|
Bitcoin Core pull request (basic support) at: https://github.com/bitcoin/bitcoin/pull/24058
|
|
</li>
|
|
<li>
|
|
btcd pull request (complete support, source of test vectors) at:
|
|
https://github.com/btcsuite/btcd/pull/2521
|
|
</li>
|
|
</ul>
|
|
|
|
== Acknowledgements ==
|
|
|
|
Thanks to David Harding, Jim Posen, Kalle Rosenbaum, Pieter Wuille, Andrew Poelstra, Luke Dashjr,
|
|
and many others for their feedback on the specification.
|
|
|
|
== References ==
|
|
|
|
<ol>
|
|
<li>
|
|
Original mailing list thread:
|
|
https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-March/015818.html
|
|
</li>
|
|
</ol>
|
|
|
|
== Changelog ==
|
|
|
|
* '''1.0.0''' (2026-04-15):
|
|
** Mark Complete
|
|
** Breaking change: Add human-readable prefix to encoded signature
|
|
** Breaking change: format of "Proof of Funds" signatures to be base64-encoded finalized PSBT
|
|
** Add new PSBT input field for PSBT-based signing
|
|
* '''0.0.1''' (2018-09-10):
|
|
** Proposed as draft
|
|
|
|
== Copyright ==
|
|
|
|
This document is licensed under the Creative Commons CC0 1.0 Universal license.
|
|
|
|
== Test vectors ==
|
|
|
|
Basic test vectors for message hashing, transaction hashes and "simple" variant test cases can be
|
|
found in [[bip-0322/basic-test-vectors.json|<code>basic-test-vectors.json</code>]].
|
|
|
|
Generated test vectors for more "simple" and "full" variant test cases can be found in
|
|
[[bip-0322/generated-test-vectors.json|<code>generated-test-vectors.json</code>]].
|
|
|
|
They were generated using [https://github.com/btcsuite/btcd/pull/2521 this code].
|