|
| 1 | +# Copyright (C) 2025 The python-bitcoin-utils developers |
| 2 | +# |
| 3 | +# This file is part of python-bitcoin-utils |
| 4 | +# |
| 5 | +# It is subject to the license terms in the LICENSE file found in the top-level |
| 6 | +# directory of this distribution. |
| 7 | +# |
| 8 | +# No part of python-bitcoin-utils, including this file, may be copied, |
| 9 | +# modified, propagated, or distributed except according to the terms contained |
| 10 | +# in the LICENSE file. |
| 11 | + |
| 12 | +""" |
| 13 | +Sign a specific input of a PSBT (Partially Signed Bitcoin Transaction) using a WIF private key. |
| 14 | +
|
| 15 | +This script allows targeted signing of one input in a PSBT, which is useful for multisig setups, |
| 16 | +hardware wallet integrations, or step-by-step signing processes. |
| 17 | +
|
| 18 | +Features: |
| 19 | +- Loads a PSBT from a base64-encoded string |
| 20 | +- Signs a specified input using a provided WIF-formatted private key |
| 21 | +- Supports multiple script types: P2PKH, P2SH, P2WPKH, P2WSH, P2TR |
| 22 | +- Allows optional SIGHASH type customization (default: SIGHASH_ALL) |
| 23 | +
|
| 24 | +Usage: |
| 25 | + python sign_psbt.py <psbt_base64> <private_key_wif> <input_index> [sighash_type] |
| 26 | +
|
| 27 | +Arguments: |
| 28 | + psbt_base64 The PSBT in base64 encoding |
| 29 | + private_key_wif The private key in Wallet Import Format (WIF) |
| 30 | + input_index Index of the input to sign (0-based) |
| 31 | + sighash_type (Optional) Bitcoin SIGHASH flag (e.g., SIGHASH_ALL, SIGHASH_SINGLE) |
| 32 | +
|
| 33 | +Returns: |
| 34 | + Updated PSBT with the input partially signed and printed as base64 |
| 35 | +""" |
| 36 | + |
| 37 | + |
| 38 | +import sys |
| 39 | +from bitcoinutils.setup import setup |
| 40 | +from bitcoinutils.keys import PrivateKey |
| 41 | +from bitcoinutils.psbt import PSBT |
| 42 | +from bitcoinutils.constants import SIGHASH_ALL |
| 43 | + |
| 44 | + |
| 45 | +def main(): |
| 46 | + """Main function for signing PSBT example.""" |
| 47 | + # Always call setup() first |
| 48 | + setup('testnet') |
| 49 | + |
| 50 | + # Parse command line arguments |
| 51 | + if len(sys.argv) < 4: |
| 52 | + print("Usage: python sign_psbt.py <psbt_base64> <private_key_wif> <input_index> [sighash_type]") |
| 53 | + print("\nExample:") |
| 54 | + print("python sign_psbt.py <psbt> cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo 0") |
| 55 | + sys.exit(1) |
| 56 | + |
| 57 | + psbt_base64 = sys.argv[1] |
| 58 | + private_key_wif = sys.argv[2] |
| 59 | + input_index = int(sys.argv[3]) |
| 60 | + sighash_type = int(sys.argv[4]) if len(sys.argv) > 4 else SIGHASH_ALL |
| 61 | + |
| 62 | + try: |
| 63 | + # Load PSBT from base64 |
| 64 | + psbt = PSBT.from_base64(psbt_base64) |
| 65 | + |
| 66 | + # Load private key |
| 67 | + private_key = PrivateKey.from_wif(private_key_wif) |
| 68 | + |
| 69 | + # Sign the specified input |
| 70 | + success = psbt.sign_input(input_index, private_key, sighash_type) |
| 71 | + |
| 72 | + if success: |
| 73 | + # Output the updated PSBT |
| 74 | + print(psbt.to_base64()) |
| 75 | + else: |
| 76 | + print("Failed to sign input", file=sys.stderr) |
| 77 | + sys.exit(1) |
| 78 | + |
| 79 | + except Exception as e: |
| 80 | + print(f"Error: {str(e)}", file=sys.stderr) |
| 81 | + sys.exit(1) |
| 82 | + |
| 83 | + |
| 84 | +if __name__ == "__main__": |
| 85 | + main() |
0 commit comments