diff --git a/.changeset/ripe-turkeys-dance.md b/.changeset/ripe-turkeys-dance.md new file mode 100644 index 0000000000..b76568c0f7 --- /dev/null +++ b/.changeset/ripe-turkeys-dance.md @@ -0,0 +1,15 @@ +--- +"@caravan/psbt": minor +--- + +Add BIP375 silent payment sending support to PsbtV2 + +- Add PSBT_OUT_SP_V0_INFO and PSBT_OUT_SP_V0_LABEL getters and methods +- Add PSBT_GLOBAL_SP_ECDH_SHARE, PSBT_GLOBAL_SP_DLEQ getters and methods +- Add PSBT_IN_SP_ECDH_SHARE, PSBT_IN_SP_DLEQ getters and methods +- Add silentPayment option to addOutput() for SP output construction +- Add computeSilentPaymentOutputScripts() implementing BIP352 derivation +- Add hasSilentPaymentOutputs, hasAllSPOutputScripts, hasCompleteECDHCoverage predicates +- Add eligibleIndices, sumECDHShares, computeInputHash, deriveSilentPaymentOutput to silentpayment.ts +- Update isReadyForSigner to enforce BIP375 signing rules +- Update getTransactionId() for BIP375 unique identification diff --git a/packages/caravan-psbt/src/fixtures/bip375_vectors.json b/packages/caravan-psbt/src/fixtures/bip375_vectors.json new file mode 100644 index 0000000000..48d840027c --- /dev/null +++ b/packages/caravan-psbt/src/fixtures/bip375_vectors.json @@ -0,0 +1,2074 @@ +{ + "description": "BIP-375 Test Vectors", + "version": "1.1.2", + "notes": [ + "Generated by https://github.com/macgyver13/bip375-test-generator/", + "Each vector includes: base64-encoded psbt and description", + "Supplementary material (hex, inputs, outputs, sp_proofs) is included for diagnostics and should not be used for validation", + "'checks' overrides the validation sequence, e.g. skip structure checks to test input eligibility" + ], + "invalid": [ + { + "description": "psbt structure: missing PSBT_OUT_SP_V0_INFO field when PSBT_OUT_SP_V0_LABEL set", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQDA0MWZ04xLnQHpSq5jI2/aAbRMT5OsRKl39Iml2eMiwwIgfd311m6QKccuNVB0fZJjffaj5C4W9UJpdPi+uF0mIcABAQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQMIGHMBAAAAAAABBCJRIBe/gYp0DI0Tuy5Y5sq4rrsiY8+rt5QENxNV46aiiaG0AQoEAQAAAAA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100c0d0c599d38c4b9d01e94aae63236fda01b44c4f93ac44a977f489a5d9e322c302207dddf5d66e9029c72e3550747d92637df6a3e42e16f5426974f8beb85d2621c00101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021000103081873010000000000010422512017bf818a740c8d13bb2e58e6cab8aebb2263cfabb79404371355e3a6a289a1b4010a040100000000", + "task": "fail_deserialize" + } + }, + { + "description": "psbt structure: incorrect byte length for PSBT_OUT_SP_V0_INFO field", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwgYcwEAAAAAAAEEIlEgZG9JTKC7m86tFLjbfkxpRFYfryMufMzDa91YaV90kVkBCUECekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84AA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010941027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce000", + "task": "fail_deserialize" + } + }, + { + "description": "psbt structure: incorrect byte length for PSBT_IN_SP_ECDH_SHARE field", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GggA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QoiHgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaECKE7OYVUX3K9bolxSuuQmz41SoQqm7i1bNDt7SHfihmVmLMSKKSeC9fpXOEFP3xbKKy1Q6aHB2AOPOiYIu4yAhAAEDCBhzAQAAAAAAAQQiUSBkb0lMoLubzq0UuNt+TGlEVh+vIy58zMNr3VhpX3SRWQEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682003eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "task": "fail_deserialize" + } + }, + { + "description": "psbt structure: incorrect byte length for PSBT_IN_SP_DLEQ field", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4Gg/ihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgAAEDCBhzAQAAAAAAAQQiUSBkb0lMoLubzq0UuNt+TGlEVh+vIy58zMNr3VhpX3SRWQEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0683f8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3200001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "task": "fail_deserialize" + } + }, + { + "description": "psbt structure: PSBT_GLOBAL_TX_MODIFIABLE field is non-zero when PSBT_OUT_SCRIPT set for sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAQABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwgYcwEAAAAAAAEEIlEgZG9JTKC7m86tFLjbfkxpRFYfryMufMzDa91YaV90kVkBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010100010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "task": "fail_sign" + } + }, + { + "description": "psbt structure: missing PSBT_OUT_SCRIPT field when sending to non-sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9GMEMCHwfXEdsnLfzEuix6A+aihT1VxR5DeSoM+sSpV9cRhBsCIENgnob+SDV1lgnI3tO4nBZ5YcOpGfobJDWSa7Km/n7yAQEDBAEAAAAiBgLIF7t1Ia/DXqlvO/snDm61Dd/6VWBie5Yf7ADymWUIvwgAAACAAAAAAAEQBP7///8iHQJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaCED7KT/Ebco4uD2DOYiKUOm/1W52V9ie/mpnQhLyHLVClsiHgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaECKE7OYVUX3K9bolxSuuQmz41SoQqm7i1bNDt7SHfihmVmLMSKKSeC9fpXOEFP3xbKKy1Q6aHB2AOPOiYIu4yAhAAEDCBhzAQAAAAAAAA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf463043021f07d711db272dfcc4ba2c7a03e6a2853d55c51e43792a0cfac4a957d711841b022043609e86fe4835759609c8ded3b89c167961c3a919fa1b2435926bb2a6fe7ef20101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010308187301000000000000", + "task": "fail_deserialize" + } + }, + { + "description": "ecdh coverage: only one ineligible P2SH multisig input when PSBT_OUT_SCRIPT set for sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiDNOBpFUI/j2cq2O34PcEoPVp2/1VqYEC2eozruYht19AEPBAAAAAABAFMCAAAAAXyoMfPUiQn+aMsOqqoR+Hc97n6McwhTN1kOJLsGOQ20AAAAAAD/////AaCGAQAAAAAAF6kU2OZohxTu7Qqi7dSJqhyjwXFwHk2HAAAAAAEER1IhAr5Ar99ismPLfe4rmF0cOP5BsZlNKwUHU0PRcsIY6rHEIQJ6R5JT0AogWhCpQ483IBm582TgqDaAC/g529KOfOa5VVKuARAE/v///wABAwiQXwEAAAAAAAEEIlEgzeOdiwW0lvjxjyCyfQr5oyMzCeBHIhnggT/ztdN4fikBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20cd381a45508fe3d9cab63b7e0f704a0f569dbfd55a98102d9ea33aee621b75f4010f040000000001005302000000017ca831f3d48909fe68cb0eaaaa11f8773dee7e8c73085337590e24bb06390db40000000000ffffffff01a08601000000000017a914d8e6688714eeed0aa2edd489aa1ca3c171701e4d8700000000010447522102be40afdf62b263cb7dee2b985d1c38fe41b1994d2b05075343d172c218eab1c421027a479253d00a205a10a9438f372019b9f364e0a836800bf839dbd28e7ce6b95552ae011004feffffff00010308905f0100000000000104225120cde39d8b05b496f8f18f20b27d0af9a3233309e0472219e0813ff3b5d3787e29010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "", + "public_key": "", + "prevout_txid": "f4751b62ee3aa39e2d10985ad5bf9d560f4a700f7e3bb6cad9e38f50451a38cd", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "02000000017ca831f3d48909fe68cb0eaaaa11f8773dee7e8c73085337590e24bb06390db40000000000ffffffff01a08601000000000017a914d8e6688714eeed0aa2edd489aa1ca3c171701e4d8700000000", + "sequence": 4294967294, + "signed": false + } + ], + "task": "fail_sign" + } + }, + { + "description": "ecdh coverage: missing PSBT_IN_SP_ECDH_SHARE field for input 0 when PSBT_OUT_SCRIPT set for sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////AAEOIJPTYzYn61jp3DA/bvnLG+gMFmE3Or6KbWjfR+tV8JobAQ8EAAAAAAEBHxAnAAAAAAAAFgAUNyH6c8IwXLL4joSJLWvWuXcmHmoBAwQBAAAAIgYCQ6DUDp3giCeUFhdSuuQrqQlSeEIJ8GNDDwryVjVKhbsIAAAAgAEAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghAuV6etywGNj7MVToDBS5elCZS0I1aEHqn8ExcGFEAOY3Ih4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhA9/o4HeILO0WcbkJsYhPUF1MI8kgqROMyhCMmJNTa/Vcymb868WqzAsViY2OjfUSHB/fnoevqBke8zUhiA7srpgABAwgYcwEAAAAAAAEEIlEgzeOdiwW0lvjxjyCyfQr5oyMzCeBHIhnggT/ztdN4fikBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff00010e2093d3633627eb58e9dc303f6ef9cb1be80c1661373abe8a6d68df47eb55f09a1b010f040000000001011f10270000000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a0103040100000022060243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb080000008001000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682102e57a7adcb018d8fb3154e80c14b97a50994b42356841ea9fc13170614400e637221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06840f7fa381de20b3b459c6e426c6213d4175308f2482a44e33284232624d4dafd573299bf3af16ab302c5626363a37d448707f7e7a1ebea0647bccd486203bb2ba60001030818730100000000000104225120cde39d8b05b496f8f18f20b27d0af9a3233309e0472219e0813ff3b5d3787e29010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 1, + "private_key": "586b0810bbc3c7266971aeb7f8778b41707e092a1aeaf0d953b211f956e35541", + "public_key": "0243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "prevout_txid": "1b9af055eb47df686d8abe3a3761160ce81bcbf96e3f30dce958eb273663d393", + "prevout_index": 0, + "amount": 10000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff0110270000000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a00000000", + "witness_utxo": "10270000000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "02e57a7adcb018d8fb3154e80c14b97a50994b42356841ea9fc13170614400e637", + "dleq_proof": "f7fa381de20b3b459c6e426c6213d4175308f2482a44e33284232624d4dafd573299bf3af16ab302c5626363a37d448707f7e7a1ebea0647bccd486203bb2ba6", + "input_index": 1 + } + ], + "task": "fail_sign" + } + }, + { + "description": "ecdh coverage: missing PSBT_IN_SP_DLEQ field for input when PSBT_IN_SP_ECDH_SHARE set", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbAAEDCBhzAQAAAAAAAQQiUSBkb0lMoLubzq0UuNt+TGlEVh+vIy58zMNr3VhpX3SRWQEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b0001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": null, + "input_index": 0 + } + ], + "task": "fail_deserialize" + } + }, + { + "description": "ecdh coverage: missing PSBT_GLOBAL_SP_DLEQ field when PSBT_GLOBAL_SP_ECDH_SHARE set", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBACIHAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWwABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEiBgLIF7t1Ia/DXqlvO/snDm61Dd/6VWBie5Yf7ADymWUIvwgAAACAAAAAAAEQBP7///8AAQMIGHMBAAAAAAABBCJRIGRvSUygu5vOrRS4235MaURWH68jLnzMw2vdWGlfdJFZAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb0402000000010204020000000104010101050101010601002207027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b00010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e01220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff0001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b" + } + ], + "task": "fail_deserialize" + } + }, + { + "description": "ecdh coverage: invalid proof in PSBT_IN_SP_DLEQ field", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAbvHreDwFl9ZoVl4787j95b7SgVKV9D4XAVEk1EXcy9rdKkne51lhePEhbl1NuRdP/dpjNON8kDEQjAjOE3TeDwABAwgYcwEAAAAAAAEEIlEgZG9JTKC7m86tFLjbfkxpRFYfryMufMzDa91YaV90kVkBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068406ef1eb783c0597d668565e3bf3b8fde5bed2815295f43e17015124d445dccbdadd2a49dee7596178f1216e5d4db9174ffdda6334e37c9031108c08ce1374de0f0001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "6ef1eb783c0597d668565e3bf3b8fde5bed2815295f43e17015124d445dccbdadd2a49dee7596178f1216e5d4db9174ffdda6334e37c9031108c08ce1374de0f", + "input_index": 0 + } + ], + "task": "fail_sign" + } + }, + { + "description": "ecdh coverage: invalid proof in PSBT_GLOBAL_SP_DLEQ field", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBACIHAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIIAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQOfI/UQrlNiKKmoskrQ0ZI+gB8n+CARyozeA0LUjKETQm9iLP+6G0S1DhsRlf7t4Xi0vFL/PkYV0P+EqyCUPldkAAQ4g907dH3W0uz5ddJwVv9tmNI9oBam01F/u4aLiAfUDu3EBDwQAAAAAAQEfoIYBAAAAAAAWABQeKteHLTKUE6Vt8JaL4zgiJ4MWOyICAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/RzBEAiBvYUyrFsgMJqaWcuL4qucLwIi1IC6p3v9qznjNp/ticgIgEFWHj/1ZZ1Bg62CgC/ozTJyyQfuhKEwRJJDRANnsfC4BIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////AAEDCBhzAQAAAAAAAQQiUSBkb0lMoLubzq0UuNt+TGlEVh+vIy58zMNr3VhpX3SRWQEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb0402000000010204020000000104010101050101010601002207027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b2208027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06840e7c8fd442b94d88a2a6a2c92b434648fa007c9fe080472a33780d0b5232844d09bd88b3fee86d12d4386c4657fbb785e2d2f14bfcf9185743fe12ac8250f95d900010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e01220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff0001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "2430479d2da1310a024d2aab8e4c7b49d76cd51f45ee8127c159b0393a675b6f75c581ebe3d0817ddaf3bb598cfd7a022f1a87ed479664f6b947a47db5941cb2" + } + ], + "task": "fail_sign" + } + }, + { + "description": "ecdh coverage: missing PSBT_IN_BIP32_DERIVATION field for input when PSBT_IN_SP_DLEQ set", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAAAEQBP7///8iHQJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaCED7KT/Ebco4uD2DOYiKUOm/1W52V9ie/mpnQhLyHLVClsiHgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaECKE7OYVUX3K9bolxSuuQmz41SoQqm7i1bNDt7SHfihmVmLMSKKSeC9fpXOEFP3xbKKy1Q6aHB2AOPOiYIu4yAhAAEDCBhzAQAAAAAAAQQiUSBkb0lMoLubzq0UuNt+TGlEVh+vIy58zMNr3VhpX3SRWQEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b01030401000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "task": "fail_sign" + } + }, + { + "description": "ecdh coverage: output 1 missing ECDH share for scan key with one input / three sp outputs (different scan keys)", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEDAQYBAAABDiD9LfT1i1q/m5H/Gh5D4uNSP1DGqhnVwiNgFB7EjJqAIQEPBAAAAAABAR9ADQMAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdArlFYVfpRu8H90tU+gm+Sn6Tjcr7+ye0s3LFc8BZ8SqwIQLChkR0sISqyB9uMKxe30ZnOTzmBNgI0/SZoJhOi1JJdCIdA2UdLAc/ywKk2C3aU/HVAdd6A1BmZ5hUZHOyEmts0afeIQN2iSMnxOeAru7UzhvJK7ASK3t5ENlvCtUUi0lvnD6S+yIeArlFYVfpRu8H90tU+gm+Sn6Tjcr7+ye0s3LFc8BZ8SqwQPCxHVHD/ROzjgpsjvwu4Mpxdzr2dLMVHmiSFJJcS1fIFojJ4Hi3UIhabKsoa1d+k6JJfrSWNrGvG2vILnyRElEiHgNlHSwHP8sCpNgt2lPx1QHXegNQZmeYVGRzshJrbNGn3kCY8UrEWvZFmrDITUfaU2TPsUT/kL2scy+cq8bbAA3PGpXjsx97cKBCmKUbb9RRbIHXFsmVT4rxDD1ZgJruK704AAEDCJBfAQAAAAAAAQQiUSBg9n1lOOjDNhoPtXryD47AzuIAMtDb3yc6UykBnOW/TgEJQgNlHSwHP8sCpNgt2lPx1QHXegNQZmeYVGRzshJrbNGn3gPycOClYyGDtqsBB06HfmgA2wD1x8XS+vu2j5wo1IVFJAABAwgQJwAAAAAAAAEEIlEgzeOdiwW0lvjxjyCyfQr5oyMzCeBHIhnggT/ztdN4fikBCUIDUteMQTkAMq2RgWppf8dA2OuQnPBNcIhSZLBR8jheJewC4MTBh7chX5l8hIWnW0WRtsKEd7laESO5lpItMVSGC/gAAQMIIE4AAAAAAAABBCJRIM//VLPkWViKpOGXLVboPI42pZ2WjLKZ3vuvBMJDlKnuAQlCArlFYVfpRu8H90tU+gm+Sn6Tjcr7+ye0s3LFc8BZ8SqwAhJoHj8J6uOKjy8/7NfdVvxYbPoCjoqzP3KpD4QKbSJcAA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501030106010000010e20fd2df4f58b5abf9b91ff1a1e43e2e3523f50c6aa19d5c22360141ec48c9a8021010f040000000001011f400d0300000000001600141e2ad7872d329413a56df0968be338222783163b01030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d02b9456157e946ef07f74b54fa09be4a7e938dcafbfb27b4b372c573c059f12ab02102c2864474b084aac81f6e30ac5edf4667393ce604d808d3f499a0984e8b524974221d03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de210376892327c4e780aeeed4ce1bc92bb0122b7b7910d96f0ad5148b496f9c3e92fb221e02b9456157e946ef07f74b54fa09be4a7e938dcafbfb27b4b372c573c059f12ab040f0b11d51c3fd13b38e0a6c8efc2ee0ca71773af674b3151e689214925c4b57c81688c9e078b750885a6cab286b577e93a2497eb49636b1af1b6bc82e7c911251221e03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de4098f14ac45af6459ab0c84d47da5364cfb144ff90bdac732f9cabc6db000dcf1a95e3b31f7b70a04298a51b6fd4516c81d716c9954f8af10c3d59809aee2bbd3800010308905f010000000000010422512060f67d6538e8c3361a0fb57af20f8ec0cee20032d0dbdf273a5329019ce5bf4e01094203651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de03f270e0a5632183b6ab01074e877e6800db00f5c7c5d2fafbb68f9c28d48545240001030810270000000000000104225120cde39d8b05b496f8f18f20b27d0af9a3233309e0472219e0813ff3b5d3787e290109420352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec02e0c4c187b7215f997c8485a75b4591b6c28477b95a1123b996922d3154860bf800010308204e0000000000000104225120cfff54b3e459588aa4e1972d56e83c8e36a59d968cb299defbaf04c24394a9ee01094202b9456157e946ef07f74b54fa09be4a7e938dcafbfb27b4b372c573c059f12ab00212681e3f09eae38a8f2f3fecd7dd56fc586cfa028e8ab33f72a90f840a6d225c00", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "21809a8cc41e146023c2d519aac6503f52e3e2431e1aff919bbf5a8bf5f42dfd", + "prevout_index": 0, + "amount": 200000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01400d0300000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "400d0300000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de", + "ecdh_share": "0376892327c4e780aeeed4ce1bc92bb0122b7b7910d96f0ad5148b496f9c3e92fb", + "dleq_proof": "98f14ac45af6459ab0c84d47da5364cfb144ff90bdac732f9cabc6db000dcf1a95e3b31f7b70a04298a51b6fd4516c81d716c9954f8af10c3d59809aee2bbd38", + "input_index": 0 + }, + { + "scan_key": "02b9456157e946ef07f74b54fa09be4a7e938dcafbfb27b4b372c573c059f12ab0", + "ecdh_share": "02c2864474b084aac81f6e30ac5edf4667393ce604d808d3f499a0984e8b524974", + "dleq_proof": "f0b11d51c3fd13b38e0a6c8efc2ee0ca71773af674b3151e689214925c4b57c81688c9e078b750885a6cab286b577e93a2497eb49636b1af1b6bc82e7c911251", + "input_index": 0 + } + ], + "task": "fail_sign" + } + }, + { + "description": "ecdh coverage: input 1 missing ECDH share for output 1 with two inputs / two sp outputs (different scan keys)", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQECAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdA1LXjEE5ADKtkYFqaX/HQNjrkJzwTXCIUmSwUfI4XiXsIQMJH9SAORd/RNe3npYWiEnGLrP4eADEZ2fFCo84+Y79FSIdA2UdLAc/ywKk2C3aU/HVAdd6A1BmZ5hUZHOyEmts0afeIQN2iSMnxOeAru7UzhvJK7ASK3t5ENlvCtUUi0lvnD6S+yIeA1LXjEE5ADKtkYFqaX/HQNjrkJzwTXCIUmSwUfI4XiXsQL4acjrvVeiYG5lZmpvBKzj4froBWMxwZokPImnK3kY7dzQal9KScZZNAcAkHMMi/VOQwpuZFg+CbzKTZYmMvwIiHgNlHSwHP8sCpNgt2lPx1QHXegNQZmeYVGRzshJrbNGn3kCY8UrEWvZFmrDITUfaU2TPsUT/kL2scy+cq8bbAA3PGpXjsx97cKBCmKUbb9RRbIHXFsmVT4rxDD1ZgJruK704AAEOIOdsAXEIOkxftK/i9tYfAKRzAbnQH40uR3gKt1QuN3wIAQ8EAAAAAAEBH6CGAQAAAAAAFgAUNyH6c8IwXLL4joSJLWvWuXcmHmoBAwQBAAAAIgYCQ6DUDp3giCeUFhdSuuQrqQlSeEIJ8GNDDwryVjVKhbsIAAAAgAEAAAABEAT+////Ih0DZR0sBz/LAqTYLdpT8dUB13oDUGZnmFRkc7ISa2zRp94hAnUEQAf+LQMNV3wymRzyo+deU1BCRbPL5bMFOufF8iBaIh4DZR0sBz/LAqTYLdpT8dUB13oDUGZnmFRkc7ISa2zRp95AOLnjgGtJvr7vxs7gZcKwZv2wCuzs8ei1sqr0fPBBeyma4KJW7Xy2yCcC63E31zv1eSccQoTQBuO1nXCpuWfYiQABAwiQXwEAAAAAAAEEIlEgUYxvb4GbCpCxtzrI2r6I+6L7jU21kKWeh5y2htZLPwoBCUIDZR0sBz/LAqTYLdpT8dUB13oDUGZnmFRkc7ISa2zRp94D8nDgpWMhg7arAQdOh35oANsA9cfF0vr7to+cKNSFRSQAAQMIkF8BAAAAAAABBCJRIJPCrCoXvlxLW2ZvyHz2ESYroSl4aKSY4YV32/tFpEJwAQlCA1LXjEE5ADKtkYFqaX/HQNjrkJzwTXCIUmSwUfI4XiXsAuDEwYe3IV+ZfISFp1tFkbbChHe5WhEjuZaSLTFUhgv4AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501020106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b01030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d0352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec2103091fd48039177f44d7b79e96168849c62eb3f87800c46767c50a8f38f98efd15221d03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de210376892327c4e780aeeed4ce1bc92bb0122b7b7910d96f0ad5148b496f9c3e92fb221e0352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec40be1a723aef55e8981b99599a9bc12b38f87eba0158cc7066890f2269cade463b77341a97d29271964d01c0241cc322fd5390c29b99160f826f329365898cbf02221e03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de4098f14ac45af6459ab0c84d47da5364cfb144ff90bdac732f9cabc6db000dcf1a95e3b31f7b70a04298a51b6fd4516c81d716c9954f8af10c3d59809aee2bbd3800010e20e76c0171083a4c5fb4afe2f6d61f00a47301b9d01f8d2e47780ab7542e377c08010f040000000001011fa0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a0103040100000022060243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb080000008001000000011004feffffff221d03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de210275044007fe2d030d577c32991cf2a3e75e53504245b3cbe5b3053ae7c5f2205a221e03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de4038b9e3806b49bebeefc6cee065c2b066fdb00aececf1e8b5b2aaf47cf0417b299ae0a256ed7cb6c82702eb7137d73bf579271c4284d006e3b59d70a9b967d88900010308905f0100000000000104225120518c6f6f819b0a90b1b73ac8dabe88fba2fb8d4db590a59e879cb686d64b3f0a01094203651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de03f270e0a5632183b6ab01074e877e6800db00f5c7c5d2fafbb68f9c28d485452400010308905f010000000000010422512093c2ac2a17be5c4b5b666fc87cf611262ba1297868a498e18577dbfb45a442700109420352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec02e0c4c187b7215f997c8485a75b4591b6c28477b95a1123b996922d3154860bf800", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 1, + "private_key": "586b0810bbc3c7266971aeb7f8778b41707e092a1aeaf0d953b211f956e35541", + "public_key": "0243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "prevout_txid": "087c372e54b70a78472e8d1fd0b90173a4001fd6f6e2afb45f4c3a0871016ce7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01a0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a00000000", + "witness_utxo": "a0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de", + "ecdh_share": "0376892327c4e780aeeed4ce1bc92bb0122b7b7910d96f0ad5148b496f9c3e92fb", + "dleq_proof": "98f14ac45af6459ab0c84d47da5364cfb144ff90bdac732f9cabc6db000dcf1a95e3b31f7b70a04298a51b6fd4516c81d716c9954f8af10c3d59809aee2bbd38", + "input_index": 0 + }, + { + "scan_key": "0352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec", + "ecdh_share": "03091fd48039177f44d7b79e96168849c62eb3f87800c46767c50a8f38f98efd15", + "dleq_proof": "be1a723aef55e8981b99599a9bc12b38f87eba0158cc7066890f2269cade463b77341a97d29271964d01c0241cc322fd5390c29b99160f826f329365898cbf02", + "input_index": 0 + }, + { + "scan_key": "03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de", + "ecdh_share": "0275044007fe2d030d577c32991cf2a3e75e53504245b3cbe5b3053ae7c5f2205a", + "dleq_proof": "38b9e3806b49bebeefc6cee065c2b066fdb00aececf1e8b5b2aaf47cf0417b299ae0a256ed7cb6c82702eb7137d73bf579271c4284d006e3b59d70a9b967d889", + "input_index": 1 + } + ], + "task": "fail_sign" + } + }, + { + "description": "ecdh coverage: input 1 missing ECDH share for scan key with two inputs / one sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBAAABDiDrEeGtrXwwUZqHRDUybuN6GWWIHApVyi6pr+1Blki2FgEPBAAAAAABAR9QwwAAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQ4g245T4MzJHLEs15uROavlPi9D3Liqq6r37/AsHsiwHCgBDwQAAAAAAQEfUMMAAAAAAAAWABQ3IfpzwjBcsviOhIkta9a5dyYeaiIGAkOg1A6d4IgnlBYXUrrkK6kJUnhCCfBjQw8K8lY1SoW7CAAAAIABAAAAARAE/v///wABAwgYcwEAAAAAAAEEIlEgzeOdiwW0lvjxjyCyfQr5oyMzCeBHIhnggT/ztdN4fikBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501010106010000010e20eb11e1adad7c30519a874435326ee37a1965881c0a55ca2ea9afed419648b616010f040000000001011f50c30000000000001600141e2ad7872d329413a56df0968be338222783163b01030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010e20db8e53e0ccc91cb12cd79b9139abe53e2f43dcb8aaabaaf7eff02c1ec8b01c28010f040000000001011f50c30000000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a22060243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb080000008001000000011004feffffff0001030818730100000000000104225120cde39d8b05b496f8f18f20b27d0af9a3233309e0472219e0813ff3b5d3787e29010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "16b6489641edafa92eca550a1c8865197ae36e323544879a51307cadade111eb", + "prevout_index": 0, + "amount": 50000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff0150c30000000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "50c30000000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 1, + "private_key": "586b0810bbc3c7266971aeb7f8778b41707e092a1aeaf0d953b211f956e35541", + "public_key": "0243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "prevout_txid": "281cb0c81e2cf0eff7aaabaab8dc432f3ee5ab39919bd72cb11cc9cce0538edb", + "prevout_index": 0, + "amount": 50000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff0150c30000000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a00000000", + "witness_utxo": "50c30000000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "task": "fail_sign" + } + }, + { + "description": "input eligibility: segwit version greater than 1 in transaction inputs with sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiDTD15OVpOzLW9aeJ43C7ZEcUGMAdvjy58jYGZ8HBM5pQEPBAAAAAABAR+ghgEAAAAAABZSFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQD/G0d7SFEcnvURdIK0VbinRBzrmgXCDZ4gwhD+Z4IEJAIgJ32Cr+1Q28AA/sbFs+Rp61l2dsYw+TpBveyIolGGf00BAQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQMIGHMBAAAAAAABBCJRIPGzmH+N0VjGTWFO/Otm7DX662b5nu+5arlL2tCh6dqAAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20d30f5e4e5693b32d6f5a789e370bb64471418c01dbe3cb9f2360667c1c1339a5010f040000000001011fa0860100000000001652141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100ff1b477b48511c9ef5117482b455b8a7441ceb9a05c20d9e20c210fe678204240220277d82afed50dbc000fec6c5b3e469eb597676c630f93a41bdec88a251867f4d0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120f1b3987f8dd158c64d614efceb66ec35faeb66f99eefb96ab94bdad0a1e9da80010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "a539131c7c6660239fcbe3db018c417144b60b379e785a6f2db393564e5e0fd3", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001652141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001652141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "task": "fail_sign" + }, + "checks": [ + "input_eligibility" + ] + }, + { + "description": "input eligibility: non-SIGHASH_ALL signature on input with sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCID1lvc+owIu6KcBlzqbELkBAvrwUG9UvgfUD9jrZiAZUAiBGU0AdzeUC8dVS4BTFAgx1UerNOncuiYVMYBgzYyB9FAEBAwQCAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwgYcwEAAAAAAAEEIlEgZG9JTKC7m86tFLjbfkxpRFYfryMufMzDa91YaV90kVkBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402203d65bdcfa8c08bba29c065cea6c42e4040bebc141bd52f81f503f63ad988065402204653401dcde502f1d552e014c5020c7551eacd3a772e89854c60183363207d140101030402000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "task": "fail_sp_sign" + } + }, + { + "description": "output scripts: P2TR input with NUMS internal key cannot derive sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiBgF7WQD5i+njptfZytOQKM6tP1ITmnodnsV2k+vmyaowEPBAAAAAABASsQJwAAAAAAACJRIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAAQMEAQAAAAEQBP7///8BE0GNRXo+4wxRWCxWlnde57pemE/F12ztqkpOiq6N0zSCTmgoW/X1/csnFdpquwq4GYc+jRqcEsI7W5NJsxitYlNOAQEXIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAIh0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwgcJQAAAAAAAAEEIlEgfyDVlx0Qd+n5jEZf6tapililLCV2WAM/PZUgmGiUkfQBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e206017b5900f98be9e3a6d7d9cad39028cead3f52139a7a1d9ec57693ebe6c9aa3010f040000000001012b102700000000000022512050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac001030401000000011004feffffff0113418d457a3ee30c51582c5696775ee7ba5e984fc5d76cedaa4a4e8aae8dd334824e68285bf5f5fdcb2715da6abb0ab819873e8d1a9c12c23b5b9349b318ad62534e0101172050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021000103081c2500000000000001042251207f20d5971d1077e9f98c465fead6a98a58a52c257658033f3d952098689491f4010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "a39a6cbe3e6957ecd9a1a73921f5d3ea8c0239ad9c7d6d3a9ebe980f90b51760", + "prevout_index": 0, + "amount": 10000, + "non_witness_utxo": "020000000113f106b64b57b5b1376f9f6c47190f40cc06b3bedcb8aaba97850ab3d7f67d020000000000ffffffff01102700000000000022512050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac000000000", + "witness_utxo": "102700000000000022512050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 9500, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "51207f20d5971d1077e9f98c465fead6a98a58a52c257658033f3d952098689491f4" + } + ], + "task": "fail_sign" + } + }, + { + "description": "output scripts: PSBT_OUT_SCRIPT does not match derived sp output", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQMIGHMBAAAAAAABBCJRIM3jnYsFtJb48Y8gsn0K+aMjMwngRyIZ4IE/87XTeH4pAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b01030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120cde39d8b05b496f8f18f20b27d0af9a3233309e0472219e0813ff3b5d3787e29010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120cde39d8b05b496f8f18f20b27d0af9a3233309e0472219e0813ff3b5d3787e29" + } + ], + "task": "fail_sign" + } + }, + { + "description": "output scripts: two sp outputs (same scan / different spend keys) not sorted lexicographically by spend key", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQECAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIExYL+wZvNCU5oIsqPD7MiK6sIG6J64r3IOIgwa67SNWAiAfxZx06/JBydKQqMxQ8qOYD8DANBNXtltjINXNPOpPBAEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwiQXwEAAAAAAAEEIlEgPajcATlIcUBND7sqMXcLxrF+r7rr33jiwy48KFZTJ1kBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgCi4D5lDNIleEbx2x1q254/iwluzMvIXshHEAXvx9nfYYAAQMIECcAAAAAAAABBCJRINcZ2dcurhCyj8MgCzL61dlJboWOixbkdXjXyMFEkzsEAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA6r4Yq7amM+SU5r33DN10dpfsGsSHvCh8DGp9zgv1T27AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501020106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402204c582fec19bcd094e6822ca8f0fb3222bab081ba27ae2bdc83888306baed235602201fc59c74ebf241c9d290a8cc50f2a3980fc0c0341357b65b6320d5cd3cea4f040101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010308905f01000000000001042251203da8dc01394871404d0fbb2a31770bc6b17eafbaebdf78e2c32e3c2856532759010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068028b80f994334895e11bc76c75ab6e78fe2c25bb332f217b211c4017bf1f677d860001030810270000000000000104225120d719d9d72eae10b28fc3200b32fad5d9496e858e8b16e47578d7c8c144933b04010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06803aaf862aeda98cf92539af7dc3375d1da5fb06b121ef0a1f031a9f7382fd53dbb00", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068028b80f994334895e11bc76c75ab6e78fe2c25bb332f217b211c4017bf1f677d86", + "script": "51203da8dc01394871404d0fbb2a31770bc6b17eafbaebdf78e2c32e3c2856532759" + }, + { + "output_index": 1, + "amount": 10000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06803aaf862aeda98cf92539af7dc3375d1da5fb06b121ef0a1f031a9f7382fd53dbb", + "script": "5120d719d9d72eae10b28fc3200b32fad5d9496e858e8b16e47578d7c8c144933b04" + } + ], + "task": "fail_sign" + } + }, + { + "description": "output scripts: k values assigned to wrong output indices with three sp outputs (same scan / spend keys)", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEDAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQDmsaUAuR12tiR/luLlnUQZ6/oZayCC6yzQGczKmeec6wIgVp/snmnIG0ZomQT4uGSrck/xFnuR58NgeHpzOZqLvNMBAQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQMIkF8BAAAAAAABBCJRIGRvSUygu5vOrRS4235MaURWH68jLnzMw2vdWGlfdJFZAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AAEDCBAnAAAAAAAAAQQiUSBnO3Y1anIQCkUV5BRRrprC+6ap0dft7SIJEBvVLxrrVwEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQABAwgQJwAAAAAAAAEEIlEgpRVl2ozof5Td+ErkDvaYxXSb8mLkE+ryjVDYvYtTJ8UBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501030106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100e6b1a500b91d76b6247f96e2e59d4419ebfa196b2082eb2cd019ccca99e79ceb0220569fec9e69c81b46689904f8b864ab724ff1167b91e7c360787a73399a8bbcd30101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010308905f0100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce0390001030810270000000000000104225120673b76356a72100a4515e41451ae9ac2fba6a9d1d7eded2209101bd52f1aeb57010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce0390001030810270000000000000104225120a51565da8ce87f94ddf84ae40ef698c5749bf262e413eaf28d50d8bd8b5327c5010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159" + }, + { + "output_index": 1, + "amount": 10000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120673b76356a72100a4515e41451ae9ac2fba6a9d1d7eded2209101bd52f1aeb57" + }, + { + "output_index": 2, + "amount": 10000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120a51565da8ce87f94ddf84ae40ef698c5749bf262e413eaf28d50d8bd8b5327c5" + } + ], + "task": "fail_sign" + } + }, + { + "description": "input derivation: P2WPKH BIP32_DERIVATION pubkey does not match prevout script", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAACIGA4+plDX6lbGV+mADtXE+Da7qAMH/S8LLYDK0ccl7HFljCAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQKJrr4cMdjZlp7VADdXOchNeqbQV2h/Ck5cuA0KBg03eyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQGuT/wfJyZrQjEXeF8f1vcx1OVZshsaec0slVfrS+N2b/dKk5yicBub1fk9ybpw0focikVH4GsoUDYT1KdSOi+sAAQMIGHMBAAAAAAABBCJRIDg/2sQx5SQpQX9uJOugHYH842VRzMvwmLrPHqoDNNhPAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b010304010000002206038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068210289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068406b93ff07c9c99ad08c45de17c7f5bdcc7539566c86c69e734b2555fad2f8dd9bfdd2a4e7289c06e6f57e4f726e9c347e87229151f81aca140d84f529d48e8beb0001030818730100000000000104225120383fdac431e52429417f6e24eba01d81fce36551cccbf098bacf1eaa0334d84f010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "29e8eff75528710ebbe15ca4e257292ab9e0923ae827de3dc12efce5aa37f1e8", + "public_key": "038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "0289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b", + "dleq_proof": "6b93ff07c9c99ad08c45de17c7f5bdcc7539566c86c69e734b2555fad2f8dd9bfdd2a4e7289c06e6f57e4f726e9c347e87229151f81aca140d84f529d48e8beb", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120383fdac431e52429417f6e24eba01d81fce36551cccbf098bacf1eaa0334d84f" + } + ], + "task": "deserialize" + } + }, + { + "description": "input derivation: P2PKH BIP32_DERIVATION pubkey does not match prevout script", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiBSJ0jrF3ZNKMpJSBXsjUnn0w1SvHNCLHyG63TjlwVylAEPBAAAAAABAFUCAAAAAfTCEtWu0ef2/2M/LOCcZHxXvt2TAxTZjed1A9WOlAszAAAAAAD/////AaCGAQAAAAAAGXapFB4q14ctMpQTpW3wlovjOCIngxY7iKwAAAAAAQMEAQAAACIGA4+plDX6lbGV+mADtXE+Da7qAMH/S8LLYDK0ccl7HFljCAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQKJrr4cMdjZlp7VADdXOchNeqbQV2h/Ck5cuA0KBg03eyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQGuT/wfJyZrQjEXeF8f1vcx1OVZshsaec0slVfrS+N2b/dKk5yicBub1fk9ybpw0focikVH4GsoUDYT1KdSOi+sAAQMIGHMBAAAAAAABBCJRICKBfO5dYbj9zQAUBomhNyYIpsMCvUqPU6EYTAlCDalDAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20522748eb17764d28ca494815ec8d49e7d30d52bc73422c7c86eb74e397057294010f04000000000100550200000001f4c212d5aed1e7f6ff633f2ce09c647c57bedd930314d98de77503d58e940b330000000000ffffffff01a0860100000000001976a9141e2ad7872d329413a56df0968be338222783163b88ac00000000010304010000002206038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068210289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068406b93ff07c9c99ad08c45de17c7f5bdcc7539566c86c69e734b2555fad2f8dd9bfdd2a4e7289c06e6f57e4f726e9c347e87229151f81aca140d84f529d48e8beb000103081873010000000000010422512022817cee5d61b8fdcd00140689a1372608a6c302bd4a8f53a1184c09420da943010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "29e8eff75528710ebbe15ca4e257292ab9e0923ae827de3dc12efce5aa37f1e8", + "public_key": "038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963", + "prevout_txid": "94720597e374eb867c2c4273bc520dd3e7498dec154849ca284d7617eb482752", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001f4c212d5aed1e7f6ff633f2ce09c647c57bedd930314d98de77503d58e940b330000000000ffffffff01a0860100000000001976a9141e2ad7872d329413a56df0968be338222783163b88ac00000000", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "0289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b", + "dleq_proof": "6b93ff07c9c99ad08c45de17c7f5bdcc7539566c86c69e734b2555fad2f8dd9bfdd2a4e7289c06e6f57e4f726e9c347e87229151f81aca140d84f529d48e8beb", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "512022817cee5d61b8fdcd00140689a1372608a6c302bd4a8f53a1184c09420da943" + } + ], + "task": "deserialize" + } + }, + { + "description": "input derivation: P2SH-P2WPKH BIP32_DERIVATION pubkey does not match prevout script", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiBfVGsxp4xGbEWT3iMOmTvJk1ue7NTSp39zulVcUkIDhQEPBAAAAAABAFMCAAAAAa0yiGinxhSdpSUXfZUerAPh/iyT6DzlNGVjrZNjwndMAAAAAAD/////AaCGAQAAAAAAF6kU1JxxjCdjjcMGkgbmNVqpXZ1duKWHAAAAAAEBIKCGAQAAAAAAF6kU1JxxjCdjjcMGkgbmNVqpXZ1duKWHAQMEAQAAAAEEFgAUHirXhy0ylBOlbfCWi+M4IieDFjsiBgOPqZQ1+pWxlfpgA7VxPg2u6gDB/0vCy2AytHHJexxZYwgAAACAAAAAAAEQBP7///8iHQJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaCECia6+HDHY2Zae1QA3VznITXqm0FdofwpOXLgNCgYNN3siHgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaEBrk/8Hycma0IxF3hfH9b3MdTlWbIbGnnNLJVX60vjdm/3SpOconAbm9X5Pcm6cNH6HIpFR+BrKFA2E9SnUjovrAAEDCBhzAQAAAAAAAQQiUSCWlm1C2LBhTynYvjvzYYQujiUMMJ4GK3it91Pn25LXpAEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e205f546b31a78c466c4593de230e993bc9935b9eecd4d2a77f73ba555c52420385010f04000000000100530200000001ad328868a7c6149da525177d951eac03e1fe2c93e83ce5346563ad9363c2774c0000000000ffffffff01a08601000000000017a914d49c718c27638dc3069206e6355aa95d9d5db8a58700000000010120a08601000000000017a914d49c718c27638dc3069206e6355aa95d9d5db8a5870103040100000001041600141e2ad7872d329413a56df0968be338222783163b2206038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068210289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068406b93ff07c9c99ad08c45de17c7f5bdcc7539566c86c69e734b2555fad2f8dd9bfdd2a4e7289c06e6f57e4f726e9c347e87229151f81aca140d84f529d48e8beb000103081873010000000000010422512096966d42d8b0614f29d8be3bf361842e8e250c309e062b78adf753e7db92d7a4010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "29e8eff75528710ebbe15ca4e257292ab9e0923ae827de3dc12efce5aa37f1e8", + "public_key": "038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963", + "prevout_txid": "850342525c55ba737fa7d2d4ec9e5b93c93b990e23de93456c468ca7316b545f", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001ad328868a7c6149da525177d951eac03e1fe2c93e83ce5346563ad9363c2774c0000000000ffffffff01a08601000000000017a914d49c718c27638dc3069206e6355aa95d9d5db8a58700000000", + "witness_utxo": "a08601000000000017a914d49c718c27638dc3069206e6355aa95d9d5db8a587", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "0289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b", + "dleq_proof": "6b93ff07c9c99ad08c45de17c7f5bdcc7539566c86c69e734b2555fad2f8dd9bfdd2a4e7289c06e6f57e4f726e9c347e87229151f81aca140d84f529d48e8beb", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "512096966d42d8b0614f29d8be3bf361842e8e250c309e062b78adf753e7db92d7a4" + } + ], + "task": "deserialize" + } + }, + { + "description": "input pubkey mismatch: global ECDH share computed from decoy pubkey not matching prevout script", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBACIHAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQKJrr4cMdjZlp7VADdXOchNeqbQV2h/Ck5cuA0KBg03eyIIAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQKQgTchGVBiYizypVRPX1XVPssA4q4mBwiNP48UrtRZdQ7Kyz9hps335Mr52oq54tg6JEjA8/Ggu4ox9b0lor6QAAQ4g907dH3W0uz5ddJwVv9tmNI9oBam01F/u4aLiAfUDu3EBDwQAAAAAAQEfoIYBAAAAAAAWABQeKteHLTKUE6Vt8JaL4zgiJ4MWOyIGA4+plDX6lbGV+mADtXE+Da7qAMH/S8LLYDK0ccl7HFljCAAAAIAAAAAAARAE/v///wABAwgYcwEAAAAAAAEEIlEgOD/axDHlJClBf24k66AdgfzjZVHMy/CYus8eqgM02E8BCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb0402000000010204020000000104010101050101010601002207027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068210289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b2208027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06840a4204dc8465418988b3ca95513d7d5754fb2c038ab8981c2234fe3c52bb5165d43b2b2cfd869b37df932be76a2ae78b60e8912303cfc682ee28c7d6f4968afa400010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b2206038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963080000008000000000011004feffffff0001030818730100000000000104225120383fdac431e52429417f6e24eba01d81fce36551cccbf098bacf1eaa0334d84f010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "29e8eff75528710ebbe15ca4e257292ab9e0923ae827de3dc12efce5aa37f1e8", + "public_key": "038fa99435fa95b195fa6003b5713e0daeea00c1ff4bc2cb6032b471c97b1c5963", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "0289aebe1c31d8d9969ed500375739c84d7aa6d057687f0a4e5cb80d0a060d377b", + "dleq_proof": "a4204dc8465418988b3ca95513d7d5754fb2c038ab8981c2234fe3c52bb5165d43b2b2cfd869b37df932be76a2ae78b60e8912303cfc682ee28c7d6f4968afa4" + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120383fdac431e52429417f6e24eba01d81fce36551cccbf098bacf1eaa0334d84f" + } + ], + "task": "deserialize" + } + } + ], + "valid": [ + { + "description": "can finalize: one P2PKH input single-signer", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiBSJ0jrF3ZNKMpJSBXsjUnn0w1SvHNCLHyG63TjlwVylAEPBAAAAAABAFUCAAAAAfTCEtWu0ef2/2M/LOCcZHxXvt2TAxTZjed1A9WOlAszAAAAAAD/////AaCGAQAAAAAAGXapFB4q14ctMpQTpW3wlovjOCIngxY7iKwAAAAAIgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQCKz65hp7Ug/wQxkrbclMyEJpEkQIMSdkyI3dldqY0pVQIgIIfDsRj5aZKk2iQTz/6RcPJQ4n48FMtd7z5jjDDX6oABAQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQMIGHMBAAAAAAABBCJRIOFA0oe0W0bNTqr6Q3cGFXC6voPRuLyVCnSp/qCSM9emAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20522748eb17764d28ca494815ec8d49e7d30d52bc73422c7c86eb74e397057294010f04000000000100550200000001f4c212d5aed1e7f6ff633f2ce09c647c57bedd930314d98de77503d58e940b330000000000ffffffff01a0860100000000001976a9141e2ad7872d329413a56df0968be338222783163b88ac00000000220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf4830450221008acfae61a7b520ff043192b6dc94cc84269124408312764c88ddd95da98d295502202087c3b118f96992a4da2413cffe9170f250e27e3c14cb5def3e638c30d7ea800101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120e140d287b45b46cd4eaafa4377061570babe83d1b8bc950a74a9fea09233d7a6010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "94720597e374eb867c2c4273bc520dd3e7498dec154849ca284d7617eb482752", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001f4c212d5aed1e7f6ff633f2ce09c647c57bedd930314d98de77503d58e940b330000000000ffffffff01a0860100000000001976a9141e2ad7872d329413a56df0968be338222783163b88ac00000000", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120e140d287b45b46cd4eaafa4377061570babe83d1b8bc950a74a9fea09233d7a6" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: two inputs single-signer using global ECDH share", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBACIHAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQLTJicjNSYH6E/K92UfjS1jfgIK6obfrYDTBs1PSM/MYiIIAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQMZTtx+UaBipW9w58JGERbyQOgh2tzgGDp5dsdzsMKvfVOC18XhXP1EZ3nGqY60ZtEnjvLZUY5Nsi67qTZFzkrkAAQ4g907dH3W0uz5ddJwVv9tmNI9oBam01F/u4aLiAfUDu3EBDwQAAAAAAQEfoIYBAAAAAAAWABQeKteHLTKUE6Vt8JaL4zgiJ4MWOyICAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/SDBFAiEA7BqWeJn9r3jg2rH/VnzzA3wMo9G7Im8q7sP98KfSmdcCIBHdNztMi7HrfRAkJSDvxy+E7Un3b0H78IdNp0bjoGOoASIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///wABDiC81IWnCcsl0TRjoYMtshlMbJ2f5yuWmfT+Qsgr7ZPTJgEPBAAAAAABAR+ghgEAAAAAABYAFKaSURwHlXW/N1bavFatcdQoSmkOIgIC9bWfpeSSIh6/Vbp4rUQmBb6ulRZroeujJQ0Luqx+LtxIMEUCIQDelwGo+8K1FHCnn5V0LTz/267tYvzpJKCg1dcFYFFTxQIgRd8PiHo5I7pLMWKTtgzZ/xAdiZUqfbBpxHlWMzJ8PKIBIgYC9bWfpeSSIh6/Vbp4rUQmBb6ulRZroeujJQ0Luqx+LtwIAAAAgAEAAAABEAT+////AAEDCBhzAQAAAAAAAQQiUSCZu9KYLwKAvNwmQx1rKc9nkRilu7tgkU1v+s+rvFy0WwEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb0402000000010204020000000104010201050101010601002207027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682102d3262723352607e84fcaf7651f8d2d637e020aea86dfad80d306cd4f48cfcc622208027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06840c653b71f946818a95bdc39f0918445bc903a0876b738060e9e5db1dcec30abdf54e0b5f178573f5119de71aa63ad19b449e3bcb65463936c8baeea4d917392b900010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100ec1a967899fdaf78e0dab1ff567cf3037c0ca3d1bb226f2aeec3fdf0a7d299d7022011dd373b4c8bb1eb7d10242520efc72f84ed49f76f41fbf0874da746e3a063a801220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff00010e20bcd485a709cb25d13463a1832db2194c6c9d9fe72b9699f4fe42c82bed93d326010f040000000001011fa086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e220202f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc483045022100de9701a8fbc2b51470a79f95742d3cffdbaeed62fce924a0a0d5d705605153c5022045df0f887a3923ba4b316293b60cd9ff101d89952a7db069c4795633327c3ca201220602f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc080000008001000000011004feffffff000103081873010000000000010422512099bbd2982f0280bcdc26431d6b29cf679118a5bbbb60914d6ffacfabbc5cb45b010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 1, + "private_key": "295c2eedddd8331d20b5d4cf9e69bb523ed85cb0bf35ab12e04fea66fe6d4a4a", + "public_key": "02f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc", + "prevout_txid": "26d393ed2bc842fef499962be79f9d6c4c19b22d83a16334d125cb09a785d4bc", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01a086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e00000000", + "witness_utxo": "a086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "02d3262723352607e84fcaf7651f8d2d637e020aea86dfad80d306cd4f48cfcc62", + "dleq_proof": "c653b71f946818a95bdc39f0918445bc903a0876b738060e9e5db1dcec30abdf54e0b5f178573f5119de71aa63ad19b449e3bcb65463936c8baeea4d917392b9" + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "512099bbd2982f0280bcdc26431d6b29cf679118a5bbbb60914d6ffacfabbc5cb45b" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: two inputs single-signer using per-input ECDH shares", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQDsGpZ4mf2veODasf9WfPMDfAyj0bsibyruw/3wp9KZ1wIgEd03O0yLset9ECQlIO/HL4TtSfdvQfvwh02nRuOgY6gBIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABDiC81IWnCcsl0TRjoYMtshlMbJ2f5yuWmfT+Qsgr7ZPTJgEPBAAAAAABAR+ghgEAAAAAABYAFKaSURwHlXW/N1bavFatcdQoSmkOIgIC9bWfpeSSIh6/Vbp4rUQmBb6ulRZroeujJQ0Luqx+LtxIMEUCIQDelwGo+8K1FHCnn5V0LTz/267tYvzpJKCg1dcFYFFTxQIgRd8PiHo5I7pLMWKTtgzZ/xAdiZUqfbBpxHlWMzJ8PKIBAQMEAQAAACIGAvW1n6XkkiIev1W6eK1EJgW+rpUWa6HroyUNC7qsfi7cCAAAAIABAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQM00s73Tt7URkInYH/FmsHegMEqJDOlYnFSjtzPUPpsKyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQDfADAtCoHP2tl8MS25W4Gd0s4DB3z3ii2QLEh7gs7TPeFDfRW4LXY4Zdd3/JSYsg4HiD4Us2HC94/aoMqYyW8wAAQMIGHMBAAAAAAABBCJRIJm70pgvAoC83CZDHWspz2eRGKW7u2CRTW/6z6u8XLRbAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100ec1a967899fdaf78e0dab1ff567cf3037c0ca3d1bb226f2aeec3fdf0a7d299d7022011dd373b4c8bb1eb7d10242520efc72f84ed49f76f41fbf0874da746e3a063a801220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010e20bcd485a709cb25d13463a1832db2194c6c9d9fe72b9699f4fe42c82bed93d326010f040000000001011fa086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e220202f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc483045022100de9701a8fbc2b51470a79f95742d3cffdbaeed62fce924a0a0d5d705605153c5022045df0f887a3923ba4b316293b60cd9ff101d89952a7db069c4795633327c3ca20101030401000000220602f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc080000008001000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068210334d2cef74eded4464227607fc59ac1de80c12a2433a56271528edccf50fa6c2b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0684037c00c0b42a073f6b65f0c4b6e56e06774b380c1df3de28b640b121ee0b3b4cf7850df456e0b5d8e1975ddff25262c8381e20f852cd870bde3f6a832a6325bcc000103081873010000000000010422512099bbd2982f0280bcdc26431d6b29cf679118a5bbbb60914d6ffacfabbc5cb45b010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 1, + "private_key": "295c2eedddd8331d20b5d4cf9e69bb523ed85cb0bf35ab12e04fea66fe6d4a4a", + "public_key": "02f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc", + "prevout_txid": "26d393ed2bc842fef499962be79f9d6c4c19b22d83a16334d125cb09a785d4bc", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01a086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e00000000", + "witness_utxo": "a086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + }, + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "0334d2cef74eded4464227607fc59ac1de80c12a2433a56271528edccf50fa6c2b", + "dleq_proof": "37c00c0b42a073f6b65f0c4b6e56e06774b380c1df3de28b640b121ee0b3b4cf7850df456e0b5d8e1975ddff25262c8381e20f852cd870bde3f6a832a6325bcc", + "input_index": 1 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "512099bbd2982f0280bcdc26431d6b29cf679118a5bbbb60914d6ffacfabbc5cb45b" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: two inputs / two sp outputs with mixed global and per-input ECDH shares", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQECAQYBACIHAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oIQNmz8f9zgbgjtSbGzlSuNFRqPfgdf5fbdWN1o+dre7KlCIIAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oQF6riwhtSFD+nRyflhqR+Ze2HKjQhQr8BqeL3zx0nvVAUOaStT+1sIbl54eT8B5203R/ieMXen/v9vjBYX8bBuMAAQ4g/S309Ytav5uR/xoeQ+LjUj9QxqoZ1cIjYBQexIyagCEBDwQAAAAAAQEfQA0DAAAAAAAWABQeKteHLTKUE6Vt8JaL4zgiJ4MWOyICAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/RzBEAiAKK+ZG0anqXBVNlCNCmskJl9/09NFCJp/mC8dvxE42HAIgCANa6s/ngmX6X6JTanzM6oXez4bcGYlSGOAMQI1gw7ABAQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQIQP70XPZxI1YxQIkJtBSeLyhe5qOIoJmaQGhsAueBLeZSSIeAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQQMBdpBBIfPrsN4/r5q9QBeOubIYjaBiw5VshQBfrUHPt70AXlXW13NqpBjSRrIuD/QYk1Bd6TS3UmUxGQNa4zN4AAQ4ghNQvKb9bD0rIweBsigE0tTP4LAoB9+5OE1KkBMda+y4BDwQAAAAAAQEfQA0DAAAAAAAWABSmklEcB5V1vzdW2rxWrXHUKEppDiICAvW1n6XkkiIev1W6eK1EJgW+rpUWa6HroyUNC7qsfi7cSDBFAiEA1c3ZMOY2lwfrZ4b1q8L00OgVt4cmVi2tA1VpGbbQIjgCIF8zRs9QoCxciaScoUlqFfUE49+mFdDTyCBi0nGS0uE5AQEDBAEAAAAiBgL1tZ+l5JIiHr9VunitRCYFvq6VFmuh66MlDQu6rH4u3AgAAACAAQAAAAEQBP7///8iHQKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVECEDpqibG5hqmVUz4XvtZFALVBuw1zkHHv4q4rfvsKDKa88iHgKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVEEDDSmopQLvppzVsHMb/41jdREHbWIl8upnCEut1KF59oeyhHHksl6OASTNFqyJN6dlMKzbuhSauI1KBcaMjHeczAAEDCJBfAQAAAAAAAQQiUSCxKAm+EU5RY5SZU7O++G4xbRcMZzZlTdRqkb2+RLxVEAEJQgMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKAMSZlgePoQcu5TeYupzVYOiMsTIiPpu3vLsL4cHifwd1AABAwiQXwEAAAAAAAEEIlEge2sCToSJVp8gv7oB/byYmecZMBVcHiDoeJIGlPmxpggBCUICqfH6wsxFdoTzPekAc/4g0iyUfJIWO4YrFNCrod9HFRACSkjXbiDUC89fLhpcP/6z3CqLO4jXmkhtVMnZ6qj6GI4A", + "supplementary": { + "hex": "70736274ff01fb0402000000010204020000000104010201050102010601002207033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28210366cfc7fdce06e08ed49b1b3952b8d151a8f7e075fe5f6dd58dd68f9dadeeca942208033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28405eab8b086d4850fe9d1c9f961a91f997b61ca8d0850afc06a78bdf3c749ef54050e692b53fb5b086e5e78793f01e76d3747f89e3177a7feff6f8c1617f1b06e300010e20fd2df4f58b5abf9b91ff1a1e43e2e3523f50c6aa19d5c22360141ec48c9a8021010f040000000001011f400d0300000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402200a2be646d1a9ea5c154d9423429ac90997dff4f4d142269fe60bc76fc44e361c022008035aeacfe78265fa5fa2536a7cccea85decf86dc19895218e00c408d60c3b00101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102103fbd173d9c48d58c5022426d05278bca17b9a8e2282666901a1b00b9e04b79949221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151040c05da410487cfaec378febe6af5005e3ae6c86236818b0e55b214017eb5073edef40179575b5dcdaa9063491ac8b83fd0624d4177a4d2dd4994c4640d6b8ccde00010e2084d42f29bf5b0f4ac8c1e06c8a0134b533f82c0a01f7ee4e1352a404c75afb2e010f040000000001011f400d030000000000160014a692511c079575bf3756dabc56ad71d4284a690e220202f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc483045022100d5cdd930e6369707eb6786f5abc2f4d0e815b78726562dad03556919b6d0223802205f3346cf50a02c5c89a49ca1496a15f504e3dfa615d0d3c82062d27192d2e1390101030401000000220602f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc080000008001000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102103a6a89b1b986a995533e17bed64500b541bb0d739071efe2ae2b7efb0a0ca6bcf221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151040c34a6a2940bbe9a7356c1cc6ffe358dd4441db58897cba99c212eb75285e7da1eca11c792c97a380493345ab224de9d94c2b36ee8526ae23528171a3231de73300010308905f0100000000000104225120b12809be114e5163949953b3bef86e316d170c6736654dd46a91bdbe44bc5510010942033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd400010308905f01000000000001042251207b6b024e8489569f20bfba01fdbc9899e71930155c1e20e878920694f9b1a60801094202a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e00", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "21809a8cc41e146023c2d519aac6503f52e3e2431e1aff919bbf5a8bf5f42dfd", + "prevout_index": 0, + "amount": 200000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01400d0300000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "400d0300000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 1, + "private_key": "295c2eedddd8331d20b5d4cf9e69bb523ed85cb0bf35ab12e04fea66fe6d4a4a", + "public_key": "02f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc", + "prevout_txid": "2efb5ac704a452134eeef7010a2cf833b534018a6ce0c1c84a0f5bbf292fd484", + "prevout_index": 0, + "amount": 200000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01400d030000000000160014a692511c079575bf3756dabc56ad71d4284a690e00000000", + "witness_utxo": "400d030000000000160014a692511c079575bf3756dabc56ad71d4284a690e", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "0366cfc7fdce06e08ed49b1b3952b8d151a8f7e075fe5f6dd58dd68f9dadeeca94", + "dleq_proof": "5eab8b086d4850fe9d1c9f961a91f997b61ca8d0850afc06a78bdf3c749ef54050e692b53fb5b086e5e78793f01e76d3747f89e3177a7feff6f8c1617f1b06e3" + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "03fbd173d9c48d58c5022426d05278bca17b9a8e2282666901a1b00b9e04b79949", + "dleq_proof": "c05da410487cfaec378febe6af5005e3ae6c86236818b0e55b214017eb5073edef40179575b5dcdaa9063491ac8b83fd0624d4177a4d2dd4994c4640d6b8ccde", + "input_index": 0 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "03a6a89b1b986a995533e17bed64500b541bb0d739071efe2ae2b7efb0a0ca6bcf", + "dleq_proof": "c34a6a2940bbe9a7356c1cc6ffe358dd4441db58897cba99c212eb75285e7da1eca11c792c97a380493345ab224de9d94c2b36ee8526ae23528171a3231de733", + "input_index": 1 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd4", + "script": "5120b12809be114e5163949953b3bef86e316d170c6736654dd46a91bdbe44bc5510" + }, + { + "output_index": 1, + "amount": 90000, + "sp_v0_info": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e", + "script": "51207b6b024e8489569f20bfba01fdbc9899e71930155c1e20e878920694f9b1a608" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: one input / one sp output with both global and per-input ECDH shares", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBACIHAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oIQMKGLm7QZm4kzDrF/juWseG4IU9zS88zfF0S5fOTt4FPiIIAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oQCf7kMXWHHjjEVIA/9GD0o0KtIOAYslUGTTGQW1CZ84xvUKH6TWUUsCBevDvTVDP9XhDaw0o+e2PIbeaRHZAgI4AAQ4g/S309Ytav5uR/xoeQ+LjUj9QxqoZ1cIjYBQexIyagCEBDwQAAAAAAQEfQA0DAAAAAAAWABQeKteHLTKUE6Vt8JaL4zgiJ4MWOyICAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/SDBFAiEAyFvlr5bhqKf1YcXDSFBg36YAz/htqrTzO6OY5lBittkCIBPq0/BHmz/uJrpIh+BRh2ZjzRP8fmHmDS6WBkIym0HkAQEDBAEAAAAiBgLIF7t1Ia/DXqlvO/snDm61Dd/6VWBie5Yf7ADymWUIvwgAAACAAAAAAAEQBP7///8iHQMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKCEDChi5u0GZuJMw6xf47lrHhuCFPc0vPM3xdEuXzk7eBT4iHgMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKEAAE4PUZhvocl7ykEj0jJEfifXzQxfXwMCsxg72XxtSv/96ltgzm2Jd+Dq6tXqic+3NmjXHlNrLschhFxuyZwdfAAEDCJBfAQAAAAAAAQQiUSAqcL4BPYeh6B6gH736DPH/CNUqaNGMExqMyWAfhKagrAEJQgMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKAMSZlgePoQcu5TeYupzVYOiMsTIiPpu3vLsL4cHifwd1AA=", + "supplementary": { + "hex": "70736274ff01fb0402000000010204020000000104010101050101010601002207033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2821030a18b9bb4199b89330eb17f8ee5ac786e0853dcd2f3ccdf1744b97ce4ede053e2208033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d284027fb90c5d61c78e3115200ffd183d28d0ab4838062c9541934c6416d4267ce31bd4287e9359452c0817af0ef4d50cff578436b0d28f9ed8f21b79a447640808e00010e20fd2df4f58b5abf9b91ff1a1e43e2e3523f50c6aa19d5c22360141ec48c9a8021010f040000000001011f400d0300000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100c85be5af96e1a8a7f561c5c3485060dfa600cff86daab4f33ba398e65062b6d9022013ead3f0479b3fee26ba4887e051876663cd13fc7e61e60d2e960642329b41e40101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2821030a18b9bb4199b89330eb17f8ee5ac786e0853dcd2f3ccdf1744b97ce4ede053e221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2840001383d4661be8725ef29048f48c911f89f5f34317d7c0c0acc60ef65f1b52bfff7a96d8339b625df83abab57aa273edcd9a35c794dacbb1c861171bb267075f00010308905f01000000000001042251202a70be013d87a1e81ea01fbdfa0cf1ff08d52a68d18c131a8cc9601f84a6a0ac010942033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd400", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "21809a8cc41e146023c2d519aac6503f52e3e2431e1aff919bbf5a8bf5f42dfd", + "prevout_index": 0, + "amount": 200000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01400d0300000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "400d0300000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "030a18b9bb4199b89330eb17f8ee5ac786e0853dcd2f3ccdf1744b97ce4ede053e", + "dleq_proof": "27fb90c5d61c78e3115200ffd183d28d0ab4838062c9541934c6416d4267ce31bd4287e9359452c0817af0ef4d50cff578436b0d28f9ed8f21b79a447640808e" + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd4", + "script": "51202a70be013d87a1e81ea01fbdfa0cf1ff08d52a68d18c131a8cc9601f84a6a0ac" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: three sp outputs (different scan keys) with multiple global ECDH shares", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEDAQYBACIHAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQIQLC2d9g7mmlqGYE3ZpigsIu+OLJJ22m5ZWlRj83Gq3uJCIHAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oIQLcfS7KxWiwEVF1ujzVSW/0xLbZCUItvMrrjyUvpU+L0CIHA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsIQJwvvXAapqFX8Y7/yvQvi1wAzyCC2FTQTyNbtpR8lobKSIIAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQQOyCQr97WIHO4GBWbH8TzEfkcQyJomRYwgMBswMeSBc7wL6gFoDTN1616AYRqw1Qix5Jq7VxsYeAMqrknwsC99IiCAMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKEDqQ0cOXhvjKRtIoLy1P1WVLGSGDnY177pQA8yt7XfdEo4hZpew9SO+IX7Gh1B3l8zOvFzZQ2KvG0bYA2Qr1flAIggDjtMiDnM0T5Hi0zOR4+FpHbOdrwbkI34ZftDQB78nKGxAG9/lTtSioG//mwAJrk49gPxHYWR1r98hJEz+PG0QTfJHQah1UU14ZU+5yhEY5tPlUvOPjKujVS6DM8UBvwy9PwABDiDUQOda/N1TGlkeN6vSbkryvw9v8uGRgwI1Yej8VxOPSgEPBAAAAAABAR8goQcAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQC42QsRZqzXY8+uqHOJGaBPRdBVbSvLD2Z/C6PEGO5f2QIgI64RGn6itGrUpKOIKuT++973rl0BtM22H1aXmv9SahgBIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////AAEOIOdsAXEIOkxftK/i9tYfAKRzAbnQH40uR3gKt1QuN3wIAQ8EAAAAAAEBH6CGAQAAAAAAFgAUNyH6c8IwXLL4joSJLWvWuXcmHmoiAgJDoNQOneCIJ5QWF1K65CupCVJ4QgnwY0MPCvJWNUqFu0gwRQIhAJfXTGL5WdOu1bnHpXDy1zyq0MCrseRy1E/UxirCYuS5AiAX2VXEZF+Fr+z2aKPQRlXWdZPyNXYrGm9SKYcXYECqoAEiBgJDoNQOneCIJ5QWF1K65CupCVJ4QgnwY0MPCvJWNUqFuwgAAACAAQAAAAEQBP7///8AAQMIkF8BAAAAAAABBCJRIE6KUf3Rq9Uk/FLWkolTgu5u3MSNN3228eZRXyNALkgnAQlCAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oAxJmWB4+hBy7lN5i6nNVg6IyxMiI+m7e8uwvhweJ/B3UAAEDCJBfAQAAAAAAAQQiUSB+MV8kXPlXXxNDwxcP/O42rUbTO1ZfCji5lDx8AqzXawEJQgKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVEAJKSNduINQLz18uGlw//rPcKos7iNeaSG1UydnqqPoYjgABAwiQXwEAAAAAAAEEIlEgPK1PnUbiURy2iCuvYOjtgGIgsUFRPWkE2s0r6qE3w5UBCUIDjtMiDnM0T5Hi0zOR4+FpHbOdrwbkI34ZftDQB78nKGwD+BRzhEyddMkh/xelr0ELYzc0jXr7/3OJG8XLDLJMsMAA", + "supplementary": { + "hex": "70736274ff01fb040200000001020402000000010401020105010301060100220702a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102102c2d9df60ee69a5a86604dd9a6282c22ef8e2c9276da6e595a5463f371aadee242207033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d282102dc7d2ecac568b0115175ba3cd5496ff4c4b6d909422dbccaeb8f252fa54f8bd02207038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c210270bef5c06a9a855fc63bff2bd0be2d70033c820b6153413c8d6eda51f25a1b29220802a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151040ec8242bf7b5881cee060566c7f13cc47e4710c89a26458c20301b3031e48173bc0bea01680d3375eb5e80611ab0d508b1e49abb571b1878032aae49f0b02f7d22208033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2840ea43470e5e1be3291b48a0bcb53f55952c64860e7635efba5003ccaded77dd128e216697b0f523be217ec687507797cccebc5cd94362af1b46d803642bd5f9402208038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c401bdfe54ed4a2a06fff9b0009ae4e3d80fc47616475afdf21244cfe3c6d104df24741a875514d78654fb9ca1118e6d3e552f38f8caba3552e8333c501bf0cbd3f00010e20d440e75afcdd531a591e37abd26e4af2bf0f6ff2e19183023561e8fc57138f4a010f040000000001011f20a10700000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100b8d90b1166acd763cfaea8738919a04f45d0556d2bcb0f667f0ba3c418ee5fd9022023ae111a7ea2b46ad4a4a3882ae4fefbdef7ae5d01b4cdb61f56979aff526a1801220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff00010e20e76c0171083a4c5fb4afe2f6d61f00a47301b9d01f8d2e47780ab7542e377c08010f040000000001011fa0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a22020243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb48304502210097d74c62f959d3aed5b9c7a570f2d73caad0c0abb1e472d44fd4c62ac262e4b9022017d955c4645f85afecf668a3d04655d67593f235762b1a6f522987176040aaa00122060243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb080000008001000000011004feffffff00010308905f01000000000001042251204e8a51fdd1abd524fc52d692895382ee6edcc48d377db6f1e6515f23402e4827010942033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd400010308905f01000000000001042251207e315f245cf9575f1343c3170ffcee36ad46d33b565f0a38b9943c7c02acd76b01094202a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e00010308905f01000000000001042251203cad4f9d46e2511cb6882baf60e8ed806220b141513d6904dacd2beaa137c395010942038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c03f81473844c9d74c921ff17a5af410b6337348d7afbff73891bc5cb0cb24cb0c000", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "4a8f1357fce86135028391e1f26f0fbff24a6ed2ab371e591a53ddfc5ae740d4", + "prevout_index": 0, + "amount": 500000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff0120a10700000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "20a10700000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 1, + "private_key": "586b0810bbc3c7266971aeb7f8778b41707e092a1aeaf0d953b211f956e35541", + "public_key": "0243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "prevout_txid": "087c372e54b70a78472e8d1fd0b90173a4001fd6f6e2afb45f4c3a0871016ce7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01a0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a00000000", + "witness_utxo": "a0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "02dc7d2ecac568b0115175ba3cd5496ff4c4b6d909422dbccaeb8f252fa54f8bd0", + "dleq_proof": "ea43470e5e1be3291b48a0bcb53f55952c64860e7635efba5003ccaded77dd128e216697b0f523be217ec687507797cccebc5cd94362af1b46d803642bd5f940" + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "02c2d9df60ee69a5a86604dd9a6282c22ef8e2c9276da6e595a5463f371aadee24", + "dleq_proof": "ec8242bf7b5881cee060566c7f13cc47e4710c89a26458c20301b3031e48173bc0bea01680d3375eb5e80611ab0d508b1e49abb571b1878032aae49f0b02f7d2" + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "0270bef5c06a9a855fc63bff2bd0be2d70033c820b6153413c8d6eda51f25a1b29", + "dleq_proof": "1bdfe54ed4a2a06fff9b0009ae4e3d80fc47616475afdf21244cfe3c6d104df24741a875514d78654fb9ca1118e6d3e552f38f8caba3552e8333c501bf0cbd3f" + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd4", + "script": "51204e8a51fdd1abd524fc52d692895382ee6edcc48d377db6f1e6515f23402e4827" + }, + { + "output_index": 1, + "amount": 90000, + "sp_v0_info": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e", + "script": "51207e315f245cf9575f1343c3170ffcee36ad46d33b565f0a38b9943c7c02acd76b" + }, + { + "output_index": 2, + "amount": 90000, + "sp_v0_info": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c03f81473844c9d74c921ff17a5af410b6337348d7afbff73891bc5cb0cb24cb0c0", + "script": "51203cad4f9d46e2511cb6882baf60e8ed806220b141513d6904dacd2beaa137c395" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: one P2WPKH input / two mixed outputs - labeled sp output and BIP 32 change", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQECAQYBAAABDiDUQOda/N1TGlkeN6vSbkryvw9v8uGRgwI1Yej8VxOPSgEPBAAAAAABAR8goQcAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9GMEMCIHcTD90bfOCOxkvITdaflmuTJVdETA9hMOK+XNqEia5EAh938mc1PdR7+Nrf+wdHBtYIqIWc7eTcyYzYZ3xl0LWsAQEDBAEAAAAiBgLIF7t1Ia/DXqlvO/snDm61Dd/6VWBie5Yf7ADymWUIvwgAAACAAAAAAAEQBP7///8iHQJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaCED7KT/Ebco4uD2DOYiKUOm/1W52V9ie/mpnQhLyHLVClsiHgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaECKE7OYVUX3K9bolxSuuQmz41SoQqm7i1bNDt7SHfihmVmLMSKKSeC9fpXOEFP3xbKKy1Q6aHB2AOPOiYIu4yAhAAEDCKCGAQAAAAAAAQQiUSCy11CmDsTQW9LCInHwj+IbAOJxHTgjBIu5ZaIrxBc9LwEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaAPqjyKL4rcW2s3vyygQByh08ApHb1wHvQUZFxJsxks97wEKBAEAAAAAAQMIcPMFAAAAAAABBBYAFDjBjzXdgGPjgKcP/rT5j/TvNIF3IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8MAAAAAAAAAAAAAAABAA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501020106010000010e20d440e75afcdd531a591e37abd26e4af2bf0f6ff2e19183023561e8fc57138f4a010f040000000001011f20a10700000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf463043022077130fdd1b7ce08ec64bc84dd69f966b932557444c0f6130e2be5cda8489ae44021f77f267353dd47bf8dadffb074706d608a8859cede4dcc98cd8677c65d0b5ac0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010308a0860100000000000104225120b2d750a60ec4d05bd2c22271f08fe21b00e2711d3823048bb965a22bc4173d2f010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06803ea8f228be2b716dacdefcb2810072874f00a476f5c07bd051917126cc64b3def010a04010000000001030870f3050000000000010416001438c18f35dd8063e380a70ffeb4f98ff4ef348177220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf0c00000000000000000000000100", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "4a8f1357fce86135028391e1f26f0fbff24a6ed2ab371e591a53ddfc5ae740d4", + "prevout_index": 0, + "amount": 500000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff0120a10700000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "20a10700000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 100000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06803ea8f228be2b716dacdefcb2810072874f00a476f5c07bd051917126cc64b3def", + "sp_v0_label": 1, + "script": "5120b2d750a60ec4d05bd2c22271f08fe21b00e2711d3823048bb965a22bc4173d2f" + }, + { + "output_index": 1, + "amount": 390000, + "script": "001438c18f35dd8063e380a70ffeb4f98ff4ef348177" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: one input / two sp outputs - output 0 has no label / output 1 uses label=0 convention for sp change", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQECAQYBAAABDiDXHS3QFsrGYSyer5hVH2eAhRu3czlByBTq+trO3jDcPQEPBAAAAAABAR/gkwQAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIFB2CeL9erskEbcJ/ZjL+pgC0nxcDrLBEMLU8/EJ61yYAiBeYmSIxVqzZbFYt+8gUlTszHEFFvbNOzksUNGJgWmDsQEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0CXw7Bs42ZhKfrYvFb5AMCBBDxQu301p42P1YVr9Kmts0hA84eNnXZDZkmSfqd2xH5AlSbs7AvVvbonMCgTIuMN92UIh0Ci3kOCYf96fDRI5jra+MMc3Z5PGR4ZaKgLy78lg2WZWghAlWBv6pzMVb2uY5xom9w/XazZ4ZJ9isfxed7jpq45hBQIh4CXw7Bs42ZhKfrYvFb5AMCBBDxQu301p42P1YVr9Kmts1ADolhPR9rJTbbj6kkIA2zpvjvyhciVWTVaxEuUIZbTTAuBY+m9hwp4jZqSnJp1FVaXGHWVVnb+/rJ4urf5TY31SIeAot5DgmH/enw0SOY62vjDHN2eTxkeGWioC8u/JYNlmVoQHlAgZ626fJYwVg4fApkzBb1F8fvRAkSLM6qlPTi/1N2xCR7/BcNmyY7Dj0ga2aMh+lLNN7q+gCheSsEeteIdbsAAQMIoIYBAAAAAAABBCJRIBM/6m8cjln0UbKW1K2xPs7sf8M9vFNq5NY3WropOE+LAQlCAot5DgmH/enw0SOY62vjDHN2eTxkeGWioC8u/JYNlmVoA7RDRzNcY/UF5V4mirKA8xi0pqoUSS/zecNmih9U74ybAAEDCDDmAgAAAAAAAQQiUSBgK8NLBuQ1Rvh+VIKxETqr+cn+KSUJmpItXCPYS7zqxgEJQgJfDsGzjZmEp+ti8VvkAwIEEPFC7fTWnjY/VhWv0qa2zQLOCzIZpapd+PIc45PpYs3afVFUbaTTXDjtAYilludg8wEKBAAAAAAA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501020106010000010e20d71d2dd016cac6612c9eaf98551f6780851bb7733941c814eafadacede30dc3d010f040000000001011fe0930400000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf4730440220507609e2fd7abb2411b709fd98cbfa9802d27c5c0eb2c110c2d4f3f109eb5c9802205e626488c55ab365b158b7ef205254eccc710516f6cd3b392c50d189816983b10101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d025f0ec1b38d9984a7eb62f15be403020410f142edf4d69e363f5615afd2a6b6cd2103ce1e3675d90d992649fa9ddb11f902549bb3b02f56f6e89cc0a04c8b8c37dd94221d028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d96656821025581bfaa733156f6b98e71a26f70fd76b3678649f62b1fc5e77b8e9ab8e61050221e025f0ec1b38d9984a7eb62f15be403020410f142edf4d69e363f5615afd2a6b6cd400e89613d1f6b2536db8fa924200db3a6f8efca17225564d56b112e50865b4d302e058fa6f61c29e2366a4a7269d4555a5c61d65559dbfbfac9e2eadfe53637d5221e028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568407940819eb6e9f258c158387c0a64cc16f517c7ef4409122cceaa94f4e2ff5376c4247bfc170d9b263b0e3d206b668c87e94b34deeafa00a1792b047ad78875bb00010308a0860100000000000104225120133fea6f1c8e59f451b296d4adb13eceec7fc33dbc536ae4d6375aba29384f8b010942028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d96656803b44347335c63f505e55e268ab280f318b4a6aa14492ff379c3668a1f54ef8c9b0001030830e60200000000000104225120602bc34b06e43546f87e5482b1113aabf9c9fe2925099a922d5c23d84bbceac6010942025f0ec1b38d9984a7eb62f15be403020410f142edf4d69e363f5615afd2a6b6cd02ce0b3219a5aa5df8f21ce393e962cdda7d51546da4d35c38ed0188a596e760f3010a040000000000", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "3ddc30decedafaea14c8413973b71b8580671f5598af9e2c61c6ca16d02d1dd7", + "prevout_index": 0, + "amount": 300000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01e0930400000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "e0930400000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "025f0ec1b38d9984a7eb62f15be403020410f142edf4d69e363f5615afd2a6b6cd", + "ecdh_share": "03ce1e3675d90d992649fa9ddb11f902549bb3b02f56f6e89cc0a04c8b8c37dd94", + "dleq_proof": "0e89613d1f6b2536db8fa924200db3a6f8efca17225564d56b112e50865b4d302e058fa6f61c29e2366a4a7269d4555a5c61d65559dbfbfac9e2eadfe53637d5", + "input_index": 0 + }, + { + "scan_key": "028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568", + "ecdh_share": "025581bfaa733156f6b98e71a26f70fd76b3678649f62b1fc5e77b8e9ab8e61050", + "dleq_proof": "7940819eb6e9f258c158387c0a64cc16f517c7ef4409122cceaa94f4e2ff5376c4247bfc170d9b263b0e3d206b668c87e94b34deeafa00a1792b047ad78875bb", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 100000, + "sp_v0_info": "028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d96656803b44347335c63f505e55e268ab280f318b4a6aa14492ff379c3668a1f54ef8c9b", + "script": "5120133fea6f1c8e59f451b296d4adb13eceec7fc33dbc536ae4d6375aba29384f8b" + }, + { + "output_index": 1, + "amount": 190000, + "sp_v0_info": "025f0ec1b38d9984a7eb62f15be403020410f142edf4d69e363f5615afd2a6b6cd02ce0b3219a5aa5df8f21ce393e962cdda7d51546da4d35c38ed0188a596e760f3", + "sp_v0_label": 0, + "script": "5120602bc34b06e43546f87e5482b1113aabf9c9fe2925099a922d5c23d84bbceac6" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: three sp outputs (same scan key) - output 0 uses label=1, outputs 1 and 2 uses label=2 (same spend key)", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEDAQYBAAABDiBw4GuGVZXEwnMdM/WmrSgPuHA1VGZimIDKXc2OkAfhmgEPBAAAAAABAR+AGgYAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQCUWfs0hcwTRkOekp3AdPHTla2+gwarlNndhIFCaNDsOAIgOAjuJjqIA6Fy5rMVCyyiJMlhF6GfDplTlH+lICupcGUBAQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAot5DgmH/enw0SOY62vjDHN2eTxkeGWioC8u/JYNlmVoIQJVgb+qczFW9rmOcaJvcP12s2eGSfYrH8Xne46auOYQUCIeAot5DgmH/enw0SOY62vjDHN2eTxkeGWioC8u/JYNlmVoQHlAgZ626fJYwVg4fApkzBb1F8fvRAkSLM6qlPTi/1N2xCR7/BcNmyY7Dj0ga2aMh+lLNN7q+gCheSsEeteIdbsAAQMIoYYBAAAAAAABBCJRIJPaXrkneTYjgSVQ+GmdZjtxlvDMnUiEWLtoH+srb/y6AQlCAot5DgmH/enw0SOY62vjDHN2eTxkeGWioC8u/JYNlmVoA9QxWI3uYas6OXJbKZw3QtxmoIYd7PWRtCOw5ScHD4I0AQoEAQAAAAABAwgy5gIAAAAAAAEEIlEg/euuKHi5JCPRfXT0zBQOHpmABZeNccGDE5KAQF4w5AYBCUICi3kOCYf96fDRI5jra+MMc3Z5PGR4ZaKgLy78lg2WZWgDIZOtDIdfrFJDc4AikAp3JMYXXdrJlEFlqrRXqt+cTzwBCgQCAAAAAAEDCKKGAQAAAAAAAQQiUSD04wY25I9qev6YT6CyVFslfqroyqFuxIGT2zSJJpWHWwEJQgKLeQ4Jh/3p8NEjmOtr4wxzdnk8ZHhloqAvLvyWDZZlaAMhk60Mh1+sUkNzgCKQCnckxhdd2smUQWWqtFeq35xPPAEKBAIAAAAA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501030106010000010e2070e06b865595c4c2731d33f5a6ad280fb870355466629880ca5dcd8e9007e19a010f040000000001011f801a0600000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf4830450221009459fb3485cc1346439e929dc074f1d395adbe8306ab94d9dd84814268d0ec3802203808ee263a8803a172e6b3150b2ca224c96117a19f0e9953947fa5202ba970650101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d96656821025581bfaa733156f6b98e71a26f70fd76b3678649f62b1fc5e77b8e9ab8e61050221e028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568407940819eb6e9f258c158387c0a64cc16f517c7ef4409122cceaa94f4e2ff5376c4247bfc170d9b263b0e3d206b668c87e94b34deeafa00a1792b047ad78875bb00010308a186010000000000010422512093da5eb927793623812550f8699d663b7196f0cc9d488458bb681feb2b6ffcba010942028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d96656803d431588dee61ab3a39725b299c3742dc66a0861decf591b423b0e527070f8234010a04010000000001030832e60200000000000104225120fdebae2878b92423d17d74f4cc140e1e998005978d71c183139280405e30e406010942028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568032193ad0c875fac5243738022900a7724c6175ddac9944165aab457aadf9c4f3c010a040200000000010308a2860100000000000104225120f4e30636e48f6a7afe984fa0b2545b257eaae8caa16ec48193db34892695875b010942028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568032193ad0c875fac5243738022900a7724c6175ddac9944165aab457aadf9c4f3c010a040200000000", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "9ae107908ecd5dca80986266543570b80f28ada6f5331d73c2c49555866be070", + "prevout_index": 0, + "amount": 400000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01801a0600000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "801a0600000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568", + "ecdh_share": "025581bfaa733156f6b98e71a26f70fd76b3678649f62b1fc5e77b8e9ab8e61050", + "dleq_proof": "7940819eb6e9f258c158387c0a64cc16f517c7ef4409122cceaa94f4e2ff5376c4247bfc170d9b263b0e3d206b668c87e94b34deeafa00a1792b047ad78875bb", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 100001, + "sp_v0_info": "028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d96656803d431588dee61ab3a39725b299c3742dc66a0861decf591b423b0e527070f8234", + "sp_v0_label": 1, + "script": "512093da5eb927793623812550f8699d663b7196f0cc9d488458bb681feb2b6ffcba" + }, + { + "output_index": 1, + "amount": 190002, + "sp_v0_info": "028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568032193ad0c875fac5243738022900a7724c6175ddac9944165aab457aadf9c4f3c", + "sp_v0_label": 2, + "script": "5120fdebae2878b92423d17d74f4cc140e1e998005978d71c183139280405e30e406" + }, + { + "output_index": 2, + "amount": 100002, + "sp_v0_info": "028b790e0987fde9f0d12398eb6be30c7376793c647865a2a02f2efc960d966568032193ad0c875fac5243738022900a7724c6175ddac9944165aab457aadf9c4f3c", + "sp_v0_label": 2, + "script": "5120f4e30636e48f6a7afe984fa0b2545b257eaae8caa16ec48193db34892695875b" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: two inputs using per-input ECDH shares - only eligible inputs contribute shares (P2SH excluded)", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIHX/+DN7oavaEJzJjnIcVUgz9mY0VLyglR21zhcuA3LjAiAFXY5F4lr2Gu+QPcbwd9LpuW0Ut5Op7+w5K5bqn1Hf7gEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABDiDSIiYvJocpu3yExVgSml1phhhc71NewUnA32DdSpLCBAEPBAAAAAABAFMCAAAAAUDm+qYSaPF6EBAdYlU1gogq5IWL7hM2PbgP3ygfgl/8AAAAAAD/////AfBJAgAAAAAAF6kU9F+MyiaOwm5LvomRcPE4JQ189V6HAAAAAAEER1IhAod8oC8UQFm9gtAOGzma43T3ilLO96HKN/KNeIs0DS95IQNMh6RIcvXh8AbTTYigCVkoK9RTXnR3w9aMMWWZHqGzllKuARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQJii2i2RG5qhwJZc9k6+xlOQgoQ86HMs4rdgtRkqJSkKCIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQMIkF8BAAAAAAABBCJRIBZV0TJCpxR530ke2cObPHWqWxzY0Ba/jLNUp013dB3eAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf473044022075fff8337ba1abda109cc98e721c554833f6663454bca0951db5ce172e0372e30220055d8e45e25af61aef903dc6f077d2e9b96d14b793a9efec392b96ea9f51dfee0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010e20d222262f268729bb7c84c558129a5d6986185cef535ec149c0df60dd4a92c204010f0400000000010053020000000140e6faa61268f17a10101d62553582882ae4858bee13363db80fdf281f825ffc0000000000ffffffff01f04902000000000017a914f45f8cca268ec26e4bbe899170f138250d7cf55e8700000000010447522102877ca02f144059bd82d00e1b399ae374f78a52cef7a1ca37f28d788b340d2f7921034c87a44872f5e1f006d34d88a00959282bd4535e7477c3d68c3165991ea1b39652ae011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682102628b68b6446e6a87025973d93afb194e420a10f3a1ccb38add82d464a894a428221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010308905f01000000000001042251201655d13242a71479df491ed9c39b3c75aa5b1cd8d016bf8cb354a74d77741dde010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 1, + "private_key": "", + "public_key": "", + "prevout_txid": "04c2924add60dfc049c15e53ef5c1886695d9a1258c5847cbb2987262f2622d2", + "prevout_index": 0, + "amount": 150000, + "non_witness_utxo": "020000000140e6faa61268f17a10101d62553582882ae4858bee13363db80fdf281f825ffc0000000000ffffffff01f04902000000000017a914f45f8cca268ec26e4bbe899170f138250d7cf55e8700000000", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "51201655d13242a71479df491ed9c39b3c75aa5b1cd8d016bf8cb354a74d77741dde" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: two inputs using global ECDH share - only eligible inputs contribute shares (P2SH excluded)", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBACIHAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIIAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQCQwR50toTEKAk0qq45Me0nXbNUfRe6BJ8FZsDk6Z1tvdcWB6+PQgX3a87tZjP16Ai8ah+1HlmT2uUekfbWUHLIAAQ4g907dH3W0uz5ddJwVv9tmNI9oBam01F/u4aLiAfUDu3EBDwQAAAAAAQEfoIYBAAAAAAAWABQeKteHLTKUE6Vt8JaL4zgiJ4MWOyICAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/RzBEAiB1//gze6Gr2hCcyY5yHFVIM/ZmNFS8oJUdtc4XLgNy4wIgBV2OReJa9hrvkD3G8HfS6bltFLeTqe/sOSuW6p9R3+4BIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////AAEOINIiJi8mhym7fITFWBKaXWmGGFzvU17BScDfYN1KksIEAQ8EAAAAAAEAUwIAAAABQOb6phJo8XoQEB1iVTWCiCrkhYvuEzY9uA/fKB+CX/wAAAAAAP////8B8EkCAAAAAAAXqRT0X4zKJo7Cbku+iZFw8TglDXz1XocAAAAAAQRHUiECh3ygLxRAWb2C0A4bOZrjdPeKUs73oco38o14izQNL3khA0yHpEhy9eHwBtNNiKAJWSgr1FNedHfD1owxZZkeobOWUq4BEAT+////AAEDCJBfAQAAAAAAAQQiUSAWVdEyQqcUed9JHtnDmzx1qlsc2NAWv4yzVKdNd3Qd3gEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb0402000000010204020000000104010201050101010601002207027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b2208027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068402430479d2da1310a024d2aab8e4c7b49d76cd51f45ee8127c159b0393a675b6f75c581ebe3d0817ddaf3bb598cfd7a022f1a87ed479664f6b947a47db5941cb200010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf473044022075fff8337ba1abda109cc98e721c554833f6663454bca0951db5ce172e0372e30220055d8e45e25af61aef903dc6f077d2e9b96d14b793a9efec392b96ea9f51dfee01220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff00010e20d222262f268729bb7c84c558129a5d6986185cef535ec149c0df60dd4a92c204010f0400000000010053020000000140e6faa61268f17a10101d62553582882ae4858bee13363db80fdf281f825ffc0000000000ffffffff01f04902000000000017a914f45f8cca268ec26e4bbe899170f138250d7cf55e8700000000010447522102877ca02f144059bd82d00e1b399ae374f78a52cef7a1ca37f28d788b340d2f7921034c87a44872f5e1f006d34d88a00959282bd4535e7477c3d68c3165991ea1b39652ae011004feffffff00010308905f01000000000001042251201655d13242a71479df491ed9c39b3c75aa5b1cd8d016bf8cb354a74d77741dde010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 1, + "private_key": "", + "public_key": "", + "prevout_txid": "04c2924add60dfc049c15e53ef5c1886695d9a1258c5847cbb2987262f2622d2", + "prevout_index": 0, + "amount": 150000, + "non_witness_utxo": "020000000140e6faa61268f17a10101d62553582882ae4858bee13363db80fdf281f825ffc0000000000ffffffff01f04902000000000017a914f45f8cca268ec26e4bbe899170f138250d7cf55e8700000000", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "2430479d2da1310a024d2aab8e4c7b49d76cd51f45ee8127c159b0393a675b6f75c581ebe3d0817ddaf3bb598cfd7a022f1a87ed479664f6b947a47db5941cb2" + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "51201655d13242a71479df491ed9c39b3c75aa5b1cd8d016bf8cb354a74d77741dde" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: two mixed input types - only eligible inputs contribute ECDH shares (NUMS internal key excluded)", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBAAABDiBgF7WQD5i+njptfZytOQKM6tP1ITmnodnsV2k+vmyaowEPBAAAAAABASsQJwAAAAAAACJRIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAARAE/v///wEXIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAAAEOIOdsAXEIOkxftK/i9tYfAKRzAbnQH40uR3gKt1QuN3wIAQ8EAAAAAAEBH6CGAQAAAAAAFgAUNyH6c8IwXLL4joSJLWvWuXcmHmoiAgJDoNQOneCIJ5QWF1K65CupCVJ4QgnwY0MPCvJWNUqFu0gwRQIhAO0WpquzlGlzstbNkuuIIEIYnLRxCQgyQW7wr3v6HSWoAiA1FLIzGTu4Yav6kSdimxf0vM37oWNLD/S2liY86GL7RQEBAwQBAAAAIgYCQ6DUDp3giCeUFhdSuuQrqQlSeEIJ8GNDDwryVjVKhbsIAAAAgAEAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghAuV6etywGNj7MVToDBS5elCZS0I1aEHqn8ExcGFEAOY3Ih4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhA9/o4HeILO0WcbkJsYhPUF1MI8kgqROMyhCMmJNTa/Vcymb868WqzAsViY2OjfUSHB/fnoevqBke8zUhiA7srpgABAwgcJQAAAAAAAAEEIlEgPyxAG2oKe3La4XJhY5bRV7fyUUpeQT24CXc2wsuWezYBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501010106010000010e206017b5900f98be9e3a6d7d9cad39028cead3f52139a7a1d9ec57693ebe6c9aa3010f040000000001012b102700000000000022512050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0011004feffffff01172050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac000010e20e76c0171083a4c5fb4afe2f6d61f00a47301b9d01f8d2e47780ab7542e377c08010f040000000001011fa0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a22020243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb483045022100ed16a6abb3946973b2d6cd92eb882042189cb471090832416ef0af7bfa1d25a802203514b233193bb861abfa9127629b17f4bccdfba1634b0ff4b696263ce862fb45010103040100000022060243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb080000008001000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682102e57a7adcb018d8fb3154e80c14b97a50994b42356841ea9fc13170614400e637221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06840f7fa381de20b3b459c6e426c6213d4175308f2482a44e33284232624d4dafd573299bf3af16ab302c5626363a37d448707f7e7a1ebea0647bccd486203bb2ba6000103081c2500000000000001042251203f2c401b6a0a7b72dae172616396d157b7f2514a5e413db8097736c2cb967b36010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "a39a6cbe3e6957ecd9a1a73921f5d3ea8c0239ad9c7d6d3a9ebe980f90b51760", + "prevout_index": 0, + "amount": 10000, + "non_witness_utxo": "020000000113f106b64b57b5b1376f9f6c47190f40cc06b3bedcb8aaba97850ab3d7f67d020000000000ffffffff01102700000000000022512050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac000000000", + "witness_utxo": "102700000000000022512050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 1, + "private_key": "586b0810bbc3c7266971aeb7f8778b41707e092a1aeaf0d953b211f956e35541", + "public_key": "0243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "prevout_txid": "087c372e54b70a78472e8d1fd0b90173a4001fd6f6e2afb45f4c3a0871016ce7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01a0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a00000000", + "witness_utxo": "a0860100000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "02e57a7adcb018d8fb3154e80c14b97a50994b42356841ea9fc13170614400e637", + "dleq_proof": "f7fa381de20b3b459c6e426c6213d4175308f2482a44e33284232624d4dafd573299bf3af16ab302c5626363a37d448707f7e7a1ebea0647bccd486203bb2ba6", + "input_index": 1 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 9500, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "51203f2c401b6a0a7b72dae172616396d157b7f2514a5e413db8097736c2cb967b36" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: three sp outputs (same scan key) - each output has distinct k value", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEEAQYBAAABDiBw4GuGVZXEwnMdM/WmrSgPuHA1VGZimIDKXc2OkAfhmgEPBAAAAAABAR+AGgYAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIH2bvrz6uqFt0Kqa+PjltDT3VIfbiiHm1QtEnjAT9WsrAiAlq8iYSKvhCgxaq6TPG5n553yKIkS2xy6zrFdRfncXuAEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwighgEAAAAAAAEEIlEgpL1hojWVPFX7Ib8SF+ZZlw+BcVUweVNwtqhuui4/buABCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkAAQMIoIYBAAAAAAABBCJRIEZ7FHQz3K03MqLFl4fZe6tlntq7U2+lo3EHQLVhS4t1AQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AAEDCKCGAQAAAAAAAQQiUSCkZ5TVNLTq9lSGWuFY2oR7xga4HYq3jhMySv5KWUnbhQEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQABAwiQXwEAAAAAAAEEIlEgee9WiKP6f+/DkidFWx8cLwjHAIdCTWoA+EwxQhrKjaQA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501040106010000010e2070e06b865595c4c2731d33f5a6ad280fb870355466629880ca5dcd8e9007e19a010f040000000001011f801a0600000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402207d9bbebcfabaa16dd0aa9af8f8e5b434f75487db8a21e6d50b449e3013f56b2b022025abc89848abe10a0c5aaba4cf1b99f9e77c8a2244b6c72eb3ac57517e7717b80101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010308a0860100000000000104225120a4bd61a235953c55fb21bf1217e659970f81715530795370b6a86eba2e3f6ee0010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900010308a0860100000000000104225120467b147433dcad3732a2c59787d97bab659edabb536fa5a3710740b5614b8b75010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900010308a0860100000000000104225120a46794d534b4eaf654865ae158da847bc606b81d8ab78e13324afe4a5949db85010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900010308905f010000000000010422512079ef5688a3fa7fefc39227455b1f1c2f08c70087424d6a00f84c31421aca8da400", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "9ae107908ecd5dca80986266543570b80f28ada6f5331d73c2c49555866be070", + "prevout_index": 0, + "amount": 400000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01801a0600000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "801a0600000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 100000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120a4bd61a235953c55fb21bf1217e659970f81715530795370b6a86eba2e3f6ee0" + }, + { + "output_index": 1, + "amount": 100000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120467b147433dcad3732a2c59787d97bab659edabb536fa5a3710740b5614b8b75" + }, + { + "output_index": 2, + "amount": 100000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120a46794d534b4eaf654865ae158da847bc606b81d8ab78e13324afe4a5949db85" + }, + { + "output_index": 3, + "amount": 90000, + "script": "512079ef5688a3fa7fefc39227455b1f1c2f08c70087424d6a00f84c31421aca8da4" + } + ], + "task": "sign" + } + }, + { + "description": "can finalize: three sp outputs (same scan key) / two regular outputs - k values assigned independently of output index", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEGAQYBAAABDiDUQOda/N1TGlkeN6vSbkryvw9v8uGRgwI1Yej8VxOPSgEPBAAAAAABAR8goQcAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCICcgzDtRc5g6XoCKbBZuU04tEOEjpGhrAqg+sdM9G3B6AiBdslMBO2N4nLRYrOIxjHkT9mvR6OIXHye1MrEw+uWDNQEBAwQBAAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwighgEAAAAAAAEEIlEgcjuJtcY4edW50HowRRu91I43rAOOZvcm83ykCrJkq3IBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkAAQMIUMMAAAAAAAABBCJRIJxqPSOBjoIO0dDP3rljZXyOwyd7fZuGXHjXVX9d7daiAAEDCKCGAQAAAAAAAQQiUSCvFHbuA/XpiJDsVJYDYaxJHFbjCpPrKYD8MiuYN6dYugEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQABAwhQwwAAAAAAAAEEIlEgee9WiKP6f+/DkidFWx8cLwjHAIdCTWoA+EwxQhrKjaQAAQMIoIYBAAAAAAABBCJRIJ5nNdGxGWsLGu/g5NEOytKTdJZLn1mSBdF8qrYcp4VFAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AAEDCMgsAQAAAAAAAQQiUSBvxQb4BSqfWoqpuZDV6ZT0ld3tbUe6xEyqza3Y2Jkc0AA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501060106010000010e20d440e75afcdd531a591e37abd26e4af2bf0f6ff2e19183023561e8fc57138f4a010f040000000001011f20a10700000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402202720cc3b5173983a5e808a6c166e534e2d10e123a4686b02a83eb1d33d1b707a02205db253013b63789cb458ace2318c7913f66bd1e8e2171f27b532b130fae583350101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010308a0860100000000000104225120723b89b5c63879d5b9d07a30451bbdd48e37ac038e66f726f37ca40ab264ab72010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce0390001030850c300000000000001042251209c6a3d23818e820ed1d0cfdeb963657c8ec3277b7d9b865c78d7557f5dedd6a200010308a0860100000000000104225120af1476ee03f5e98890ec54960361ac491c56e30a93eb2980fc322b9837a758ba010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce0390001030850c3000000000000010422512079ef5688a3fa7fefc39227455b1f1c2f08c70087424d6a00f84c31421aca8da400010308a08601000000000001042251209e6735d1b1196b0b1aefe0e4d10ecad29374964b9f599205d17caab61ca78545010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900010308c82c01000000000001042251206fc506f8052a9f5a8aa9b990d5e994f495dded6d47bac44caacdadd8d8991cd000", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "4a8f1357fce86135028391e1f26f0fbff24a6ed2ab371e591a53ddfc5ae740d4", + "prevout_index": 0, + "amount": 500000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff0120a10700000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "20a10700000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 100000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120723b89b5c63879d5b9d07a30451bbdd48e37ac038e66f726f37ca40ab264ab72" + }, + { + "output_index": 1, + "amount": 50000, + "script": "51209c6a3d23818e820ed1d0cfdeb963657c8ec3277b7d9b865c78d7557f5dedd6a2" + }, + { + "output_index": 2, + "amount": 100000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120af1476ee03f5e98890ec54960361ac491c56e30a93eb2980fc322b9837a758ba" + }, + { + "output_index": 3, + "amount": 50000, + "script": "512079ef5688a3fa7fefc39227455b1f1c2f08c70087424d6a00f84c31421aca8da4" + }, + { + "output_index": 4, + "amount": 100000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "51209e6735d1b1196b0b1aefe0e4d10ecad29374964b9f599205d17caab61ca78545" + }, + { + "output_index": 5, + "amount": 77000, + "script": "51206fc506f8052a9f5a8aa9b990d5e994f495dded6d47bac44caacdadd8d8991cd0" + } + ], + "task": "sign" + } + }, + { + "description": "in progress: two P2TR inputs, neither is signed", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBAAABDiDiYfrxyOMpNDlULSpad+W66m8QMFi8FfyycqjakMbjzQEPBAAAAAABAStADQMAAAAAACJRIMgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/AQMEAQAAAAEQBP7///8BFyDIF7t1Ia/DXqlvO/snDm61Dd/6VWBie5Yf7ADymWUIvyIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQ4giCh0OW239Sen4z00WqO4+1UfjMVFKfg7vOT9davhuskBDwQAAAAAAQErECcAAAAAAAAiUSBDoNQOneCIJ5QWF1K65CupCVJ4QgnwY0MPCvJWNUqFuwEDBAEAAAABEAT+////ARcgQ6DUDp3giCeUFhdSuuQrqQlSeEIJ8GNDDwryVjVKhbsiHQJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaCEC5Xp63LAY2PsxVOgMFLl6UJlLQjVoQeqfwTFwYUQA5jciHgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaED3+jgd4gs7RZxuQmxiE9QXUwjySCpE4zKEIyYk1Nr9VzKZvzrxarMCxWJjY6N9RIcH9+eh6+oGR7zNSGIDuyumAAEDCLj5AgAAAAAAAQQiUSDuvwDmhUt84x4LCQCf5zbeTa0t0Hk6nrKLDm+jAO2+FAEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501010106010000010e20e261faf1c8e3293439542d2a5a77e5baea6f103058bc15fcb272a8da90c6e3cd010f040000000001012b400d030000000000225120c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf01030401000000011004feffffff011720c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010e20882874396db7f527a7e33d345aa3b8fb551f8cc54529f83bbce4fd75abe1bac9010f040000000001012b102700000000000022512043a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb01030401000000011004feffffff01172043a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682102e57a7adcb018d8fb3154e80c14b97a50994b42356841ea9fc13170614400e637221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe06840f7fa381de20b3b459c6e426c6213d4175308f2482a44e33284232624d4dafd573299bf3af16ab302c5626363a37d448707f7e7a1ebea0647bccd486203bb2ba600010308b8f90200000000000104225120eebf00e6854b7ce31e0b09009fe736de4dad2dd0793a9eb28b0e6fa300edbe14010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "cde3c690daa872b2fc15bc5830106feabae5775a2a2d54393429e3c8f1fa61e2", + "prevout_index": 0, + "amount": 200000, + "non_witness_utxo": "020000000113f106b64b57b5b1376f9f6c47190f40cc06b3bedcb8aaba97850ab3d7f67d020000000000ffffffff01400d030000000000225120c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf00000000", + "witness_utxo": "400d030000000000225120c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 1, + "private_key": "586b0810bbc3c7266971aeb7f8778b41707e092a1aeaf0d953b211f956e35541", + "public_key": "0243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "prevout_txid": "c9bae1ab75fde4bc3bf82945c58c1f55fbb8a35a343de3a727f5b76d39742888", + "prevout_index": 0, + "amount": 10000, + "non_witness_utxo": "02000000012b9037ff41dd174e5522f0f4045c3f40436232af2600d4da5c9ea13cc3cab4b50000000000ffffffff01102700000000000022512043a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb00000000", + "witness_utxo": "102700000000000022512043a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + }, + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "02e57a7adcb018d8fb3154e80c14b97a50994b42356841ea9fc13170614400e637", + "dleq_proof": "f7fa381de20b3b459c6e426c6213d4175308f2482a44e33284232624d4dafd573299bf3af16ab302c5626363a37d448707f7e7a1ebea0647bccd486203bb2ba6", + "input_index": 1 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 195000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120eebf00e6854b7ce31e0b09009fe736de4dad2dd0793a9eb28b0e6fa300edbe14" + } + ], + "task": "fail_sign" + } + }, + { + "description": "in progress: one P2TR input / one sp output with no ECDH shares when PSBT_OUT_SCRIPT field is not set", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiCjwqvtvpEx1eOGV4Vg1H42ikDZqyYJ2yCkecMEsGRTbAEPBAAAAAABASughgEAAAAAACJRIMgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/ARAE/v///wEXIMgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/AAEDCBhzAQAAAAAAAQlCAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoA2HhseneXkLLIAf3ylS54NV+0Tk4+tVtPxnldROo/OA5AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20a3c2abedbe9131d5e386578560d47e368a40d9ab2609db20a479c304b064536c010f040000000001012ba086010000000000225120c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf011004feffffff011720c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf000103081873010000000000010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "6c5364b004c379a420db0926abd9408a367ed460855786e3d53191beedabc2a3", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000113f106b64b57b5b1376f9f6c47190f40cc06b3bedcb8aaba97850ab3d7f67d020000000000ffffffff01a086010000000000225120c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf00000000", + "witness_utxo": "a086010000000000225120c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039" + } + ], + "task": "fail_sign" + } + }, + { + "description": "in progress: two inputs / one sp output, input 1 missing ECDH share when PSBT_OUT_SCRIPT field is not set", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQIBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoIQPspP8Rtyji4PYM5iIpQ6b/VbnZX2J7+amdCEvIctUKWyIeAnpIf8Gft2mHe4dC1uoYEY88TnKx6oxt5gKnrUpB2+BoQIoTs5hVRfcr1uiXFK65CbPjVKhCqbuLVs0O3tId+KGZWYsxIopJ4L1+lc4QU/fFsorLVDpocHYA486Jgi7jICEAAQ4gSQv/chrf7ISJdgPfb7uyrbjEZTqaQrLW0VICyiQN4LEBDwQAAAAAAQEf8EkCAAAAAAAWABQ3IfpzwjBcsviOhIkta9a5dyYeaiIGAkOg1A6d4IgnlBYXUrrkK6kJUnhCCfBjQw8K8lY1SoW7CAAAAIABAAAAARAE/v///wABAwhADQMAAAAAAAEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040102010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b01030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee3202100010e20490bff721adfec84897603df6fbbb2adb8c4653a9a42b2d6d15202ca240de0b1010f040000000001011ff0490200000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a22060243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb080000008001000000011004feffffff00010308400d030000000000010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 1, + "private_key": "586b0810bbc3c7266971aeb7f8778b41707e092a1aeaf0d953b211f956e35541", + "public_key": "0243a0d40e9de0882794161752bae42ba90952784209f063430f0af256354a85bb", + "prevout_txid": "b1e00d24ca0252d1d6b2429a3a65c4b8adb2bb6fdf03768984ecdf1a72ff0b49", + "prevout_index": 0, + "amount": 150000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01f0490200000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a00000000", + "witness_utxo": "f0490200000000001600143721fa73c2305cb2f88e84892d6bd6b977261e6a", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 200000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039" + } + ], + "task": "fail_sign" + } + }, + { + "description": "in progress: one input / two sp outputs, input 0 missing ECDH share for output 0 when PSBT_OUT_SCRIPT field is not set", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQECAQYBAAABDiD9LfT1i1q/m5H/Gh5D4uNSP1DGqhnVwiNgFB7EjJqAIQEPBAAAAAABAR9ADQMAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7AQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdA1LXjEE5ADKtkYFqaX/HQNjrkJzwTXCIUmSwUfI4XiXsIQMJH9SAORd/RNe3npYWiEnGLrP4eADEZ2fFCo84+Y79FSIeA1LXjEE5ADKtkYFqaX/HQNjrkJzwTXCIUmSwUfI4XiXsQL4acjrvVeiYG5lZmpvBKzj4froBWMxwZokPImnK3kY7dzQal9KScZZNAcAkHMMi/VOQwpuZFg+CbzKTZYmMvwIAAQMIkF8BAAAAAAABCUIDZR0sBz/LAqTYLdpT8dUB13oDUGZnmFRkc7ISa2zRp94D8nDgpWMhg7arAQdOh35oANsA9cfF0vr7to+cKNSFRSQAAQMIkF8BAAAAAAABBCJRIGMlBrk4zY0hMZ/eTlk5KyP5juuXb0OS1jPxg+Iut/qxAQlCA1LXjEE5ADKtkYFqaX/HQNjrkJzwTXCIUmSwUfI4XiXsAuDEwYe3IV+ZfISFp1tFkbbChHe5WhEjuZaSLTFUhgv4AA==", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501020106010000010e20fd2df4f58b5abf9b91ff1a1e43e2e3523f50c6aa19d5c22360141ec48c9a8021010f040000000001011f400d0300000000001600141e2ad7872d329413a56df0968be338222783163b01030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d0352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec2103091fd48039177f44d7b79e96168849c62eb3f87800c46767c50a8f38f98efd15221e0352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec40be1a723aef55e8981b99599a9bc12b38f87eba0158cc7066890f2269cade463b77341a97d29271964d01c0241cc322fd5390c29b99160f826f329365898cbf0200010308905f01000000000001094203651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de03f270e0a5632183b6ab01074e877e6800db00f5c7c5d2fafbb68f9c28d485452400010308905f0100000000000104225120632506b938cd8d21319fde4e59392b23f98eeb976f4392d633f183e22eb7fab10109420352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec02e0c4c187b7215f997c8485a75b4591b6c28477b95a1123b996922d3154860bf800", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "21809a8cc41e146023c2d519aac6503f52e3e2431e1aff919bbf5a8bf5f42dfd", + "prevout_index": 0, + "amount": 200000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01400d0300000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "400d0300000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": false + } + ], + "sp_proofs": [ + { + "scan_key": "0352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec", + "ecdh_share": "03091fd48039177f44d7b79e96168849c62eb3f87800c46767c50a8f38f98efd15", + "dleq_proof": "be1a723aef55e8981b99599a9bc12b38f87eba0158cc7066890f2269cade463b77341a97d29271964d01c0241cc322fd5390c29b99160f826f329365898cbf02", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 90000, + "sp_v0_info": "03651d2c073fcb02a4d82dda53f1d501d77a0350666798546473b2126b6cd1a7de03f270e0a5632183b6ab01074e877e6800db00f5c7c5d2fafbb68f9c28d4854524" + }, + { + "output_index": 1, + "amount": 90000, + "sp_v0_info": "0352d78c41390032ad91816a697fc740d8eb909cf04d70885264b051f2385e25ec02e0c4c187b7215f997c8485a75b4591b6c28477b95a1123b996922d3154860bf8", + "script": "5120632506b938cd8d21319fde4e59392b23f98eeb976f4392d633f183e22eb7fab1" + } + ], + "task": "fail_sign" + } + }, + { + "description": "in progress: large PSBT with nine mixed inputs / six outputs - some inputs signed", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQkBBQEGAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQDPsSEeWDjGsF0FsZcQLy2uWTOEkfcPouMzyf2guy63mwIgK43jFBV2xpxTFxI5xIUrAwMXmVJigEm+buytVQUsBw0BAQMEAQAAACIGAsgXu3Uhr8NeqW87+ycObrUN3/pVYGJ7lh/sAPKZZQi/CAAAAIAAAAAAARAE/v///yIdAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQIQP70XPZxI1YxQIkJtBSeLyhe5qOIoJmaQGhsAueBLeZSSIdAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oIQMKGLm7QZm4kzDrF/juWseG4IU9zS88zfF0S5fOTt4FPiIdA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsIQNzctF59PYo2oLMvU5CF72wgJ8UF8mr6qNfqAXUitZVTCIeAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQQMBdpBBIfPrsN4/r5q9QBeOubIYjaBiw5VshQBfrUHPt70AXlXW13NqpBjSRrIuD/QYk1Bd6TS3UmUxGQNa4zN4iHgMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKEAAE4PUZhvocl7ykEj0jJEfifXzQxfXwMCsxg72XxtSv/96ltgzm2Jd+Dq6tXqic+3NmjXHlNrLschhFxuyZwdfIh4DjtMiDnM0T5Hi0zOR4+FpHbOdrwbkI34ZftDQB78nKGxApoctTrEZ/ir3CVP3UqIiNrVKO1f3DlEfEL2LQv9Wtaz2NlCTxIDqnxN3Z4SUW1kxisKSfZFariRM+2g/QYijpwABDiC81IWnCcsl0TRjoYMtshlMbJ2f5yuWmfT+Qsgr7ZPTJgEPBAAAAAABAR+ghgEAAAAAABYAFKaSURwHlXW/N1bavFatcdQoSmkOIgIC9bWfpeSSIh6/Vbp4rUQmBb6ulRZroeujJQ0Luqx+LtxIMEUCIQC7sLCEPmrqB9GNzaIgk7pzNnmDsVkzvfhDAPYN68qVDQIgUOXw9VOPcUnkj83kJzV7wSrw5/GGCKI2Wc+JFyequ4wBAQMEAQAAACIGAvW1n6XkkiIev1W6eK1EJgW+rpUWa6HroyUNC7qsfi7cCAAAAIABAAAAARAE/v///yIdAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQIQOmqJsbmGqZVTPhe+1kUAtUG7DXOQce/irit++woMprzyIdAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oIQL2rnuKrJoPnJ8E6rSEBiFy3y442fL27DG0BLtaKGqr8CIdA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsIQKx0+0vpLwxagjrFIX6de191Uynqa4Y0MShfak/MMOF1SIeAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQQMNKailAu+mnNWwcxv/jWN1EQdtYiXy6mcIS63UoXn2h7KEceSyXo4BJM0WrIk3p2UwrNu6FJq4jUoFxoyMd5zMiHgMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKEAzSs7YEG66pCh9rKVsyiZ5Xy0qc5eEz2tzTaM3B1f0meEgwOQL5AQ2zXTE7yaQVwb1L6f6bo52RR6Fg3gwUahDIh4DjtMiDnM0T5Hi0zOR4+FpHbOdrwbkI34ZftDQB78nKGxA2EGjc60olrlyuM/qFjT/FKMPgNhM/W7xiJM5e480bIBRnJsWGnIkTQ6bZOVDbJjOndThegco/Jl7XHvPOc7LaAABDiCinXdnRAJ1ylMq9gkfClxWMpiVAg07C9iK/0O0EyAjnAEPBAAAAAABAR+ghgEAAAAAABYAFNTckD9xFmAu41jsjt8yhOb/ApTjIgICZV712vBdKNHKc7qOIRMA2ytwQWc3GD4PqMNV7kwcusZIMEUCIQDMZVDw0zT3jRg/6hCny3T0bylQTZHSj9+tDnBeG3/w5wIgbhv+u1VdOe9VpkOd+1vFdXlP/enJDrZtAgpqd8U9MFUBAQMEAQAAACIGAmVe9drwXSjRynO6jiETANsrcEFnNxg+D6jDVe5MHLrGCAAAAIACAAAAARAE/v///yIdAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQIQPfcG/ybWcv5QxvVqLKHnF051BVySC70zfhp9a/KCb23CIdAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oIQO/uGJTvrlvWLjEaeRCz8+feKVBOpVCO+jmhnZPL6e9PyIdA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsIQOGBKqM/zCd3fSbHzZvicJpYWWH/EHbYIVA+UMVNvZkbyIeAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQQP0ujCK5tnLTu54m1LbaLcPxJUValp/Y4rLBunkQdq1xs4wB+SGMPWd2/YldLzBnSEmW2F4mg5DCtDPmxLIYkfEiHgMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKEBS3/vwCV8psd4kydaNVJ0cVLzmkARU/jf9EPXJA9/uhfe62Kcq2o5SzZCS9R2ekLWn5PNsoE35jnf7rRNHMFvHIh4DjtMiDnM0T5Hi0zOR4+FpHbOdrwbkI34ZftDQB78nKGxAk+Hl1IiLwc/gLuz6neoUTq2E8joQ/BowEQPB5WOTUntjQXxsSlr0U1n/i24Xmvc5eOTWLoYu7dKihvUnjkyzQAABDiAef87nvuWNqIGXxAlZpi4GA4Ca3jUTdJPfLPqPhVMEuwEPBAAAAAABAR+ghgEAAAAAABYAFPttCN+xTwAdyYzxfE1zIrB78HVPIgIDA6D0Uo0mTo6VJWY0uUQU4nSPcpYnBP5X6LCizETSOD1HMEQCIAi72DwAjm0U50qpHe/MnQa/WaeO+rZDQR8+A5ni4qwUAiAG4W2T0g2pLx02QToI540N1Rlf4c7KbZeIcAVchNhUtQEBAwQBAAAAIgYDA6D0Uo0mTo6VJWY0uUQU4nSPcpYnBP5X6LCizETSOD0IAAAAgAMAAAABEAT+////Ih0CqfH6wsxFdoTzPekAc/4g0iyUfJIWO4YrFNCrod9HFRAhA4ApmYxzwrE523VVfsMBHsZezSEkR5YwBlcYUqPpIonMIh0DM2HT/3LzTmtOenvvluW4FR5mqXmtznU8OcWDy+V2bSghApgLrHJk4Uv4IMxDW2mnjfcmwXfrAm8bgbUt6BEnL1jrIh0DjtMiDnM0T5Hi0zOR4+FpHbOdrwbkI34ZftDQB78nKGwhA6J9nx+lPkP3CDWmmQlUt4o190cGb3uCtKnqgui7XgamIh4CqfH6wsxFdoTzPekAc/4g0iyUfJIWO4YrFNCrod9HFRBAOBzjwayfx/alFTZFYlKYR2jo+9AUBwI59MsTsWeTx0zF7Wd8in6swXPpiNNTo/KJx+IUHbektBRcVJnsg382riIeAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oQDjgNGO2RQ29BRBlqBKm8mMQh/eVHkashOZtqBF1VxfAkxgOTUmCe4wJfKcJP+ktOT+VpdethJpBgC3E5FWKvekiHgOO0yIOczRPkeLTM5Hj4Wkds52vBuQjfhl+0NAHvycobEBzKqCVep2yx1njmspdAWfvE9KjSkPIEunMnXEtRY97IoXadRHrFvYflgDSC+TpTf3SvDrjf9lD/DSUffw/3GeXAAEOINMRWt3++6Md33GrVWfUNcxY9IBtRfqGWosHDsn4dBkHAQ8EAAAAAAEBH6CGAQAAAAAAFgAUCxhF9MgNq+LF3IpWf75BCnjkhsgiAgOokRvrWkj+EZywFQiM8MOhGM8CZ3JEiXLRtwx2SsWUEkcwRAIgTRryhJDWSySTB6X6BGrX0MxpiRmEGhxjFyRgTjuTNpACICR5P8a+ewoj0+3S/3H3m+RPWX0EPrNpodbKkpFYS6/DAQEDBAEAAAAiBgOokRvrWkj+EZywFQiM8MOhGM8CZ3JEiXLRtwx2SsWUEggAAACABAAAAAEQBP7///8iHQKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVECECvvRzjG8yfxcksUB5iJWc3yvRkhCJS/0ENTW2ETgnCBgiHQMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKCECfrfBxK/NfmKratPSuiczo3RSIGQfkZA+v+e8xdvca10iHQOO0yIOczRPkeLTM5Hj4Wkds52vBuQjfhl+0NAHvycobCEDyoi8220fUpHpDHXT2mAai9KZkeq79/lLLzlIPjhYyaEiHgKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVEEAKWEknECggt7bK1rz7Axojo3MSrYfSPxy1qDWb4tX/Obaiov43zQ1T7jR/E+azUldpsueJ8GmcuYVYjqwtrxDdIh4DM2HT/3LzTmtOenvvluW4FR5mqXmtznU8OcWDy+V2bShAd7FXIzbZvU4vc0EeuPapYjWhMPREy+sHpIn0R5IeN0idcf09sooLuqNbiMN7dXns2/bOFjhwDbgd/Ia/ec0b5yIeA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsQF0N6KJ/DVKIAs8zVKGvUHvPD+1BnaZBycCAfNdU4Hr4eQtRHHBdX79jMFqyKv4El/rPBwta/q/O46aQBUd2d1YAAQ4gkJNrWGPf/YXCuMds0iGo3ur9Ur7bA0LgllLaI4W11w0BDwQAAAAAAQEroIYBAAAAAAAiUSDRVXE8Ugzi2CdhZCFdZZq2I8X3MG+GUsF1biaDPohuAQEDBAEAAAABEAT+////ARcg0VVxPFIM4tgnYWQhXWWatiPF9zBvhlLBdW4mgz6IbgEiHQKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVECECTyoVpLFaa3jwpjL8f98RKSn2S9TdFPZ6Y89PuPMlogQiHQMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKCEDgCtps2DaRYVRKxz5Z7GEAQIm11zlt2LnegEovLBozLsiHQOO0yIOczRPkeLTM5Hj4Wkds52vBuQjfhl+0NAHvycobCECQHYVUF7L3qiBMSUE7vb0aBomMW73PTNTen/Xk/RljqkiHgKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVEECPIj3ieYbdh5KgPZ1bZiMj6Gl4MOurtnNjiB/nLIZIKuYaCSaNCDuDVM/CutNcFI7rKRr2It1GBjRgYzKvG4KXIh4DM2HT/3LzTmtOenvvluW4FR5mqXmtznU8OcWDy+V2bShAEDrgXBDkMpg3bD/uHcXw0EOJ9PIK9JNG1I6tMk1hXW8o/KCjGERRMOpWqGIBmy3gwmN9s8QYwLB0tYVIrosgySIeA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsQPBVmQc4VE0JmxWSkOf1RCy5EiYmAXSqnYwcgxC3ywHOK5TMXSuP34FmfgL7eW2w5cJ4d94NQaKg5wmwFEW68pYAAQ4g+HkR+gM6As4X8pY2A85gV123O5qXR31IH3Iy2fCk4SMBDwQAAAAAAQEroIYBAAAAAAAiUSDQDhX7Ymp+/uhcW85nbWNrYEiRTpo0rOC0y8RLyUgHegEDBAEAAAABEAT+////ARcg0A4V+2Jqfv7oXFvOZ21ja2BIkU6aNKzgtMvES8lIB3oiHQKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVECECFT/N/paucDY/0VQmRtMJwhMrgyVUDj3X+I43+XlgeaYiHQMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKCECD6o6DDGudpXnaVRuMKp4Kr0x+2gblwoTqjXMId/ROAAiHQOO0yIOczRPkeLTM5Hj4Wkds52vBuQjfhl+0NAHvycobCED8xP49HXrAePOy8DqrC9ybSkDLG/3w61sw7+LsQGGUnwiHgKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVEEBDIOn2D9PCpvc3qs5UbCOwx9duhBWcCtKJwd9MD4pQDlEgnylvnX0iOh0pK9QdJm+qyxvoQ77PS3BusV26cCgGIh4DM2HT/3LzTmtOenvvluW4FR5mqXmtznU8OcWDy+V2bShA5AdKbsiT6rgG1d+adO0lfnhf83hkPbqnkzx4E6e19skMqCtiU585s4wscv5c+BwipeZB9nNkT2xIaz21d0ZEYyIeA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsQDsp4Sz2k/JyE590RS8rzMK80HQy3Oj7EHNUwUWKEqR8hUTS1soeM7zgV4tlCM+KWTRnP5/ENaX4SiKlS1rcvPwAAQ4gtjaLvDMM3f6eJVDtt9/BWudMrJvMfZZ/6B5vJ/hZex0BDwQAAAAAAQBTAgAAAAH+oU89FpsrBADbFJliIbMRgruehsoWnpG5x72T+cc+iAAAAAAA/////wGghgEAAAAAABepFA3xATV/c+ZlhQDPVvOhMte7ivvdhwAAAAABASCghgEAAAAAABepFA3xATV/c+ZlhQDPVvOhMte7ivvdhyICAgUA8WfPZp59rDnmrs2h8oxmt47HCX7v7yXVT3vnhef2RzBEAiBnUxh5GhdDzu+RXKUFJbWHHLbxGC0scTSYGTdzC1I75gIgAkCdeVIWIzw2VtZZyHbDwGJ3+gmQLlfPTlF1Mqh/ThcBAQMEAQAAAAEEFgAUxryBBexttgxNpTrDXNogQGnpDooiBgIFAPFnz2aefaw55q7NofKMZreOxwl+7+8l1U9754Xn9ggAAACABwAAAAEQBP7///8iHQKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVECEC/nhBzd+0b9ssqb3lbJVYwtGzYSFmVlkIAiTiQDFDhAgiHQMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKCECbwJ7I1p1k8qJQ8bXt+N9kuqzOWF/fww0QQbFjdDLxqoiHQOO0yIOczRPkeLTM5Hj4Wkds52vBuQjfhl+0NAHvycobCECBhFFDGwZROzey3j2GBbHZ/ukNo8h9+mxaXecdvI89MwiHgKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVEECIByVRZiw+6+5UXxiLja/Ggpc6LyGOfKB/yOQv9XoRNGMESf1wMXfXoS0MnO0CSETcG54OytZ1h91cR5Qxs2oaIh4DM2HT/3LzTmtOenvvluW4FR5mqXmtznU8OcWDy+V2bShAFrWBSPe6/3g+QxDxhVA/6SQX26Q7lmyDohhDIssfIEJMudBArmoa6k50RL3HhiWKl1ZEzhoBlVZMK5/DxgaikiIeA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsQEqza91p6xzQ1LCurkA9zk21Ioxbo6KR3HJd4jOC0XNtJl17wz+DaQpcpWCXGfGegZUtTI1eKI/Qy4xkERBLgKMAAQ4gA7zrpTedc9rq/md5crA9z37zC38Q6qg60EvAvwDYsvcBDwQAAAAAAQBVAgAAAAEqNKwbDbd6gZjB4pACzEe7/NbtgwlgME0smjq1SEhrXQAAAAAA/////wGghgEAAAAAABl2qRRWm/MR5oo4N2e0P4MELfq+YAk+3oisAAAAACICAxmdLxVfMuuxZ66wzMpuWvtzQImN8bermTZQD21DkZAqRzBEAiAH83qYp+oJ9hVEmj+ADfLsVcIzEc4rGkUXFuOeedHxLQIgUPVeeZ4r49ZwvGamjsliI+DR7jlgLkaNssx7Jch6puABAQMEAQAAACIGAxmdLxVfMuuxZ66wzMpuWvtzQImN8bermTZQD21DkZAqCAAAAIAIAAAAARAE/v///yIdAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQIQLzwXWwiyB2N2Fqp05nuqwaGAfJS85wgA929bF7UsAILSIdAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oIQL6HO2TJZiif6KEELlV6mdHm1pAM7afLJnk4mdnu6ClViIdA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsIQMA4P0XENxWrXwXOqkUHXMVdwCbw9/8uoV2pI53qzTZcCIeAqnx+sLMRXaE8z3pAHP+INIslHySFjuGKxTQq6HfRxUQQJkiVlj+3nqMJDfrOCG9ydNwCryJbottzvhOKTR7eLwrA+baM4NuT0B2c5DDZkTOAWs2sdVGljVA+lHQsEB9ttciHgMzYdP/cvNOa056e++W5bgVHmapea3OdTw5xYPL5XZtKECglIxRfXCXbA45ymer8Z5yFwQNvhcruWU0Ez5v+jlBwWWUFvVAZit1Ye+3AGS01xqbF7Y7xWP2MNtEIvJz4N8SIh4DjtMiDnM0T5Hi0zOR4+FpHbOdrwbkI34ZftDQB78nKGxA7gqqZcpzzMVHsxwrftKuMaT0zNrqc/Kt0kYw1gjt6a6l2AhogYbrykK4d++rE/NeYPIQ1PYgYC+FD8BzHCAekQABAwgwdQAAAAAAAAEEIlEgGvpdiBiM75uRs/EAKxHg+elK05gZeMTRKgYFVkwIEjMBCUIDM2HT/3LzTmtOenvvluW4FR5mqXmtznU8OcWDy+V2bSgDEmZYHj6EHLuU3mLqc1WDojLEyIj6bt7y7C+HB4n8HdQAAQMIMHUAAAAAAAABBCJRIMq/fkoN5CTsm7rdf3JCzOdnPhcB9J1qGalwVdozKxMkAQlCAzNh0/9y805rTnp775bluBUeZql5rc51PDnFg8vldm0oAxJmWB4+hBy7lN5i6nNVg6IyxMiI+m7e8uwvhweJ/B3UAAEDCCBOAAAAAAAAAQQiUSBKrcngpZDSHgwZyyAk8nFA+bGcKhKC1Q6nxfResD/UogEJQgKp8frCzEV2hPM96QBz/iDSLJR8khY7hisU0Kuh30cVEAJKSNduINQLz18uGlw//rPcKos7iNeaSG1UydnqqPoYjgABAwggTgAAAAAAAAEEIlEgL6Q3AOodKP161NyzMrPl5aDYy1Qlj2ZhxN4Dd9coBOUBCUICqfH6wsxFdoTzPekAc/4g0iyUfJIWO4YrFNCrod9HFRACSkjXbiDUC89fLhpcP/6z3CqLO4jXmkhtVMnZ6qj6GI4AAQMIECcAAAAAAAABBCJRIFGYb67jGUNrUbOECcGzAPQ5bisy48yaEq4qS+E12m9uAQlCA47TIg5zNE+R4tMzkePhaR2zna8G5CN+GX7Q0Ae/JyhsA/gUc4RMnXTJIf8Xpa9BC2M3NI16+/9ziRvFywyyTLDAAAEDCFDDAAAAAAAAAQQiUSBvxQb4BSqfWoqpuZDV6ZT0ld3tbUe6xEyqza3Y2Jkc0AA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040109010501060106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf483045022100cfb1211e5838c6b05d05b197102f2dae59338491f70fa2e333c9fda0bb2eb79b02202b8de3141576c69c53171239c4852b0303179952628049be6eecad55052c070d0101030401000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102103fbd173d9c48d58c5022426d05278bca17b9a8e2282666901a1b00b9e04b79949221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2821030a18b9bb4199b89330eb17f8ee5ac786e0853dcd2f3ccdf1744b97ce4ede053e221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c21037372d179f4f628da82ccbd4e4217bdb0809f1417c9abeaa35fa805d48ad6554c221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151040c05da410487cfaec378febe6af5005e3ae6c86236818b0e55b214017eb5073edef40179575b5dcdaa9063491ac8b83fd0624d4177a4d2dd4994c4640d6b8ccde221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2840001383d4661be8725ef29048f48c911f89f5f34317d7c0c0acc60ef65f1b52bfff7a96d8339b625df83abab57aa273edcd9a35c794dacbb1c861171bb267075f221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c40a6872d4eb119fe2af70953f752a22236b54a3b57f70e511f10bd8b42ff56b5acf6365093c480ea9f13776784945b59318ac2927d915aae244cfb683f4188a3a700010e20bcd485a709cb25d13463a1832db2194c6c9d9fe72b9699f4fe42c82bed93d326010f040000000001011fa086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e220202f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc483045022100bbb0b0843e6aea07d18dcda22093ba73367983b15933bdf84300f60debca950d022050e5f0f5538f7149e48fcde427357bc12af0e7f18608a23659cf891727aabb8c0101030401000000220602f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc080000008001000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102103a6a89b1b986a995533e17bed64500b541bb0d739071efe2ae2b7efb0a0ca6bcf221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d282102f6ae7b8aac9a0f9c9f04eab484062172df2e38d9f2f6ec31b404bb5a286aabf0221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c2102b1d3ed2fa4bc316a08eb1485fa75ed7dd54ca7a9ae18d0c4a17da93f30c385d5221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151040c34a6a2940bbe9a7356c1cc6ffe358dd4441db58897cba99c212eb75285e7da1eca11c792c97a380493345ab224de9d94c2b36ee8526ae23528171a3231de733221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2840334aced8106ebaa4287daca56cca26795f2d2a739784cf6b734da3370757f499e120c0e40be40436cd74c4ef26905706f52fa7fa6e8e76451e8583783051a843221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c40d841a373ad2896b972b8cfea1634ff14a30f80d84cfd6ef18893397b8f346c80519c9b161a72244d0e9b64e5436c98ce9dd4e17a0728fc997b5c7bcf39cecb6800010e20a29d7767440275ca532af6091f0a5c56329895020d3b0bd88aff43b41320239c010f040000000001011fa086010000000000160014d4dc903f7116602ee358ec8edf3284e6ff0294e3220202655ef5daf05d28d1ca73ba8e211300db2b70416737183e0fa8c355ee4c1cbac6483045022100cc6550f0d334f78d183fea10a7cb74f46f29504d91d28fdfad0e705e1b7ff0e702206e1bfebb555d39ef55a6439dfb5bc575794ffde9c90eb66d020a6a77c53d30550101030401000000220602655ef5daf05d28d1ca73ba8e211300db2b70416737183e0fa8c355ee4c1cbac6080000008002000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102103df706ff26d672fe50c6f56a2ca1e7174e75055c920bbd337e1a7d6bf2826f6dc221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d282103bfb86253beb96f58b8c469e442cfcf9f78a5413a95423be8e686764f2fa7bd3f221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c21038604aa8cff309dddf49b1f366f89c269616587fc41db608540f9431536f6646f221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151040fd2e8c22b9b672d3bb9e26d4b6da2dc3f125455a969fd8e2b2c1ba791076ad71b38c01f9218c3d6776fd895d2f3067484996d85e268390c2b433e6c4b21891f1221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d284052dffbf0095f29b1de24c9d68d549d1c54bce6900454fe37fd10f5c903dfee85f7bad8a72ada8e52cd9092f51d9e90b5a7e4f36ca04df98e77fbad1347305bc7221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c4093e1e5d4888bc1cfe02eecfa9dea144ead84f23a10fc1a301103c1e56393527b63417c6c4a5af45359ff8b6e179af73978e4d62e862eedd2a286f5278e4cb34000010e201e7fcee7bee58da88197c40959a62e0603809ade35137493df2cfa8f855304bb010f040000000001011fa086010000000000160014fb6d08dfb14f001dc98cf17c4d7322b07bf0754f22020303a0f4528d264e8e95256634b94414e2748f72962704fe57e8b0a2cc44d2383d473044022008bbd83c008e6d14e74aa91defcc9d06bf59a78efab643411f3e0399e2e2ac14022006e16d93d20da92f1d36413a08e78d0dd5195fe1ceca6d978870055c84d854b5010103040100000022060303a0f4528d264e8e95256634b94414e2748f72962704fe57e8b0a2cc44d2383d080000008003000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151021038029998c73c2b139db75557ec3011ec65ecd212447963006571852a3e92289cc221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d282102980bac7264e14bf820cc435b69a78df726c177eb026f1b81b52de811272f58eb221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c2103a27d9f1fa53e43f70835a6990954b78a35f747066f7b82b4a9ea82e8bb5e06a6221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151040381ce3c1ac9fc7f6a51536456252984768e8fbd014070239f4cb13b16793c74cc5ed677c8a7eacc173e988d353a3f289c7e2141db7a4b4145c5499ec837f36ae221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d284038e03463b6450dbd051065a812a6f2631087f7951e46ac84e66da811755717c093180e4d49827b8c097ca7093fe92d393f95a5d7ad849a41802dc4e4558abde9221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c40732aa0957a9db2c759e39aca5d0167ef13d2a34a43c812e9cc9d712d458f7b2285da7511eb16f61f9600d20be4e94dfdd2bc3ae37fd943fc34947dfc3fdc679700010e20d3115addfefba31ddf71ab5567d435cc58f4806d45fa865a8b070ec9f8741907010f040000000001011fa0860100000000001600140b1845f4c80dabe2c5dc8a567fbe410a78e486c8220203a8911beb5a48fe119cb015088cf0c3a118cf026772448972d1b70c764ac5941247304402204d1af28490d64b249307a5fa046ad7d0cc698919841a1c631724604e3b933690022024793fc6be7b0a23d3edd2ff71f79be44f597d043eb369a1d6ca9291584bafc30101030401000000220603a8911beb5a48fe119cb015088cf0c3a118cf026772448972d1b70c764ac59412080000008004000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102102bef4738c6f327f1724b1407988959cdf2bd19210894bfd043535b61138270818221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2821027eb7c1c4afcd7e62ab6ad3d2ba2733a3745220641f91903ebfe7bcc5dbdc6b5d221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c2103ca88bcdb6d1f5291e90c75d3da601a8bd29991eabbf7f94b2f39483e3858c9a1221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510400a584927102820b7b6cad6bcfb031a23a37312ad87d23f1cb5a8359be2d5ff39b6a2a2fe37cd0d53ee347f13e6b3525769b2e789f0699cb985588eac2daf10dd221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d284077b1572336d9bd4e2f73411eb8f6a96235a130f444cbeb07a489f447921e37489d71fd3db28a0bbaa35b88c37b7579ecdbf6ce1638700db81dfc86bf79cd1be7221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c405d0de8a27f0d528802cf3354a1af507bcf0fed419da641c9c0807cd754e07af8790b511c705d5fbf63305ab22afe0497facf070b5afeafcee3a690054776775600010e2090936b5863dffd85c2b8c76cd221a8deeafd52bedb0342e09652da2385b5d70d010f040000000001012ba086010000000000225120d155713c520ce2d8276164215d659ab623c5f7306f8652c1756e26833e886e0101030401000000011004feffffff011720d155713c520ce2d8276164215d659ab623c5f7306f8652c1756e26833e886e01221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df47151021024f2a15a4b15a6b78f0a632fc7fdf112929f64bd4dd14f67a63cf4fb8f325a204221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d282103802b69b360da4585512b1cf967b184010226d75ce5b762e77a0128bcb068ccbb221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c2102407615505ecbdea881312504eef6f4681a26316ef73d33537a7fd793f4658ea9221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510408f223de27986dd8792a03d9d5b662323e8697830ebabb67363881fe72c86482ae61a09268d083b8354cfc2bad35c148eeb291af622dd460634606332af1b8297221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2840103ae05c10e43298376c3fee1dc5f0d04389f4f20af49346d48ead324d615d6f28fca0a318445130ea56a862019b2de0c2637db3c418c0b074b58548ae8b20c9221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c40f055990738544d099b159290e7f5442cb91226260174aa9d8c1c8310b7cb01ce2b94cc5d2b8fdf81667e02fb796db0e5c27877de0d41a2a0e709b01445baf29600010e20f87911fa033a02ce17f2963603ce60575db73b9a97477d481f7232d9f0a4e123010f040000000001012ba086010000000000225120d00e15fb626a7efee85c5bce676d636b6048914e9a34ace0b4cbc44bc948077a01030401000000011004feffffff011720d00e15fb626a7efee85c5bce676d636b6048914e9a34ace0b4cbc44bc948077a221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102102153fcdfe96ae70363fd1542646d309c2132b8325540e3dd7f88e37f9796079a6221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2821020faa3a0c31ae7695e769546e30aa782abd31fb681b970a13aa35cc21dfd13800221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c2103f313f8f475eb01e3cecbc0eaac2f726d29032c6ff7c3ad6cc3bf8bb10186527c221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510404320e9f60fd3c2a6f737aace546c23b0c7d76e84159c0ad289c1df4c0f8a500e51209f296f9d7d223a1d292bd41d266faacb1be843becf4b706eb15dba702806221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2840e4074a6ec893eab806d5df9a74ed257e785ff378643dbaa7933c7813a7b5f6c90ca82b62539f39b38c2c72fe5cf81c22a5e641f673644f6c486b3db577464463221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c403b29e12cf693f272139f74452f2bccc2bcd07432dce8fb107354c1458a12a47c8544d2d6ca1e33bce0578b6508cf8a5934673f9fc435a5f84a22a54b5adcbcfc00010e20b6368bbc330cddfe9e2550edb7dfc15ae74cac9bcc7d967fe81e6f27f8597b1d010f04000000000100530200000001fea14f3d169b2b0400db14996221b31182bb9e86ca169e91b9c7bd93f9c73e880000000000ffffffff01a08601000000000017a9140df101357f73e6658500cf56f3a132d7bb8afbdd8700000000010120a08601000000000017a9140df101357f73e6658500cf56f3a132d7bb8afbdd872202020500f167cf669e7dac39e6aecda1f28c66b78ec7097eefef25d54f7be785e7f64730440220675318791a1743ceef915ca50525b5871cb6f1182d2c7134981937730b523be6022002409d795216233c3656d659c876c3c06277fa09902e57cf4e517532a87f4e1701010304010000000104160014c6bc8105ec6db60c4da53ac35cda204069e90e8a2206020500f167cf669e7dac39e6aecda1f28c66b78ec7097eefef25d54f7be785e7f6080000008007000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102102fe7841cddfb46fdb2ca9bde56c9558c2d1b36121665659080224e24031438408221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2821026f027b235a7593ca8943c6d7b7e37d92eab339617f7f0c344106c58dd0cbc6aa221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c21020611450c6c1944ecdecb78f61816c767fba4368f21f7e9b169779c76f23cf4cc221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715104088072551662c3eebee545f188b8dafc682973a2f218e7ca07fc8e42ff57a1134630449fd703177d7a12d0c9ced024844dc1b9e0ecad67587dd5c479431b36a1a221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d284016b58148f7baff783e4310f185503fe92417dba43b966c83a2184322cb1f20424cb9d040ae6a1aea4e7444bdc786258a975644ce1a0195564c2b9fc3c606a292221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c404ab36bdd69eb1cd0d4b0aeae403dce4db5228c5ba3a291dc725de23382d1736d265d7bc33f83690a5ca5609719f19e81952d4c8d5e288fd0cb8c6411104b80a300010e2003bceba5379d73daeafe677972b03dcf7ef30b7f10eaa83ad04bc0bf00d8b2f7010f040000000001005502000000012a34ac1b0db77a8198c1e29002cc47bbfcd6ed830960304d2c9a3ab548486b5d0000000000ffffffff01a0860100000000001976a914569bf311e68a383767b43f83042dfabe60093ede88ac00000000220203199d2f155f32ebb167aeb0ccca6e5afb7340898df1b7ab9936500f6d4391902a473044022007f37a98a7ea09f615449a3f800df2ec55c23311ce2b1a451716e39e79d1f12d022050f55e799e2be3d670bc66a68ec96223e0d1ee39602e468db2cc7b25c87aa6e00101030401000000220603199d2f155f32ebb167aeb0ccca6e5afb7340898df1b7ab9936500f6d4391902a080000008008000000011004feffffff221d02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715102102f3c175b08b207637616aa74e67baac1a1807c94bce70800f76f5b17b52c0082d221d033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d282102fa1ced932598a27fa28410b955ea67479b5a4033b69f2c99e4e26767bba0a556221d038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c210300e0fd1710dc56ad7c173aa9141d731577009bc3dffcba8576a48e77ab34d970221e02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df4715104099225658fede7a8c2437eb3821bdc9d3700abc896e8b6dcef84e29347b78bc2b03e6da33836e4f40767390c36644ce016b36b1d546963540fa51d0b0407db6d7221e033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d2840a0948c517d70976c0e39ca67abf19e7217040dbe172bb96534133e6ffa3941c1659416f540662b7561efb70064b4d71a9b17b63bc563f630db4422f273e0df12221e038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c40ee0aaa65ca73ccc547b31c2b7ed2ae31a4f4ccdaea73f2add24630d608ede9aea5d808688186ebca42b877efab13f35e60f210d4f620602f850fc0731c201e9100010308307500000000000001042251201afa5d88188cef9b91b3f1002b11e0f9e94ad3981978c4d12a0605564c081233010942033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd40001030830750000000000000104225120cabf7e4a0de424ec9bbadd7f7242cce7673e1701f49d6a19a97055da332b1324010942033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd400010308204e00000000000001042251204aadc9e0a590d21e0c19cb2024f27140f9b19c2a1282d50ea7c5f45eb03fd4a201094202a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e00010308204e00000000000001042251202fa43700ea1d28fd7ad4dcb332b3e5e5a0d8cb54258f6661c4de0377d72804e501094202a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e000103081027000000000000010422512051986faee319436b51b38409c1b300f4396e2b32e3cc9a12ae2a4be135da6f6e010942038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c03f81473844c9d74c921ff17a5af410b6337348d7afbff73891bc5cb0cb24cb0c00001030850c300000000000001042251206fc506f8052a9f5a8aa9b990d5e994f495dded6d47bac44caacdadd8d8991cd000", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 1, + "private_key": "295c2eedddd8331d20b5d4cf9e69bb523ed85cb0bf35ab12e04fea66fe6d4a4a", + "public_key": "02f5b59fa5e492221ebf55ba78ad442605beae95166ba1eba3250d0bbaac7e2edc", + "prevout_txid": "26d393ed2bc842fef499962be79f9d6c4c19b22d83a16334d125cb09a785d4bc", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001be9d65c83915fb09248abbdfca8ca3eee6ce350c554f65e8d526e5df527ab5220000000000ffffffff01a086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e00000000", + "witness_utxo": "a086010000000000160014a692511c079575bf3756dabc56ad71d4284a690e", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 2, + "private_key": "e6db4a04e2fc29745ea1a9dcf1fed7449c8228ffe0503d8171e64126d5399800", + "public_key": "02655ef5daf05d28d1ca73ba8e211300db2b70416737183e0fa8c355ee4c1cbac6", + "prevout_txid": "9c232013b443ff8ad80b3b0d02959832565c0a1f09f62a53ca75024467779da2", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001d041c742ca364472d1a18c7a8eae07e6e904a9ea1b85f198525fb83ef276e3430000000000ffffffff01a086010000000000160014d4dc903f7116602ee358ec8edf3284e6ff0294e300000000", + "witness_utxo": "a086010000000000160014d4dc903f7116602ee358ec8edf3284e6ff0294e3", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 3, + "private_key": "f5208ed67b0019ba4e306aff029d247931e0dfacd1fe6e69091bc6bc70a42619", + "public_key": "0303a0f4528d264e8e95256634b94414e2748f72962704fe57e8b0a2cc44d2383d", + "prevout_txid": "bb0453858ffa2cdf93741335de9a8003062ea65909c49781a88de5bee7ce7f1e", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000152262cd5d402bf32616d07fc03286a8f7fe78af7ac411dfff41655ddc1011e6f0000000000ffffffff01a086010000000000160014fb6d08dfb14f001dc98cf17c4d7322b07bf0754f00000000", + "witness_utxo": "a086010000000000160014fb6d08dfb14f001dc98cf17c4d7322b07bf0754f", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 4, + "private_key": "0c19c34dc1005feb5ca60104d20472f7f2f97bd4d521264618196bf71155b20a", + "public_key": "03a8911beb5a48fe119cb015088cf0c3a118cf026772448972d1b70c764ac59412", + "prevout_txid": "071974f8c90e078b5a86fa456d80f458cc35d46755ab71df1da3fbfedd5a11d3", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001e298eaf24fe1ca68b41e4b6b83cc3d91ced99c6e78d5b992cfb15771b54570640000000000ffffffff01a0860100000000001600140b1845f4c80dabe2c5dc8a567fbe410a78e486c800000000", + "witness_utxo": "a0860100000000001600140b1845f4c80dabe2c5dc8a567fbe410a78e486c8", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 5, + "private_key": "5aaa151cbdeb566911784d166b01ce57f35993b98f96846efec1cfefcc0d8f56", + "public_key": "02d155713c520ce2d8276164215d659ab623c5f7306f8652c1756e26833e886e01", + "prevout_txid": "0dd7b58523da5296e04203dbbe52fdeadea821d26cc7b8c285fddf63586b9390", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "02000000011730833ecb5be01362d7149522604484216e1c7b18cf313d1cf1543ef85df3b60000000000ffffffff01a086010000000000225120d155713c520ce2d8276164215d659ab623c5f7306f8652c1756e26833e886e0100000000", + "witness_utxo": "a086010000000000225120d155713c520ce2d8276164215d659ab623c5f7306f8652c1756e26833e886e01", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 6, + "private_key": "d92c1506167b3a00a21f4d90d7b5ccb4713c00194aa66f9c7deb162c467f9643", + "public_key": "02d00e15fb626a7efee85c5bce676d636b6048914e9a34ace0b4cbc44bc948077a", + "prevout_txid": "23e1a4f0d932721f487d47979a3bb75d5760ce033696f217ce023a03fa1179f8", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001e93532e0eda39c4d39da2d3f91d14529bc435fc2efb9196e25fbaac4b4e89b810000000000ffffffff01a086010000000000225120d00e15fb626a7efee85c5bce676d636b6048914e9a34ace0b4cbc44bc948077a00000000", + "witness_utxo": "a086010000000000225120d00e15fb626a7efee85c5bce676d636b6048914e9a34ace0b4cbc44bc948077a", + "sequence": 4294967294, + "signed": false + }, + { + "input_index": 7, + "private_key": "d8bc8d0e1233a97133f3573d6dceb6736e8b6d2e4839925145022ea3efdad8f8", + "public_key": "020500f167cf669e7dac39e6aecda1f28c66b78ec7097eefef25d54f7be785e7f6", + "prevout_txid": "1d7b59f8276f1ee87f967dcc9bac4ce75ac1dfb7ed50259efedd0c33bc8b36b6", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001fea14f3d169b2b0400db14996221b31182bb9e86ca169e91b9c7bd93f9c73e880000000000ffffffff01a08601000000000017a9140df101357f73e6658500cf56f3a132d7bb8afbdd8700000000", + "witness_utxo": "a08601000000000017a9140df101357f73e6658500cf56f3a132d7bb8afbdd87", + "sequence": 4294967294, + "signed": true + }, + { + "input_index": 8, + "private_key": "81e30f5b5d049bdf5c5bea9c3329bf57cc8b473240182a9f2a6eee07435bd54a", + "public_key": "03199d2f155f32ebb167aeb0ccca6e5afb7340898df1b7ab9936500f6d4391902a", + "prevout_txid": "f7b2d800bfc04bd03aa8ea107f0bf37ecf3db0727967feeada739d37a5ebbc03", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "02000000012a34ac1b0db77a8198c1e29002cc47bbfcd6ed830960304d2c9a3ab548486b5d0000000000ffffffff01a0860100000000001976a914569bf311e68a383767b43f83042dfabe60093ede88ac00000000", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "030a18b9bb4199b89330eb17f8ee5ac786e0853dcd2f3ccdf1744b97ce4ede053e", + "dleq_proof": "001383d4661be8725ef29048f48c911f89f5f34317d7c0c0acc60ef65f1b52bfff7a96d8339b625df83abab57aa273edcd9a35c794dacbb1c861171bb267075f", + "input_index": 0 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "03fbd173d9c48d58c5022426d05278bca17b9a8e2282666901a1b00b9e04b79949", + "dleq_proof": "c05da410487cfaec378febe6af5005e3ae6c86236818b0e55b214017eb5073edef40179575b5dcdaa9063491ac8b83fd0624d4177a4d2dd4994c4640d6b8ccde", + "input_index": 0 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "037372d179f4f628da82ccbd4e4217bdb0809f1417c9abeaa35fa805d48ad6554c", + "dleq_proof": "a6872d4eb119fe2af70953f752a22236b54a3b57f70e511f10bd8b42ff56b5acf6365093c480ea9f13776784945b59318ac2927d915aae244cfb683f4188a3a7", + "input_index": 0 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "02f6ae7b8aac9a0f9c9f04eab484062172df2e38d9f2f6ec31b404bb5a286aabf0", + "dleq_proof": "334aced8106ebaa4287daca56cca26795f2d2a739784cf6b734da3370757f499e120c0e40be40436cd74c4ef26905706f52fa7fa6e8e76451e8583783051a843", + "input_index": 1 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "03a6a89b1b986a995533e17bed64500b541bb0d739071efe2ae2b7efb0a0ca6bcf", + "dleq_proof": "c34a6a2940bbe9a7356c1cc6ffe358dd4441db58897cba99c212eb75285e7da1eca11c792c97a380493345ab224de9d94c2b36ee8526ae23528171a3231de733", + "input_index": 1 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "02b1d3ed2fa4bc316a08eb1485fa75ed7dd54ca7a9ae18d0c4a17da93f30c385d5", + "dleq_proof": "d841a373ad2896b972b8cfea1634ff14a30f80d84cfd6ef18893397b8f346c80519c9b161a72244d0e9b64e5436c98ce9dd4e17a0728fc997b5c7bcf39cecb68", + "input_index": 1 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "03bfb86253beb96f58b8c469e442cfcf9f78a5413a95423be8e686764f2fa7bd3f", + "dleq_proof": "52dffbf0095f29b1de24c9d68d549d1c54bce6900454fe37fd10f5c903dfee85f7bad8a72ada8e52cd9092f51d9e90b5a7e4f36ca04df98e77fbad1347305bc7", + "input_index": 2 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "03df706ff26d672fe50c6f56a2ca1e7174e75055c920bbd337e1a7d6bf2826f6dc", + "dleq_proof": "fd2e8c22b9b672d3bb9e26d4b6da2dc3f125455a969fd8e2b2c1ba791076ad71b38c01f9218c3d6776fd895d2f3067484996d85e268390c2b433e6c4b21891f1", + "input_index": 2 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "038604aa8cff309dddf49b1f366f89c269616587fc41db608540f9431536f6646f", + "dleq_proof": "93e1e5d4888bc1cfe02eecfa9dea144ead84f23a10fc1a301103c1e56393527b63417c6c4a5af45359ff8b6e179af73978e4d62e862eedd2a286f5278e4cb340", + "input_index": 2 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "02980bac7264e14bf820cc435b69a78df726c177eb026f1b81b52de811272f58eb", + "dleq_proof": "38e03463b6450dbd051065a812a6f2631087f7951e46ac84e66da811755717c093180e4d49827b8c097ca7093fe92d393f95a5d7ad849a41802dc4e4558abde9", + "input_index": 3 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "038029998c73c2b139db75557ec3011ec65ecd212447963006571852a3e92289cc", + "dleq_proof": "381ce3c1ac9fc7f6a51536456252984768e8fbd014070239f4cb13b16793c74cc5ed677c8a7eacc173e988d353a3f289c7e2141db7a4b4145c5499ec837f36ae", + "input_index": 3 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "03a27d9f1fa53e43f70835a6990954b78a35f747066f7b82b4a9ea82e8bb5e06a6", + "dleq_proof": "732aa0957a9db2c759e39aca5d0167ef13d2a34a43c812e9cc9d712d458f7b2285da7511eb16f61f9600d20be4e94dfdd2bc3ae37fd943fc34947dfc3fdc6797", + "input_index": 3 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "027eb7c1c4afcd7e62ab6ad3d2ba2733a3745220641f91903ebfe7bcc5dbdc6b5d", + "dleq_proof": "77b1572336d9bd4e2f73411eb8f6a96235a130f444cbeb07a489f447921e37489d71fd3db28a0bbaa35b88c37b7579ecdbf6ce1638700db81dfc86bf79cd1be7", + "input_index": 4 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "02bef4738c6f327f1724b1407988959cdf2bd19210894bfd043535b61138270818", + "dleq_proof": "0a584927102820b7b6cad6bcfb031a23a37312ad87d23f1cb5a8359be2d5ff39b6a2a2fe37cd0d53ee347f13e6b3525769b2e789f0699cb985588eac2daf10dd", + "input_index": 4 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "03ca88bcdb6d1f5291e90c75d3da601a8bd29991eabbf7f94b2f39483e3858c9a1", + "dleq_proof": "5d0de8a27f0d528802cf3354a1af507bcf0fed419da641c9c0807cd754e07af8790b511c705d5fbf63305ab22afe0497facf070b5afeafcee3a6900547767756", + "input_index": 4 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "03802b69b360da4585512b1cf967b184010226d75ce5b762e77a0128bcb068ccbb", + "dleq_proof": "103ae05c10e43298376c3fee1dc5f0d04389f4f20af49346d48ead324d615d6f28fca0a318445130ea56a862019b2de0c2637db3c418c0b074b58548ae8b20c9", + "input_index": 5 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "024f2a15a4b15a6b78f0a632fc7fdf112929f64bd4dd14f67a63cf4fb8f325a204", + "dleq_proof": "8f223de27986dd8792a03d9d5b662323e8697830ebabb67363881fe72c86482ae61a09268d083b8354cfc2bad35c148eeb291af622dd460634606332af1b8297", + "input_index": 5 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "02407615505ecbdea881312504eef6f4681a26316ef73d33537a7fd793f4658ea9", + "dleq_proof": "f055990738544d099b159290e7f5442cb91226260174aa9d8c1c8310b7cb01ce2b94cc5d2b8fdf81667e02fb796db0e5c27877de0d41a2a0e709b01445baf296", + "input_index": 5 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "020faa3a0c31ae7695e769546e30aa782abd31fb681b970a13aa35cc21dfd13800", + "dleq_proof": "e4074a6ec893eab806d5df9a74ed257e785ff378643dbaa7933c7813a7b5f6c90ca82b62539f39b38c2c72fe5cf81c22a5e641f673644f6c486b3db577464463", + "input_index": 6 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "02153fcdfe96ae70363fd1542646d309c2132b8325540e3dd7f88e37f9796079a6", + "dleq_proof": "4320e9f60fd3c2a6f737aace546c23b0c7d76e84159c0ad289c1df4c0f8a500e51209f296f9d7d223a1d292bd41d266faacb1be843becf4b706eb15dba702806", + "input_index": 6 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "03f313f8f475eb01e3cecbc0eaac2f726d29032c6ff7c3ad6cc3bf8bb10186527c", + "dleq_proof": "3b29e12cf693f272139f74452f2bccc2bcd07432dce8fb107354c1458a12a47c8544d2d6ca1e33bce0578b6508cf8a5934673f9fc435a5f84a22a54b5adcbcfc", + "input_index": 6 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "026f027b235a7593ca8943c6d7b7e37d92eab339617f7f0c344106c58dd0cbc6aa", + "dleq_proof": "16b58148f7baff783e4310f185503fe92417dba43b966c83a2184322cb1f20424cb9d040ae6a1aea4e7444bdc786258a975644ce1a0195564c2b9fc3c606a292", + "input_index": 7 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "02fe7841cddfb46fdb2ca9bde56c9558c2d1b36121665659080224e24031438408", + "dleq_proof": "88072551662c3eebee545f188b8dafc682973a2f218e7ca07fc8e42ff57a1134630449fd703177d7a12d0c9ced024844dc1b9e0ecad67587dd5c479431b36a1a", + "input_index": 7 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "020611450c6c1944ecdecb78f61816c767fba4368f21f7e9b169779c76f23cf4cc", + "dleq_proof": "4ab36bdd69eb1cd0d4b0aeae403dce4db5228c5ba3a291dc725de23382d1736d265d7bc33f83690a5ca5609719f19e81952d4c8d5e288fd0cb8c6411104b80a3", + "input_index": 7 + }, + { + "scan_key": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28", + "ecdh_share": "02fa1ced932598a27fa28410b955ea67479b5a4033b69f2c99e4e26767bba0a556", + "dleq_proof": "a0948c517d70976c0e39ca67abf19e7217040dbe172bb96534133e6ffa3941c1659416f540662b7561efb70064b4d71a9b17b63bc563f630db4422f273e0df12", + "input_index": 8 + }, + { + "scan_key": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510", + "ecdh_share": "02f3c175b08b207637616aa74e67baac1a1807c94bce70800f76f5b17b52c0082d", + "dleq_proof": "99225658fede7a8c2437eb3821bdc9d3700abc896e8b6dcef84e29347b78bc2b03e6da33836e4f40767390c36644ce016b36b1d546963540fa51d0b0407db6d7", + "input_index": 8 + }, + { + "scan_key": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c", + "ecdh_share": "0300e0fd1710dc56ad7c173aa9141d731577009bc3dffcba8576a48e77ab34d970", + "dleq_proof": "ee0aaa65ca73ccc547b31c2b7ed2ae31a4f4ccdaea73f2add24630d608ede9aea5d808688186ebca42b877efab13f35e60f210d4f620602f850fc0731c201e91", + "input_index": 8 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 30000, + "sp_v0_info": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd4", + "script": "51201afa5d88188cef9b91b3f1002b11e0f9e94ad3981978c4d12a0605564c081233" + }, + { + "output_index": 1, + "amount": 30000, + "sp_v0_info": "033361d3ff72f34e6b4e7a7bef96e5b8151e66a979adce753c39c583cbe5766d28031266581e3e841cbb94de62ea735583a232c4c888fa6edef2ec2f870789fc1dd4", + "script": "5120cabf7e4a0de424ec9bbadd7f7242cce7673e1701f49d6a19a97055da332b1324" + }, + { + "output_index": 2, + "amount": 20000, + "sp_v0_info": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e", + "script": "51204aadc9e0a590d21e0c19cb2024f27140f9b19c2a1282d50ea7c5f45eb03fd4a2" + }, + { + "output_index": 3, + "amount": 20000, + "sp_v0_info": "02a9f1fac2cc457684f33de90073fe20d22c947c92163b862b14d0aba1df471510024a48d76e20d40bcf5f2e1a5c3ffeb3dc2a8b3b88d79a486d54c9d9eaa8fa188e", + "script": "51202fa43700ea1d28fd7ad4dcb332b3e5e5a0d8cb54258f6661c4de0377d72804e5" + }, + { + "output_index": 4, + "amount": 10000, + "sp_v0_info": "038ed3220e73344f91e2d33391e3e1691db39daf06e4237e197ed0d007bf27286c03f81473844c9d74c921ff17a5af410b6337348d7afbff73891bc5cb0cb24cb0c0", + "script": "512051986faee319436b51b38409c1b300f4396e2b32e3cc9a12ae2a4be135da6f6e" + }, + { + "output_index": 5, + "amount": 50000, + "script": "51206fc506f8052a9f5a8aa9b990d5e994f495dded6d47bac44caacdadd8d8991cd0" + } + ], + "task": "fail_sign" + } + }, + { + "description": "can finalize: P2WPKH with decoy BIP32_DERIVATION before the matching key", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiD3Tt0fdbS7Pl10nBW/22Y0j2gFqbTUX+7houIB9QO7cQEPBAAAAAABAR+ghgEAAAAAABYAFB4q14ctMpQTpW3wlovjOCIngxY7IgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9HMEQCIG9hTKsWyAwmppZy4viq5wvAiLUgLqne/2rOeM2n+2JyAiAQVYeP/VlnUGDrYKAL+jNMnLJB+6EoTBEkkNEA2ex8LgEBAwQBAAAAIgYCpRa89dF+FVVFALBtY95Srqd8dFqTvkLq2/Sunj4dEqAIAAAAgP8AAAAiBgLIF7t1Ia/DXqlvO/snDm61Dd/6VWBie5Yf7ADymWUIvwgAAACAAAAAAAEQBP7///8iHQJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaCED7KT/Ebco4uD2DOYiKUOm/1W52V9ie/mpnQhLyHLVClsiHgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaECKE7OYVUX3K9bolxSuuQmz41SoQqm7i1bNDt7SHfihmVmLMSKKSeC9fpXOEFP3xbKKy1Q6aHB2AOPOiYIu4yAhAAEDCBhzAQAAAAAAAQQiUSBkb0lMoLubzq0UuNt+TGlEVh+vIy58zMNr3VhpX3SRWQEJQgJ6SH/Bn7dph3uHQtbqGBGPPE5yseqMbeYCp61KQdvgaANh4bHp3l5CyyAH98pUueDVftE5OPrVbT8Z5XUTqPzgOQA=", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20f74edd1f75b4bb3e5d749c15bfdb66348f6805a9b4d45feee1a2e201f503bb71010f040000000001011fa0860100000000001600141e2ad7872d329413a56df0968be338222783163b220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf47304402206f614cab16c80c26a69672e2f8aae70bc088b5202ea9deff6ace78cda7fb627202201055878ffd59675060eb60a00bfa334c9cb241fba1284c112490d100d9ec7c2e0101030401000000220602a516bcf5d17e15554500b06d63de52aea77c745a93be42eadbf4ae9e3e1d12a00800000080ff000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "71bb03f501e2a2e1ee5fd4b4a905688f3466dbbf159c745d3ebbb4751fdd4ef7", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "020000000118a717663b0bab14b12a1a771323ff1e4079dd532e5dd13e28ea1081c700984a0000000000ffffffff01a0860100000000001600141e2ad7872d329413a56df0968be338222783163b00000000", + "witness_utxo": "a0860100000000001600141e2ad7872d329413a56df0968be338222783163b", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120646f494ca0bb9bcead14b8db7e4c6944561faf232e7cccc36bdd58695f749159" + } + ], + "task": "deserialize" + } + }, + { + "description": "can finalize: P2PKH with decoy BIP32_DERIVATION before the matching key", + "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEAQEBBQEBAQYBAAABDiBSJ0jrF3ZNKMpJSBXsjUnn0w1SvHNCLHyG63TjlwVylAEPBAAAAAABAFUCAAAAAfTCEtWu0ef2/2M/LOCcZHxXvt2TAxTZjed1A9WOlAszAAAAAAD/////AaCGAQAAAAAAGXapFB4q14ctMpQTpW3wlovjOCIngxY7iKwAAAAAIgICyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL9IMEUCIQCKz65hp7Ug/wQxkrbclMyEJpEkQIMSdkyI3dldqY0pVQIgIIfDsRj5aZKk2iQTz/6RcPJQ4n48FMtd7z5jjDDX6oABAQMEAQAAACIGAqUWvPXRfhVVRQCwbWPeUq6nfHRak75C6tv0rp4+HRKgCAAAAID/AAAAIgYCyBe7dSGvw16pbzv7Jw5utQ3f+lVgYnuWH+wA8pllCL8IAAAAgAAAAAABEAT+////Ih0Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GghA+yk/xG3KOLg9gzmIilDpv9VudlfYnv5qZ0IS8hy1QpbIh4Cekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GhAihOzmFVF9yvW6JcUrrkJs+NUqEKpu4tWzQ7e0h34oZlZizEiikngvX6VzhBT98WyistUOmhwdgDjzomCLuMgIQABAwgYcwEAAAAAAAEEIlEg4UDSh7RbRs1OqvpDdwYVcLq+g9G4vJUKdKn+oJIz16YBCUICekh/wZ+3aYd7h0LW6hgRjzxOcrHqjG3mAqetSkHb4GgDYeGx6d5eQssgB/fKVLng1X7ROTj61W0/GeV1E6j84DkA", + "supplementary": { + "hex": "70736274ff01fb04020000000102040200000001040101010501010106010000010e20522748eb17764d28ca494815ec8d49e7d30d52bc73422c7c86eb74e397057294010f04000000000100550200000001f4c212d5aed1e7f6ff633f2ce09c647c57bedd930314d98de77503d58e940b330000000000ffffffff01a0860100000000001976a9141e2ad7872d329413a56df0968be338222783163b88ac00000000220202c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf4830450221008acfae61a7b520ff043192b6dc94cc84269124408312764c88ddd95da98d295502202087c3b118f96992a4da2413cffe9170f250e27e3c14cb5def3e638c30d7ea800101030401000000220602a516bcf5d17e15554500b06d63de52aea77c745a93be42eadbf4ae9e3e1d12a00800000080ff000000220602c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf080000008000000000011004feffffff221d027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0682103eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b221e027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068408a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee320210001030818730100000000000104225120e140d287b45b46cd4eaafa4377061570babe83d1b8bc950a74a9fea09233d7a6010942027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce03900", + "inputs": [ + { + "input_index": 0, + "private_key": "7e31eeeb1aa2597b6d63b357541461d75ddae76b7603d24619f5ebed9e88ec31", + "public_key": "02c817bb7521afc35ea96f3bfb270e6eb50ddffa5560627b961fec00f2996508bf", + "prevout_txid": "94720597e374eb867c2c4273bc520dd3e7498dec154849ca284d7617eb482752", + "prevout_index": 0, + "amount": 100000, + "non_witness_utxo": "0200000001f4c212d5aed1e7f6ff633f2ce09c647c57bedd930314d98de77503d58e940b330000000000ffffffff01a0860100000000001976a9141e2ad7872d329413a56df0968be338222783163b88ac00000000", + "sequence": 4294967294, + "signed": true + } + ], + "sp_proofs": [ + { + "scan_key": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe068", + "ecdh_share": "03eca4ff11b728e2e0f60ce6222943a6ff55b9d95f627bf9a99d084bc872d50a5b", + "dleq_proof": "8a13b3985545f72bd6e89714aeb909b3e354a842a9bb8b56cd0eded21df8a199598b31228a49e0bd7e95ce1053f7c5b28acb543a68707600e3ce89822ee32021", + "input_index": 0 + } + ], + "outputs": [ + { + "output_index": 0, + "amount": 95000, + "sp_v0_info": "027a487fc19fb769877b8742d6ea18118f3c4e72b1ea8c6de602a7ad4a41dbe0680361e1b1e9de5e42cb2007f7ca54b9e0d57ed13938fad56d3f19e57513a8fce039", + "script": "5120e140d287b45b46cd4eaafa4377061570babe83d1b8bc950a74a9fea09233d7a6" + } + ], + "task": "deserialize" + } + } + ] +} \ No newline at end of file diff --git a/packages/caravan-psbt/src/psbtv2/dleq.test.ts b/packages/caravan-psbt/src/psbtv2/dleq.test.ts new file mode 100644 index 0000000000..c67e3048eb --- /dev/null +++ b/packages/caravan-psbt/src/psbtv2/dleq.test.ts @@ -0,0 +1,209 @@ +import { describe, expect, it } from "vitest"; +import { secp256k1 } from "@noble/curves/secp256k1"; + +import { + generateDLEQProof, + multiplyCompressedPoint, + verifyDLEQProof, +} from "./dleq"; + +function hex(s: string): Buffer { + return Buffer.from(s, "hex"); +} + +function pubkeyFromSecret(secret: Buffer): Buffer { + return Buffer.from( + secp256k1.ProjectivePoint.BASE.multiply( + BigInt(`0x${secret.toString("hex")}`), + ).toRawBytes(true), + ); +} + +describe("BIP374 DLEQ", () => { + it("generates a proof that verifies", () => { + const secret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const baseSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const auxRand = Buffer.alloc(32, 0); + + const publicKey = pubkeyFromSecret(secret); + const basePoint = pubkeyFromSecret(baseSecret); + const result = multiplyCompressedPoint(basePoint, secret); + + const proof = generateDLEQProof({ + secret, + basePoint, + auxRand, + }); + + expect(proof.length).toBe(64); + + expect( + verifyDLEQProof({ + proof, + publicKey, + basePoint, + result, + }), + ).toBe(true); + }); + + it("fails verification with the wrong public key", () => { + const secret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const wrongSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + const baseSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + + const basePoint = pubkeyFromSecret(baseSecret); + const result = multiplyCompressedPoint(basePoint, secret); + const wrongPublicKey = pubkeyFromSecret(wrongSecret); + + const proof = generateDLEQProof({ + secret, + basePoint, + auxRand: Buffer.alloc(32, 0), + }); + + expect( + verifyDLEQProof({ + proof, + publicKey: wrongPublicKey, + basePoint, + result, + }), + ).toBe(false); + }); + + it("fails verification with the wrong base point", () => { + const secret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const baseSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const wrongBaseSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + + const publicKey = pubkeyFromSecret(secret); + const basePoint = pubkeyFromSecret(baseSecret); + const wrongBasePoint = pubkeyFromSecret(wrongBaseSecret); + const result = multiplyCompressedPoint(basePoint, secret); + + const proof = generateDLEQProof({ + secret, + basePoint, + auxRand: Buffer.alloc(32, 0), + }); + + expect( + verifyDLEQProof({ + proof, + publicKey, + basePoint: wrongBasePoint, + result, + }), + ).toBe(false); + }); + + it("fails verification with the wrong ECDH result", () => { + const secret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const baseSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const wrongSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + + const publicKey = pubkeyFromSecret(secret); + const basePoint = pubkeyFromSecret(baseSecret); + const wrongResult = multiplyCompressedPoint(basePoint, wrongSecret); + + const proof = generateDLEQProof({ + secret, + basePoint, + auxRand: Buffer.alloc(32, 0), + }); + + expect( + verifyDLEQProof({ + proof, + publicKey, + basePoint, + result: wrongResult, + }), + ).toBe(false); + }); + + it("fails verification when proof bytes are mutated", () => { + const secret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const baseSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + + const publicKey = pubkeyFromSecret(secret); + const basePoint = pubkeyFromSecret(baseSecret); + const result = multiplyCompressedPoint(basePoint, secret); + + const proof = generateDLEQProof({ + secret, + basePoint, + auxRand: Buffer.alloc(32, 0), + }); + + const mutated = Buffer.from(proof); + mutated[0] ^= 1; + + expect( + verifyDLEQProof({ + proof: mutated, + publicKey, + basePoint, + result, + }), + ).toBe(false); + }); + + it("rejects malformed proof lengths", () => { + const secret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const baseSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + + const publicKey = pubkeyFromSecret(secret); + const basePoint = pubkeyFromSecret(baseSecret); + const result = multiplyCompressedPoint(basePoint, secret); + + expect( + verifyDLEQProof({ + proof: Buffer.alloc(63), + publicKey, + basePoint, + result, + }), + ).toBe(false); + + expect( + verifyDLEQProof({ + proof: Buffer.alloc(65), + publicKey, + basePoint, + result, + }), + ).toBe(false); + }); +}); diff --git a/packages/caravan-psbt/src/psbtv2/dleq.ts b/packages/caravan-psbt/src/psbtv2/dleq.ts new file mode 100644 index 0000000000..b50fe67693 --- /dev/null +++ b/packages/caravan-psbt/src/psbtv2/dleq.ts @@ -0,0 +1,251 @@ +import { randomBytes } from "crypto"; +import { secp256k1 } from "@noble/curves/secp256k1"; +import { bytesToNumberBE, numberToBytesBE } from "@noble/curves/abstract/utils"; +import { mod } from "@noble/curves/abstract/modular"; +import { taggedHash } from "./functions"; + +export type ProjectivePoint = InstanceType; + +const N = secp256k1.CURVE.n; +const G = secp256k1.ProjectivePoint.BASE; +const ZERO = secp256k1.ProjectivePoint.ZERO; + +function scalarFromPrivateKey(bytes: Buffer, context: string): bigint { + if (!secp256k1.utils.isValidPrivateKey(bytes)) { + throw new Error(`${context}: invalid secp256k1 scalar.`); + } + + return bytesToNumberBE(bytes); +} + +function assertMessage(message?: Buffer): Buffer { + if (!message) return Buffer.alloc(0); + + if (message.length !== 32) { + throw new Error(`BIP374 message must be 32 bytes, got ${message.length}.`); + } + + return message; +} + +function assertAuxRand(auxRand: Buffer): void { + if (auxRand.length !== 32) { + throw new Error(`BIP374 auxRand must be 32 bytes, got ${auxRand.length}.`); + } +} + +function xor32(a: Buffer, b: Buffer): Buffer { + if (a.length !== 32 || b.length !== 32) { + throw new Error("xor32 requires two 32-byte buffers."); + } + + const out = Buffer.alloc(32); + + for (let i = 0; i < 32; i++) { + out[i] = a[i] ^ b[i]; + } + + return out; +} + +function pointFromCompressed(bytes: Buffer): ProjectivePoint { + return secp256k1.ProjectivePoint.fromHex(bytes); +} + +function pointToCompressedBytes(point: ProjectivePoint): Buffer { + if (point.equals(ZERO)) { + throw new Error("Cannot serialize point at infinity."); + } + + return Buffer.from(point.toRawBytes(true)); +} + +/** + * Computes scalar * compressedPoint and returns a compressed point. + */ +export function multiplyCompressedPoint( + compressedPoint: Buffer, + scalarBytes: Buffer, +): Buffer { + const scalar = scalarFromPrivateKey( + scalarBytes, + "multiplyCompressedPoint scalar", + ); + + const result = + secp256k1.ProjectivePoint.fromHex(compressedPoint).multiply(scalar); + + if (result.equals(ZERO)) { + throw new Error("multiplyCompressedPoint produced point at infinity."); + } + + return Buffer.from(result.toRawBytes(true)); +} + +function getTaggedChallenge( + A: ProjectivePoint, + B: ProjectivePoint, + C: ProjectivePoint, + R1: ProjectivePoint, + R2: ProjectivePoint, + m: Buffer, +): Buffer { + return taggedHash( + "BIP0374/challenge", + Buffer.concat([ + pointToCompressedBytes(A), + pointToCompressedBytes(B), + pointToCompressedBytes(C), + pointToCompressedBytes(G), + pointToCompressedBytes(R1), + pointToCompressedBytes(R2), + m, + ]), + ); +} + +export function generateDLEQProof({ + secret, + basePoint, + auxRand = randomBytes(32), + message, +}: { + secret: Buffer; + basePoint: Buffer; + auxRand?: Buffer; + message?: Buffer; +}): Buffer { + const a = scalarFromPrivateKey(secret, "BIP374 secret"); + const B = pointFromCompressed(basePoint); + const m = assertMessage(message); + + assertAuxRand(auxRand); + + const A = G.multiply(a); + const C = B.multiply(a); + + if (A.equals(ZERO) || C.equals(ZERO)) { + throw new Error("BIP374 proof generation produced point at infinity."); + } + + const ABytes = pointToCompressedBytes(A); + const CBytes = pointToCompressedBytes(C); + + const t = xor32(secret, taggedHash("BIP0374/aux", auxRand)); + + const rand = taggedHash( + "BIP0374/nonce", + Buffer.concat([t, ABytes, CBytes, m]), + ); + + const k = mod(bytesToNumberBE(rand), N); + + if (k === 0n) { + throw new Error("BIP374 nonce produced zero scalar."); + } + + const R1 = G.multiply(k); + const R2 = B.multiply(k); + + if (R1.equals(ZERO) || R2.equals(ZERO)) { + throw new Error("BIP374 nonce produced point at infinity."); + } + + const eBytes = getTaggedChallenge(A, B, C, R1, R2, m); + + const e = bytesToNumberBE(eBytes); + const s = mod(k + mod(e, N) * a, N); + + const proof = Buffer.concat([eBytes, Buffer.from(numberToBytesBE(s, 32))]); + + if ( + !verifyDLEQProofForPoints({ + A, + B, + C, + proof, + message, + }) + ) { + throw new Error("Generated BIP374 DLEQ proof did not verify."); + } + + return proof; +} + +function verifyDLEQProofForPoints({ + A, + B, + C, + proof, + message, +}: { + A: ProjectivePoint; + B: ProjectivePoint; + C: ProjectivePoint; + proof: Buffer; + message?: Buffer; +}): boolean { + if (proof.length !== 64) { + return false; + } + + const eBytes = proof.subarray(0, 32); + const sBytes = proof.subarray(32, 64); + + const e = bytesToNumberBE(eBytes); + const s = bytesToNumberBE(sBytes); + + if (s >= N) { + return false; + } + + const eReduced = mod(e, N); + + const R1 = G.multiply(s).add(A.multiply(eReduced).negate()); + const R2 = B.multiply(s).add(C.multiply(eReduced).negate()); + + if (R1.equals(ZERO) || R2.equals(ZERO)) { + return false; + } + + let m: Buffer; + + try { + m = assertMessage(message); + } catch { + return false; + } + + const expectedE = getTaggedChallenge(A, B, C, R1, R2, m); + + return expectedE.equals(eBytes); +} + +export function verifyDLEQProof({ + publicKey, + basePoint, + result, + proof, + message, +}: { + publicKey: Buffer; + basePoint: Buffer; + result: Buffer; + proof: Buffer; + message?: Buffer; +}): boolean { + let A: ProjectivePoint; + let B: ProjectivePoint; + let C: ProjectivePoint; + + try { + A = pointFromCompressed(publicKey); + B = pointFromCompressed(basePoint); + C = pointFromCompressed(result); + } catch { + return false; + } + + return verifyDLEQProofForPoints({ A, B, C, proof, message }); +} diff --git a/packages/caravan-psbt/src/psbtv2/functions.ts b/packages/caravan-psbt/src/psbtv2/functions.ts index d52f3f3b09..d53cda4441 100644 --- a/packages/caravan-psbt/src/psbtv2/functions.ts +++ b/packages/caravan-psbt/src/psbtv2/functions.ts @@ -1,5 +1,6 @@ import { BufferReader, BufferWriter } from "bufio"; import { validateBIP32Path } from "@caravan/bitcoin"; +import { sha256 } from "@noble/hashes/sha2"; import { PSBT_MAGIC_BYTES } from "../constants"; import { Key, Value, NonUniqueKeyTypeValue, KeyType } from "./types"; import { @@ -142,3 +143,8 @@ export function getPsbtVersionNumber(psbt: string | Buffer): number { readAndSetKeyPairs(map, br); return map.get(KeyType.PSBT_GLOBAL_VERSION)?.readUInt32LE(0) || 0; } + +export function taggedHash(tag: string, msg: Buffer): Buffer { + const tagHash = Buffer.from(sha256(Buffer.from(tag, "utf8"))); + return Buffer.from(sha256(Buffer.concat([tagHash, tagHash, msg]))); +} diff --git a/packages/caravan-psbt/src/psbtv2/psbtv2-bip375.test.ts b/packages/caravan-psbt/src/psbtv2/psbtv2-bip375.test.ts new file mode 100644 index 0000000000..c62639904a --- /dev/null +++ b/packages/caravan-psbt/src/psbtv2/psbtv2-bip375.test.ts @@ -0,0 +1,479 @@ +/** + * BIP375 test vectors for PsbtV2 silent payment PSBT validation. + */ + +import { describe, expect, test } from "vitest"; +import { PsbtV2 } from "./psbtv2"; +import bip375Vectors from "../fixtures/bip375_vectors.json"; +import { KeyType } from "src/psbtv2/types"; +import { secp256k1 } from "@noble/curves/secp256k1"; +import { hash160 } from "@caravan/bitcoin"; + +function hex(s: string): Buffer { + return Buffer.from(s, "hex"); +} + +function pubkeyFromSecret(secret: Buffer): Buffer { + return Buffer.from( + secp256k1.ProjectivePoint.BASE.multiply( + BigInt(`0x${secret.toString("hex")}`), + ).toRawBytes(true), + ); +} + +function p2wpkhScript(pubkey: Buffer): Buffer { + return Buffer.concat([Buffer.from([0x00, 0x14]), hash160(pubkey)]); +} + +// ── Invalid vectors ──────────────────────────────────────────────────────── + +describe("BIP375 invalid vectors", () => { + test.each(bip375Vectors.invalid)("$description", ({ psbt }) => { + let thrown: unknown; + expect(() => { + try { + new PsbtV2(psbt); + } catch (e) { + thrown = e; + throw e; + } + }).toThrow(); + + console.log(` throw reason: ${(thrown as Error).message}`); + }); +}); + +// ── Valid vectors ────────────────────────────────────────────────────────── +describe("BIP375 valid vectors", () => { + test.each(bip375Vectors.valid)("$description", ({ psbt, supplementary }) => { + const p = new PsbtV2(psbt); + + expect(() => p.validate()).not.toThrow(); + + // ── Output checks ────────────────────────────────────────────────────── + + for (const output of supplementary.outputs ?? []) { + const outputMap = p.outputMaps[output.output_index]; + expect(outputMap, `output ${output.output_index} exists`).toBeDefined(); + + if ( + "script" in output && + output.script !== null && + output.script !== undefined + ) { + const script = outputMap.get(KeyType.PSBT_OUT_SCRIPT); + expect( + script?.toString("hex"), + `output ${output.output_index} script`, + ).toBe(output.script); + } else { + expect( + outputMap.has(KeyType.PSBT_OUT_SCRIPT), + `output ${output.output_index} should not have PSBT_OUT_SCRIPT`, + ).toBe(false); + } + + // SP V0 info (bscan || bspend): only check unlabeled outputs. + // For labeled outputs, the supplementary bspend is the label-tweaked key + // (B_spend + label·G), but PSBT_OUT_SP_V0_INFO stores the raw bspend. + // The label relationship is verified separately via PSBT_OUT_SP_V0_LABEL. + const hasLabel = "sp_v0_label" in output && output.sp_v0_label !== null; + if (output.sp_v0_info && !hasLabel) { + const info = p.getSilentPaymentOutputInfo(output.output_index); + expect(info, `output ${output.output_index} sp_v0_info`).not.toBeNull(); + const combined = + info!.bscan.toString("hex") + info!.bspend.toString("hex"); + expect(combined, `output ${output.output_index} sp_v0_info`).toBe( + output.sp_v0_info, + ); + } + + // SP V0 label + if (hasLabel) { + expect( + p.PSBT_OUT_SP_V0_LABEL[output.output_index], + `output ${output.output_index} sp_v0_label`, + ).toBe(output.sp_v0_label); + } + } + + // ── Input / proof checks ─────────────────────────────────────────────── + + for (const proof of supplementary.sp_proofs ?? []) { + const isGlobal = + proof.input_index === undefined || proof.input_index === null; + + if (isGlobal) { + if (proof.ecdh_share) { + const entry = p.PSBT_GLOBAL_SP_ECDH_SHARE.find( + (s) => s.key === KeyType.PSBT_GLOBAL_SP_ECDH_SHARE + proof.scan_key, + ); + expect( + entry?.value, + `global ECDH share for scan key ${proof.scan_key}`, + ).toBe(proof.ecdh_share); + } + if (proof.dleq_proof) { + const entry = p.PSBT_GLOBAL_SP_DLEQ.find( + (s) => s.key === KeyType.PSBT_GLOBAL_SP_DLEQ + proof.scan_key, + ); + expect( + entry?.value, + `global DLEQ proof for scan key ${proof.scan_key}`, + ).toBe(proof.dleq_proof); + } + } else { + if (proof.ecdh_share) { + const entry = p.PSBT_IN_SP_ECDH_SHARE[proof.input_index].find( + (s) => s.key === KeyType.PSBT_IN_SP_ECDH_SHARE + proof.scan_key, + ); + expect( + entry?.value, + `input ${proof.input_index} ECDH share for scan key ${proof.scan_key}`, + ).toBe(proof.ecdh_share); + } + if (proof.dleq_proof) { + const entry = p.PSBT_IN_SP_DLEQ[proof.input_index].find( + (s) => s.key === KeyType.PSBT_IN_SP_DLEQ + proof.scan_key, + ); + expect( + entry?.value, + `input ${proof.input_index} DLEQ proof for scan key ${proof.scan_key}`, + ).toBe(proof.dleq_proof); + } + } + } + }); +}); + +describe("BIP375 DLEQ integration", () => { + it("adds and validates a global ECDH share with DLEQ proof", () => { + const inputSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const scanSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const spendSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + + const inputPubkey = pubkeyFromSecret(inputSecret); + const scanKey = pubkeyFromSecret(scanSecret); + const spendKey = pubkeyFromSecret(spendSecret); + + const psbt = new PsbtV2(); + + psbt.addInput({ + previousTxId: Buffer.alloc(32, 1), + outputIndex: 0, + witnessUtxo: { + amount: 100_000, + script: p2wpkhScript(inputPubkey), + }, + bip32Derivation: [ + { + pubkey: inputPubkey, + masterFingerprint: Buffer.alloc(4, 0), + path: "m/84'/0'/0'/0/0", + }, + ], + }); + + psbt.addOutput({ + amount: 50_000, + silentPayment: { + bscan: scanKey, + bspend: spendKey, + }, + }); + + psbt.addGlobalSPECDHShareWithDLEQ( + scanKey, + inputSecret, + Buffer.alloc(32, 0), + ); + + psbt.computeSilentPaymentOutputScripts(); + + expect(() => new PsbtV2(psbt.serialize())).not.toThrow(); + }); + + it("rejects a mutated global DLEQ proof", () => { + const inputSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const scanSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const spendSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + + const inputPubkey = pubkeyFromSecret(inputSecret); + const scanKey = pubkeyFromSecret(scanSecret); + const spendKey = pubkeyFromSecret(spendSecret); + + const psbt = new PsbtV2(); + + psbt.addInput({ + previousTxId: Buffer.alloc(32, 1), + outputIndex: 0, + witnessUtxo: { + amount: 100_000, + script: p2wpkhScript(inputPubkey), + }, + bip32Derivation: [ + { + pubkey: inputPubkey, + masterFingerprint: Buffer.alloc(4, 0), + path: "m/84'/0'/0'/0/0", + }, + ], + }); + + psbt.addOutput({ + amount: 50_000, + silentPayment: { + bscan: scanKey, + bspend: spendKey, + }, + }); + + psbt.addGlobalSPECDHShareWithDLEQ( + scanKey, + inputSecret, + Buffer.alloc(32, 0), + ); + + const proofKey = KeyType.PSBT_GLOBAL_SP_DLEQ + scanKey.toString("hex"); + const proof = Buffer.from(psbt.globalMap.get(proofKey) as Buffer); + proof[0] ^= 1; + psbt.globalMap.set(proofKey, proof); + + // The producer verifies DLEQ proofs before deriving, so the tampered proof + // is rejected at compute time rather than later on round-trip construction. + expect(() => psbt.computeSilentPaymentOutputScripts()).toThrow( + /Invalid global silent payment DLEQ proof/, + ); + }); + + it("adds and validates per-input ECDH shares with DLEQ proofs", () => { + const inputSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const scanSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const spendSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + + const inputPubkey = pubkeyFromSecret(inputSecret); + const scanKey = pubkeyFromSecret(scanSecret); + const spendKey = pubkeyFromSecret(spendSecret); + + const psbt = new PsbtV2(); + + psbt.addInput({ + previousTxId: Buffer.alloc(32, 1), + outputIndex: 0, + witnessUtxo: { + amount: 100_000, + script: p2wpkhScript(inputPubkey), + }, + bip32Derivation: [ + { + pubkey: inputPubkey, + masterFingerprint: Buffer.alloc(4, 0), + path: "m/84'/0'/0'/0/0", + }, + ], + }); + + psbt.addOutput({ + amount: 50_000, + silentPayment: { + bscan: scanKey, + bspend: spendKey, + }, + }); + + psbt.addInputSPECDHShareWithDLEQ( + 0, + scanKey, + inputSecret, + Buffer.alloc(32, 0), + ); + + psbt.computeSilentPaymentOutputScripts(); + + expect(() => new PsbtV2(psbt.serialize())).not.toThrow(); + }); + + it("rejects a mutated per-input DLEQ proof", () => { + const inputSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const scanSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const spendSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + + const inputPubkey = pubkeyFromSecret(inputSecret); + const scanKey = pubkeyFromSecret(scanSecret); + const spendKey = pubkeyFromSecret(spendSecret); + + const psbt = new PsbtV2(); + + psbt.addInput({ + previousTxId: Buffer.alloc(32, 1), + outputIndex: 0, + witnessUtxo: { + amount: 100_000, + script: p2wpkhScript(inputPubkey), + }, + bip32Derivation: [ + { + pubkey: inputPubkey, + masterFingerprint: Buffer.alloc(4, 0), + path: "m/84'/0'/0'/0/0", + }, + ], + }); + + psbt.addOutput({ + amount: 50_000, + silentPayment: { + bscan: scanKey, + bspend: spendKey, + }, + }); + + psbt.addInputSPECDHShareWithDLEQ( + 0, + scanKey, + inputSecret, + Buffer.alloc(32, 0), + ); + + const proofKey = KeyType.PSBT_IN_SP_DLEQ + scanKey.toString("hex"); + const proof = Buffer.from(psbt.inputMaps[0].get(proofKey) as Buffer); + proof[0] ^= 1; + psbt.inputMaps[0].set(proofKey, proof); + + // The producer verifies DLEQ proofs before deriving, so the tampered proof + // is rejected at compute time rather than later on round-trip construction. + expect(() => psbt.computeSilentPaymentOutputScripts()).toThrow( + /Invalid input 0 silent payment DLEQ proof/, + ); + }); +}); + +describe("BIP375 signing gate", () => { + const inputSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000001", + ); + const scanSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000002", + ); + const spendSecret = hex( + "0000000000000000000000000000000000000000000000000000000000000003", + ); + + const inputPubkey = pubkeyFromSecret(inputSecret); + const scanKey = pubkeyFromSecret(scanSecret); + const spendKey = pubkeyFromSecret(spendSecret); + + // 71-byte SIGHASH_ALL dummy sig: only the trailing sighash byte is parsed + // by addPartialSig (handleSighashType reads the last byte). + const dummySig = Buffer.concat([Buffer.alloc(71, 0), Buffer.from([0x01])]); + + function buildSPPsbt(): PsbtV2 { + const psbt = new PsbtV2(); + + psbt.addInput({ + previousTxId: Buffer.alloc(32, 1), + outputIndex: 0, + witnessUtxo: { + amount: 100_000, + script: p2wpkhScript(inputPubkey), + }, + bip32Derivation: [ + { + pubkey: inputPubkey, + masterFingerprint: Buffer.alloc(4, 0), + path: "m/84'/0'/0'/0/0", + }, + ], + }); + + psbt.addOutput({ + amount: 50_000, + silentPayment: { + bscan: scanKey, + bspend: spendKey, + }, + }); + + psbt.addGlobalSPECDHShareWithDLEQ( + scanKey, + inputSecret, + Buffer.alloc(32, 0), + ); + + return psbt; + } + + it("signs a valid SP PSBT on the live object after computing scripts", () => { + const psbt = buildSPPsbt(); + psbt.computeSilentPaymentOutputScripts(); + + expect(() => psbt.addPartialSig(0, inputPubkey, dummySig)).not.toThrow(); + expect(psbt.PSBT_IN_PARTIAL_SIG[0].length).toBe(1); + }); + + it("rejects signing when the SP output script was tampered after computing", () => { + const psbt = buildSPPsbt(); + psbt.computeSilentPaymentOutputScripts(); + + const proofKey = KeyType.PSBT_GLOBAL_SP_DLEQ + scanKey.toString("hex"); + const proof = Buffer.from(psbt.globalMap.get(proofKey) as Buffer); + proof[0] ^= 1; + psbt.globalMap.set(proofKey, proof); + + expect(() => psbt.addPartialSig(0, inputPubkey, dummySig)).toThrow(); + // The signature must not have been written. + expect(psbt.PSBT_IN_PARTIAL_SIG[0].length).toBe(0); + }); + + it("allows signing a non-SP PSBT (early-return path is a no-op)", () => { + const psbt = new PsbtV2(); + + psbt.addInput({ + previousTxId: Buffer.alloc(32, 1), + outputIndex: 0, + witnessUtxo: { + amount: 100_000, + script: p2wpkhScript(inputPubkey), + }, + bip32Derivation: [ + { + pubkey: inputPubkey, + masterFingerprint: Buffer.alloc(4, 0), + path: "m/84'/0'/0'/0/0", + }, + ], + }); + + psbt.addOutput({ + amount: 50_000, + script: p2wpkhScript(spendKey), + }); + + expect(() => psbt.addPartialSig(0, inputPubkey, dummySig)).not.toThrow(); + expect(psbt.PSBT_IN_PARTIAL_SIG[0].length).toBe(1); + }); +}); diff --git a/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts b/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts index 08a65cb97c..5218304468 100644 --- a/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts +++ b/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts @@ -2325,11 +2325,7 @@ describe("PsbtV2.combine", () => { // Stub handleSighashType so addPartialSig doesn't throw on sighash // validation. thisPsbt.handleSighashType = vi.fn(); - thisPsbt.addPartialSig( - 0, - Buffer.from([0x01]), - Buffer.from([0x02]), - ); + thisPsbt.addPartialSig(0, Buffer.from([0x01]), Buffer.from([0x02])); } return { thisPsbt, otherPsbt }; diff --git a/packages/caravan-psbt/src/psbtv2/psbtv2.ts b/packages/caravan-psbt/src/psbtv2/psbtv2.ts index 5ddb8470dc..2ac02a1798 100644 --- a/packages/caravan-psbt/src/psbtv2/psbtv2.ts +++ b/packages/caravan-psbt/src/psbtv2/psbtv2.ts @@ -1,3 +1,4 @@ +import { secp256k1 } from "@noble/curves/secp256k1"; import { BufferReader, BufferWriter } from "bufio"; import { Psbt } from "bitcoinjs-lib-v6"; @@ -18,6 +19,29 @@ import { } from "./functions"; import { PsbtConversionMaps, PsbtV2Maps } from "./psbtv2maps"; import { bufferize } from "../functions"; +import { + assertValidBscan, + assertValidBspend, + assertValidDLEQProof, + assertValidECDHShare, + assertValidLabel, + assertValidOutputK, + assertValidSPV0Info, + computeInputHash, + deriveSilentPaymentOutput, + contributingIndices, + getSilentPaymentPubkeyFromInputDescriptor, + groupSilentPaymentOutputs, + hasSegwitV2PlusInput, + isNumsScriptPathSpend, + SPInputDescriptor, + SPOutputEntry, + sumECDHShares, + generateSilentPaymentDLEQProof, + verifySilentPaymentDLEQProof, +} from "src/psbtv2/silentpayment"; +import { ProjectivePoint } from "src/psbtv2/dleq"; + /** * The PsbtV2 class is intended to represent an easily modifiable and * serializable psbt of version 2 conforming to BIP0174. Getters exist for all @@ -157,6 +181,20 @@ export class PsbtV2 extends PsbtV2Maps { this.globalMap.set(KeyType.PSBT_GLOBAL_TX_MODIFIABLE, br.render()); } + get PSBT_GLOBAL_SP_ECDH_SHARE(): NonUniqueKeyTypeValue[] { + return getNonUniqueKeyTypeValues( + this.globalMap, + KeyType.PSBT_GLOBAL_SP_ECDH_SHARE, + ) as NonUniqueKeyTypeValue[]; + } + + get PSBT_GLOBAL_SP_DLEQ(): NonUniqueKeyTypeValue[] { + return getNonUniqueKeyTypeValues( + this.globalMap, + KeyType.PSBT_GLOBAL_SP_DLEQ, + ) as NonUniqueKeyTypeValue[]; + } + get PSBT_GLOBAL_VERSION() { const version = this.globalMap .get(KeyType.PSBT_GLOBAL_VERSION) @@ -379,6 +417,20 @@ export class PsbtV2 extends PsbtV2Maps { ); } + get PSBT_IN_SP_ECDH_SHARE(): NonUniqueKeyTypeValue[][] { + return getNonUniqueKeyTypeValues( + this.inputMaps, + KeyType.PSBT_IN_SP_ECDH_SHARE, + ) as NonUniqueKeyTypeValue[][]; + } + + get PSBT_IN_SP_DLEQ(): NonUniqueKeyTypeValue[][] { + return getNonUniqueKeyTypeValues( + this.inputMaps, + KeyType.PSBT_IN_SP_DLEQ, + ) as NonUniqueKeyTypeValue[][]; + } + get PSBT_IN_PROPRIETARY() { return getNonUniqueKeyTypeValues( this.inputMaps, @@ -458,6 +510,20 @@ export class PsbtV2 extends PsbtV2Maps { ); } + get PSBT_OUT_SP_V0_INFO(): (string | null)[] { + return getOptionalMappedBytesAsHex( + this.outputMaps, + KeyType.PSBT_OUT_SP_V0_INFO, + ); + } + + get PSBT_OUT_SP_V0_LABEL(): (number | null)[] { + return getOptionalMappedBytesAsUInt( + this.outputMaps, + KeyType.PSBT_OUT_SP_V0_LABEL, + ); + } + get PSBT_OUT_PROPRIETARY() { return getNonUniqueKeyTypeValues( this.outputMaps, @@ -534,7 +600,9 @@ export class PsbtV2 extends PsbtV2Maps { return false; } - return true; + // For non-SP transactions this is vacuously true. For SP transactions, + // every SP output must have a non-empty PSBT_OUT_SCRIPT before signing. + return this.hasAllSPOutputScripts; } /** @@ -612,13 +680,11 @@ export class PsbtV2 extends PsbtV2Maps { this.PSBT_IN_POR_COMMITMENT[i] || this.PSBT_IN_TAP_KEY_SIG[i] || this.PSBT_IN_TAP_INTERNAL_KEY[i] || - this.PSBT_IN_TAP_MERKLE_ROOT[i] || - // Numbers + this.PSBT_IN_TAP_MERKLE_ROOT[i] || // Numbers this.PSBT_IN_SIGHASH_TYPE[i] !== null || this.PSBT_IN_SEQUENCE[i] !== null || this.PSBT_IN_REQUIRED_TIME_LOCKTIME[i] !== null || - this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME[i] !== null || - // Arrays of non-unique keytype values + this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME[i] !== null || // Arrays of non-unique keytype values this.PSBT_IN_PARTIAL_SIG[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_BIP32_DERIVATION[i].filter((el) => el !== null).length > 0 || @@ -758,9 +824,15 @@ export class PsbtV2 extends PsbtV2Maps { throw Error("PsbtV2 input is missing PSBT_OUT_AMOUNT"); } } - for (const script of this.PSBT_OUT_SCRIPT) { - if (!script) { - throw Error("PsbtV2 input is missing PSBT_OUT_SCRIPT"); + for (let i = 0; i < this.outputMaps.length; i++) { + if ( + !this.hasNonEmptyOutputScript(i) && + !this.outputMaps[i].has(KeyType.PSBT_OUT_SP_V0_INFO) + ) { + throw Error( + `PsbtV2 output ${i} is missing PSBT_OUT_SCRIPT and has no ` + + "PSBT_OUT_SP_V0_INFO. An output must have one or both per BIP375.", + ); } } for (const locktime of this.PSBT_IN_REQUIRED_TIME_LOCKTIME) { @@ -773,6 +845,434 @@ export class PsbtV2 extends PsbtV2Maps { throw Error("PsbtV2 input hight locktime is gte 500000000."); } } + this.validateSilentPayments(); + } + + private hasNonEmptyOutputScript(outputIndex: number): boolean { + const script = this.outputMaps[outputIndex]?.get(KeyType.PSBT_OUT_SCRIPT); + return !!script && script.length > 0; + } + + private getSilentPaymentInputDescriptors(): SPInputDescriptor[] { + return this.inputMaps.map((map, i) => { + const outputIndex = map.get(KeyType.PSBT_IN_OUTPUT_INDEX); + + return { + witnessUtxo: map.get(KeyType.PSBT_IN_WITNESS_UTXO) ?? null, + nonWitnessUtxo: map.get(KeyType.PSBT_IN_NON_WITNESS_UTXO) ?? null, + outputIndex: outputIndex ? outputIndex.readUInt32LE(0) : null, + redeemScript: map.get(KeyType.PSBT_IN_REDEEM_SCRIPT) ?? null, + tapInternalKey: this.PSBT_IN_TAP_INTERNAL_KEY[i], + tapLeafScriptKeys: this.PSBT_IN_TAP_LEAF_SCRIPT[i].map((e) => e.key), + }; + }); + } + + private getAllOutpoints(): Buffer[] { + return this.inputMaps.flatMap((map) => { + const txid = map.get(KeyType.PSBT_IN_PREVIOUS_TXID); + const vout = map.get(KeyType.PSBT_IN_OUTPUT_INDEX); + return txid && vout ? [Buffer.concat([txid, vout])] : []; + }); + } + + private getSilentPaymentOutputGroups( + onlyWithScripts = false, + skipLabeled = false, + ): Map { + const entries: SPOutputEntry[] = []; + + for (let i = 0; i < this.outputMaps.length; i++) { + const info = this.getSilentPaymentOutputInfo(i); + if (!info) continue; + + if (skipLabeled && this.outputMaps[i].has(KeyType.PSBT_OUT_SP_V0_LABEL)) { + continue; + } + + if (onlyWithScripts && !this.hasNonEmptyOutputScript(i)) { + continue; + } + + entries.push({ outputIndex: i, ...info }); + } + + return groupSilentPaymentOutputs(entries); + } + + private getFinalScriptWitnessPubkeys(inputIndex: number): Buffer[] { + const witnessHex = this.PSBT_IN_FINAL_SCRIPTWITNESS[inputIndex]; + if (!witnessHex) return []; + + const witness = Buffer.from(witnessHex, "hex"); + const pubkeys: Buffer[] = []; + + for (let i = 0; i <= witness.length - 33; i++) { + const candidate = witness.subarray(i, i + 33); + if (candidate[0] === 0x02 || candidate[0] === 0x03) { + pubkeys.push(Buffer.from(candidate)); + } + } + + return pubkeys; + } + + private getFinalScriptSigPubkeys(inputIndex: number): Buffer[] { + const scriptSigHex = this.PSBT_IN_FINAL_SCRIPTSIG[inputIndex]; + if (!scriptSigHex) return []; + + const scriptSig = Buffer.from(scriptSigHex, "hex"); + const pubkeys: Buffer[] = []; + + for (let i = 0; i <= scriptSig.length - 33; i++) { + const candidate = scriptSig.subarray(i, i + 33); + if (candidate[0] === 0x02 || candidate[0] === 0x03) { + pubkeys.push(Buffer.from(candidate)); + } + } + + return pubkeys; + } + + private getSilentPaymentCandidatePubkeys(inputIndex: number): Buffer[] { + const bip32Pubkeys = this.PSBT_IN_BIP32_DERIVATION[inputIndex].map( + (entry) => Buffer.from(entry.key.slice(2), "hex"), + ); + + const partialSigPubkeys = this.PSBT_IN_PARTIAL_SIG[inputIndex].map( + (entry) => Buffer.from(entry.key.slice(2), "hex"), + ); + + return [ + ...bip32Pubkeys, + ...partialSigPubkeys, + ...this.getFinalScriptWitnessPubkeys(inputIndex), + ...this.getFinalScriptSigPubkeys(inputIndex), + ]; + } + + private tryGetInputAggregatePubkey( + contributing: number[], + ): ProjectivePoint | null { + let combinedPubkey: ProjectivePoint | null = null; + const descriptors = this.getSilentPaymentInputDescriptors(); + + for (const i of contributing) { + const pubkeyBytes = getSilentPaymentPubkeyFromInputDescriptor( + descriptors[i], + this.getSilentPaymentCandidatePubkeys(i), + ); + + if (!pubkeyBytes) { + return null; + } + + const point = secp256k1.ProjectivePoint.fromHex(pubkeyBytes); + combinedPubkey = combinedPubkey ? combinedPubkey.add(point) : point; + } + + return combinedPubkey; + } + + private getInputAggregatePubkey(contributing: number[]): ProjectivePoint { + const aggregate = this.tryGetInputAggregatePubkey(contributing); + + if (!aggregate) { + throw Error("Missing matching public key for silent payment derivation."); + } + + return aggregate; + } + + /** + * Computes the BIP352 input hash from all outpoints and the aggregate public + * key of the contributing inputs. This is strict because computed SP output + * scripts can only be verified when every contributing input has a pubkey that + * matches its prevout script. + */ + private computeSilentPaymentInputHash(contributingInputs: number[]): Buffer { + const outpoints = this.getAllOutpoints(); + if (outpoints.length === 0) { + throw Error("At least one outpoint is required to compute inputHash."); + } + + const combinedPubkey = this.getInputAggregatePubkey(contributingInputs); + + return computeInputHash( + outpoints, + Buffer.from(combinedPubkey.toRawBytes(true)), + ); + } + + /** + * Resolves the ECDH share for a scan key while verifying its DLEQ proof(s). + * + * Returns the share — either the global share or the sum of per-input shares + * — or null when the scan key's output is still in progress (no derivable + * share has been contributed yet). + */ + private resolveAndVerifyScanKeyEcdhShare( + bscanHex: string, + contributingInputs: number[], + ): Buffer | null { + const globalShareKey = KeyType.PSBT_GLOBAL_SP_ECDH_SHARE + bscanHex; + + if (this.globalMap.has(globalShareKey)) { + const proofKey = KeyType.PSBT_GLOBAL_SP_DLEQ + bscanHex; + const ecdhShare = this.globalMap.get(globalShareKey) as Buffer; + const proof = this.globalMap.get(proofKey); + + if (!proof) { + throw Error( + `Global ECDH share missing PSBT_GLOBAL_SP_DLEQ for scan key ${bscanHex}.`, + ); + } + + const aggregatePubkey = + this.tryGetInputAggregatePubkey(contributingInputs); + if (!aggregatePubkey) { + return null; + } + + if ( + !verifySilentPaymentDLEQProof({ + publicKey: Buffer.from(aggregatePubkey.toRawBytes(true)), + scanKey: Buffer.from(bscanHex, "hex"), + ecdhShare, + proof, + }) + ) { + throw Error( + `Invalid global silent payment DLEQ proof for scan key ${bscanHex}.`, + ); + } + + return ecdhShare; + } + + // At least one contributing input when there is no global share is required + if (contributingInputs.length === 0) { + throw Error( + `Output script set for scan key ${bscanHex} but no contributing inputs can derive it.`, + ); + } + + const perInputBuffers: Buffer[] = []; + + for (const i of contributingInputs) { + const shareKey = KeyType.PSBT_IN_SP_ECDH_SHARE + bscanHex; + const proofKey = KeyType.PSBT_IN_SP_DLEQ + bscanHex; + const ecdhShare = this.inputMaps[i].get(shareKey); + + if (!ecdhShare) { + throw Error( + `Output script set but eligible input ${i} missing ECDH share for scan key ${bscanHex}`, + ); + } + + const inputPubkey = this.tryGetInputAggregatePubkey([i]); + const proof = this.inputMaps[i].get(proofKey) as Buffer; + + if (!proof) { + throw Error( + `Input ${i} ECDH share missing PSBT_IN_SP_DLEQ for scan key ${bscanHex}.`, + ); + } + + if (!inputPubkey) { + throw Error( + `Input ${i} missing public key for silent payment DLEQ verification.`, + ); + } + + if ( + !verifySilentPaymentDLEQProof({ + publicKey: Buffer.from(inputPubkey.toRawBytes(true)), + scanKey: Buffer.from(bscanHex, "hex"), + ecdhShare, + proof, + }) + ) { + throw Error( + `Invalid input ${i} silent payment DLEQ proof for scan key ${bscanHex}.`, + ); + } + + perInputBuffers.push(ecdhShare); + } + + if (perInputBuffers.length === 0) { + return null; + } + + return Buffer.from(sumECDHShares(perInputBuffers).toRawBytes(true)); + } + + /** + * Validates all BIP375 silent payment constraints. + * + * Three phases: + * 1. Output map structural checks — always run + * 2. Input eligibility checks — only when SP outputs present + * 3. ECDH coverage checks — only when SP outputs have PSBT_OUT_SCRIPT set + */ + private validateSilentPayments() { + if (!this.hasSilentPaymentOutputs) { + return; + } + + // ── Output map structural checks ─────────────────────────────────────── + for (const [i, outputMap] of this.outputMaps.entries()) { + const spInfo = outputMap.get(KeyType.PSBT_OUT_SP_V0_INFO); + const spLabel = outputMap.get(KeyType.PSBT_OUT_SP_V0_LABEL); + const script = outputMap.get(KeyType.PSBT_OUT_SCRIPT); + + if (spLabel && !spInfo) { + throw Error( + `PsbtV2 output ${i} has PSBT_OUT_SP_V0_LABEL but no PSBT_OUT_SP_V0_INFO.`, + ); + } + if (spInfo) { + assertValidSPV0Info(spInfo, i); + } else { + continue; + } + + if ( + outputMap.has(KeyType.PSBT_OUT_SCRIPT) && + !this.hasNonEmptyOutputScript(i) + ) { + throw Error(`PsbtV2 output ${i} has empty PSBT_OUT_SCRIPT.`); + } + + if ( + spInfo && + script && + script.length > 0 && + this.PSBT_GLOBAL_TX_MODIFIABLE.length > 0 + ) { + throw Error( + "PSBT_OUT_SCRIPT set for silent payment output but PSBT_GLOBAL_TX_MODIFIABLE is not zeroed.", + ); + } + } + + // ── Global map: keydata/valuedata + pairing checks ──────────────────── + for (const [key, value] of this.globalMap.entries()) { + if (key.startsWith(KeyType.PSBT_GLOBAL_SP_ECDH_SHARE)) { + assertValidECDHShare(value); + } + if (key.startsWith(KeyType.PSBT_GLOBAL_SP_DLEQ)) { + assertValidDLEQProof(value); + } + } + + // ── Input map: keydata/valuedata + pairing checks ───────────────────── + for (const inputMap of this.inputMaps.values()) { + for (const [key, value] of inputMap) { + if (key.startsWith(KeyType.PSBT_IN_SP_ECDH_SHARE)) { + assertValidECDHShare(value); + } + if (key.startsWith(KeyType.PSBT_IN_SP_DLEQ)) { + assertValidDLEQProof(value); + } + } + } + + // ── SP-wide restrictions that apply whenever SP outputs exist ────────── + const descriptors = this.getSilentPaymentInputDescriptors(); + + if (hasSegwitV2PlusInput(descriptors)) { + throw Error( + "A PSBT with PSBT_OUT_SP_V0_INFO must not contain SegWit v2+ inputs.", + ); + } + + for (const [i, inputMap] of this.inputMaps.entries()) { + if (!isNumsScriptPathSpend(descriptors[i])) continue; + + for (const key of inputMap.keys()) { + if ( + key.startsWith(KeyType.PSBT_IN_SP_ECDH_SHARE) || + key.startsWith(KeyType.PSBT_IN_SP_DLEQ) + ) { + throw Error( + `Input ${i} is a NUMS taproot script-path spend and must not have silent payment ECDH/DLEQ data.`, + ); + } + } + } + + for (const [i, inputMap] of this.inputMaps.entries()) { + const sighash = inputMap.get(KeyType.PSBT_IN_SIGHASH_TYPE); + + if (sighash && sighash.length >= 4) { + const sighashType = sighash.readUInt32LE(0); + + if (sighashType !== SighashType.SIGHASH_ALL) { + throw Error( + `PsbtV2 input ${i} uses non-SIGHASH_ALL (${sighashType}) with silent payments.`, + ); + } + } + } + + // ECDH coverage is only required per scan key that has a computed SP output + // script. Scan keys whose outputs are still in progress (no PSBT_OUT_SCRIPT) + // may have missing ECDH/DLEQ data. Labeled outputs are skipped here until + // label-aware public recomputation is implemented. + const outputGroups = this.getSilentPaymentOutputGroups(true, true); + + if (outputGroups.size === 0) { + return; + } + + const contributingInputs = this.getContributingInputsForSilentPayments(); + + if (contributingInputs.length === 0) { + throw Error("No contributing inputs for silent payment ECDH derivation."); + } + + const inputHash = this.computeSilentPaymentInputHash(contributingInputs); + + for (const [bscanHex, group] of outputGroups) { + const ecdhShare = this.resolveAndVerifyScanKeyEcdhShare( + bscanHex, + contributingInputs, + ); + + if (!ecdhShare) { + throw Error( + `Missing silent payment ECDH share for scan key ${bscanHex}.`, + ); + } + + for (let k = 0; k < group.length; k++) { + const { outputIndex, bspend } = group[k]; + const actualScript = this.outputMaps[outputIndex].get( + KeyType.PSBT_OUT_SCRIPT, + ); + + if (!actualScript || actualScript.length === 0) { + continue; + } + + assertValidOutputK(k, outputIndex); + + const expectedScript = deriveSilentPaymentOutput( + ecdhShare, + inputHash, + bspend, + k, + ); + + if (!actualScript.equals(expectedScript)) { + throw Error( + `PsbtV2 output ${outputIndex} PSBT_OUT_SCRIPT does not match silent payment derivation.`, + ); + } + } + } } /** @@ -992,12 +1492,18 @@ export class PsbtV2 extends PsbtV2Maps { public addOutput({ amount, script, + silentPayment, redeemScript, witnessScript, bip32Derivation, }: { amount: number; - script: Buffer; + script?: Buffer; + silentPayment?: { + bscan: Buffer; + bspend: Buffer; + label?: number; + }; redeemScript?: Buffer; witnessScript?: Buffer; bip32Derivation?: { @@ -1016,12 +1522,36 @@ export class PsbtV2 extends PsbtV2Maps { "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE outputs cannot be modified.", ); } + // Per BIP375: every output must have PSBT_OUT_SCRIPT, PSBT_OUT_SP_V0_INFO, + // or both. A regular output with no script and no SP info is invalid. + if (!script && !silentPayment) { + throw Error( + "addOutput requires either a script (regular output) or " + + "silentPayment { bscan, bspend } (SP output).", + ); + } + const map = new Map(); const bw = new BufferWriter(); + bw.writeI64(amount); map.set(KeyType.PSBT_OUT_AMOUNT, bw.render()); - bw.writeBytes(script); - map.set(KeyType.PSBT_OUT_SCRIPT, bw.render()); + + if (script) { + bw.writeBytes(script); + map.set(KeyType.PSBT_OUT_SCRIPT, bw.render()); + } + + if (silentPayment) { + const { bscan, bspend, label } = silentPayment; + const outputIndex = this.outputMaps.length; + + this.setOutputSPInfoOnMap(map, bscan, bspend); + + if (label !== undefined) { + this.setOutputSPLabelOnMap(map, outputIndex, label); + } + } if (redeemScript) { bw.writeBytes(redeemScript); @@ -1136,9 +1666,7 @@ export class PsbtV2 extends PsbtV2Maps { if (!pubkey || !sig) { throw Error( - `PsbtV2.addPartialSig() missing argument ${ - (!pubkey && "pubkey") || (!sig && "sig") - }`, + `PsbtV2.addPartialSig() missing argument ${(!pubkey && "pubkey") || (!sig && "sig")}`, ); } @@ -1149,12 +1677,29 @@ export class PsbtV2 extends PsbtV2Maps { ); } + if (this.hasSilentPaymentOutputs) { + if (sig.length === 0) { + throw Error("PsbtV2.addPartialSig() received empty signature."); + } + + const sighashType = sig[sig.length - 1]; + + if (sighashType !== SighashType.SIGHASH_ALL) { + throw Error( + "Silent payment PSBTs require partial signatures to use SIGHASH_ALL.", + ); + } + } + + // Per BIP375: re-verify silent-payment consistency on the live object before + // a signature locks the inputs. No-op when there are no SP outputs. + this.validateSilentPayments(); + const modBackup = this.PSBT_GLOBAL_TX_MODIFIABLE; try { this.inputMaps[inputIndex].set(key, sig); this.handleSighashType(sig); - } catch (err) { - console.error(err); + } catch { // To remain atomic, attempt to reset everything to the way it was. this.inputMaps[inputIndex].delete(key); this.PSBT_GLOBAL_TX_MODIFIABLE = modBackup; @@ -1198,6 +1743,170 @@ export class PsbtV2 extends PsbtV2Maps { } } + // ── Global SP methods ───────────────────────────────────────────────────── + + public addGlobalSPECDHShare(bscan: Buffer, share: Buffer): void { + assertValidBscan(bscan); + assertValidECDHShare(share); + + const key = KeyType.PSBT_GLOBAL_SP_ECDH_SHARE + bscan.toString("hex"); + this.globalMap.set(key, share); + } + + public addGlobalSPDLEQProof(bscan: Buffer, proof: Buffer): void { + assertValidBscan(bscan); + assertValidDLEQProof(proof); + + const shareKey = KeyType.PSBT_GLOBAL_SP_ECDH_SHARE + bscan.toString("hex"); + + if (!this.globalMap.has(shareKey)) { + throw new Error( + "Cannot add global SP DLEQ proof: no matching ECDH share for this " + + "bscan. Call addGlobalSPECDHShare first.", + ); + } + + const key = KeyType.PSBT_GLOBAL_SP_DLEQ + bscan.toString("hex"); + this.globalMap.set(key, proof); + } + + public addGlobalSPECDHShareWithDLEQ( + bscan: Buffer, + aggregateSecret: Buffer, + auxRand?: Buffer, + ): void { + const { ecdhShare, proof } = generateSilentPaymentDLEQProof({ + secret: aggregateSecret, + scanKey: bscan, + auxRand, + }); + + this.addGlobalSPECDHShare(bscan, ecdhShare); + this.addGlobalSPDLEQProof(bscan, proof); + } + + public addInputSPECDHShareWithDLEQ( + inputIndex: number, + bscan: Buffer, + inputSecret: Buffer, + auxRand?: Buffer, + ): void { + if (inputIndex < 0 || inputIndex >= this.inputMaps.length) { + throw new Error( + `inputIndex ${inputIndex} out of range (${this.inputMaps.length} inputs)`, + ); + } + + const { ecdhShare, proof } = generateSilentPaymentDLEQProof({ + secret: inputSecret, + scanKey: bscan, + auxRand, + }); + + this.addInputSPECDHShare(inputIndex, bscan, ecdhShare); + this.addInputSPDLEQProof(inputIndex, bscan, proof); + } + + // ── Per-input SP methods ────────────────────────────────────────────────── + + public addInputSPECDHShare( + inputIndex: number, + bscan: Buffer, + share: Buffer, + ): void { + if (inputIndex < 0 || inputIndex >= this.inputMaps.length) { + throw new Error( + `inputIndex ${inputIndex} out of range (${this.inputMaps.length} inputs)`, + ); + } + assertValidBscan(bscan); + assertValidECDHShare(share); + const key = KeyType.PSBT_IN_SP_ECDH_SHARE + bscan.toString("hex"); + this.inputMaps[inputIndex].set(key, share); + } + + public addInputSPDLEQProof( + inputIndex: number, + bscan: Buffer, + proof: Buffer, + ): void { + if (inputIndex < 0 || inputIndex >= this.inputMaps.length) { + throw new Error( + `inputIndex ${inputIndex} out of range (${this.inputMaps.length} inputs)`, + ); + } + assertValidBscan(bscan); + assertValidDLEQProof(proof); + const shareKey = KeyType.PSBT_IN_SP_ECDH_SHARE + bscan.toString("hex"); + if (!this.inputMaps[inputIndex].has(shareKey)) { + throw new Error( + `Cannot add SP DLEQ proof on input ${inputIndex}: no matching ECDH ` + + "share for this bscan. Call addInputSPECDHShare first.", + ); + } + const key = KeyType.PSBT_IN_SP_DLEQ + bscan.toString("hex"); + this.inputMaps[inputIndex].set(key, proof); + } + + // ── Per-output SP methods ───────────────────────────────────────────────── + private setOutputSPInfoOnMap( + map: Map, + bscan: Buffer, + bspend: Buffer, + ): void { + assertValidBscan(bscan); + assertValidBspend(bspend); + + const bw = new BufferWriter(); + bw.writeBytes(bscan); + bw.writeBytes(bspend); + map.set(KeyType.PSBT_OUT_SP_V0_INFO, bw.render()); + } + + private setOutputSPLabelOnMap( + map: Map, + outputIndex: number, + label: number, + ): void { + if (!map.has(KeyType.PSBT_OUT_SP_V0_INFO)) { + throw new Error( + `Output ${outputIndex} has no SP info. Call setOutputSPInfo first.`, + ); + } + + assertValidLabel(label, outputIndex); + + const bw = new BufferWriter(); + bw.writeU32(label); + map.set(KeyType.PSBT_OUT_SP_V0_LABEL, bw.render()); + } + + public setOutputSPInfo( + outputIndex: number, + bscan: Buffer, + bspend: Buffer, + ): void { + const map = this.outputMaps[outputIndex]; + + if (!map) { + throw new Error( + `outputIndex ${outputIndex} out of range (${this.outputMaps.length} outputs)`, + ); + } + this.setOutputSPInfoOnMap(map, bscan, bspend); + } + + public setOutputSPLabel(outputIndex: number, label: number): void { + const map = this.outputMaps[outputIndex]; + + if (!map) { + throw new Error( + `outputIndex ${outputIndex} out of range (${this.outputMaps.length} outputs)`, + ); + } + this.setOutputSPLabelOnMap(map, outputIndex, label); + } + /** * Sets values on the proprietary keytype for a global, input, or output map. * BIP 174 allows for proprietary values to be set on all maps with the @@ -1513,4 +2222,187 @@ export class PsbtV2 extends PsbtV2Maps { throw Error("Failed to combine PSBTs."); } } + + /** + * Returns `true` if any output has `PSBT_OUT_SP_V0_INFO` set. + * Used by the Signer to determine whether SP rules apply. + */ + get hasSilentPaymentOutputs(): boolean { + return this.outputMaps.some( + (map) => + map.has(KeyType.PSBT_OUT_SP_V0_INFO) || + map.has(KeyType.PSBT_OUT_SP_V0_LABEL), + ); + } + + /** + * Returns `true` if every output that has `PSBT_OUT_SP_V0_INFO` also has + * `PSBT_OUT_SCRIPT` set. Non-SP outputs are excluded from this check since + * `validate()` already guarantees they have a script. + * + * Per BIP375: the Signer must not add a signature until this is true. + */ + get hasAllSPOutputScripts(): boolean { + return this.outputMaps.every( + (map, i) => + !map.has(KeyType.PSBT_OUT_SP_V0_INFO) || + this.hasNonEmptyOutputScript(i), + ); + } + + /** + * Splits the raw 66-byte `PSBT_OUT_SP_V0_INFO` value for a given output + * into its typed `bscan` and `bspend` components. + * + * @param outputIndex - Zero-based index of the output. + * @returns `{ bscan, bspend }` or `null` if the output is not an SP output. + * @throws {Error} If the stored value is not exactly 66 bytes. + */ + getSilentPaymentOutputInfo(outputIndex: number): { + bscan: Buffer; + bspend: Buffer; + } | null { + const raw = this.outputMaps[outputIndex]?.get(KeyType.PSBT_OUT_SP_V0_INFO); + if (!raw) return null; + if (raw.length !== 66) { + throw new Error( + `PSBT_OUT_SP_V0_INFO at output ${outputIndex}: ` + + `expected 66 bytes, got ${raw.length}`, + ); + } + return { + bscan: raw.subarray(0, 33), + bspend: raw.subarray(33, 66), + }; + } + + /** + * Returns the eligible inputs that contribute an ECDH share — i.e. eligible + * by type and not a NUMS taproot script-path spend. + * + * Delegates to {@link contributingIndices} in `silentpayment.ts`. + * + * @returns Array of contributing input indices. + */ + getContributingInputsForSilentPayments(): number[] { + return contributingIndices(this.getSilentPaymentInputDescriptors()); + } + + /** + * Returns `true` when all eligible inputs have an ECDH share, or when a + * global ECDH share exists for every unique scan key in the SP outputs. + * + * Must return `true` before {@link computeSilentPaymentOutputScripts} can run. + */ + hasCompleteECDHCoverage(): boolean { + if (!this.hasSilentPaymentOutputs) return false; + + const scanKeys = [...this.getSilentPaymentOutputGroups().keys()]; + const contributing = this.getContributingInputsForSilentPayments(); + + for (const bscanHex of scanKeys) { + if (this.globalMap.has(KeyType.PSBT_GLOBAL_SP_ECDH_SHARE + bscanHex)) { + continue; + } + const allContributingInputsCovered = contributing.every((i) => + this.inputMaps[i].has(KeyType.PSBT_IN_SP_ECDH_SHARE + bscanHex), + ); + if (!allContributingInputsCovered) return false; + } + + return scanKeys.length > 0; + } + + /** + * Signer role: derives taproot output scripts for all silent payment outputs + * and writes them to `PSBT_OUT_SCRIPT` on each SP output map. + * + * Implements the BIP352 output derivation algorithm: + * ``` + * ecdhSecret = inputHash · ecdhShare + * Pk = Bspend + taggedHash("BIP0352/SharedSecret", ecdhSecret || k) · G + * script = OP_1 <0x20> + * ``` + * + * After setting all output scripts, locks `PSBT_GLOBAL_TX_MODIFIABLE` by + * clearing the Inputs and Outputs Modifiable flags per BIP375. + * + * @throws {Error} If there are no SP outputs. + * @throws {Error} If {@link hasCompleteECDHCoverage} returns `false`. + * @throws {Error} If eligible input public keys cannot be extracted. + * @throws {Error} If no ECDH share is found for a scan key group. + */ + public computeSilentPaymentOutputScripts(): void { + if (!this.hasSilentPaymentOutputs) { + throw new Error("No silent payment outputs found."); + } + + const hasLabeledSilentPaymentOutput = this.outputMaps.some( + (map) => + map.has(KeyType.PSBT_OUT_SP_V0_INFO) && + map.has(KeyType.PSBT_OUT_SP_V0_LABEL), + ); + + if (hasLabeledSilentPaymentOutput) { + throw new Error( + "Cannot compute labeled silent payment output scripts without label tweak derivation.", + ); + } + + if (!this.hasCompleteECDHCoverage()) { + throw new Error( + "Incomplete ECDH coverage — call addGlobalSPECDHShare or " + + "addInputSPECDHShare for all eligible inputs first.", + ); + } + + if (hasSegwitV2PlusInput(this.getSilentPaymentInputDescriptors())) { + throw new Error( + "A PSBT with PSBT_OUT_SP_V0_INFO must not contain SegWit v2+ inputs.", + ); + } + + // ── Step 1: Build the inputHash from outpoints + aggregate pubkey ─────── + const contributing = this.getContributingInputsForSilentPayments(); + const inputHash = this.computeSilentPaymentInputHash(contributing); + + // ── Step 2: Group SP outputs by Bscan, sort within groups ────────────── + const scanKeyGroups = this.getSilentPaymentOutputGroups(); + + // ── Step 3: Resolve ECDH share and derive output scripts ─────────────── + for (const [bscanHex, group] of scanKeyGroups) { + const ecdhShare = this.resolveAndVerifyScanKeyEcdhShare( + bscanHex, + contributing, + ); + + // The producer is about to derive the script, so the share must be fully + // derivable and its DLEQ proof(s) verified before deriving. + if (!ecdhShare) { + throw new Error(`No ECDH share found for scan key ${bscanHex}`); + } + + for (let k = 0; k < group.length; k++) { + const { outputIndex, bspend } = group[k]; + + assertValidOutputK(k, outputIndex); + + const script = deriveSilentPaymentOutput( + ecdhShare, + inputHash, + bspend, + k, + ); + + this.outputMaps[outputIndex].set(KeyType.PSBT_OUT_SCRIPT, script); + } + } + + // ── Step 4: Lock modifiable flags per BIP375 ─────────────────────────── + this.PSBT_GLOBAL_TX_MODIFIABLE = this.PSBT_GLOBAL_TX_MODIFIABLE.filter( + (f) => + f !== PsbtGlobalTxModifiableBits.INPUTS && + f !== PsbtGlobalTxModifiableBits.OUTPUTS, + ); + } } diff --git a/packages/caravan-psbt/src/psbtv2/psbtv2maps.ts b/packages/caravan-psbt/src/psbtv2/psbtv2maps.ts index 0d5b5ec9a1..116e822706 100644 --- a/packages/caravan-psbt/src/psbtv2/psbtv2maps.ts +++ b/packages/caravan-psbt/src/psbtv2/psbtv2maps.ts @@ -128,13 +128,13 @@ export abstract class PsbtV2Maps { if (from.inputMaps.length !== this.inputMaps.length) { throw new Error( `Cannot combine PSBTs with different input counts: ` + - `this has ${this.inputMaps.length}, other has ${from.inputMaps.length}` + `this has ${this.inputMaps.length}, other has ${from.inputMaps.length}`, ); } if (from.outputMaps.length !== this.outputMaps.length) { throw new Error( `Cannot combine PSBTs with different output counts: ` + - `this has ${this.outputMaps.length}, other has ${from.outputMaps.length}` + `this has ${this.outputMaps.length}, other has ${from.outputMaps.length}`, ); } } @@ -224,12 +224,15 @@ export class PsbtConversionMaps extends PsbtV2Maps { } for (let i = 0; i < numOutputs; i++) { + const spInfo = this.outputMaps[i].get(KeyType.PSBT_OUT_SP_V0_INFO); + const script = this.outputMaps[i].get(KeyType.PSBT_OUT_SCRIPT); + if ( - !this.outputMaps[i].has(KeyType.PSBT_OUT_SCRIPT) || + (!spInfo && !script) || !this.outputMaps[i].has(KeyType.PSBT_OUT_AMOUNT) ) { console.warn( - `Output ${i} is missing previous out script or amount. Skipping.`, + `Output ${i} is missing SP_INFO, previous out script or amount. Skipping.`, ); continue; } @@ -237,10 +240,14 @@ export class PsbtConversionMaps extends PsbtV2Maps { this.outputMaps[i].get(KeyType.PSBT_OUT_AMOUNT) as Buffer ).readBigInt64LE(); const numberAmount = parseInt(bigintAmount.toString()); - tx.addOutput( - this.outputMaps[i].get(KeyType.PSBT_OUT_SCRIPT) as Buffer, - numberAmount, - ); + + // BIP375 unique identification uses v0 || Bscan || Bspend when + // PSBT_OUT_SP_V0_INFO is present, so the txid is stable before and after + // the real output script has been computed. + const outputScript = spInfo + ? Buffer.concat([Buffer.from([0x00]), spInfo]) + : (script as Buffer); + tx.addOutput(outputScript, numberAmount); } return tx.toBuffer(); @@ -277,6 +284,8 @@ export class PsbtConversionMaps extends PsbtV2Maps { this.v0delete(this.globalMap, KeyType.PSBT_GLOBAL_INPUT_COUNT); this.v0delete(this.globalMap, KeyType.PSBT_GLOBAL_OUTPUT_COUNT); this.v0delete(this.globalMap, KeyType.PSBT_GLOBAL_TX_MODIFIABLE); + this.v0delete(this.globalMap, KeyType.PSBT_GLOBAL_SP_ECDH_SHARE); + this.v0delete(this.globalMap, KeyType.PSBT_GLOBAL_SP_DLEQ); this.v0delete(this.globalMap, KeyType.PSBT_GLOBAL_VERSION); for (const inputMap of this.inputMaps) { @@ -285,11 +294,15 @@ export class PsbtConversionMaps extends PsbtV2Maps { this.v0delete(inputMap, KeyType.PSBT_IN_SEQUENCE); this.v0delete(inputMap, KeyType.PSBT_IN_REQUIRED_TIME_LOCKTIME); this.v0delete(inputMap, KeyType.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME); + this.v0delete(inputMap, KeyType.PSBT_IN_SP_ECDH_SHARE); + this.v0delete(inputMap, KeyType.PSBT_IN_SP_DLEQ); } for (const outputMap of this.outputMaps) { this.v0delete(outputMap, KeyType.PSBT_OUT_AMOUNT); this.v0delete(outputMap, KeyType.PSBT_OUT_SCRIPT); + this.v0delete(outputMap, KeyType.PSBT_OUT_SP_V0_INFO); + this.v0delete(outputMap, KeyType.PSBT_OUT_SP_V0_LABEL); } }; @@ -311,7 +324,7 @@ export class PsbtConversionMaps extends PsbtV2Maps { ); throw new Error( "Cannot compute transaction ID: PSBT has 0 inputs and 1 output, " + - "which produces an ambiguous transaction format. " + "which produces an ambiguous transaction format. ", ); } diff --git a/packages/caravan-psbt/src/psbtv2/silentpayment.ts b/packages/caravan-psbt/src/psbtv2/silentpayment.ts new file mode 100644 index 0000000000..3c7637b20e --- /dev/null +++ b/packages/caravan-psbt/src/psbtv2/silentpayment.ts @@ -0,0 +1,587 @@ +/** + * @file BIP352 / BIP375 Silent Payment cryptographic primitives. + * + * Pure functions with no PSBT state. Imported by {@link PsbtV2} for use in + * {@link PsbtV2.computeSilentPaymentOutputScripts}. + * + * @see {@link https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki BIP352} + * @see {@link https://github.com/bitcoin/bips/blob/master/bip-0375.mediawiki BIP375} + */ + +import { secp256k1, schnorr } from "@noble/curves/secp256k1"; +import { script, Transaction } from "bitcoinjs-lib-v6"; +import { taggedHash } from "./functions"; + +const CURVE_ORDER = secp256k1.CURVE.n; +const { bytesToNumberBE } = schnorr.utils; +const { OPS } = script; +import { hash160 } from "@caravan/bitcoin"; +import { + generateDLEQProof, + multiplyCompressedPoint, + verifyDLEQProof, + ProjectivePoint, +} from "./dleq"; + +// ── Public types ─────────────────────────────────────────────────────────── + +/** + * A single silent payment output entry within a scan-key group, used to + * determine recipient ordering and k-value assignment per BIP375. + */ +export interface SPOutputEntry { + /** Index of this output in the PSBT output maps. */ + outputIndex: number; + /** 33-byte compressed scan public key. */ + bscan: Buffer; + /** 33-byte compressed spend public key. */ + bspend: Buffer; +} + +/** + * Input descriptor passed to {@link eligibleIndices}. One entry per input, + * in original index order. + */ +export interface SPInputDescriptor { + witnessUtxo: Buffer | null; + nonWitnessUtxo?: Buffer | null; + outputIndex?: number | null; + redeemScript?: Buffer | null; + tapInternalKey?: string | null; // PSBT_IN_TAP_INTERNAL_KEY, hex + tapLeafScriptKeys?: string[]; // PSBT_IN_TAP_LEAF_SCRIPT entry keys, hex +} + +export type SPInputScriptType = + | "p2tr" + | "p2wpkh" + | "p2wsh" + | "segwit_v2plus" + | "p2pkh_or_unknown_legacy" + | "p2sh_p2wpkh" + | "ineligible"; + +export const BIP352_NUMS_H = + "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"; + +// ── Field validators ─────────────────────────────────────────────────────── +// Called from both field setters in PsbtV2 and validateSilentPayments(). + +/** + * Asserts that a scan public key is a valid 33-byte compressed point. + * + * @param bscan - Candidate scan public key buffer. + * @throws {Error} If `bscan` is not exactly 33 bytes. + */ +function assertValidCompressedPoint(value: Buffer, name: string): void { + if (value.length !== 33) { + throw new Error( + `${name} must be a 33-byte compressed pubkey, got ${value.length}`, + ); + } + if (value[0] !== 0x02 && value[0] !== 0x03) { + throw new Error( + `${name} must use compressed secp256k1 prefix 0x02 or 0x03`, + ); + } + secp256k1.ProjectivePoint.fromHex(value); +} + +export function assertValidBscan(bscan: Buffer): void { + assertValidCompressedPoint(bscan, "bscan"); +} + +/** + * Asserts that a spend public key is a valid 33-byte compressed point. + * + * @param bspend - Candidate scan public key buffer. + * @throws {Error} If `bspend` is not exactly 33 bytes. + */ +export function assertValidBspend(bspend: Buffer): void { + assertValidCompressedPoint(bspend, "bspend"); +} + +/** + * Asserts that an ECDH share is a valid 33-byte compressed EC point. + * + * @param share - Candidate ECDH share buffer. + * @throws {Error} If `share` is not exactly 33 bytes. + */ +export function assertValidECDHShare(share: Buffer): void { + assertValidCompressedPoint(share, "ECDH share"); +} + +/** + * Asserts that a DLEQ proof is exactly 64 bytes. + * + * @param proof - Candidate DLEQ proof buffer. + * @throws {Error} If `proof` is not exactly 64 bytes. + */ +export function assertValidDLEQProof(proof: Buffer): void { + if (proof.length !== 64) { + throw new Error(`DLEQ proof must be 64 bytes, got ${proof.length}`); + } +} + +/** + * Asserts that a `PSBT_OUT_SP_V0_INFO` value is exactly 66 bytes + * (`bscan(33) || bspend(33)`). + * + * @param raw - Candidate SP V0 info buffer. + * @param outputIndex - Output index for error context. + * @throws {Error} If `raw` is not exactly 66 bytes. + */ +export function assertValidSPV0Info(raw: Buffer, outputIndex: number): void { + if (raw.length !== 66) { + throw new Error( + `PSBT_OUT_SP_V0_INFO at output ${outputIndex}: ` + + `expected 66 bytes, got ${raw.length}`, + ); + } + assertValidBscan(raw.subarray(0, 33)); + assertValidBspend(raw.subarray(33, 66)); +} + +export function assertValidLabel(m: number, outputIndex: number): void { + if (!Number.isInteger(m) || m < 0 || m > 0xffffffff) { + throw new Error( + `Silent payment label m is invalid at output ${outputIndex}: ${m}`, + ); + } +} + +export function assertValidOutputK(k: number, outputIndex: number): void { + if (!Number.isInteger(k) || k < 0 || k >= 2323) { + throw new Error( + `Silent payment recipient index should be 0 < k < 2323 (Kmax) but was at output ${outputIndex}: ${k}`, + ); + } +} + +function assertValidScalar(value: bigint, name: string): void { + if (value === 0n || value >= CURVE_ORDER) { + throw new Error(`${name} is not a valid secp256k1 scalar`); + } +} + +// ── Eligible input indices ───────────────────────────────────────────────── + +function readWitnessUtxoScript(witnessUtxo: Buffer): Buffer { + if (witnessUtxo.length < 9) return Buffer.alloc(0); + const scriptLen = witnessUtxo[8]; + return witnessUtxo.subarray(9, 9 + scriptLen); +} + +function readNonWitnessUtxoScript( + nonWitnessUtxo?: Buffer | null, + outputIndex?: number | null, +): Buffer | null { + if (!nonWitnessUtxo || outputIndex === null || outputIndex === undefined) { + return null; + } + + const tx = Transaction.fromBuffer(nonWitnessUtxo); + return tx.outs[outputIndex]?.script ?? null; +} + +export function classifyWitnessScript(scriptPubKey: Buffer): SPInputScriptType { + if ( + scriptPubKey.length === 34 && + scriptPubKey[0] === OPS.OP_1 && + scriptPubKey[1] === 0x20 + ) { + return "p2tr"; + } + if ( + scriptPubKey.length === 22 && + scriptPubKey[0] === OPS.OP_0 && + scriptPubKey[1] === 0x14 + ) { + return "p2wpkh"; + } + if ( + scriptPubKey.length === 34 && + scriptPubKey[0] === OPS.OP_0 && + scriptPubKey[1] === 0x20 + ) { + return "p2wsh"; + } + if ( + scriptPubKey.length >= 4 && + scriptPubKey[0] >= OPS.OP_2 && + scriptPubKey[0] <= OPS.OP_16 + ) { + return "segwit_v2plus"; + } + if ( + scriptPubKey.length === 25 && + scriptPubKey[0] === OPS.OP_DUP && + scriptPubKey[1] === OPS.OP_HASH160 && + scriptPubKey[2] === 0x14 && + scriptPubKey[23] === OPS.OP_EQUALVERIFY && + scriptPubKey[24] === OPS.OP_CHECKSIG + ) { + return "p2pkh_or_unknown_legacy"; + } + if ( + scriptPubKey.length === 23 && + scriptPubKey[0] === OPS.OP_HASH160 && + scriptPubKey[1] === 0x14 && + scriptPubKey[22] === OPS.OP_EQUAL + ) { + return "ineligible"; + } + return "ineligible"; +} + +export function classifyInputDescriptor( + input: SPInputDescriptor, +): SPInputScriptType { + const script = input.witnessUtxo + ? readWitnessUtxoScript(input.witnessUtxo) + : readNonWitnessUtxoScript(input.nonWitnessUtxo, input.outputIndex); + + if (!script) { + return "ineligible"; + } + + const scriptType = classifyWitnessScript(script); + + if (scriptType === "p2sh_p2wpkh") { + return scriptType; + } + + if ( + script.length === 23 && + script[0] === OPS.OP_HASH160 && + script[1] === 0x14 && + script[22] === OPS.OP_EQUAL + ) { + if ( + input.redeemScript && + classifyWitnessScript(input.redeemScript) === "p2wpkh" + ) { + return "p2sh_p2wpkh"; + } + + return "ineligible"; + } + + return scriptType; +} + +export function isEligibleInputType(type: SPInputScriptType): boolean { + return ( + type === "p2tr" || + type === "p2wpkh" || + type === "p2sh_p2wpkh" || + type === "p2pkh_or_unknown_legacy" + ); +} + +/** + * Determines which transaction inputs are eligible for silent payment ECDH + * derivation per BIP352. + * + * Eligible input types: + * - P2TR (Taproot keypath) — `OP_1 <32-byte x-only key>` + * - P2WPKH — `OP_0 <20-byte hash>` + * - P2SH-P2WPKH / P2PKH — no witness UTXO present + * + * Ineligible input types: + * - P2WSH — `OP_0 <32-byte hash>` (multisig, multiple keys) + * - Segwit v2+ — not permitted alongside SP outputs per BIP375 + * + * @param inputs - One entry per input, in original index order. The array + * must be complete and unfiltered so that returned indices correctly + * correspond to positions in the original input list. + * @returns Array of input indices eligible for SP ECDH derivation. + */ +function eligibleIndices(inputs: SPInputDescriptor[]): number[] { + const eligible: number[] = []; + + for (let i = 0; i < inputs.length; i++) { + if (isEligibleInputType(classifyInputDescriptor(inputs[i]))) { + eligible.push(i); + } + } + + return eligible; +} + +/** + * A taproot input spent via script path using the BIP352 NUMS point H as its + * internal key is eligible by type but never contributes an ECDH share. + */ +export function isNumsScriptPathSpend(input: SPInputDescriptor): boolean { + if (input.tapInternalKey === BIP352_NUMS_H) { + return true; + } + + return (input.tapLeafScriptKeys ?? []).some((key) => { + const keydata = Buffer.from(key.slice(2), "hex"); + + if (keydata.length < 33) { + return false; + } + + return keydata.subarray(1, 33).toString("hex") === BIP352_NUMS_H; + }); +} + +/** + * Eligible inputs that actually contribute an ECDH share — i.e. eligible by + * type and not a NUMS script-path spend. + */ +export function contributingIndices(inputs: SPInputDescriptor[]): number[] { + return eligibleIndices(inputs).filter( + (i) => !isNumsScriptPathSpend(inputs[i]), + ); +} + +export function hasSegwitV2PlusInput(inputs: SPInputDescriptor[]): boolean { + return inputs.some( + (input) => classifyInputDescriptor(input) === "segwit_v2plus", + ); +} + +export function getTaprootOutputKeyFromWitnessUtxo( + witnessUtxo: Buffer, +): Buffer | null { + const scriptPubKey = readWitnessUtxoScript(witnessUtxo); + if (classifyWitnessScript(scriptPubKey) !== "p2tr") return null; + return Buffer.concat([Buffer.from([0x02]), scriptPubKey.subarray(2, 34)]); +} + +export function getSilentPaymentPubkeyFromInputDescriptor( + input: SPInputDescriptor, + candidatePubkeys: Buffer[], +): Buffer | null { + const scriptPubKey = input.witnessUtxo + ? readWitnessUtxoScript(input.witnessUtxo) + : readNonWitnessUtxoScript(input.nonWitnessUtxo, input.outputIndex); + + if (!scriptPubKey) return null; + + const scriptType = classifyInputDescriptor(input); + + if (scriptType === "p2tr") { + return input.witnessUtxo + ? getTaprootOutputKeyFromWitnessUtxo(input.witnessUtxo) + : null; + } + + for (const pubkey of candidatePubkeys) { + assertValidCompressedPoint(pubkey, "silent payment input pubkey"); + const pubkeyHash = hash160(pubkey); + + if (scriptType === "p2wpkh") { + if (pubkeyHash.equals(scriptPubKey.subarray(2, 22))) return pubkey; + continue; + } + + if (scriptType === "p2pkh_or_unknown_legacy") { + if (pubkeyHash.equals(scriptPubKey.subarray(3, 23))) return pubkey; + continue; + } + + if (scriptType === "p2sh_p2wpkh") { + if (!input.redeemScript) continue; + + const p2shHash = scriptPubKey.subarray(2, 22); + if (!hash160(input.redeemScript).equals(p2shHash)) continue; + if (classifyWitnessScript(input.redeemScript) !== "p2wpkh") continue; + + const redeemWitnessProgram = input.redeemScript.subarray(2, 22); + if (pubkeyHash.equals(redeemWitnessProgram)) return pubkey; + } + } + + return null; +} + +export function groupSilentPaymentOutputs( + entries: SPOutputEntry[], +): Map { + const groups = new Map(); + for (const entry of entries) { + const key = entry.bscan.toString("hex"); + if (!groups.has(key)) groups.set(key, []); + groups.get(key)!.push(entry); + } + for (const group of groups.values()) { + group.sort((a, b) => { + const cmp = a.bspend.compare(b.bspend); + return cmp !== 0 ? cmp : a.outputIndex - b.outputIndex; + }); + } + return groups; +} + +// ── ECDH share accumulation ──────────────────────────────────────────────── + +/** + * Sums a list of 33-byte compressed EC points (per-input ECDH shares) into a + * single point. Used when a global ECDH share is not available and per-input + * shares must be combined before output script derivation. + * + * @param shares - Array of 33-byte compressed EC point buffers. + * @returns The accumulated projective point. + * @throws {Error} If `shares` is empty. + */ +export function sumECDHShares(shares: Buffer[]): ProjectivePoint { + if (shares.length === 0) { + throw new Error("Cannot sum zero ECDH shares."); + } + let sum: ProjectivePoint | null = null; + for (const buf of shares) { + const point = secp256k1.ProjectivePoint.fromHex(buf); + sum = sum ? sum.add(point) : point; + } + return sum!; +} + +// ── Input hash ──────────────────────────────────────────────────────────── + +/** + * Computes the BIP352 input hash used to bind the silent payment derivation + * to the specific set of transaction inputs. + * + * ``` + * inputHash = taggedHash("BIP0352/Inputs", outpointL || A) + * ``` + * + * Where `outpointL` is the lexicographically smallest outpoint and `A` is + * the sum of compressed public keys of all eligible inputs. + * + * @param outpoints - Array of 36-byte buffers, each `txid(32 LE) || vout(4 LE)`. + * @param combinedPubkey - 33-byte compressed sum of eligible input public keys. + * @returns 32-byte input hash buffer. + * @throws {Error} If `outpoints` is empty. + */ +export function computeInputHash( + outpoints: Buffer[], + combinedPubkey: Buffer, +): Buffer { + if (outpoints.length === 0) { + throw new Error("At least one outpoint is required to compute inputHash."); + } + const sorted = [...outpoints].sort(Buffer.compare); + const data = Buffer.concat([sorted[0], combinedPubkey]); + return taggedHash("BIP0352/Inputs", data); +} + +// ── Output script derivation ─────────────────────────────────────────────── + +/** + * Derives the taproot (P2TR) output script for a single silent payment + * recipient within a scan-key group. + * + * Per BIP352: + * ``` + * ecdhSecret = inputHash · ecdhShare + * tweak_k = taggedHash("BIP0352/SharedSecret", ecdhSecret_compressed || k_be32) + * Pk = Bspend + tweak_k · G + * outputScript = OP_1 <0x20> + * ``` + * + * Uses full compressed point arithmetic for `Bspend` to correctly handle + * both even-y (0x02) and odd-y (0x03) spend keys. + * + * @param ecdhShare - 33-byte compressed EC point `C = a·Bscan`, where `a` is + * the sum of eligible input private keys (global share) or a single input's + * private key (per-input share). + * @param inputHash - 32-byte scalar produced by {@link computeInputHash}. + * @param bspend - 33-byte compressed spend public key from the recipient's + * silent payment address. + * @param k - Zero-based recipient index within the scan-key group. Increments + * for each recipient sharing the same `Bscan`. + * @returns 34-byte P2TR output script: `OP_1 <0x20> <32-byte x-only pubkey>`. + */ +export function deriveSilentPaymentOutput( + ecdhShare: Buffer, + inputHash: Buffer, + bspend: Buffer, + k: number, +): Buffer { + const inputScalar = bytesToNumberBE(inputHash); + assertValidScalar(inputScalar, "Silent payment input hash"); + + // ecdhSecret = inputHash · ecdhShare + const ecdhSecretPoint = + secp256k1.ProjectivePoint.fromHex(ecdhShare).multiply(inputScalar); + const ecdhSecretBytes = ecdhSecretPoint.toRawBytes(true); + + // tweak_k = taggedHash("BIP0352/SharedSecret", ecdhSecret_compressed || k_be32) + const kBuf = Buffer.allocUnsafe(4); + kBuf.writeUInt32BE(k, 0); + const tweak = taggedHash( + "BIP0352/SharedSecret", + Buffer.concat([ecdhSecretBytes, kBuf]), + ); + + const tweakScalar = bytesToNumberBE(tweak); + assertValidScalar(tweakScalar, "Silent payment shared-secret tweak"); + + // Pk = Bspend + tweak_k·G + const Pk = secp256k1.ProjectivePoint.fromHex(bspend).add( + secp256k1.ProjectivePoint.BASE.multiply(tweakScalar), + ); + + // P2TR output script: OP_1 <0x20> + const xOnlyPk = Pk.toRawBytes(true).subarray(1); + return Buffer.concat([Buffer.from([OPS.OP_1, 0x20]), xOnlyPk]); +} + +export function generateSilentPaymentDLEQProof({ + secret, + scanKey, + auxRand, +}: { + secret: Buffer; + scanKey: Buffer; + auxRand?: Buffer; +}): { + ecdhShare: Buffer; + proof: Buffer; +} { + assertValidBscan(scanKey); + + const ecdhShare = multiplyCompressedPoint(scanKey, secret); + assertValidECDHShare(ecdhShare); + + const proof = generateDLEQProof({ + secret, + basePoint: scanKey, + auxRand, + }); + + assertValidDLEQProof(proof); + + return { + ecdhShare, + proof, + }; +} + +export function verifySilentPaymentDLEQProof({ + publicKey, + scanKey, + ecdhShare, + proof, +}: { + publicKey: Buffer; + scanKey: Buffer; + ecdhShare: Buffer; + proof: Buffer; +}): boolean { + assertValidBscan(scanKey); + assertValidECDHShare(ecdhShare); + assertValidDLEQProof(proof); + + return verifyDLEQProof({ + publicKey, + basePoint: scanKey, + result: ecdhShare, + proof, + }); +} diff --git a/packages/caravan-psbt/src/psbtv2/types.ts b/packages/caravan-psbt/src/psbtv2/types.ts index da33e250e0..9c3f21c5d8 100644 --- a/packages/caravan-psbt/src/psbtv2/types.ts +++ b/packages/caravan-psbt/src/psbtv2/types.ts @@ -25,6 +25,8 @@ export enum KeyType { PSBT_GLOBAL_INPUT_COUNT = "04", PSBT_GLOBAL_OUTPUT_COUNT = "05", PSBT_GLOBAL_TX_MODIFIABLE = "06", + PSBT_GLOBAL_SP_ECDH_SHARE = "07", + PSBT_GLOBAL_SP_DLEQ = "08", PSBT_GLOBAL_VERSION = "fb", PSBT_GLOBAL_PROPRIETARY = "fc", @@ -53,6 +55,8 @@ export enum KeyType { PSBT_IN_TAP_BIP32_DERIVATION = "16", PSBT_IN_TAP_INTERNAL_KEY = "17", PSBT_IN_TAP_MERKLE_ROOT = "18", + PSBT_IN_SP_ECDH_SHARE = "1d", + PSBT_IN_SP_DLEQ = "1e", PSBT_IN_PROPRIETARY = "fc", PSBT_OUT_REDEEM_SCRIPT = "00", @@ -63,6 +67,8 @@ export enum KeyType { PSBT_OUT_TAP_INTERNAL_KEY = "05", PSBT_OUT_TAP_TREE = "06", PSBT_OUT_TAP_BIP32_DERIVATION = "07", + PSBT_OUT_SP_V0_INFO = "09", + PSBT_OUT_SP_V0_LABEL = "0a", PSBT_OUT_PROPRIETARY = "fc", }