Learning Bitcoin Script/Miniscript and where to apply in a transaction
Partially Signed Bitcoin Transactions (PSBTs) are a standardized way of representing a Bitcoin transaction and its signatures, allowing different parties to collaborate in creating a transaction without sharing private keys. PSBTs are often used in multi-signature setups or with hardware wallets.
In this article we’ll discover more about how Bitcoin Script can be created with miniscript, where the hex of that script is placed in a transaction (psbt) and how it is reversed back to Bitcoin script for evaluation. If it evaluates to true, the spending condition is true, and funds can be spent. Also, check out Minsc
Both the locking script placed on an UTXO and the unlocking script are written in this scripting language. When a transaction is validated, the unlocking script in each input is executed alongside the corresponding locking script to see if it satisfies the spending condition.
Mastering Bitcoin 2nd Edition
For more on transactions check out “Mastering Bitcoin”
Transaction Serialization –inputs
Transaction serialization—outputs
You can also study Bitcoin free with the Saylor Academy
Encoding Bitcoin script in the PSBT inputs field
If you have a Bitcoin script that you want to include in a PSBT, you typically encode it within an input
field of the PSBT. PSBTs have multiple fields for each input and output, and you would place your script in the appropriate input field.
Here’s a simplified example of how you might structure a PSBT:
{
"psbt": "base64-encoded-partially-signed-transaction",
"inputs": [
{
"non_witness_utxo": "base64-encoded-previous-transaction",
"witness_utxo": {
"amount": value_in_satoshis,
"scriptPubKey": "hex-encoded-output-script"
},
"partial_sigs": {
"public_key_1": "signature_1",
"public_key_2": "signature_2"
},
"redeem_script": "hex-encoded-redeem-script",
"witness_script": "hex-encoded-witness-script"
},
// More input fields...
],
"outputs": [
{
"redeem_script": "hex-encoded-redeem-script",
"witness_script": "hex-encoded-witness-script",
"scriptPubKey": "hex-encoded-output-script",
"partial_sigs": {
"public_key_1": "signature_1",
"public_key_2": "signature_2"
}
},
// More output fields...
]
}
In this structure:
redeem_script
: This is where your Bitcoin script would typically go for a P2SH (Pay-to-Script-Hash) input. If your script is a simple P2PKH (Pay-to-Public-Key-Hash), it might be in thescriptPubKey
field directly.witness_script
: This is for the witness script, which is needed for certain script types like P2WSH (Pay-to-Witness-Script-Hash).scriptPubKey
: This is the locking script of the output.
In a PSBT, the redeem script for a multisig input is typically included in the redeem_script
field within the corresponding input. Here’s an example:
In this example, the multisig redeem script is placed in the redeem_script
field of the input. This is because for a multisig output, the redeem script is necessary to spend funds from that output. The partial_sigs
field contains the partial signatures corresponding to the public keys involved in the multisig setup.
Multisig
Ensure that the scriptPubKey
and witness_script
fields are correctly set based on the type of multisig script you’re using. If it’s a P2WSH (Pay-to-Witness-Script-Hash) multisig, the witness_script
field will be populated, and if it’s a P2SH multisig, the scriptPubKey
field will have the corresponding script.
If you have a simple 2-of-2 multisig script where <K>
represents a public key and <A>
represents another public key, the corresponding redeem script might look something like this:
OP_2 <K> <A> OP_2 OP_CHECKMULTISIG
This script specifies that at least 2 out of the 2 provided public keys must produce valid signatures to spend the funds. The OP_CHECKMULTISIG
opcode verifies the multiple signatures.
If you want to hex encode this script, you would convert the script into its hexadecimal representation. Assuming <K>
and <A>
are 33-byte compressed public keys, the hex-encoded script would look like this:
5221<K>21<A>52ae
Here:
52
is the opcode forOP_2
.21
is the length of the following data (33 bytes for a compressed public key).<K>
is the hex representation of the first public key.21
is the length of the following data (33 bytes for a compressed public key).<A>
is the hex representation of the second public key.52
is the opcode forOP_2
.ae
is the opcode forOP_CHECKMULTISIG
.
Make sure to replace <K>
and <A>
with the actual hex representations of your public keys. This is a basic example, and the exact structure may vary based on your specific needs and the tools or libraries you are using.
Here is an example with dummy data of a 2-of-2 multisig transaction
{
"psbt": "cHNidP8BAFICAAAAAQAAAAqUA...base64-encoded-partially-signed-transaction...AgAAAAAB",
"inputs": [
{
"non_witness_utxo": "0100000001...base64-encoded-previous-transaction...ffffffff",
"witness_utxo": {
"amount": 100000000,
"scriptPubKey": "a9140123456789abcdef0123456789abcdef0123456787"
},
"partial_sigs": {
"02374afd77a7fb123456789abcdef0123456789abcdef0123456789abcdef01": "30440220123456789abcdef0123456789abcdef0123456789abcdef0123456789012345678902204d123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01"
},
"redeem_script": "522103123456789abcdef0123456789abcdef0123456789210223456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0152ae",
"witness_script": "",
"hd_keypaths": {
"02374afd77a7fb123456789abcdef0123456789abcdef0123456789abcdef01": "m/0/0",
"03456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123": "m/0/1"
}
}
],
"outputs": [
{
"redeem_script": "",
"witness_script": "",
"scriptPubKey": "a91456789abcdef0123456789abcdef0123456789abcdef87",
"partial_sigs": {
"02374afd77a7fb123456789abcdef0123456789abcdef0123456789abcdef01": "304502210123456789abcdef0123456789abcdef0123456789abcdef0123456789012345678902202c123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01"
}
}
]
}
Convert the ‘redeem script’ hex code back to Bitcoin script
Let’s break down the redeem script and convert it back into the corresponding Bitcoin script:
522103123456789abcdef0123456789abcdef0123456789210223456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0152ae
Breaking it down:
52
:OP_2
– This opcode pushes the number 2 onto the stack.21
: 33-byte data follows.03123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01
: This is the hex representation of the first public key.21
: 33-byte data follows.0223456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01
: This is the hex representation of the second public key.52
:OP_2
– This opcode pushes the number 2 onto the stack.ae
:OP_CHECKMULTISIG
– This opcode checks the signatures for the multisig script.
So, when converted to a Bitcoin script, this redeem script represents a 2-of-2 multisig setup where two public keys (03123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01
and 0223456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01
) must produce valid signatures to spend the funds.
In simple terms, this script says that to spend the funds locked by this script, you need signatures from both public keys. It’s a basic form of a multisignature (multisig) script.
Put simply, scripts,however complex, just need to evaluate to TRUE
Miniscript allows a more human readable version on the Bitcoin script. Miniscript compiles to the same hex.
Links :
https://bitcoin.sipa.be/miniscript/
https://en.bitcoin.it/wiki/Script
https://github.com/bitcoin-core/btcdeb