{"id":19125844,"url":"https://github.com/stepansnigirev/psbt_flow","last_synced_at":"2026-03-19T08:13:15.818Z","repository":{"id":94053660,"uuid":"478052261","full_name":"stepansnigirev/psbt_flow","owner":"stepansnigirev","description":"PSBT signing by example","archived":false,"fork":false,"pushed_at":"2022-04-13T14:30:40.000Z","size":27,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-22T14:49:47.029Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stepansnigirev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-05T09:09:00.000Z","updated_at":"2022-04-23T03:22:48.000Z","dependencies_parsed_at":"2023-03-12T13:15:33.407Z","dependency_job_id":null,"html_url":"https://github.com/stepansnigirev/psbt_flow","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stepansnigirev/psbt_flow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stepansnigirev%2Fpsbt_flow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stepansnigirev%2Fpsbt_flow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stepansnigirev%2Fpsbt_flow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stepansnigirev%2Fpsbt_flow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stepansnigirev","download_url":"https://codeload.github.com/stepansnigirev/psbt_flow/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stepansnigirev%2Fpsbt_flow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29903617,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T14:46:13.553Z","status":"ssl_error","status_checked_at":"2026-02-27T14:46:10.522Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T05:36:47.604Z","updated_at":"2026-02-27T16:03:36.236Z","avatar_url":"https://github.com/stepansnigirev.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# psbt_flow\n\nPSBT signing by example\n\n# Wallet keys\n\n## Recovery phrase ([BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)):\n\nConverted from raw 128-bit entropy (all zeroes in this case) by appending a hash-based checksum - take first 4 bits of sha256(entropy), split resulting 132 bits to 11-bit chunks and convert each chunk to a word from the 2048-word dictionary:\n\n```\nabandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about\n```\n\n## [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) seed (with empty BIP39 password):\n\nDerived by applying pbkdf2-hmac-sha512 to the mnemonic with `\"mnemonic\"+password` as a salt using 2048 iterations:\n\n```\n5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4\n```\n\n## Root BIP32 key:\n\nOutput of the `hmac-sha512(\"Bitcoin seed\", seed)` is splitted in two parts, first part is a root private key, second part is the chain code.\n\n```\nMainnet: xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu\nTestnet: tprv8ZgxMBicQKsPe5YMU9gHen4Ez3ApihUfykaqUorj9t6FDqy3nP6eoXiAo2ssvpAjoLroQxHqr3R5nE3a5dU3DHTjTgJDd7zrbniJr6nrCzd\n```\n\n## Master fingerprint of the root key, used to detect pubkeys in PSBT that are derived from this root:\n\nFingerprint is calculated from the root key by applying `hash160() = ripemd160(sha256())` to the sec-serialized public key of the root key. Sec-serialized public key has a length of 33 bytes (compressed representation).\n\n```\nFingerprint: 73c5da0a\n```\n\n## BIP-32 derivation\n\nDeriving `m/49'/1'/0'/1/0` key from root key above ([specs](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Private_parent_key_rarr_private_child_key)):\n\n```\nroot = xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu\ndecoding it:\nchain code: 7923408dadd3c7b56eed15567707ae5e5dca089de972e07f3b860450e2a3b70e\nsecret: 1837c1be8e2995ec11cda2b066151be2cfb48adf9e47b151d46adab3a21cdf67\n\nChild with index 49' (hardened):\nindex = 0x80000000 + 49 = 80000031 in big endian\n\nFor hardened derivation we use private key in the hash:\n\nchild_tweak, child_chain_code = hmac-sha512(chain_code, \u003c00\u003e\u003cpriv_key\u003e\u003cindex\u003e)\nhmac-sha512(7923408dadd3c7b56eed15567707ae5e5dca089de972e07f3b860450e2a3b70e, 001837c1be8e2995ec11cda2b066151be2cfb48adf9e47b151d46adab3a21cdf6780000031)\nresult:\n6a3ececfca6e6b1eabd5167925467858ae4451894a83fddc88aa966a438ce413fe82159c44da72e34203f1215d494638d17a1ee587db3d11651654ac4e2b1ff3\nchild chain_code: fe82159c44da72e34203f1215d494638d17a1ee587db3d11651654ac4e2b1ff3\nprivate key tweak: 6a3ececfca6e6b1eabd5167925467858ae4451894a83fddc88aa966a438ce413\nchild private key = parent private key + tweak = 8276908e5898010abda2b9298b5b943b7df8dc68e8cbaf2e5d15711de5a9c37a\n\nNext step - index 1' (80000001 in big endian)\nchain code: 3b0af4d37b373d810fcf34cdf2e87cf68df5022812768d7d28d4451dc30e8951\nprivate key: 7eae2f0d227922ea9e95d7577a2d31a25b22a43be6856749db6eb5e220dabeea\n\nNext - index 0' (80000000 in big endian):\nchain code: 29493969d5af07bdca312802a84f43f87f2522ee84d4f880947d10849675bd3d\nsecret: 25411fe7b0d083e9265a2d0f29ce7b10eb9c5570306144c77f0f4dfe9238747e\n\nNext - index 1 (00000001 in big endian), it's not hardened so we use public key in hmac:\nchild_tweak, child_chain_code = hmac-sha512(chain_code, \u003cpublic_key\u003e\u003cindex\u003e)\nhmac-sha512(29493969d5af07bdca312802a84f43f87f2522ee84d4f880947d10849675bd3d, 0262c1521f5fd87bbb4055f9f6e866d3eaebd179d5bfb9adac3aec682f12948a6700000001)\nresult:\n5f51bb0ce3f1ae23ebec65614a3308f3bb0eeead9d5af6dc4e400759673dac2591fab97e3048e663e757405b7b37e476ccb7aa765a0d1ce90908c4fc325c01c8\nchild chain_code: 91fab97e3048e663e757405b7b37e476ccb7aa765a0d1ce90908c4fc325c01c8\nprivate key tweak: 5f51bb0ce3f1ae23ebec65614a3308f3bb0eeead9d5af6dc4e400759673dac25\nchild private key = parent private key + tweak = 8492daf494c2320d1246927074018404a6ab441dcdbc3ba3cd4f5557f97620a3\n\nNext - index 0 (00000000 in be), not hardened:\nchain code: 6016fd78e15211b3260f67911dbe28f59889e471b6f05547ef39f3f98ba85825\nprivate key: f0f6c08500d34c351d14434589913c50e56e03c41e399488db476114c487053f\n```\n\n# Example PSBT\n\nAssuming here a Bitcoin wallet that uses a single-key policy with the root key from above, using wrapped-segwit addresses and derivation path for regtest `m/49'/1'/0'/{0,1}/*`. This derivation path standard is defined in [BIP-49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki). For different address types it is recommended to use [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) for legacy addresses, [BIP-49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki) for wrapped segwit, [BIP-84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki) for native segwit.\n\n## Base64-encoded PSBT:\n\nThis PSBT is spending two inputs - from receiving addresses with indexes 0 and 1 of the wallet, and has two outputs - output 0 goes back to change address #0 and output 1 goes to external address `bcrt1qydtsw90p4smqkztaxfup6t2hr7w9mzs8mt68ccnurc00kfxtttqqxlges6`, the fee is 266 bytes:\n\n```\ncHNidP8BAKcCAAAAAhy21k6/lcoj6dYme5JdvRjDk19pGoZ/O4OquPjXRdhcAQAAAAD9////6g2Nk+ObJ+nH+3bdvBIqsgkmMNdFiTPTXyltvwra8McAAAAAAP3///8C9gc9AAAAAAAXqRQlHdEUV6JZw7pH5cyjcX/kIU4CmIfA2KcAAAAAACIAICNXBxXhrDYLCX0yeB0tVx+cXYoH2vR8YnweHvsky1rA2QAAAAABAHICAAAAAdqaS4Kq2IAX8kqlREL9tohEwkNBzSF64RpIIxL0YlOjAQAAAAD+////Alji3iIBAAAAFgAUQ5WpqejZobzUS49CW0p3nPMkV3OAlpgAAAAAABepFDNsqhPgi5YICjK12BjVm0qzs2dChwAAAAABASCAlpgAAAAAABepFDNsqhPgi5YICjK12BjVm0qzs2dChwEEFgAUOJcfc5MPbBQdl3rE/UpyfIVJNbMiBgOhr4BKwQiopReCGYwtA0sov5DIgD9aU/didvpppOrnfxhzxdoKMQAAgAEAAIAAAACAAAAAAAAAAAAAAQByAgAAAAHw8+Znx3tHgVAG2s23K+8Hvb6aNvocYolsRpzzJMC4/gEAAAAA/v///wJAS0wAAAAAABepFIHXS804DAX3kdH0yBg3Vl3smyNKh5nEwyMBAAAAFgAUOaRgB4EiNS4w6LlSDhbdYD85OVEAAAAAAQEgQEtMAAAAAAAXqRSB10vNOAwF95HR9MgYN1Zd7JsjSocBBBYAFL18ec12pUkfARFbgTcs3JsFztsAIgYDsi01fWSqDBDK/82usi/KKCsx8BHIwsjG1eVqZ21SyAMYc8XaCjEAAIABAACAAAAAgAAAAAABAAAAAAEAFgAUcL6x4EpQCUDp86uqZuGkmsVbjzUiAgKi/ImWxSYiSLXa78Wk0M3NAMEwR9DLEwKBNupjDYdahxhzxdoKMQAAgAEAAIAAAACAAQAAAAAAAAAAAA==\n```\n\n## Hex-encoded PSBT:\n\n```\n70736274ff0100a702000000021cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c0100000000fdffffffea0d8d93e39b27e9c7fb76ddbc122ab2092630d7458933d35f296dbf0adaf0c70000000000fdffffff02f6073d000000000017a914251dd11457a259c3ba47e5cca3717fe4214e029887c0d8a7000000000022002023570715e1ac360b097d32781d2d571f9c5d8a07daf47c627c1e1efb24cb5ac0d9000000000100720200000001da9a4b82aad88017f24aa54442fdb68844c24341cd217ae11a482312f46253a30100000000feffffff0258e2de22010000001600144395a9a9e8d9a1bcd44b8f425b4a779cf3245773809698000000000017a914336caa13e08b96080a32b5d818d59b4ab3b367428700000000010120809698000000000017a914336caa13e08b96080a32b5d818d59b4ab3b3674287010416001438971f73930f6c141d977ac4fd4a727c854935b3220603a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f1873c5da0a3100008001000080000000800000000000000000000100720200000001f0f3e667c77b47815006dacdb72bef07bdbe9a36fa1c62896c469cf324c0b8fe0100000000feffffff02404b4c000000000017a91481d74bcd380c05f791d1f4c81837565dec9b234a8799c4c3230100000016001439a460078122352e30e8b9520e16dd603f39395100000000010120404b4c000000000017a91481d74bcd380c05f791d1f4c81837565dec9b234a870104160014bd7c79cd76a5491f01115b81372cdc9b05cedb00220603b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c8031873c5da0a310000800100008000000080000000000100000000010016001470beb1e04a500940e9f3abaa66e1a49ac55b8f35220202a2fc8996c5262248b5daefc5a4d0cdcd00c13047d0cb13028136ea630d875a871873c5da0a31000080010000800000008001000000000000000000\n```\n\n## PSBT splitted to fields:\n\nPSBT has three scopes - global, per-input and per-output, and contains all metadata needed for the hardware wallet to verify and sign transaction. Global scope contains a raw unsigned bitcoin transaction, per-input and per-output scopes contain extra data like bip32 derivation paths, witness scripts and other stuff. Per input scopes also contain information about utxos it is spending (amount and scriptpubkey).\n\n```\n# PSBT magic b\"psbt\\xff\"\n70736274ff\n===== GLOBAL SCOPE =======\n# key 00, global transaction - unsigned raw bitcoin transaction\n01 00\n# transaction itself\na7 - length of the transaction field\n  02000000 - version, little-endian (version = 2)\n  ---- inputs -----\n  02 - number of inputs\n  ---- input 0 ----\n  1cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c - previous tx hash (reversed txid of the transaction we are spending)\n  01000000 - prev vout, little-endian (vout = 1)\n  00 - scriptsig, empty because transaction is unsigned\n  fdffffff - sequence number, little endian\n  ---- input 1 ----\n  ea0d8d93e39b27e9c7fb76ddbc122ab2092630d7458933d35f296dbf0adaf0c7 - prev tx hash\n  00000000 - prev vout\n  00 - scriptsig\n  fdffffff - sequence number\n  ---- outputs -----\n  02 - 2 outputs\n  ---- output 0 ----\n  f6073d0000000000 - amount, 8-byte little endian, 3999734 sats\n  17a914251dd11457a259c3ba47e5cca3717fe4214e029887 - scriptpubkey of the output, address - 2MvdUi5o3f2tnEFh9yGvta6FzptTZtkPJC8\n  ---- output 1 ----\n  c0d8a70000000000 - amount, 11000000 sats\n  22002023570715e1ac360b097d32781d2d571f9c5d8a07daf47c627c1e1efb24cb5ac0 - scriptpubkey of the output, (addr bcrt1qydtsw90p4smqkztaxfup6t2hr7w9mzs8mt68ccnurc00kfxtttqqxlges6 on regtest)\nd9000000 - locktime\n\n00 - end of global scope\n\n============== INPUT SCOPES =================\n---------- INPUT 0 --------------\n# non_witness_utxo - full previous transaction. We can verify that this transaction hashes to the same tx hash as in input 0 of global transaction, and drop everything except output 1 - there we can get amount and scriptpubkey for signing.\n# non witness utxo key\n01 00\n# non witness utxo value - full previous transaction\n72 0200000001da9a4b82aad88017f24aa54442fdb68844c24341cd217ae11a482312f46253a30100000000feffffff0258e2de22010000001600144395a9a9e8d9a1bcd44b8f425b4a779cf3245773809698000000000017a914336caa13e08b96080a32b5d818d59b4ab3b367428700000000\n------\n# witness utxo - only output that we need for signing with segwit. Present only in segwit transaction, currently in most cases for segwit transaction both non_witness_utxo and witness_utxo are present, but sometimes wallets keep only witness_utxo.\n# witness-utxo key\n01 01\n# witness-utxo value\n20 - length of the witness utxo\n  8096980000000000 - amount, little endian, 8 bytes. 10000000 sats\n  17a914336caa13e08b96080a32b5d818d59b4ab3b3674287 - scriptpubkey (addr - 2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2)\n# redeem script, when finalizing transcation we need to put this to scriptpubkey.\n01 04 - redeem script key\n16 001438971f73930f6c141d977ac4fd4a727c854935b3 - redeem script value\n# bip32 derivation. Key is the public key, value is the derivation (key: \u003clen\u003e\u003c0x06\u003e\u003cpubkey\u003e)\n22 06 03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f - pubkey\n18 - length of derivation value, derivation path - fingerprint 73c5da0a, derivation m/49'/1'/0'/0/0\n  73c5da0a - fingerprint\n  31000080 - 49'\n  01000080 - 1'\n  00000080 - 0'\n  00000000 - 0\n  00000000 - 0\n00 - end of scope\n---------- INPUT 1 --------------\n# similar to input 0, same fields\n0100720200000001f0f3e667c77b47815006dacdb72bef07bdbe9a36fa1c62896c469cf324c0b8fe0100000000feffffff02404b4c000000000017a91481d74bcd380c05f791d1f4c81837565dec9b234a8799c4c3230100000016001439a460078122352e30e8b9520e16dd603f39395100000000010120404b4c000000000017a91481d74bcd380c05f791d1f4c81837565dec9b234a870104160014bd7c79cd76a5491f01115b81372cdc9b05cedb00220603b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c8031873c5da0a310000800100008000000080000000000100000000\n============== OUTPUT SCOPES ===============\n---------- OUTPUT 0 ---------------\n# redeem script for this output, required for verification that this output is indeed change output\n01 00\n16 001470beb1e04a500940e9f3abaa66e1a49ac55b8f35 - redeem script for this output\n# bip32 derivation. Key is the public key, value is the derivation (key: \u003clen\u003e\u003c0x02\u003e\u003cpubkey\u003e)\n22 02 02a2fc8996c5262248b5daefc5a4d0cdcd00c13047d0cb13028136ea630d875a87\n18 - length of derivation\n  73c5da0a - fingerprint\n  31000080 - 49'\n  01000080 - 1'\n  00000080 - 0'\n  01000000 - 1\n  00000000 - 0\n00 - end of scope\n----------- OUTPUT 1 ------------\n00 - empty, we don't know anything about this output\n```\n\n# Signing PSBT\n\nWhen signing PSBT we need to go through every input and calculate a hash for it. Depending on the type of input we need to use either legacy signing algorithm, or segwit.\n\n## Segwit signing algorithm:\n\nFirst, we can calculate a few hashes that can be reused between inputs:\n\n```\n# hash txid vout of all inputs concatenated\nhash_prevouts = sha256(sha256(\u003ctxhash0\u003e\u003cvout0\u003e\u003ctxhash1\u003e\u003cvout1\u003e...))\n# hash sequences of all inputs concatenated\nhash_sequence = sha256(sha256(\u003csequence0\u003e\u003csequence1\u003e...))\n# hash all outputs concatenated\nhash_outputs = sha256(sha256(\u003camount0\u003e\u003cscriptpubkey0\u003e\u003camount1\u003e\u003cscriptpubkey1\u003e))\n```\n\nIn our case:\n```\nprevouts = 1cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c 01000000 ea0d8d93e39b27e9c7fb76ddbc122ab2092630d7458933d35f296dbf0adaf0c7 00000000\nsequences = fdffffff fdffffff\noutputs = f6073d0000000000 17a914251dd11457a259c3ba47e5cca3717fe4214e029887\nc0d8a70000000000 22002023570715e1ac360b097d32781d2d571f9c5d8a07daf47c627c1e1efb24cb5ac0\n```\n\n```\nhash_prevouts = 33555b25a146e6a7c9ece37d2c2f73f340864fe3c3fa071470db685d3b83027e\nhash_sequence = 957879fdce4d8ab885e32ff307d54e75884da52522cc53d3c4fdb60edb69a098\nhash_outputs = e642b66847d70b33ce142851945e4210861f796398b171e91470df9aa1b3551a\n```\n\nNow let's sign input 0. We need to get two values from the input scope 0:\n- Amount of the previous output - 10000000 sats\n- Previous Script - either witness script (if multisig), or redeem script (if wrapped segwit), or witness_utxo.script_pubkey (if native segwit). In our case (wrapped segwit) we take redeem script `001438971f73930f6c141d977ac4fd4a727c854935b3`\n\nIf the script is single-sig segwit (like in our case), we need to convert it to legacy p2pkh script - we take pubkey hash from the script (`38971f73930f6c141d977ac4fd4a727c854935b3`) and insert it into legacy p2pkh script: `76a91438971f73930f6c141d977ac4fd4a727c854935b388ac`.\n\nTo get a hash for signing we need to hash the following things:\n- tx version (`02000000`)\n- hash_prevouts (`33555b25a146e6a7c9ece37d2c2f73f340864fe3c3fa071470db685d3b83027e`)\n- hash_sequence (`957879fdce4d8ab885e32ff307d54e75884da52522cc53d3c4fdb60edb69a098`)\n- prev tx hash and vout of our input (`1cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c 01000000`)\n- script that we got above with length (`1976a91438971f73930f6c141d977ac4fd4a727c854935b388ac`)\n- value that we got above (`8096980000000000` = 10000000 sats)\n- sequence of our input (`fdffffff`)\n- hash_outputs (`e642b66847d70b33ce142851945e4210861f796398b171e91470df9aa1b3551a`)\n- locktime (`d9000000`)\n- sighash (SIGHASH_ALL in our case - `01000000`)\n\n```\nhash = sha256(sha256( 02000000 33555b25a146e6a7c9ece37d2c2f73f340864fe3c3fa071470db685d3b83027e 957879fdce4d8ab885e32ff307d54e75884da52522cc53d3c4fdb60edb69a098 1cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c 01000000 1976a91438971f73930f6c141d977ac4fd4a727c854935b388ac 8096980000000000 fdffffff e642b66847d70b33ce142851945e4210861f796398b171e91470df9aa1b3551a d9000000 01000000 )) =\n```\n\nAnd the resulting hash is `7d56777c37679edbfbdc635c4e90f87e17676571f8f6311a431cf086c9030d74`.\n\nNow, in order to sign this hash we need to derive the private key from the root key using derivation path `m/49'/1'/0'/0/0`:\n\n```\nroot: xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu\nderivation: m/49'/1'/0'/0/0\nderived xprv: xprvA3xqazGezXcjYigcosBVV6C613TjcQSCzGkw2wsMx6Kn8LU1NcU2y2nVuZwv9afxiD1QGJMXXeKUUuQCTABDkeV2peoBfK7MEMxbPR3qobP\nderived 32-byte secret: c9bdb49cfbaedca21c4b1f3a7803c34636b1d7dc55a717132443fc3f4c5867e8\ncorresponding public key: 03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f\n\nDER-signature: 304402206bb98cc2682fb71a7ce2bc72033dae383b51318359c04f1cbcbceb2263d825a80220723513601ce9a43c3e26c64170ed610eed5370a269af8fea1d84dd283bc05186\n```\n\nRepeating the same process for all inputs we receive the following data:\n```\nInput 0:\npubkey: 03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f\nsignature: 304402206bb98cc2682fb71a7ce2bc72033dae383b51318359c04f1cbcbceb2263d825a80220723513601ce9a43c3e26c64170ed610eed5370a269af8fea1d84dd283bc05186\n\nInput 1:\npubkey: 03b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c803\nsignature: 304402206a3fdc2759544f19d112c6186f530d790e5776abbc9263b98e2c554f0ff143cf022008482ed584455ffb0bc32b244998cc4f2d4a0a1c1ba9b9560a6d2129236e2c74\n```\n\n# Including signature to the PSBT\n\nWe need to include signatures to every input metadata of the psbt. To decrease the size of the transaction we could remove some fields, like non-witness utxo, but for now we will keep everything as it was and only include signatures.\n\nPartial signatures are serialized with key `\u003c02\u003e\u003cpubkey\u003e` and value `\u003cder_signature\u003e\u003csighash\u003e` - notice that signature also has a sighash byte at the end, `0x01` in case of SIGHASH_ALL (default sighash in Bitcoin).\n\n```\n# old input metadata\n0100720200000001da9a4b82aad88017f24aa54442fdb68844c24341cd217ae11a482312f46253a30100000000feffffff0258e2de22010000001600144395a9a9e8d9a1bcd44b8f425b4a779cf3245773809698000000000017a914336caa13e08b96080a32b5d818d59b4ab3b367428700000000010120809698000000000017a914336caa13e08b96080a32b5d818d59b4ab3b3674287010416001438971f73930f6c141d977ac4fd4a727c854935b3220603a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f1873c5da0a3100008001000080000000800000000000000000\n# key - \u003c02\u003epubkey\n220203a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f\n# value - \u003cder_signature\u003e\u003csighash\u003e\n47304402206bb98cc2682fb71a7ce2bc72033dae383b51318359c04f1cbcbceb2263d825a80220723513601ce9a43c3e26c64170ed610eed5370a269af8fea1d84dd283bc0518601\n# end of input metadata\n00\n```\n\nThe same for second input:\n\n```\n# old input metadata\n0100720200000001f0f3e667c77b47815006dacdb72bef07bdbe9a36fa1c62896c469cf324c0b8fe0100000000feffffff02404b4c000000000017a91481d74bcd380c05f791d1f4c81837565dec9b234a8799c4c3230100000016001439a460078122352e30e8b9520e16dd603f39395100000000010120404b4c000000000017a91481d74bcd380c05f791d1f4c81837565dec9b234a87\n0104160014bd7c79cd76a5491f01115b81372cdc9b05cedb00220603b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c8031873c5da0a3100008001000080000000800000000001000000\n# pubkey\n220203b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c803\n# signature\n47304402206a3fdc2759544f19d112c6186f530d790e5776abbc9263b98e2c554f0ff143cf022008482ed584455ffb0bc32b244998cc4f2d4a0a1c1ba9b9560a6d2129236e2c7401\n# end of input\n00\n```\n\nThese values can be added to input at any place, I added them at the end for simplicity\n\n# Finalizing transaction\n\nOn the host side, when we receive a signed psbt, we need to extract a raw bitcoin transaction ready for broadcasting.\n\nWe start by taking a raw unsigned transaction from psbt:\n\n```\n02000000 - version, little-endian (version = 2)\n---- inputs -----\n02 - number of inputs\n---- input 0 ----\n1cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c - previous tx hash (reversed txid of the transaction we are spending)\n01000000 - prev vout, little-endian (vout = 1)\n00 - scriptsig, empty because transaction is unsigned\nfdffffff - sequence number, little endian\n---- input 1 ----\nea0d8d93e39b27e9c7fb76ddbc122ab2092630d7458933d35f296dbf0adaf0c7 - prev tx hash\n00000000 - prev vout\n00 - scriptsig\nfdffffff - sequence number\n---- outputs -----\n02 - 2 outputs\n---- output 0 ----\nf6073d0000000000 - amount, 8-byte little endian, 3999734 sats\n17a914251dd11457a259c3ba47e5cca3717fe4214e029887 - scriptpubkey of the output, address - 2MvdUi5o3f2tnEFh9yGvta6FzptTZtkPJC8\n---- output 1 ----\nc0d8a70000000000 - amount, 11000000 sats\n22002023570715e1ac360b097d32781d2d571f9c5d8a07daf47c627c1e1efb24cb5ac0 - scriptpubkey\n----------------\nd9000000 - locktime\n```\n\nWe only need to change inputs, and in case of segwit transactions (our case) also add a segwit marker and witness data\n\nFor every input we need to:\n\n- inject redeem script to scriptsig if it's not empty (yes in our case)\n- if it's a segwit transaction - construct witness data (yes in our case)\n- if it's a segwit transaction - add a segwit marker after the version\n\nAn easy way to detect if the transaction is segwit or not - to look at psbt inputs metadata. Normally it's enough to check if `witness_utxo` is not empty - this should work in the 99% of cases.\n\nFor more complete check any of the following should be true:\n- witness_utxo for any input is not empty\n- witness_script for any input is not empty\n- redeem script starts with `00` and followed by 20 or 32-byte len-encoded string (`0014\u003cpubkeyhash\u003e` or `0020\u003cscripthash\u003e`)\n- redeem script is empty but previous utxo scriptpubkey starts with `00` followed by 20 or 32-byte len-encoded string\n\nWitness data for single-sig contains two elements - a signature and a pubkey:\n\n```\n# witness for input 0:\n02 - number of items\n# der-signature with sighash\n47304402206bb98cc2682fb71a7ce2bc72033dae383b51318359c04f1cbcbceb2263d825a80220723513601ce9a43c3e26c64170ed610eed5370a269af8fea1d84dd283bc0518601\n# public key\n2103a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f\n\n# witness for input 1:\n02 - number of items\n# signature\n47304402206a3fdc2759544f19d112c6186f530d790e5776abbc9263b98e2c554f0ff143cf022008482ed584455ffb0bc32b244998cc4f2d4a0a1c1ba9b9560a6d2129236e2c7401\n# pubkey\n2103b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c803\n```\n\nAnnotated transaction with injected witnesses, segwit marker and redeem script:\n\n```\n02000000 - version\n0001 - segwit flag and marker\n---- inputs -----\n02 - number of inputs\n---- input 0 ----\n1cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c - txid\n01000000 - vout\n1716001438971f73930f6c141d977ac4fd4a727c854935b3 - scriptsig (redeem script from psbt input 0)\nfdffffff - sequence number\n---- input 1 ----\nea0d8d93e39b27e9c7fb76ddbc122ab2092630d7458933d35f296dbf0adaf0c7 - txid\n00000000 - vout\n17160014bd7c79cd76a5491f01115b81372cdc9b05cedb00 - scriptsig (redeem script from psbt input 1)\nfdffffff - sequence number\n---- outputs ----\n02 - number of outputs\n---- output 0 ----\nf6073d0000000000 - amount\n17a914251dd11457a259c3ba47e5cca3717fe4214e029887 - scriptpubkey\n---- output 1 ----\nc0d8a70000000000 - amount\n22002023570715e1ac360b097d32781d2d571f9c5d8a07daf47c627c1e1efb24cb5ac0 - scriptpubkey\n---- witness data ----\n---- witness for input 0 ---\n0247304402206bb98cc2682fb71a7ce2bc72033dae383b51318359c04f1cbcbceb2263d825a80220723513601ce9a43c3e26c64170ed610eed5370a269af8fea1d84dd283bc05186012103a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f\n---- witness for input 1 ----\n0247304402206a3fdc2759544f19d112c6186f530d790e5776abbc9263b98e2c554f0ff143cf022008482ed584455ffb0bc32b244998cc4f2d4a0a1c1ba9b9560a6d2129236e2c74012103b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c803\n---- locktime ---\nd9000000\n```\n\nFinal transaction ready for broadcast:\n\n```\n020000000001021cb6d64ebf95ca23e9d6267b925dbd18c3935f691a867f3b83aab8f8d745d85c010000001716001438971f73930f6c141d977ac4fd4a727c854935b3fdffffffea0d8d93e39b27e9c7fb76ddbc122ab2092630d7458933d35f296dbf0adaf0c70000000017160014bd7c79cd76a5491f01115b81372cdc9b05cedb00fdffffff02f6073d000000000017a914251dd11457a259c3ba47e5cca3717fe4214e029887c0d8a7000000000022002023570715e1ac360b097d32781d2d571f9c5d8a07daf47c627c1e1efb24cb5ac00247304402206bb98cc2682fb71a7ce2bc72033dae383b51318359c04f1cbcbceb2263d825a80220723513601ce9a43c3e26c64170ed610eed5370a269af8fea1d84dd283bc05186012103a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f0247304402206a3fdc2759544f19d112c6186f530d790e5776abbc9263b98e2c554f0ff143cf022008482ed584455ffb0bc32b244998cc4f2d4a0a1c1ba9b9560a6d2129236e2c74012103b22d357d64aa0c10caffcdaeb22fca282b31f011c8c2c8c6d5e56a676d52c803d9000000\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstepansnigirev%2Fpsbt_flow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstepansnigirev%2Fpsbt_flow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstepansnigirev%2Fpsbt_flow/lists"}