diff --git a/README.md b/README.md index 22879f0..9fd09d6 100644 --- a/README.md +++ b/README.md @@ -161,10 +161,10 @@ We have integrated three APIs—Mempool, BlockCypher, and Electrum—into the pl final publicKey = ECPublic.fromHex('.....'); // Generate a Pay-to-Public-Key-Hash (P2PKH) address from the public key. - final p2pkh = publicKey.toAddress(); + final p2pkh = publicKey.toP2pkhAddress(); // Generate a Pay-to-Witness-Public-Key-Hash (P2WPKH) Segregated Witness (SegWit) address from the public key. - final p2wpkh = publicKey.toSegwitAddress(); + final p2wpkh = publicKey.toP2wpkhAddress(); // Generate a Pay-to-Witness-Script-Hash (P2WSH) Segregated Witness (SegWit) address from the public key. final p2wsh = publicKey.toP2wshAddress(); @@ -303,8 +303,8 @@ In the [example](https://github.com/mrtnetwork/bitcoin_base/tree/main/example/li final privateKey = ECPrivate.fromHex( "76257aafc9b954351c7f6445b2d07277f681a5e83d515a1f32ebf54989c2af4f"); final examplePublicKey = privateKey.getPublic(); - final spender1 = examplePublicKey.toAddress(); - final spender2 = examplePublicKey.toSegwitAddress(); + final spender1 = examplePublicKey.toP2pkhAddress(); + final spender2 = examplePublicKey.toP2wpkhAddress(); final spender3 = examplePublicKey.toTaprootAddress(); final spender4 = examplePublicKey.toP2pkhInP2sh(); final spender5 = examplePublicKey.toP2pkInP2sh(); @@ -353,9 +353,9 @@ In the [example](https://github.com/mrtnetwork/bitcoin_base/tree/main/example/li /// P2pkhAddress.fromAddress(address: ".....", network: network); /// P2trAddress.fromAddress(address: "....", network: network) /// .... - final List outPuts = [ + final List outputs = [ BitcoinOutput( - address: examplePublicKey2.toSegwitAddress(), + address: examplePublicKey2.toP2wpkhAddress(), value: BtcUtils.toSatoshi("0.00001")), BitcoinOutput( address: examplePublicKey2.toTaprootAddress(), @@ -382,11 +382,11 @@ In the [example](https://github.com/mrtnetwork/bitcoin_base/tree/main/example/li int transactionSize = BitcoinTransactionBuilder.estimateTransactionSize( utxos: accountsUtxos, outputs: [ - ...outPuts, + ...outputs, /// I add more output for change value to get correct transaction size BitcoinOutput( - address: examplePublicKey2.toAddress(), value: BigInt.zero) + address: examplePublicKey2.toP2pkhAddress(), value: BigInt.zero) ], /// network @@ -413,13 +413,13 @@ In the [example](https://github.com/mrtnetwork/bitcoin_base/tree/main/example/li } //// if we have change value we back amount to account if (changeValue > BigInt.zero) { - outPuts.add(BitcoinOutput( - address: examplePublicKey2.toAddress(), value: changeValue)); + outputs.add(BitcoinOutput( + address: examplePublicKey2.toP2pkhAddress(), value: changeValue)); } /// create transaction builder final builder = BitcoinTransactionBuilder( - outPuts: outPuts, + outputs: outputs, fee: fee, network: network, utxos: accountsUtxos, @@ -482,7 +482,7 @@ In the [example](https://github.com/mrtnetwork/bitcoin_base/tree/main/example/li /// p2pkh with token address () final receiver1 = P2pkhAddress.fromHash160( - addrHash: publicKey.toAddress().addressProgram, + h160: publicKey.toP2pkhAddress().addressProgram, type: P2pkhAddressType.p2pkhwt); /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. @@ -531,7 +531,7 @@ In the [example](https://github.com/mrtnetwork/bitcoin_base/tree/main/example/li previousValue + element.utxo.token!.amount); final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ /// change address for bch values (sum of bch amout - (outputs amount + fee)) BitcoinOutput( address: p2pkhAddress.baseAddress, @@ -695,7 +695,7 @@ In the [example](https://github.com/mrtnetwork/bitcoin_base/tree/main/example/li // index of utxo txInIndex: i, // spender script pub key - script: utxo[i].public().toAddress().toScriptPubKey(), + script: utxo[i].public().toP2pkhAddress().toScriptPubKey(), ); // sign transaction diff --git a/example/lib/bitcoin_cash/burn_token_example.dart b/example/lib/bitcoin_cash/burn_token_example.dart index b49fa02..a4a53b7 100644 --- a/example/lib/bitcoin_cash/burn_token_example.dart +++ b/example/lib/bitcoin_cash/burn_token_example.dart @@ -29,10 +29,10 @@ void main() async { /// p2pkh with token address () final receiver1 = P2pkhAddress.fromHash160( - addrHash: publicKey.toAddress().addressProgram, + h160: publicKey.toP2pkhAddress().addressProgram, type: P2pkhAddressType.p2pkhwt); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -80,7 +80,7 @@ void main() async { previousValue + element.utxo.token!.amount); final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ /// change address for bch values (sum of bch amout - (outputs amount + fee)) BitcoinOutput( address: p2pkhAddress.baseAddress, diff --git a/example/lib/bitcoin_cash/create_cash_token_example.dart b/example/lib/bitcoin_cash/create_cash_token_example.dart index 9edbd44..87f89c5 100644 --- a/example/lib/bitcoin_cash/create_cash_token_example.dart +++ b/example/lib/bitcoin_cash/create_cash_token_example.dart @@ -25,9 +25,9 @@ void main() async { /// Derives a P2PKH address from the given public key and converts it to a Bitcoin Cash address /// for enhanced accessibility within the network. - final p2pkhAddress = publicKey.toAddress(); + final p2pkhAddress = publicKey.toP2pkhAddress(); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -65,7 +65,7 @@ void main() async { return; } final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ BitcoinTokenOutput( address: p2pkhAddress, diff --git a/example/lib/bitcoin_cash/create_nft_example.dart b/example/lib/bitcoin_cash/create_nft_example.dart index 64efa27..982e01a 100644 --- a/example/lib/bitcoin_cash/create_nft_example.dart +++ b/example/lib/bitcoin_cash/create_nft_example.dart @@ -26,9 +26,9 @@ void main() async { /// Derives a P2PKH address from the given public key and converts it to a Bitcoin Cash address /// for enhanced accessibility within the network. final p2pkhAddress = - BitcoinCashAddress.fromBaseAddress(publicKey.toAddress()); + BitcoinCashAddress.fromBaseAddress(publicKey.toP2pkhAddress()); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -66,7 +66,7 @@ void main() async { return; } final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ BitcoinOutput( address: p2pkhAddress.baseAddress, value: sumOfUtxo - diff --git a/example/lib/bitcoin_cash/make_vout0_example.dart b/example/lib/bitcoin_cash/make_vout0_example.dart index b3f5746..8031e39 100644 --- a/example/lib/bitcoin_cash/make_vout0_example.dart +++ b/example/lib/bitcoin_cash/make_vout0_example.dart @@ -26,9 +26,9 @@ void main() async { /// Derives a P2PKH address from the given public key and converts it to a Bitcoin Cash address /// for enhanced accessibility within the network. - final p2pkhAddress = publicKey.toAddress(); + final p2pkhAddress = publicKey.toP2pkhAddress(); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -48,7 +48,7 @@ void main() async { final sumOfUtxo = utxos.sumOfUtxosValue(); final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ BitcoinOutput( address: p2pkhAddress, value: sumOfUtxo - BtcUtils.toSatoshi("0.00003"), diff --git a/example/lib/bitcoin_cash/minting_nft_example.dart b/example/lib/bitcoin_cash/minting_nft_example.dart index 4e74ac7..5a1ca29 100644 --- a/example/lib/bitcoin_cash/minting_nft_example.dart +++ b/example/lib/bitcoin_cash/minting_nft_example.dart @@ -28,7 +28,7 @@ void main() async { final p2pkhAddress = BitcoinCashAddress.fromBaseAddress( publicKey.toP2pkInP2sh(useBCHP2sh32: true)); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -55,7 +55,7 @@ void main() async { "3f0d87791e5996aaddbce16c12651dd8b5b881cf7338340504bb7b2c6c08bfc4"; final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ BitcoinOutput( address: p2pkhAddress.baseAddress, value: sumOfUtxo - diff --git a/example/lib/bitcoin_cash/old_examples/old_example.dart b/example/lib/bitcoin_cash/old_examples/old_example.dart index 1c52cd9..99dbce5 100644 --- a/example/lib/bitcoin_cash/old_examples/old_example.dart +++ b/example/lib/bitcoin_cash/old_examples/old_example.dart @@ -101,7 +101,7 @@ void _spendFrom2P2SHAnd2P2PKHAddress() async { ]); final b = ForkedTransactionBuilder( - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the P2shAddress and a value of 0.01 BCH BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("0.01")), @@ -121,7 +121,7 @@ void _spendFrom2P2SHAnd2P2PKHAddress() async { /// Specify the network for the litcoin transaction network: network, - /// Define a list of Unspent Transaction Outputs (UTXOs) for the Bitcoin transaction + /// Define a list of Unspent Transaction outputs (UTXOs) for the Bitcoin transaction utxos: [ UtxoWithAddress( @@ -138,13 +138,13 @@ void _spendFrom2P2SHAnd2P2PKHAddress() async { vout: 0, /// Script type indicates the type of script associated with the UTXO's address - scriptType: examplePublicKey2.toAddress().type, + scriptType: examplePublicKey2.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey2.toHex(), - address: examplePublicKey2.toAddress())), + address: examplePublicKey2.toP2pkhAddress())), ]); /// Build the transaction by invoking the buildTransaction method on the ForkedTransactionBuilder @@ -247,7 +247,7 @@ void _spendFrom2P2SHAnd1P2PKHAddress() async { final b = ForkedTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the P2pkhAddress and a value of 0.01 BCH BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("0.01")), @@ -267,7 +267,7 @@ void _spendFrom2P2SHAnd1P2PKHAddress() async { /// Add a memo to the transaction, linking to the GitHub repository memo: "https://github.com/mrtnetwork", - /// Define a list of Unspent Transaction Outputs (UTXOs) for the Bitcoin transaction + /// Define a list of Unspent Transaction outputs (UTXOs) for the Bitcoin transaction utxos: [ UtxoWithAddress( @@ -324,13 +324,13 @@ void _spendFrom2P2SHAnd1P2PKHAddress() async { vout: 2, /// Script type indicates the type of script associated with the UTXO's address - scriptType: examplePublicKey.toAddress().type, + scriptType: examplePublicKey.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey.toHex(), - address: examplePublicKey.toAddress())), + address: examplePublicKey.toP2pkhAddress())), UtxoWithAddress( utxo: BitcoinUtxo( /// Transaction hash uniquely identifies the referenced transaction diff --git a/example/lib/bitcoin_cash/p2sh32_spend_example.dart b/example/lib/bitcoin_cash/p2sh32_spend_example.dart index d621909..6a2697a 100644 --- a/example/lib/bitcoin_cash/p2sh32_spend_example.dart +++ b/example/lib/bitcoin_cash/p2sh32_spend_example.dart @@ -27,7 +27,7 @@ void main() async { /// Derives a P2PKH address from the given public key and converts it to a Bitcoin Cash address /// for enhanced accessibility within the network. final p2pkhAddress = - BitcoinCashAddress.fromBaseAddress(publicKey.toAddress()); + BitcoinCashAddress.fromBaseAddress(publicKey.toP2pkhAddress()); /// Initialize two P2SH32 addresses for receiving funds. /// bchtest:pvw39llgap0a4vm8jn9sjsvfsthah4wgemjlh6epdtzr3pl2fqtmsn3s4vcm7 @@ -42,7 +42,7 @@ void main() async { final p2sh32Example2 = BitcoinCashAddress.fromBaseAddress( publicKey.toP2pkInP2sh(useBCHP2sh32: true)); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final example1ElectrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -79,7 +79,7 @@ void main() async { return; } final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ BitcoinOutput( address: p2pkhAddress.baseAddress, value: BtcUtils.toSatoshi("0.00001"), diff --git a/example/lib/bitcoin_cash/send_ft_token_example.dart b/example/lib/bitcoin_cash/send_ft_token_example.dart index 0b589f5..97dff3b 100644 --- a/example/lib/bitcoin_cash/send_ft_token_example.dart +++ b/example/lib/bitcoin_cash/send_ft_token_example.dart @@ -30,10 +30,10 @@ void main() async { /// p2pkh with token address () final receiver1 = P2pkhAddress.fromHash160( - addrHash: publicKey.toAddress().addressProgram, + h160: publicKey.toP2pkhAddress().addressProgram, type: P2pkhAddressType.p2pkhwt); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -81,7 +81,7 @@ void main() async { previousValue + element.utxo.token!.amount); final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ /// change address for bch values (sum of bch amout - (outputs amount + fee)) BitcoinOutput( address: p2pkhAddress.baseAddress, diff --git a/example/lib/bitcoin_cash/transfer_bch_example.dart b/example/lib/bitcoin_cash/transfer_bch_example.dart index 324ff80..93ea1c6 100644 --- a/example/lib/bitcoin_cash/transfer_bch_example.dart +++ b/example/lib/bitcoin_cash/transfer_bch_example.dart @@ -27,7 +27,7 @@ void main() async { /// Derives a P2PKH address from the given public key and converts it to a Bitcoin Cash address /// for enhanced accessibility within the network. final p2pkhAddress = - BitcoinCashAddress.fromBaseAddress(publicKey.toAddress()); + BitcoinCashAddress.fromBaseAddress(publicKey.toP2pkhAddress()); /// Initialize two P2SH32 addresses for receiving funds. final p2sh32Example1 = BitcoinCashAddress( @@ -37,7 +37,7 @@ void main() async { "bchtest:pvw39llgap0a4vm8jn9sjsvfsthah4wgemjlh6epdtzr3pl2fqtmsn3s4vcm7", network: network); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -60,7 +60,7 @@ void main() async { } final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ /// change input (sumofutxos - spend) BitcoinOutput( address: p2pkhAddress.baseAddress, diff --git a/example/lib/global/bch_example.dart b/example/lib/global/bch_example.dart index f6caefe..c2f9768 100644 --- a/example/lib/global/bch_example.dart +++ b/example/lib/global/bch_example.dart @@ -24,7 +24,7 @@ void main() async { /// Derives a P2PKH address from the given public key and converts it to a Bitcoin Cash address /// for enhanced accessibility within the network. final p2pkhAddress = - BitcoinCashAddress.fromBaseAddress(publicKey.toAddress()); + BitcoinCashAddress.fromBaseAddress(publicKey.toP2pkhAddress()); /// Initialize two P2SH32 addresses for receiving funds. final p2sh32Example1 = BitcoinCashAddress( @@ -34,7 +34,7 @@ void main() async { "bchtest:pvw39llgap0a4vm8jn9sjsvfsthah4wgemjlh6epdtzr3pl2fqtmsn3s4vcm7", network: network); - /// Reads all UTXOs (Unspent Transaction Outputs) associated with the account. + /// Reads all UTXOs (Unspent Transaction outputs) associated with the account. /// We does not need tokens utxo and we set to false. final elctrumUtxos = await provider.request(ElectrumRequestScriptHashListUnspent( @@ -57,7 +57,7 @@ void main() async { } final bchTransaction = ForkedTransactionBuilder( - outPuts: [ + outputs: [ /// change input (sumofutxos - spend) BitcoinOutput( address: p2pkhAddress.baseAddress, diff --git a/example/lib/global/old_examples/bitcoin_example.dart b/example/lib/global/old_examples/bitcoin_example.dart index 2f64098..bdcbfb8 100644 --- a/example/lib/global/old_examples/bitcoin_example.dart +++ b/example/lib/global/old_examples/bitcoin_example.dart @@ -68,7 +68,7 @@ void _spendFromP2pkhTo10DifferentType() async { network: network); final out3 = P2wpkhAddress.fromAddress( address: "tb1q3zqgu9j368wgk8u5f9vtmkdwq8geetdxry690d", network: network); - final out4 = P2pkAddress(publicKey: examplePublicKey.publicKey.toHex()); + final out4 = P2pkAddress.fromPubkey(pubkey: examplePublicKey.publicKey.toHex()); final out5 = P2shAddress.fromAddress( address: "2N5hVdETdJMwLDxxttfqeWgMuny6K4SYGSc", network: network); final out6 = P2shAddress.fromAddress( @@ -97,7 +97,7 @@ void _spendFromP2pkhTo10DifferentType() async { final builder = BitcoinTransactionBuilder( /// outputs and values - outPuts: [ + outputs: [ BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("0.001")), BitcoinOutput(address: out2, value: BtcUtils.toSatoshi("0.001")), BitcoinOutput(address: out3, value: BtcUtils.toSatoshi("0.001")), @@ -122,7 +122,7 @@ void _spendFromP2pkhTo10DifferentType() async { /// memo memo: "https://github.com/mrtnetwork", - /// Define a list of Unspent Transaction Outputs (UTXOs) for the Bitcoin transaction + /// Define a list of Unspent Transaction outputs (UTXOs) for the Bitcoin transaction utxos: [ /// Create a UTXO using a BitcoinUtxo with specific details UtxoWithAddress( @@ -140,24 +140,24 @@ void _spendFromP2pkhTo10DifferentType() async { vout: 3, /// Script type indicates the type of script associated with the UTXO's address - scriptType: examplePublicKey2.toAddress().type, + scriptType: examplePublicKey2.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey2.toHex(), - address: examplePublicKey2.toAddress())), + address: examplePublicKey2.toP2pkhAddress())), UtxoWithAddress( utxo: BitcoinUtxo( txHash: "6ff0bdb2966f62f5e202c924e1cab1368b0258833e48986cc0a70fbca624ba93", value: BigInt.from(812830), vout: 0, - scriptType: examplePublicKey2.toAddress().type, + scriptType: examplePublicKey2.toP2pkhAddress().type, ), ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey2.toHex(), - address: examplePublicKey2.toAddress())), + address: examplePublicKey2.toP2pkhAddress())), ]); /// Build the transaction by invoking the buildTransaction method on the BitcoinTransactionBuilder @@ -255,7 +255,7 @@ void _spendFrom10DifferentTypeToP2pkh() async { final builder = BitcoinTransactionBuilder( /// outputs - outPuts: [BitcoinOutput(address: out1, value: change)], + outputs: [BitcoinOutput(address: out1, value: change)], /// Set the transaction fee fee: BtcUtils.toSatoshi("0.00005"), @@ -265,7 +265,7 @@ void _spendFrom10DifferentTypeToP2pkh() async { /// Add a memo to the transaction, linking to the GitHub repository memo: "https://github.com/mrtnetwork", - /// Define a list of Unspent Transaction Outputs (UTXOs) for the Bitcoin transaction. + /// Define a list of Unspent Transaction outputs (UTXOs) for the Bitcoin transaction. /// We are selecting 10 UTXOs for spending, and each UTXO has a different address type. /// These UTXOs are related to the previous example at the top of this page. utxos: [ @@ -282,13 +282,13 @@ void _spendFrom10DifferentTypeToP2pkh() async { vout: 0, /// Script type indicates the type of script associated with the UTXO's address - scriptType: childKey1PublicKey.toAddress().type, + scriptType: childKey1PublicKey.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: childKey1PublicKey.toHex(), - address: childKey1PublicKey.toAddress())), + address: childKey1PublicKey.toP2pkhAddress())), UtxoWithAddress( utxo: BitcoinUtxo( txHash: @@ -306,11 +306,11 @@ void _spendFrom10DifferentTypeToP2pkh() async { "05411dce1a1c9e3f44b54413bdf71e7ab3eff1e2f94818a3568c39814c27b258", value: BtcUtils.toSatoshi("0.001"), vout: 2, - scriptType: childKey1PublicKey.toSegwitAddress().type, + scriptType: childKey1PublicKey.toP2wpkhAddress().type, ), ownerDetails: UtxoAddressDetails( publicKey: childKey1PublicKey.toHex(), - address: childKey1PublicKey.toSegwitAddress())), + address: childKey1PublicKey.toP2wpkhAddress())), UtxoWithAddress( utxo: BitcoinUtxo( txHash: diff --git a/example/lib/global/old_examples/dash_example/dash.dart b/example/lib/global/old_examples/dash_example/dash.dart index d6a8880..236a015 100644 --- a/example/lib/global/old_examples/dash_example/dash.dart +++ b/example/lib/global/old_examples/dash_example/dash.dart @@ -78,7 +78,7 @@ void _spendFromTwoP2shAndOneP2PKH() async { final b = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the P2shAddress and a value of 1.0 DASH BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("1")), @@ -112,13 +112,13 @@ void _spendFromTwoP2shAndOneP2PKH() async { vout: 2, /// Script type indicates the type of script associated with the UTXO's address - scriptType: examplePublicKey2.toAddress().type, + scriptType: examplePublicKey2.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey2.toHex(), - address: examplePublicKey2.toAddress())), + address: examplePublicKey2.toP2pkhAddress())), ]); /// Build the transaction by invoking the buildTransaction method on the BitcoinTransactionBuilder @@ -184,7 +184,7 @@ void _spendP2SH() async { final b = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ BitcoinOutput(address: out1, value: change), ], diff --git a/example/lib/global/old_examples/doge_example/doge_example.dart b/example/lib/global/old_examples/doge_example/doge_example.dart index 6eab54b..814e857 100644 --- a/example/lib/global/old_examples/doge_example/doge_example.dart +++ b/example/lib/global/old_examples/doge_example/doge_example.dart @@ -85,7 +85,7 @@ void _spendFrom3P2shAddress() async { final builder = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the P2shAddress and a value of 1 DOGE BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("1")), @@ -119,13 +119,13 @@ void _spendFrom3P2shAddress() async { vout: 1, /// Script type indicates the type of script associated with the UTXO's address - scriptType: childKey1PublicKey.toAddress().type, + scriptType: childKey1PublicKey.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: childKey1PublicKey.toHex(), - address: childKey1PublicKey.toAddress())), + address: childKey1PublicKey.toP2pkhAddress())), ]); final tr = builder.buildTransaction((trDigest, utxo, publicKey, sighash) { if (publicKey == childKey1PublicKey.toHex()) { @@ -213,7 +213,7 @@ void _spendFromP2pkhAndP2sh() async { final b = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the P2pkhAddress and a value of 1.0 DOGE BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("1")), diff --git a/example/lib/global/old_examples/litecoin_example/litecoin_example.dart b/example/lib/global/old_examples/litecoin_example/litecoin_example.dart index eb55185..3fd6a27 100644 --- a/example/lib/global/old_examples/litecoin_example/litecoin_example.dart +++ b/example/lib/global/old_examples/litecoin_example/litecoin_example.dart @@ -78,7 +78,7 @@ void _spendLTCP2pkhAddress() async { final builder = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the first P2shAddress and a value of 0.0001 LTC BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("0.0001")), @@ -115,12 +115,12 @@ void _spendLTCP2pkhAddress() async { vout: 3, /// Script type indicates the type of script associated with the UTXO's address - scriptType: pub.toAddress().type, + scriptType: pub.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( - publicKey: pub.toHex(), address: pub.toAddress())), + publicKey: pub.toHex(), address: pub.toP2pkhAddress())), ]); /// Build the transaction by invoking the buildTransaction method on the BitcoinTransactionBuilder @@ -200,7 +200,7 @@ void _spendFrom2P2shAddressAndOneMultiSigP2shAddress() async { final builder = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the third P2shAddress and a value equal to the 'change' variable BitcoinOutput(address: out1, value: change), ], @@ -338,7 +338,7 @@ void _spendFromNestedSegwitP2WPKHInP2SH() async { final builder = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the third P2wpkhAddress and a value equal to the 'change' variable BitcoinOutput(address: out1, value: change), ], @@ -456,7 +456,7 @@ void _spendFromSegwitP2WPKHAddress() async { final builder = BitcoinTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the third P2pkhAddress and a value equal to the 'change' variable BitcoinOutput(address: input1, value: change), ], @@ -487,13 +487,13 @@ void _spendFromSegwitP2WPKHAddress() async { vout: 0, /// Script type indicates the type of script associated with the UTXO's address - scriptType: examplePublicKey.toSegwitAddress().type, + scriptType: examplePublicKey.toP2wpkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey.toHex(), - address: examplePublicKey.toSegwitAddress())), + address: examplePublicKey.toP2wpkhAddress())), ]); /// Build the transaction by invoking the buildTransaction method on the BitcoinTransactionBuilder instance (builder) diff --git a/example/lib/global/old_examples/spending_with_scripts/spending_single_type.dart b/example/lib/global/old_examples/spending_with_scripts/spending_single_type.dart index 9e51c71..f4663e5 100644 --- a/example/lib/global/old_examples/spending_with_scripts/spending_single_type.dart +++ b/example/lib/global/old_examples/spending_with_scripts/spending_single_type.dart @@ -26,7 +26,7 @@ Future spendingP2WPKH(ECPrivate sWallet, ECPrivate rWallet) async { // In this section, you can add any number of addresses with type P2PWPH to this transaction. final publicKey = sWallet.getPublic(); // P2WPKH - final sender = publicKey.toSegwitAddress(); + final sender = publicKey.toP2wpkhAddress(); // Read UTXOs of accounts from the BlockCypher API. final utxo = await api.getAccountUtxo( UtxoAddressDetails(address: sender, publicKey: publicKey.toHex())); @@ -44,7 +44,7 @@ Future spendingP2WPKH(ECPrivate sWallet, ECPrivate rWallet) async { final prive = sWallet; final recPub = rWallet.getPublic(); // P2WPKH - final receiver = recPub.toSegwitAddress(); + final receiver = recPub.toP2wpkhAddress(); // P2TR final changeAddress = recPub.toTaprootAddress(); @@ -124,9 +124,9 @@ Future spendingP2WSH(ECPrivate sWallet, ECPrivate rWallet) async { final prive = sWallet; final recPub = rWallet.getPublic(); - final receiver = recPub.toSegwitAddress(); + final receiver = recPub.toP2wpkhAddress(); - final changeAddress = recPub.toSegwitAddress(); + final changeAddress = recPub.toP2wpkhAddress(); final List outputsAdress = [ BitcoinOutput(address: receiver, value: BigInt.zero), BitcoinOutput(address: changeAddress, value: BigInt.zero) @@ -160,7 +160,7 @@ Future spendingP2PKH(ECPrivate sWallet, ECPrivate rWallet) async { // and we use method `buildP2pkhTransaction` to create the transaction. final addr = sWallet.getPublic(); // P2PKH - final sender = addr.toAddress(); + final sender = addr.toP2pkhAddress(); final utxo = await api.getAccountUtxo( UtxoAddressDetails(address: sender, publicKey: addr.toHex())); final sumOfUtxo = utxo.sumOfUtxosValue(); @@ -173,8 +173,8 @@ Future spendingP2PKH(ECPrivate sWallet, ECPrivate rWallet) async { final prive = sWallet; final recPub = rWallet.getPublic(); - final receiver = recPub.toSegwitAddress(); - final changeAddress = recPub.toSegwitAddress(); + final receiver = recPub.toP2wpkhAddress(); + final changeAddress = recPub.toP2wpkhAddress(); final List outputsAdress = [ BitcoinOutput(address: receiver, value: BigInt.zero), BitcoinOutput(address: changeAddress, value: BigInt.zero) @@ -225,8 +225,8 @@ Future spendingP2SHNoneSegwit( final prive = sWallet; final recPub = rWallet.getPublic(); - final receiver = recPub.toSegwitAddress(); - final changeAddress = recPub.toSegwitAddress(); + final receiver = recPub.toP2wpkhAddress(); + final changeAddress = recPub.toP2wpkhAddress(); final List outputsAdress = [ BitcoinOutput(address: receiver, value: BigInt.zero), BitcoinOutput(address: changeAddress, value: BigInt.zero) @@ -275,9 +275,9 @@ Future spendingP2shSegwit(ECPrivate sWallet, ECPrivate rWallet) async { final prive = sWallet; final recPub = rWallet.getPublic(); - final receiver = recPub.toSegwitAddress(); + final receiver = recPub.toP2wpkhAddress(); - final changeAddress = recPub.toSegwitAddress(); + final changeAddress = recPub.toP2wpkhAddress(); final List outputsAdress = [ BitcoinOutput(address: receiver, value: BigInt.zero), BitcoinOutput(address: changeAddress, value: BigInt.zero) @@ -327,8 +327,8 @@ Future spendingP2TR(ECPrivate sWallet, ECPrivate rWallet) async { final prive = sWallet; final recPub = rWallet.getPublic(); - final receiver = recPub.toSegwitAddress(); - final changeAddress = recPub.toSegwitAddress(); + final receiver = recPub.toP2wpkhAddress(); + final changeAddress = recPub.toP2wpkhAddress(); final List outputsAdress = [ BitcoinOutput(address: receiver, value: BigInt.zero), BitcoinOutput(address: changeAddress, value: BigInt.zero) diff --git a/example/lib/global/old_examples/spending_with_transaction_builder/multi_sig_transactions.dart b/example/lib/global/old_examples/spending_with_transaction_builder/multi_sig_transactions.dart index 2320f5d..a3c4d45 100644 --- a/example/lib/global/old_examples/spending_with_transaction_builder/multi_sig_transactions.dart +++ b/example/lib/global/old_examples/spending_with_transaction_builder/multi_sig_transactions.dart @@ -60,7 +60,7 @@ void main() async { // tb1qxt3c7849m0m6cv3z3s35c3zvdna3my3yz0r609qd9g0dcyyk580sgyldhe final p2wshMultiSigAddress = - multiSignatureAddress.toP2wshAddress(network: network).toAddress(network); + multiSignatureAddress.toP2wshAddress(network: network).toP2pkhAddress(network); // p2sh(p2wsh) multisig final signerP2sh1 = @@ -80,12 +80,12 @@ void main() async { // 2N8co8bth9CNKtnWGfHW6HuUNgnNPNdpsMj final p2shMultisigAddress = p2shMultiSignature .toP2wshInP2shAddress(network: network) - .toAddress(network); + .toP2pkhAddress(network); // P2TR final exampleAddr2 = public2.toTaprootAddress(); // P2KH - final exampleAddr4 = public3.toAddress(); + final exampleAddr4 = public3.toP2pkhAddress(); // Spending List // i use some different address type for this // now i want to spending from 8 address in one transaction @@ -203,7 +203,7 @@ void main() async { // Now, we provide the UTXOs we want to spend. utxos: utxos, // We select transaction outputs - outPuts: [output1, output2, output3, output4], + outputs: [output1, output2, output3, output4], /* Transaction fee Ensure that you have accurately calculated the amounts. diff --git a/example/lib/global/old_examples/spending_with_transaction_builder/transaction_builder_example.dart b/example/lib/global/old_examples/spending_with_transaction_builder/transaction_builder_example.dart index 49fd392..614685f 100644 --- a/example/lib/global/old_examples/spending_with_transaction_builder/transaction_builder_example.dart +++ b/example/lib/global/old_examples/spending_with_transaction_builder/transaction_builder_example.dart @@ -37,7 +37,7 @@ void main() async { final public4 = private4.getPublic(); // P2PKH ADDRESS - final exampleAddr1 = public1.toAddress(); + final exampleAddr1 = public1.toP2pkhAddress(); // P2TR final exampleAddr2 = public2.toTaprootAddress(); @@ -45,7 +45,7 @@ void main() async { // P2PKHINP2SH final exampleAddr3 = public2.toP2pkhInP2sh(); // P2KH - final exampleAddr4 = public3.toAddress(); + final exampleAddr4 = public3.toP2pkhAddress(); // P2PKHINP2SH final exampleAddr5 = public3.toP2pkhInP2sh(); // P2WSHINP2SH 1-1 multisig @@ -55,7 +55,7 @@ void main() async { // P2PKINP2SH final exampleAddr8 = public4.toP2pkInP2sh(); // P2WPKH - final exampleAddr9 = public3.toSegwitAddress(); + final exampleAddr9 = public3.toP2wpkhAddress(); // P2WSH 1-1 multisig final exampleAddr10 = public3.toP2wshAddress(); @@ -143,7 +143,7 @@ void main() async { // Now, we provide the UTXOs we want to spend. utxos: utxos, // We select transaction outputs - outPuts: [ + outputs: [ output1, output2, output3, diff --git a/example/lib/main.dart b/example/lib/main.dart index 0775f1f..fc0ba8f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -101,7 +101,7 @@ void _spendFrom2P2SHAnd2P2PKHAddress() async { ]); final b = ForkedTransactionBuilder( - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the P2shAddress and a value of 0.01 BCH BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("0.01")), @@ -121,7 +121,7 @@ void _spendFrom2P2SHAnd2P2PKHAddress() async { /// Specify the network for the litcoin transaction network: network, - /// Define a list of Unspent Transaction Outputs (UTXOs) for the Bitcoin transaction + /// Define a list of Unspent Transaction outputs (UTXOs) for the Bitcoin transaction utxos: [ UtxoWithAddress( @@ -138,13 +138,13 @@ void _spendFrom2P2SHAnd2P2PKHAddress() async { vout: 0, /// Script type indicates the type of script associated with the UTXO's address - scriptType: examplePublicKey2.toAddress().type, + scriptType: examplePublicKey2.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey2.toHex(), - address: examplePublicKey2.toAddress())), + address: examplePublicKey2.toP2pkhAddress())), ]); /// Build the transaction by invoking the buildTransaction method on the ForkedTransactionBuilder @@ -247,7 +247,7 @@ void _spendFrom2P2SHAnd1P2PKHAddress() async { final b = ForkedTransactionBuilder( /// outputs - outPuts: [ + outputs: [ /// Define a BitcoinOutput with the P2pkhAddress and a value of 0.01 BCH BitcoinOutput(address: out1, value: BtcUtils.toSatoshi("0.01")), @@ -267,7 +267,7 @@ void _spendFrom2P2SHAnd1P2PKHAddress() async { /// Add a memo to the transaction, linking to the GitHub repository memo: "https://github.com/mrtnetwork", - /// Define a list of Unspent Transaction Outputs (UTXOs) for the Bitcoin transaction + /// Define a list of Unspent Transaction outputs (UTXOs) for the Bitcoin transaction utxos: [ UtxoWithAddress( @@ -324,13 +324,13 @@ void _spendFrom2P2SHAnd1P2PKHAddress() async { vout: 2, /// Script type indicates the type of script associated with the UTXO's address - scriptType: examplePublicKey.toAddress().type, + scriptType: examplePublicKey.toP2pkhAddress().type, ), /// Include owner details with the public key and address associated with the UTXO ownerDetails: UtxoAddressDetails( publicKey: examplePublicKey.toHex(), - address: examplePublicKey.toAddress())), + address: examplePublicKey.toP2pkhAddress())), UtxoWithAddress( utxo: BitcoinUtxo( /// Transaction hash uniquely identifies the referenced transaction diff --git a/lib/src/bitcoin/address/util.dart b/lib/src/bitcoin/address/util.dart new file mode 100644 index 0000000..7ec257d --- /dev/null +++ b/lib/src/bitcoin/address/util.dart @@ -0,0 +1,44 @@ +import 'package:bitcoin_base/src/utils/utils.dart'; +import 'package:blockchain_utils/blockchain_utils.dart'; +import 'package:bitcoin_base/src/bitcoin/address/address.dart'; +import 'package:bitcoin_base/src/models/network.dart'; + +class BitcoinAddressUtils { + static bool validateAddress({required String address, required BasedUtxoNetwork network}) { + try { + addressToOutputScript(address: address, network: network); + return true; + } catch (_) { + return false; + } + } + + static List addressToOutputScript( + {required String address, required BasedUtxoNetwork network}) { + final addressType = RegexUtils.addressTypeFromStr(address, network); + + if (addressType.type == SegwitAddresType.mweb) { + return BytesUtils.fromHexString( + MwebAddress.fromAddress(address: address, network: network).addressProgram, + ); + } + + return addressType.toScriptPubKey().toBytes(); + } + + static String scriptHash(String address, {required BasedUtxoNetwork network}) { + final outputScript = addressToOutputScript(address: address, network: network); + final parts = BytesUtils.toHexString(QuickCrypto.sha256Hash(outputScript)).split(''); + var res = ''; + + for (var i = parts.length - 1; i >= 0; i--) { + final char = parts[i]; + i--; + final nextChar = parts[i]; + res += nextChar; + res += char; + } + + return res; + } +} diff --git a/lib/src/bitcoin/script/outpoint.dart b/lib/src/bitcoin/script/outpoint.dart new file mode 100644 index 0000000..8af5748 --- /dev/null +++ b/lib/src/bitcoin/script/outpoint.dart @@ -0,0 +1,18 @@ +import 'package:blockchain_utils/blockchain_utils.dart'; + +class Outpoint { + Outpoint({required this.txid, required this.index, this.value}); + + String txid; + int index; + int? value; + + factory Outpoint.fromBytes(List txid, int index, {int? value}) { + return Outpoint(txid: BytesUtils.toHexString(txid), index: index, value: value); + } + + @override + String toString() { + return 'Outpoint{txid: $txid, index: $index, value: $value}'; + } +} diff --git a/lib/src/bitcoin/silent_payments/address.dart b/lib/src/bitcoin/silent_payments/address.dart new file mode 100644 index 0000000..e622851 --- /dev/null +++ b/lib/src/bitcoin/silent_payments/address.dart @@ -0,0 +1,202 @@ +// ignore_for_file: constant_identifier_names +// ignore_for_file: non_constant_identifier_names +part of 'package:bitcoin_base/src/bitcoin/silent_payments/silent_payments.dart'; + +const SCAN_PATH = "m/352'/1'/0'/1'/0"; + +const SPEND_PATH = "m/352'/1'/0'/0'/0"; + +class SilentPaymentOwner extends SilentPaymentAddress { + final ECPrivate b_scan; + final ECPrivate b_spend; + + SilentPaymentOwner({ + required super.version, + required super.B_scan, + required super.B_spend, + required this.b_scan, + required this.b_spend, + super.network, + }) : super(); + + factory SilentPaymentOwner.fromPrivateKeys({ + required ECPrivate b_scan, + required ECPrivate b_spend, + required BasedUtxoNetwork network, + int? version, + }) { + return SilentPaymentOwner( + b_scan: b_scan, + b_spend: b_spend, + B_scan: b_scan.getPublic(), + B_spend: b_spend.getPublic(), + network: network, + version: version ?? 0, + ); + } + + factory SilentPaymentOwner.fromHd(Bip32Slip10Secp256k1 bip32, {String? hrp, int? version}) { + final scanDerivation = bip32.derivePath(SCAN_PATH); + final spendDerivation = bip32.derivePath(SPEND_PATH); + + return SilentPaymentOwner( + b_scan: ECPrivate(scanDerivation.privateKey), + b_spend: ECPrivate(spendDerivation.privateKey), + B_scan: ECPublic.fromBip32(scanDerivation.publicKey), + B_spend: ECPublic.fromBip32(spendDerivation.publicKey), + network: hrp == "tsp" ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet, + version: version ?? 0, + ); + } + + factory SilentPaymentOwner.fromMnemonic(String mnemonic, {String? hrp, int? version}) { + return SilentPaymentOwner.fromHd( + Bip32Slip10Secp256k1.fromSeed( + Bip39MnemonicDecoder().decode(mnemonic), + hrp == "tsp" ? Bip32Const.testNetKeyNetVersions : Bip32Const.mainNetKeyNetVersions, + ), + hrp: hrp, + version: version); + } + + List generateLabel(int m) { + return taggedHash(BytesUtils.concatBytes([b_scan.toBytes(), serUint32(m)]), "BIP0352/Label"); + } + + SilentPaymentOwner toLabeledSilentPaymentAddress(int m) { + final B_m = B_spend.tweakAdd(BigintUtils.fromBytes(generateLabel(m))); + return SilentPaymentOwner( + b_scan: b_scan, + b_spend: b_spend, + B_scan: B_scan, + B_spend: B_m, + network: network, + version: version, + ); + } +} + +class SilentPaymentDestination extends SilentPaymentAddress { + SilentPaymentDestination({ + required super.version, + required ECPublic scanPubkey, + required ECPublic spendPubkey, + super.network, + required this.amount, + }) : super(B_scan: scanPubkey, B_spend: spendPubkey); + + int amount; + + factory SilentPaymentDestination.fromAddress(String address, int amount) { + final receiver = SilentPaymentAddress.fromAddress(address); + + return SilentPaymentDestination( + scanPubkey: receiver.B_scan, + spendPubkey: receiver.B_spend, + network: receiver.network, + version: receiver.version, + amount: amount, + ); + } +} + +class SilentPaymentAddress implements BitcoinBaseAddress { + static RegExp get regex => RegExp(r'(tsp|sp|sprt)1[0-9a-zA-Z]{113}'); + + final int version; + final ECPublic B_scan; + final ECPublic B_spend; + @override + BasedUtxoNetwork? network; + final String hrp; + + SilentPaymentAddress({ + required this.B_scan, + required this.B_spend, + this.network = BitcoinNetwork.mainnet, + this.version = 0, + }) : hrp = (network == BitcoinNetwork.testnet ? "tsp" : "sp") { + if (version != 0) { + throw Exception("Can't have other version than 0 for now"); + } + } + + factory SilentPaymentAddress.fromAddress(String address) { + final decoded = Bech32DecoderBase.decodeBech32( + address, + SegwitBech32Const.separator, + SegwitBech32Const.checksumStrLen, + (hrp, data) => Bech32Utils.verifyChecksum(hrp, data, Bech32Encodings.bech32m), + ); + final prefix = decoded.item1; + final words = decoded.item2; + + if (prefix != 'sp' && prefix != 'sprt' && prefix != 'tsp') { + throw Exception('Invalid prefix: $prefix'); + } + + final version = words[0]; + if (version != 0) throw ArgumentError('Invalid version'); + + final key = Bech32BaseUtils.convertFromBase32(words.sublist(1)); + + return SilentPaymentAddress( + B_scan: ECPublic.fromBytes(key.sublist(0, 33)), + B_spend: ECPublic.fromBytes(key.sublist(33)), + network: prefix == 'tsp' ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet, + version: version, + ); + } + + @override + String toAddress([BasedUtxoNetwork? network]) { + return toString(network: network); + } + + @override + String toString({BasedUtxoNetwork? network}) { + return Bech32EncoderBase.encodeBech32( + hrp, + [ + version, + ...Bech32BaseUtils.convertToBase32( + [...B_scan.toCompressedBytes(), ...B_spend.toCompressedBytes()]) + ], + SegwitBech32Const.separator, + (hrp, data) => Bech32Utils.computeChecksum(hrp, data, Bech32Encodings.bech32m), + ); + } + + @override + BitcoinAddressType get type => SilentPaymentsAddresType.p2sp; + + @override + Script toScriptPubKey() { + throw UnimplementedError(); + } + + @override + String pubKeyHash() { + throw UnimplementedError(); + } + + @override + String get addressProgram => ""; +} + +class Bech32U5 { + final int value; + + Bech32U5(this.value) { + if (value < 0 || value > 31) { + throw Exception('Value is outside the valid range.'); + } + } + + static Bech32U5 tryFromInt(int value) { + if (value < 0 || value > 31) { + throw Exception('Value is outside the valid range.'); + } + return Bech32U5(value); + } +} diff --git a/lib/src/bitcoin/silent_payments/payment.dart b/lib/src/bitcoin/silent_payments/payment.dart new file mode 100644 index 0000000..c04cf12 --- /dev/null +++ b/lib/src/bitcoin/silent_payments/payment.dart @@ -0,0 +1,242 @@ +// ignore_for_file: non_constant_identifier_names +part of 'package:bitcoin_base/src/bitcoin/silent_payments/silent_payments.dart'; + +class SilentPaymentOutput { + final P2trAddress address; + final int amount; + + SilentPaymentOutput(this.address, this.amount); +} + +class SilentPaymentScanningOutput { + final SilentPaymentOutput output; + final String tweak; + final String? label; + + SilentPaymentScanningOutput({required this.output, required this.tweak, this.label}); +} + +class ECPrivateInfo { + final ECPrivate privkey; + final bool isTaproot; + final bool tweak; + + ECPrivateInfo(this.privkey, this.isTaproot, {this.tweak = false}); +} + +class SilentPaymentBuilder { + final List vinOutpoints; + final List? pubkeys; + ECPublic? A_sum; + List? inputHash; + String? receiverTweak; + + SilentPaymentBuilder({ + required this.vinOutpoints, + this.pubkeys, + this.receiverTweak, + }) { + if (receiverTweak == null && pubkeys != null) { + _getAsum(); + _getInputHash(); + } + } + + void _getAsum() { + final head = pubkeys!.first; + final tail = pubkeys!.sublist(1); + + A_sum = + tail.fold(head, (acc, item) => ECPublic.fromBip32(acc.publicKey).pubkeyAdd(item)); + } + + void _getInputHash() { + final sortedOutpoints = >[]; + + for (final outpoint in vinOutpoints) { + sortedOutpoints.add(BytesUtils.concatBytes([ + BytesUtils.fromHexString(outpoint.txid).reversed.toList(), + BigintUtils.toBytes(BigInt.from(outpoint.index), length: 4, order: Endian.little) + ])); + } + + sortedOutpoints.sort(BytesUtils.compareBytes); + final lowestOutpoint = sortedOutpoints.first; + + inputHash = taggedHash( + BytesUtils.concatBytes([lowestOutpoint, A_sum!.toCompressedBytes()]), "BIP0352/Inputs"); + } + + Map> createOutputs( + List inputPrivKeyInfos, + List silentPaymentDestinations, + ) { + ECPrivate? a_sum; + + for (final info in inputPrivKeyInfos) { + var k = info.privkey; + final isTaproot = info.isTaproot; + + if (isTaproot) { + if (info.tweak) { + k = k.toTweakedTaprootKey(); + } + + final xOnlyPubkey = k.getPublic(); + final isOdd = xOnlyPubkey.publicKey.point.y % BigInt.two != BigInt.zero; + + if (isOdd) { + k = k.negate(); + } + } + + if (a_sum == null) { + a_sum = k; + } else { + a_sum = a_sum.tweakAdd(BigintUtils.fromBytes(k.toBytes())); + } + } + + A_sum = a_sum!.getPublic(); + _getInputHash(); + + Map>> silentPaymentGroups = {}; + + for (final silentPaymentDestination in silentPaymentDestinations) { + final B_scan = silentPaymentDestination.B_scan; + final scanPubkey = B_scan.toHex(); + + if (silentPaymentGroups.containsKey(scanPubkey)) { + // Current key already in silentPaymentGroups, simply add up the new destination + // with the already calculated ecdhSharedSecret + final group = silentPaymentGroups[scanPubkey]!; + final ecdhSharedSecret = group.keys.first; + final recipients = group.values.first; + + silentPaymentGroups[scanPubkey] = { + ecdhSharedSecret: [...recipients, silentPaymentDestination] + }; + } else { + final senderPartialSecret = a_sum.tweakMul(BigintUtils.fromBytes(inputHash!)).toBytes(); + final ecdhSharedSecret = + B_scan.tweakMul(BigintUtils.fromBytes(senderPartialSecret)).toHex(); + + silentPaymentGroups[scanPubkey] = { + ecdhSharedSecret: [silentPaymentDestination] + }; + } + } + + Map> result = {}; + for (final group in silentPaymentGroups.entries) { + final ecdhSharedSecret = group.value.keys.first; + final destinations = group.value.values.first; + + int k = 0; + for (final destination in destinations) { + final t_k = taggedHash( + BytesUtils.concatBytes([ + ECPublic.fromHex(ecdhSharedSecret).toCompressedBytes(), + BigintUtils.toBytes(BigInt.from(k), length: 4) + ]), + "BIP0352/SharedSecret"); + + final P_mn = destination.B_spend.tweakAdd(BigintUtils.fromBytes(t_k)); + final resOutput = + SilentPaymentOutput(P_mn.toTaprootAddress(tweak: false), destination.amount); + + if (result.containsKey(destination.toString())) { + result[destination.toString()]!.add(resOutput); + } else { + result[destination.toString()] = [resOutput]; + } + + k++; + } + } + + return result; + } + + Map scanOutputs( + ECPrivate b_scan, + ECPublic B_spend, + List outputsToCheck, { + Map? precomputedLabels, + }) { + final tweakDataForRecipient = receiverTweak != null + ? ECPublic.fromHex(receiverTweak!) + : A_sum!.tweakMul(BigintUtils.fromBytes(inputHash!)); + final ecdhSharedSecret = tweakDataForRecipient.tweakMul(b_scan.toBigInt()); + + final matches = {}; + var k = 0; + + do { + final t_k = taggedHash( + BytesUtils.concatBytes([ + ecdhSharedSecret.toCompressedBytes(), + BigintUtils.toBytes(BigInt.from(k), length: 4, order: Endian.big) + ]), + "BIP0352/SharedSecret"); + + final P_k = B_spend.tweakAdd(BigintUtils.fromBytes(t_k)); + final length = outputsToCheck.length; + + for (var i = 0; i < length; i++) { + final output = outputsToCheck[i].script.toBytes().sublist(2); + final outputPubkey = BytesUtils.toHexString(output); + final outputAmount = outputsToCheck[i].value.toInt(); + + if ((BytesUtils.compareBytes(output, P_k.toCompressedBytes().sublist(1)) == 0)) { + matches[outputPubkey] = SilentPaymentScanningOutput( + output: SilentPaymentOutput(P_k.toTaprootAddress(tweak: false), outputAmount), + tweak: BytesUtils.toHexString(t_k), + ); + outputsToCheck.removeAt(i); + k++; + break; + } + + if (precomputedLabels != null && precomputedLabels.isNotEmpty) { + var m_G_sub = ECPublic.fromBytes(output).pubkeyAdd(P_k.negate()); + var m_G = precomputedLabels[m_G_sub.toHex()]; + + if (m_G == null) { + m_G_sub = ECPublic.fromBytes(output).negate().pubkeyAdd(P_k.negate()); + m_G = precomputedLabels[m_G_sub.toHex()]; + } + + if (m_G != null) { + final P_km = P_k.tweakAdd(BigintUtils.fromBytes(BytesUtils.fromHexString(m_G))); + + matches[outputPubkey] = SilentPaymentScanningOutput( + output: SilentPaymentOutput(P_km.toTaprootAddress(tweak: false), outputAmount), + tweak: ECPrivate.fromBytes(t_k) + .tweakAdd(BigintUtils.fromBytes(BytesUtils.fromHexString(m_G))) + .toHex(), + label: m_G, + ); + + outputsToCheck.removeAt(i); + k++; + break; + } + } + + outputsToCheck.removeAt(i); + + if (i + 1 >= outputsToCheck.length) { + break; + } + } + } while (outputsToCheck.isNotEmpty); + + return matches; + } +} + +BitcoinScriptOutput getScriptFromOutput(String pubkey, int amount) { + return BitcoinScriptOutput( + script: Script(script: [BitcoinOpCodeConst.OP_1, pubkey]), value: BigInt.from(amount)); +} diff --git a/lib/src/bitcoin/silent_payments/silent_payments.dart b/lib/src/bitcoin/silent_payments/silent_payments.dart new file mode 100644 index 0000000..d839c6b --- /dev/null +++ b/lib/src/bitcoin/silent_payments/silent_payments.dart @@ -0,0 +1,23 @@ +// Library for Bitcoin Silent Payments handling in the bitcoin_base package. +// +// The library includes essential components such as: +// - Core address functionality. +// - encode/decode address support. +// - Utility functions for address manipulation. +// - Generate labeled addresses. +// - Scan transactions. +// - Generate payment outputs. +library bitcoin_base.silent_payments; + +import 'dart:typed_data'; + +import 'package:bitcoin_base/src/bitcoin/address/address.dart'; +import 'package:bitcoin_base/src/provider/models/models.dart'; +import 'package:bitcoin_base/src/bitcoin/script/scripts.dart'; +import 'package:bitcoin_base/src/crypto/crypto.dart'; +import 'package:bitcoin_base/src/models/network.dart'; +import 'package:blockchain_utils/blockchain_utils.dart'; + +part 'address.dart'; +part 'payment.dart'; +part 'utils.dart'; diff --git a/lib/src/bitcoin/silent_payments/utils.dart b/lib/src/bitcoin/silent_payments/utils.dart new file mode 100644 index 0000000..1f68c07 --- /dev/null +++ b/lib/src/bitcoin/silent_payments/utils.dart @@ -0,0 +1,112 @@ +// ignore_for_file: non_constant_identifier_names +part of 'package:bitcoin_base/src/bitcoin/silent_payments/silent_payments.dart'; + +final NUMS_H = BigInt.parse("0x50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"); + +int deserCompactSize(ByteData f) { + final view = f.buffer; + int nbytes = view.lengthInBytes; + if (nbytes == 0) { + return 0; // end of stream + } + + int nit = f.getUint8(0); + if (nit == 253) { + nit = f.getUint16(1, Endian.little); + } else if (nit == 254) { + nit = f.getUint32(3, Endian.little); + } else if (nit == 255) { + nit = f.getUint64(7, Endian.little); + } + return nit; +} + +ByteData deserString(ByteData f) { + final nit = deserCompactSize(f); + int offset = 1; + return ByteData.sublistView(f.buffer.asUint8List().sublist(offset, nit + offset)); +} + +List deserStringVector(ByteData f) { + int offset = 0; + + final nit = deserCompactSize(f); + offset += 1; + + List result = []; + for (int i = 0; i < nit; i++) { + final t = deserString(ByteData.sublistView(f.buffer.asUint8List().sublist(offset))); + + result.add(t); + offset += t.lengthInBytes + 1; + } + return result; +} + +class VinInfo { + final Outpoint outpoint; + final List scriptSig; + final TxWitnessInput txinwitness; + final Script prevOutScript; + final ECPrivate? privkey; + + VinInfo({ + required this.outpoint, + required this.scriptSig, + required this.txinwitness, + required this.prevOutScript, + this.privkey, + }); +} + +ECPublic? getPubkeyFromInput(VinInfo vin) { + switch (vin.prevOutScript.getAddressType()) { + case P2pkhAddressType.p2pkh: + for (var i = vin.scriptSig.length; i > 0; i--) { + if (i - 33 >= 0) { + final pubkeyBytes = vin.scriptSig.sublist(i - 33, i); + final pubkeyHash = BytesUtils.toHexString(QuickCrypto.hash160(pubkeyBytes)); + if (pubkeyHash == + P2pkhAddress.fromScriptPubkey(script: vin.prevOutScript).addressProgram) { + return ECPublic.fromBytes(pubkeyBytes); + } + } + } + break; + case P2shAddressType.p2pkhInP2sh: + final redeemScript = vin.scriptSig.sublist(1); + if (Script.fromRaw(byteData: redeemScript).getAddressType() == SegwitAddresType.p2wpkh) { + return ECPublic.fromBytes(vin.txinwitness.scriptWitness.stack.last.buffer.asUint8List()); + } + break; + case SegwitAddresType.p2wpkh: + return ECPublic.fromBytes(vin.txinwitness.scriptWitness.stack.last.buffer.asUint8List()); + case SegwitAddresType.p2tr: + final witnessStack = vin.txinwitness.scriptWitness.stack; + if (witnessStack.isNotEmpty) { + if (witnessStack.length > 1 && witnessStack.last.buffer.asUint8List()[0] == 0x50) { + witnessStack.removeLast(); + } + + if (witnessStack.length > 1) { + final controlBlock = witnessStack.last.buffer.asUint8List(); + final internalKey = controlBlock.sublist(1, 33); + if (BytesUtils.compareBytes( + internalKey, BigintUtils.toBytes(NUMS_H, length: 32, order: Endian.big)) == + 0) { + return null; + } + } + return ECPublic.fromBytes(vin.prevOutScript.toBytes().sublist(2)); + } + break; + default: + return null; + } + + return null; +} + +List serUint32(int n) { + return BigintUtils.toBytes(BigInt.from(n), length: 4); +} diff --git a/lib/src/crypto/keypair/sign_utils.dart b/lib/src/crypto/keypair/sign_utils.dart new file mode 100644 index 0000000..0b3f226 --- /dev/null +++ b/lib/src/crypto/keypair/sign_utils.dart @@ -0,0 +1,190 @@ +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:pointycastle/export.dart'; +import 'package:pointycastle/src/utils.dart'; +import 'package:pointycastle/ecc/ecc_fp.dart' as fp; + +final ECDomainParameters curve = ECCurve_secp256k1(); + +extension ECUtils on Uint8List { + ECSignature toECSignature() { + final sigLength = (this.length / 2).round(); + final r = BigInt.parse( + SignUtils.getHexString(this, offset: 0, length: sigLength), + radix: 16, + ); + final s = BigInt.parse( + SignUtils.getHexString(this, offset: sigLength, length: sigLength), + radix: 16, + ); + return ECSignature(r, s); + } + + bool isCompressedPoint() => curve.curve.decodePoint(this)!.isCompressed; +} + +class SignUtils { + /// Returns the recovery ID, a byte with value between 0 and 3, inclusive, that specifies which of 4 possible + /// curve points was used to sign a message. This value is also referred to as "v". + /// + /// @throws RuntimeException if no recovery ID can be found. + static int findRecoveryId(String hash, ECSignature sig, Uint8List pub) { + var recId = -1; + final Q = curve.curve.decodePoint(pub); + for (var i = 0; i < 4; i++) { + final k = recoverFromSignature(i, sig, hash); + if (k != null && k == Q) { + recId = i; + break; + } + } + if (recId == -1) { + throw Exception("Could not construct a recoverable key. This should never happen."); + } + return recId; + } + + static String getHexString( + List list, { + required int offset, + required int length, + }) { + final sublist = list.getRange(offset, offset + length); + return [for (var byte in sublist) byte.toRadixString(16).padLeft(2, '0').toUpperCase()].join(); + } + + ///

Given the components of a signature and a selector value, recover and return the public key + /// that generated the signature according to the algorithm in SEC1v2 section 4.1.6.

+ /// + ///

The recId is an index from 0 to 3 which indicates which of the 4 possible keys is the correct one. Because + /// the key recovery operation yields multiple potential keys, the correct key must either be stored alongside the + /// signature, or you must be willing to try each recId in turn until you find one that outputs the key you are + /// expecting.

+ /// + ///

If this method returns null it means recovery was not possible and recId should be iterated.

+ /// + ///

Given the above two points, a correct usage of this method is inside a for loop from 0 to 3, and if the + /// output is null OR a key that is not the one you expect, you try again with the next recId.

+ /// + /// @param recId Which possible key to recover. + /// @param sig the R and S components of the signature, wrapped. + /// @param message Hash of the data that was signed. + /// @param compressed Whether or not the original pubkey was compressed. + /// @return An ECKey containing only the public part, or null if recovery wasn't possible. + static ECPoint? recoverFromSignature(int recId, ECSignature sig, String message) { + // see https://www.secg.org/sec1-v2.pdf, section 4.1.6 + // 1.0 For j from 0 to h (h == recId here and the loop is outside this function) + // 1.1 Let x = r + jn + final n = curve.n; // Curve order. + final i = BigInt.from(recId / 2); + final x = sig.r + (i * n); + // 1.2. Convert the integer x to an octet string X of length mlen using the conversion routine + // specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉. + // 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the + // conversion routine specified in Section 2.3.4. If this conversion routine outputs "invalid", then + // do another iteration of Step 1. + // + // More concisely, what these points mean is to use X as a compressed public key. + final prime = (curve.curve as fp.ECCurve).q!; + if (x.compareTo(prime) >= 0) { + // Cannot have point co-ordinates larger than this as everything takes place modulo Q. + return null; + } + // Compressed keys require you to know an extra bit of data about the y-coord as there are two possibilities. + // So it's encoded in the recId. + final R = _decompressKey(x, (recId & 1) == 1); + // 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers responsibility). + if (!(R * n)!.isInfinity) return null; + // 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification. + final e = BigInt.parse(message, radix: 16); + // 1.6. For k from 1 to 2 do the following. (loop is outside this function via iterating recId) + // 1.6.1. Compute a candidate public key as: + // Q = mi(r) * (sR - eG) + // + // Where mi(x) is the modular multiplicative inverse. We transform this into the following: + // Q = (mi(r) * s ** R) + (mi(r) * -e ** G) + // Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation + // ** is point multiplication and + is point addition (the EC group operator). + // + // We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive + // inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8. + final eInv = (BigInt.zero - e) % n; + final rInv = sig.r.modInverse(n); + final srInv = (rInv * sig.s) % n; + final eInvrInv = (rInv * eInv) % n; + return sumOfTwoMultiplies(curve.G, eInvrInv, R, srInv)!; + } + + /// Decompress a compressed public key (x co-ord and low-bit of y-coord). + static ECPoint _decompressKey(BigInt xBN, bool yBit) { + final curveByteLength = ((curve.curve.fieldSize + 7) ~/ 8); + final compEnc = _x9IntegerToBytes(xBN, 1 + curveByteLength); + compEnc[0] = (yBit ? 0x03 : 0x02); + return curve.curve.decodePoint(compEnc)!; + } + +// Extracted from pointycastle/lib/ecc/ecc_fp.dart + static Uint8List _x9IntegerToBytes(BigInt? s, int qLength) { + var bytes = Uint8List.fromList(encodeBigInt(s)); + + if (qLength < bytes.length) { + return bytes.sublist(bytes.length - qLength); + } else if (qLength > bytes.length) { + return Uint8List(qLength)..setAll(qLength - bytes.length, bytes); + } + + return bytes; + } + + // Extracted from pointycastle/lib/signers/ecdsa_signer.dart + static ECPoint? sumOfTwoMultiplies(ECPoint P, BigInt a, ECPoint Q, BigInt b) { + var c = P.curve; + + if (c != Q.curve) { + throw ArgumentError('P and Q must be on same curve'); + } + + // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick + // TODO: uncomment this when F2m available + /* + if( c is ECCurve.F2m ) { + ECCurve.F2m f2mCurve = (ECCurve.F2m)c; + if( f2mCurve.isKoblitz() ) { + return P.multiply(a).add(Q.multiply(b)); + } + } + */ + + return _implShamirsTrick(P, a, Q, b); + } + + // Extracted from pointycastle/lib/signers/ecdsa_signer.dart + static ECPoint? _implShamirsTrick(ECPoint P, BigInt k, ECPoint Q, BigInt l) { + var m = max(k.bitLength, l.bitLength); + + var Z = P + Q; + var R = P.curve.infinity; + + for (var i = m - 1; i >= 0; --i) { + R = R!.twice(); + + if (_testBit(k, i)) { + if (_testBit(l, i)) { + R = R! + Z; + } else { + R = R! + P; + } + } else { + if (_testBit(l, i)) { + R = R! + Q; + } + } + } + + return R; + } + + // Extracted from pointycastle/lib/signers/ecdsa_signer.dart + static bool _testBit(BigInt i, int n) => (i & (BigInt.one << n)) != BigInt.zero; +} diff --git a/lib/src/utils/regex.dart b/lib/src/utils/regex.dart new file mode 100644 index 0000000..9508d66 --- /dev/null +++ b/lib/src/utils/regex.dart @@ -0,0 +1,40 @@ +import 'package:bitcoin_base/src/bitcoin/address/address.dart'; +import 'package:bitcoin_base/src/bitcoin/silent_payments/silent_payments.dart'; +import 'package:bitcoin_base/src/models/network.dart'; + +class RegexUtils { + static bool stringIsAddress(String string, RegExp addressRegex) { + return RegExp("^${addressRegex.pattern}\$").hasMatch(string); + } + + static bool addressInString(String string, RegExp addressRegex) { + return RegExp("(^|\\s)${addressRegex.pattern}(\$|\\s)").hasMatch(string); + } + + static BitcoinBaseAddress addressTypeFromStr(String address, BasedUtxoNetwork network) { + if (network is BitcoinCashNetwork) { + if (!address.startsWith("bitcoincash:") && + (address.startsWith("q") || address.startsWith("p"))) { + address = "bitcoincash:$address"; + } + + return BitcoinCashAddress(address).baseAddress; + } + + if (stringIsAddress(address, P2pkhAddress.regex)) { + return P2pkhAddress.fromAddress(address: address, network: network); + } else if (stringIsAddress(address, P2shAddress.regex)) { + return P2shAddress.fromAddress(address: address, network: network); + } else if (stringIsAddress(address, P2wshAddress.regex)) { + return P2wshAddress.fromAddress(address: address, network: network); + } else if (stringIsAddress(address, P2trAddress.regex)) { + return P2trAddress.fromAddress(address: address, network: network); + } else if (stringIsAddress(address, SilentPaymentAddress.regex)) { + return SilentPaymentAddress.fromAddress(address); + } else if (stringIsAddress(address, MwebAddress.regex)) { + return MwebAddress.fromAddress(address: address, network: network); + } else { + return P2wpkhAddress.fromAddress(address: address, network: network); + } + } +} diff --git a/lib/src/utils/script.dart b/lib/src/utils/script.dart new file mode 100644 index 0000000..f5a3838 --- /dev/null +++ b/lib/src/utils/script.dart @@ -0,0 +1,36 @@ +import 'package:bitcoin_base/src/bitcoin/script/scripts.dart'; + +bool isDefinedHashType(sighash) { + final hashTypeMod = sighash & ~BitcoinOpCodeConst.SIGHASH_ANYONECANPAY; + return hashTypeMod > BitcoinOpCodeConst.SIGHASH_ALL && + hashTypeMod < BitcoinOpCodeConst.SIGHASH_SINGLE; +} + +bool bip66check(buffer) { + if (buffer.length < 8) return false; + if (buffer.length > 72) return false; + if (buffer[0] != 0x30) return false; + if (buffer[1] != buffer.length - 2) return false; + if (buffer[2] != 0x02) return false; + + var lenR = buffer[3]; + if (lenR == 0) return false; + if (5 + lenR >= buffer.length) return false; + if (buffer[4 + lenR] != 0x02) return false; + + var lenS = buffer[5 + lenR]; + if (lenS == 0) return false; + if ((6 + lenR + lenS) != buffer.length) return false; + + if (buffer[4] & 0x80 != 0) return false; + if (lenR > 1 && (buffer[4] == 0x00) && buffer[5] & 0x80 == 0) return false; + + if (buffer[lenR + 6] & 0x80 != 0) return false; + if (lenS > 1 && (buffer[lenR + 6] == 0x00) && buffer[lenR + 7] & 0x80 == 0) return false; + return true; +} + +bool isCanonicalScriptSignature(List buffer) { + if (!isDefinedHashType(buffer[buffer.length - 1])) return false; + return bip66check(buffer.sublist(0, buffer.length - 1)); +} diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index b0b050d..2bd2b02 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -1,2 +1,3 @@ export 'btc_utils.dart'; export 'enumerate.dart'; +export 'regex.dart'; diff --git a/test/fixtures/silent_payments.json b/test/fixtures/silent_payments.json new file mode 100644 index 0000000..a54c584 --- /dev/null +++ b/test/fixtures/silent_payments.json @@ -0,0 +1,2766 @@ +[ + { + "comment": "Simple send: two inputs", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + }, + "private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + } + } + ], + "outputs": [ + "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", + "priv_key_tweak": "f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6", + "signature": "74f85b856337fbe837643b86f462118159f93ac4acc2671522f27e8f67b079959195ccc7a5dbee396d2909f5d680d6e30cda7359aa2755822509b70d6b0687a1" + } + ] + } + } + ] + }, + { + "comment": "Simple send: two inputs, order reversed", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + }, + "private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + } + } + ], + "outputs": [ + "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", + "priv_key_tweak": "f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6", + "signature": "74f85b856337fbe837643b86f462118159f93ac4acc2671522f27e8f67b079959195ccc7a5dbee396d2909f5d680d6e30cda7359aa2755822509b70d6b0687a1" + } + ] + } + } + ] + }, + { + "comment": "Simple send: two inputs from the same transaction", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 3, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 7, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + }, + "private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 3, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 7, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + } + } + ], + "outputs": [ + "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6", + "priv_key_tweak": "4851455bfbe1ab4f80156570aa45063201aa5c9e1b1dcd29f0f8c33d10bf77ae", + "signature": "10332eea808b6a13f70059a8a73195808db782012907f5ba32b6eae66a2f66b4f65147e2b968a1678c5f73d57d5d195dbaf667b606ff80c8490eac1f3b710657" + } + ] + } + } + ] + }, + { + "comment": "Simple send: two inputs from the same transaction, order reversed", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 7, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 3, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + }, + "private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 7, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 3, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + } + } + ], + "outputs": [ + "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38", + "priv_key_tweak": "ab0c9b87181bf527879f48db9f14a02233619b986f8e8f2d5d408ce68a709f51", + "signature": "398a9790865791a9db41a8015afad3a47d60fec5086c50557806a49a1bc038808632b8fe679a7bb65fc6b455be994502eed849f1da3729cd948fc7be73d67295" + } + ] + } + } + ] + }, + { + "comment": "Single recipient: multiple UTXOs from the same public key", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + } + ], + "outputs": [ + "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566", + "priv_key_tweak": "f032695e2636619efa523fffaa9ef93c8802299181fd0461913c1b8daf9784cd", + "signature": "f238386c5d5e5444f8d2c75aabbcb28c346f208c76f60823f5de3b67b79e0ec72ea5de2d7caec314e0971d3454f122dda342b3eede01b3857e83654e36b25f76" + } + ] + } + } + ] + }, + { + "comment": "Single recipient: taproot only inputs with even y-values", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1", + "prevout": { + "scriptPubKey": { + "hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338" + } + }, + "private_key": "fc8716a97a48ba9a05a98ae47b5cd201a25a7fd5d8b73c203c5f7b6b6b3b6ad7" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1", + "prevout": { + "scriptPubKey": { + "hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338" + } + } + } + ], + "outputs": [ + "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb", + "priv_key_tweak": "3fb9ce5ce1746ced103c8ed254e81f6690764637ddbc876ec1f9b3ddab776b03", + "signature": "c5acd25a8f021a4192f93bc34403fd8b76484613466336fb259c72d04c169824f2690ca34e96cee86b69f376c8377003268fda56feeb1b873e5783d7e19bcca5" + } + ] + } + } + ] + }, + { + "comment": "Single recipient: taproot only with mixed even/odd y-values", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "", + "txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5", + "prevout": { + "scriptPubKey": { + "hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4" + } + }, + "private_key": "1d37787c2b7116ee983e9f9c13269df29091b391c04db94239e0d2bc2182c3bf" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "", + "txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5", + "prevout": { + "scriptPubKey": { + "hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4" + } + } + } + ], + "outputs": [ + "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1", + "priv_key_tweak": "f5382508609771068ed079b24e1f72e4a17ee6d1c979066bf1d4e2a5676f09d4", + "signature": "ff65833b8fd1ed3ef9d0443b4f702b45a3f2dd457ba247687e8207745c3be9d2bdad0ab3f07118f8b2efc6a04b95f7b3e218daf8a64137ec91bd2fc67fc137a5" + } + ] + } + } + ] + }, + { + "comment": "Single recipient: taproot input with even y-value and non-taproot input", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac" + } + }, + "private_key": "8d4751f6e8a3586880fb66c19ae277969bd5aa06f61c4ee2f1e2486efdf666d3" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac" + } + } + } + ], + "outputs": [ + "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0", + "priv_key_tweak": "b40017865c79b1fcbed68896791be93186d08f47e416b289b8c063777e14e8df", + "signature": "d1edeea28cf1033bcb3d89376cabaaaa2886cbd8fda112b5c61cc90a4e7f1878bdd62180b07d1dfc8ffee1863c525a0c7b5bcd413183282cfda756cb65787266" + } + ] + } + } + ] + }, + { + "comment": "Single recipient: taproot input with odd y-value and non-taproot input", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5", + "prevout": { + "scriptPubKey": { + "hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4" + } + }, + "private_key": "1d37787c2b7116ee983e9f9c13269df29091b391c04db94239e0d2bc2182c3bf" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac" + } + }, + "private_key": "8d4751f6e8a3586880fb66c19ae277969bd5aa06f61c4ee2f1e2486efdf666d3" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5", + "prevout": { + "scriptPubKey": { + "hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac" + } + } + } + ], + "outputs": [ + "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a", + "priv_key_tweak": "a2f9dd05d1d398347c885d9c61a64d18a264de6d49cea4326bafc2791d627fa7", + "signature": "96038ad233d8befe342573a6e54828d863471fb2afbad575cc65271a2a649480ea14912b6abbd3fbf92efc1928c036f6e3eef927105af4ec1dd57cb909f360b8" + } + ] + } + } + ] + }, + { + "comment": "Multiple outputs: multiple outputs, same recipient", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 2.0 + ], + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 3.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + 2.0 + ], + [ + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + 3.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" + }, + { + "pub_key": "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "priv_key_tweak": "d97e442d110c0bdd31161a7bb6e7862e038d02a09b1484dfbb463f2e0f7c9230", + "signature": "29bd25d0f808d7fcd2aa6d5ed206053899198397506c301b218a9e47a3d7070af03e903ff718978d50d1b6b9af8cc0e313d84eda5d5b1e8e85e5516d630bbeb9" + } + ] + } + } + ] + }, + { + "comment": "Multiple outputs: multiple outputs, multiple recipients", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 2.0 + ], + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 3.0 + ], + [ + "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn", + 4.0 + ], + [ + "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn", + 5.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + 2.0 + ], + [ + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + 3.0 + ], + [ + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + 4.0 + ], + [ + "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a", + 5.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" + }, + { + "pub_key": "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "priv_key_tweak": "d97e442d110c0bdd31161a7bb6e7862e038d02a09b1484dfbb463f2e0f7c9230", + "signature": "29bd25d0f808d7fcd2aa6d5ed206053899198397506c301b218a9e47a3d7070af03e903ff718978d50d1b6b9af8cc0e313d84eda5d5b1e8e85e5516d630bbeb9" + } + ] + } + }, + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a" + ], + "key_material": { + "spend_priv_key": "9902c3c56e84002a7cd410113a9ab21d142be7f53cf5200720bb01314c5eb920", + "scan_priv_key": "060b751d7892149006ed7b98606955a29fe284a1e900070c0971f5fb93dbf422" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn" + ], + "outputs": [ + { + "pub_key": "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + "priv_key_tweak": "2f17ea873a0047fc01ba8010fef0969e76d0e4283f600d48f735098b1fee6eb9", + "signature": "c26f4e3cf371b90b840f48ea0e761b5ec31883ed55719f9ef06a90e282d85f565790ab780a3f491bc2668cc64e944dca849d1022a878cdadb8d168b8da4a6da3" + }, + { + "pub_key": "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a", + "priv_key_tweak": "72cd082cccb633bf85240a83494b32dc943a4d05647a6686d23ad4ca59c0ebe4", + "signature": "38745f3d9f5eef0b1cfb17ca314efa8c521efab28a23aa20ec5e3abb561d42804d539906dce60c4ee7977966184e6f2cab1faa0e5377ceb7148ec5218b4e7878" + } + ] + } + } + ] + }, + { + "comment": "Receiving with labels: label with odd parity", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [ + 2, + 3, + 1001337 + ] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5" + ], + "outputs": [ + { + "pub_key": "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a", + "priv_key_tweak": "51d4e9d0d482b5700109b4b2e16ff508269b03d800192a043d61dca4a0a72a52", + "signature": "c30fa63bad6f0a317f39a773a5cbf0b0f8193c71dfebba05ee6ae4ed28e3775e6e04c3ea70a83703bb888122855dc894cab61692e7fd10c9b3494d479a60785e" + } + ] + } + } + ] + }, + { + "comment": "Receiving with labels: label with odd parity", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [ + 2, + 3, + 1001337 + ] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5" + ], + "outputs": [ + { + "pub_key": "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c", + "priv_key_tweak": "6024ae214876356b8d917716e7707d267ae16a0fdb07de2a786b74a7bbcddead", + "signature": "a86d554d0d6b7aa0907155f7e0b47f0182752472fffaeddd68da90e99b9402f166fd9b33039c302c7115098d971c1399e67c19e9e4de180b10ea0b9d6f0db832" + } + ] + } + } + ] + }, + { + "comment": "Receiving with labels: label with odd parity", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [ + 2, + 3, + 1001337 + ] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5" + ], + "outputs": [ + { + "pub_key": "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951", + "priv_key_tweak": "e336b92330c33030285ce42e4115ad92d5197913c88e06b9072b4a9b47c664a2", + "signature": "c9e80dd3bdd25ca2d352ce77510f1aed37ba3509dc8cc0677f2d7c2dd04090707950ce9dd6c83d2a428063063aff5c04f1744e334f661f2fc01b4ef80b50f739" + } + ] + } + } + ] + }, + { + "comment": "Multiple outputs with labels: multiple outputs for labeled address; same recipient", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ], + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + 2.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + 1.0 + ], + [ + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + 2.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [ + 1 + ] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj" + ], + "outputs": [ + { + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" + }, + { + "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914", + "signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75" + } + ] + } + } + ] + }, + { + "comment": "Multiple outputs with labels: multiple outputs for labeled address; same recipient", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + 3.0 + ], + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + 4.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + 3.0 + ], + [ + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + 4.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [ + 1 + ] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj" + ], + "outputs": [ + { + "pub_key": "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + "priv_key_tweak": "9d5fd3b91cac9ddfea6fc2e6f9386f680e6cee623cda02f53706306c081de87f", + "signature": "db0dfacc98b6a6fcc67cc4631f080b1ca38c60d8c397f2f19843f8f95ec91594b24e47c5bd39480a861c1209f7e3145c440371f9191fb96e324690101eac8e8e" + }, + { + "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914", + "signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75" + } + ] + } + } + ] + }, + { + "comment": "Multiple outputs with labels: multiple outputs for labeled address; same recipient", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 5.0 + ], + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + 6.0 + ], + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5", + 7.0 + ], + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5", + 8.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + 5.0 + ], + [ + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + 6.0 + ], + [ + "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", + 7.0 + ], + [ + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b", + 8.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [ + 1 + ] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj" + ], + "outputs": [ + { + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" + }, + { + "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914", + "signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75" + } + ] + } + } + ] + }, + { + "comment": "Single recipient: use silent payments for sender change", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ], + [ + "sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqlv6saelkk5snl4wfutyxrchpzzwm8rjp3z6q7apna59z9huq4x754e5atr", + 2.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + 1.0 + ], + [ + "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff", + 2.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff" + ], + "key_material": { + "spend_priv_key": "b8f87388cbb41934c50daca018901b00070a5ff6cc25a7e9e716a9d5b9e4d664", + "scan_priv_key": "11b7a82e06ca2648d5fded2366478078ec4fc9dc1d8ff487518226f229d768fd" + }, + "labels": [ + 0 + ] + }, + "expected": { + "addresses": [ + "sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqauj52ymtc4xdkmx3tgyhrsemg2g3303xk2gtzfy8h8ejet8fz8jcw23zua", + "sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqlv6saelkk5snl4wfutyxrchpzzwm8rjp3z6q7apna59z9huq4x754e5atr" + ], + "outputs": [ + { + "pub_key": "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff", + "priv_key_tweak": "80cd767ed20bd0bb7d8ea5e803f8c381293a62e8a073cf46fb0081da46e64e1f", + "signature": "7fbd5074cf1377273155eefafc7c330cb61b31da252f22206ac27530d2b2567040d9af7808342ed4a09598c26d8307446e4ed77079e6a2e61fea736e44da5f5a" + } + ] + } + }, + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" + } + ] + } + } + ] + }, + { + "comment": "Single receipient: taproot input with NUMS point", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0440c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b22205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5ac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac00150", + "prevout": { + "scriptPubKey": { + "hex": "5120da6f0595ecb302bbe73e2f221f05ab10f336b06817d36fd28fc6691725ddaa85" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1", + "prevout": { + "scriptPubKey": { + "hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338" + } + }, + "private_key": "fc8716a97a48ba9a05a98ae47b5cd201a25a7fd5d8b73c203c5f7b6b6b3b6ad7" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 1, + "scriptSig": "", + "txinwitness": "0340268d31a9276f6380107d5321cafa6d9e8e5ea39204318fdc8206b31507c891c3bbcea3c99e2208d73bd127a8e8c5f1e45a54f1bd217205414ddb566ab7eda0092220e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85dac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0", + "prevout": { + "scriptPubKey": { + "hex": "51200a3c9365ceb131f89b0a4feb6896ebd67bb15a98c31eaa3da143bb955a0f3fcb" + } + }, + "private_key": "8d4751f6e8a3586880fb66c19ae277969bd5aa06f61c4ee2f1e2486efdf666d3" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0440c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b22205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5ac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac00150", + "prevout": { + "scriptPubKey": { + "hex": "5120da6f0595ecb302bbe73e2f221f05ab10f336b06817d36fd28fc6691725ddaa85" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1", + "prevout": { + "scriptPubKey": { + "hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 1, + "scriptSig": "", + "txinwitness": "0340268d31a9276f6380107d5321cafa6d9e8e5ea39204318fdc8206b31507c891c3bbcea3c99e2208d73bd127a8e8c5f1e45a54f1bd217205414ddb566ab7eda0092220e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85dac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0", + "prevout": { + "scriptPubKey": { + "hex": "51200a3c9365ceb131f89b0a4feb6896ebd67bb15a98c31eaa3da143bb955a0f3fcb" + } + } + } + ], + "outputs": [ + "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d", + "priv_key_tweak": "3ddec3232609d348d6b8b53123b4f40f6d4f5398ca586f087b0416ec3b851496", + "signature": "d7d06e3afb68363031e4eb18035c46ceae41bdbebe7888a4754bc9848c596436869aeaecff0527649a1f458b71c9ceecec10b535c09d01d720229aa228547706" + } + ] + } + } + ] + }, + { + "comment": "Pubkey extraction from malleated p2pkh", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 1, + "scriptSig": "0075473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 2, + "scriptSig": "5163473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187372102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d67483046022100c0d3c851d3bd562ae93d56bcefd735ea57c027af46145a4d5e9cac113bfeb0c2022100ee5b2239af199fa9b7aa1d98da83a29d0a2cf1e4f29e2f37134ce386d51c544c2102ad0f26ddc7b3fcc340155963b3051b85289c1869612ecb290184ac952e2864ec68", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914c82c5ec473cbc6c86e5ef410e36f9495adcf979988ac" + } + }, + "private_key": "72b8ae09175ca7977f04993e651d88681ed932dfb92c5158cdf0161dd23fda6e" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 1, + "scriptSig": "0075473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 2, + "scriptSig": "5163473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187372102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d67483046022100c0d3c851d3bd562ae93d56bcefd735ea57c027af46145a4d5e9cac113bfeb0c2022100ee5b2239af199fa9b7aa1d98da83a29d0a2cf1e4f29e2f37134ce386d51c544c2102ad0f26ddc7b3fcc340155963b3051b85289c1869612ecb290184ac952e2864ec68", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914c82c5ec473cbc6c86e5ef410e36f9495adcf979988ac" + } + } + } + ], + "outputs": [ + "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f", + "priv_key_tweak": "10bde9781def20d7701e7603ef1b1e5e71c67bae7154818814e3c81ef5b1a3d3", + "signature": "6137969f810e9e8ef6c9755010e808f5dd1aed705882e44d7f0ae64eb0c509ec8b62a0671bee0d5914ac27d2c463443e28e999d82dc3d3a4919f093872d947bb" + } + ] + } + } + ] + }, + { + "comment": "P2PKH and P2WPKH Uncompressed Keys are skipped", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 1, + "scriptSig": "", + "txinwitness": "02473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187374104e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d6fe8190e189be57d0d5bcd17dbcbcd04c9b4a1c5f605b10d5c90abfcc0d12884", + "prevout": { + "scriptPubKey": { + "hex": "00140423f731a07491364e8dce98b7c00bda63336950" + } + }, + "private_key": "72b8ae09175ca7977f04993e651d88681ed932dfb92c5158cdf0161dd23fda6e" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 1, + "scriptSig": "", + "txinwitness": "02473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187374104e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d6fe8190e189be57d0d5bcd17dbcbcd04c9b4a1c5f605b10d5c90abfcc0d12884", + "prevout": { + "scriptPubKey": { + "hex": "00140423f731a07491364e8dce98b7c00bda63336950" + } + } + } + ], + "outputs": [ + "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", + "priv_key_tweak": "688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf", + "signature": "72e7ad573ac23255d4651d5b0326a200496588acb7a4894b22092236d5eda6a0a9a4d8429b022c2219081fefce5b33795cae488d10f5ea9438849ed8353624f2" + } + ] + } + } + ] + }, + { + "comment": "Skip invalid P2SH inputs", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "16001419c2f3ae0ca3b642bd3e49598b8da89f50c14161", + "txinwitness": "02483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "prevout": { + "scriptPubKey": { + "hex": "a9148629db5007d5fcfbdbb466637af09daf9125969387" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 1, + "scriptSig": "1600144b92ac4ac6fe6212393894addda332f2e47a3156", + "txinwitness": "02473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", + "prevout": { + "scriptPubKey": { + "hex": "a9146c9bf136fbb7305fd99d771a95127fcf87dedd0d87" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 2, + "scriptSig": "00493046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d601483045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b97014c695221025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be52103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233382102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d53ae", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "a9141044ddc6cea09e4ac40fbec2ba34ad62de6db25b87" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", + 1.0 + ] + ] + } + }, + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "16001419c2f3ae0ca3b642bd3e49598b8da89f50c14161", + "txinwitness": "02483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "prevout": { + "scriptPubKey": { + "hex": "a9148629db5007d5fcfbdbb466637af09daf9125969387" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 1, + "scriptSig": "1600144b92ac4ac6fe6212393894addda332f2e47a3156", + "txinwitness": "02473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", + "prevout": { + "scriptPubKey": { + "hex": "a9146c9bf136fbb7305fd99d771a95127fcf87dedd0d87" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 2, + "scriptSig": "00493046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d601483045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b97014c695221025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be52103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233382102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d53ae", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "a9141044ddc6cea09e4ac40fbec2ba34ad62de6db25b87" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "16001419c2f3ae0ca3b642bd3e49598b8da89f50c14161", + "txinwitness": "02483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "prevout": { + "scriptPubKey": { + "hex": "a9148629db5007d5fcfbdbb466637af09daf9125969387" + } + } + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 1, + "scriptSig": "1600144b92ac4ac6fe6212393894addda332f2e47a3156", + "txinwitness": "02473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", + "prevout": { + "scriptPubKey": { + "hex": "a9146c9bf136fbb7305fd99d771a95127fcf87dedd0d87" + } + } + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 2, + "scriptSig": "00493046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d601483045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b97014c695221025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be52103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233382102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d53ae", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "a9141044ddc6cea09e4ac40fbec2ba34ad62de6db25b87" + } + } + } + ], + "outputs": [ + "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", + "priv_key_tweak": "688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf", + "signature": "72e7ad573ac23255d4651d5b0326a200496588acb7a4894b22092236d5eda6a0a9a4d8429b022c2219081fefce5b33795cae488d10f5ea9438849ed8353624f2" + } + ] + } + } + ] + }, + { + "comment": "Recipient ignores unrelated outputs", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [ + [ + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + 1.0 + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "", + "txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b", + "prevout": { + "scriptPubKey": { + "hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" + } + } + } + ], + "outputs": [ + "782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [] + } + } + ] + }, + { + "comment": "No valid inputs, sender generates no outputs", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d641045a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5c61836c9b1688ba431f7ea3039742251f62f0dca3da1bee58a47fa9b456c2d52", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914460e8b41545d2dbe7e0671f0f573e2232814260a88ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac" + } + }, + "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" + } + ], + "recipients": [ + [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + 1.0 + ] + ] + }, + "expected": { + "outputs": [] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 0, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d641045a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5c61836c9b1688ba431f7ea3039742251f62f0dca3da1bee58a47fa9b456c2d52", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914460e8b41545d2dbe7e0671f0f573e2232814260a88ac" + } + } + }, + { + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "vout": 0, + "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac" + } + } + } + ], + "outputs": [ + "782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", + "e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [] + } + } + ] + } +] diff --git a/test/silent_payments.dart b/test/silent_payments.dart new file mode 100644 index 0000000..c40862a --- /dev/null +++ b/test/silent_payments.dart @@ -0,0 +1,214 @@ +// ignore_for_file: non_constant_identifier_names +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:bitcoin_base/src/bitcoin/script/outpoint.dart'; +import 'package:bitcoin_base/src/bitcoin/script/scripts.dart'; +import 'package:bitcoin_base/src/bitcoin/address/address.dart'; +import 'package:bitcoin_base/src/bitcoin/silent_payments/silent_payments.dart'; +import 'package:bitcoin_base/src/crypto/crypto.dart'; +import 'package:blockchain_utils/blockchain_utils.dart'; +import 'package:blockchain_utils/crypto/crypto/cdsa/point/base.dart'; +import 'package:test/test.dart'; + +// G , needed for generating the labels "database" +final G = ECPublic.fromBytes(BigintUtils.toBytes(Curves.generatorSecp256k1.x, length: 32)); + +main() { + final fixtures = + json.decode(File('test/fixtures/silent_payments.json').readAsStringSync(encoding: utf8)); + + for (var testCase in fixtures) { + test(testCase['comment'], () { + Map> sendingOutputs = {}; + + // Test sending + for (var sendingTest in testCase['sending']) { + List vinOutpoints = []; + List inputPrivKeyInfos = []; + List inputPubKeys = []; + + var given = sendingTest["given"]; + + for (var input in given['vin']) { + final prevoutScript = Script.fromRaw(hexData: input['prevout']['scriptPubKey']['hex']); + final privkey = ECPrivate.fromHex(input['private_key']); + + final vin = VinInfo( + outpoint: Outpoint(txid: input['txid'], index: input['vout']), + scriptSig: BytesUtils.fromHexString(input['scriptSig']), + txinwitness: TxWitnessInput( + stack: [], + scriptWitness: ScriptWitness( + stack: deserStringVector( + ByteData.sublistView( + Uint8List.fromList( + BytesUtils.fromHexString(input['txinwitness']), + ), + ), + ))), + prevOutScript: prevoutScript, + privkey: privkey, + ); + + vinOutpoints.add(vin.outpoint); + + final pubkey = getPubkeyFromInput(vin); + + if (pubkey == null || pubkey.getEncodeType() != EncodeType.compressed) { + continue; + } + + inputPrivKeyInfos.add(ECPrivateInfo( + privkey, + prevoutScript.getAddressType() == SegwitAddresType.p2tr, + tweak: false, + )); + inputPubKeys.add(pubkey); + } + + if (inputPubKeys.isNotEmpty) { + List silentPaymentDestinations = + (given['recipients'] as List) + .map((recipient) => + SilentPaymentDestination.fromAddress(recipient[0], recipient[1].floor())) + .toList(); + + final spb = SilentPaymentBuilder(pubkeys: inputPubKeys, vinOutpoints: vinOutpoints); + sendingOutputs = spb.createOutputs(inputPrivKeyInfos, silentPaymentDestinations); + + List expectedDestinations = sendingTest['expected']['outputs']; + + for (final destination in silentPaymentDestinations) { + expect(sendingOutputs[destination.toString()] != null, true); + } + + final generatedOutputs = sendingOutputs.values.expand((element) => element).toList(); + for (final expected in expectedDestinations) { + final expectedPubkey = expected[0]; + final generatedPubkey = generatedOutputs.firstWhere((output) => + BytesUtils.toHexString(output.address.pubkey!.toCompressedBytes().sublist(1)) == + expectedPubkey); + + expect( + BytesUtils.toHexString( + generatedPubkey.address.pubkey!.toCompressedBytes().sublist(1)), + expectedPubkey); + } + } + } + + final msg = SHA256().update(utf8.encode('message')).digest(); + final aux = SHA256().update(utf8.encode('random auxiliary data')).digest(); + + // Test receiving + for (final receivingTest in testCase['receiving']) { + List vinOutpoints = []; + List inputPubKeys = []; + + final given = receivingTest["given"]; + final expected = receivingTest['expected']; + + List outputsToCheck = + (given['outputs'] as List).map((output) => output.toString()).toList(); + + final List receivingAddresses = []; + + final silentPaymentOwner = SilentPaymentOwner.fromPrivateKeys( + b_scan: ECPrivate.fromHex(given["key_material"]["scan_priv_key"]), + b_spend: ECPrivate.fromHex(given["key_material"]["spend_priv_key"])); + + // Add change address + receivingAddresses.add(silentPaymentOwner); + + Map? preComputedLabels; + for (var label in given['labels']) { + receivingAddresses.add(silentPaymentOwner.toLabeledSilentPaymentAddress(label)); + final generatedLabel = silentPaymentOwner.generateLabel(label); + + preComputedLabels ??= {}; + preComputedLabels[G.tweakMul(BigintUtils.fromBytes(generatedLabel)).toHex()] = + BytesUtils.toHexString(generatedLabel); + } + + for (var address in expected['addresses']) { + expect(receivingAddresses.indexWhere((sp) => sp.toString() == address.toString()), + isNot(-1)); + } + + for (var input in given['vin']) { + final prevoutScript = Script.fromRaw(hexData: input['prevout']['scriptPubKey']['hex']); + + final vin = VinInfo( + outpoint: Outpoint(txid: input['txid'], index: input['vout']), + scriptSig: BytesUtils.fromHexString(input['scriptSig']), + txinwitness: TxWitnessInput( + stack: [], + scriptWitness: ScriptWitness( + stack: deserStringVector( + ByteData.sublistView( + Uint8List.fromList( + BytesUtils.fromHexString(input['txinwitness']), + ), + ), + ))), + prevOutScript: prevoutScript, + ); + + vinOutpoints.add(vin.outpoint); + + final pubkey = getPubkeyFromInput(vin); + + if (pubkey == null || pubkey.getEncodeType() != EncodeType.compressed) { + continue; + } + + inputPubKeys.add(pubkey); + } + + if (inputPubKeys.isNotEmpty) { + final spb = SilentPaymentBuilder(pubkeys: inputPubKeys, vinOutpoints: vinOutpoints); + + final addToWallet = spb.scanOutputs(silentPaymentOwner.b_scan, silentPaymentOwner.B_spend, + outputsToCheck.map((o) => getScriptFromOutput(o, 0)).toList(), + precomputedLabels: preComputedLabels); + + final expectedDestinations = expected['outputs']; + + // Check that the private key is correct for the found output public key + for (int i = 0; i < expectedDestinations.length; i++) { + final output = addToWallet.entries.elementAt(i); + final pubkey = output.key; + final expectedPubkey = expectedDestinations[i]["pub_key"]; + expect(pubkey, expectedPubkey); + + final privKeyTweak = output.value.tweak; + final expectedPrivKeyTweak = expectedDestinations[i]["priv_key_tweak"]; + expect(privKeyTweak, expectedPrivKeyTweak); + + var fullPrivateKey = + silentPaymentOwner.b_spend.tweakAdd(BigintUtils.parse(privKeyTweak)); + + if (fullPrivateKey.toBytes()[0] == 0x03) { + fullPrivateKey = fullPrivateKey.negate(); + } + + // Sign the message with schnorr + final btcSigner = BitcoinSigner.fromKeyBytes(fullPrivateKey.toBytes()); + List sig = + btcSigner.signSchnorrTransaction(msg, tapScripts: [], tweak: false, aux: aux); + + // Verify the message is correct + expect(btcSigner.verifyKey.verifySchnorr(msg, sig, isTweak: false), true); + + // Verify the signature is correct + expect(BytesUtils.toHexString(sig), expectedDestinations[i]["signature"]); + + i++; + } + } + } + }); + } +}