Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BRC20]: Fix bug when revealing BRC20 with extra P2TR #4152

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions rust/frameworks/tw_utxo/src/modules/sighash_computer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ where
.input_args()
.iter()
.enumerate()
.map(|(input_index, utxo)| {
.map(|(signing_input_index, utxo)| {
let signing_method = utxo.signing_method;

let utxo_args = UtxoPreimageArgs {
input_index,
input_index: signing_input_index,
script_pubkey: utxo.script_pubkey.clone(),
amount: utxo.amount,
// TODO move `leaf_hash_code_separator` to `UtxoTaprootPreimageArgs`.
Expand All @@ -90,12 +90,14 @@ where
let tr_spent_script_pubkeys: Vec<Script> = unsigned_tx
.input_args()
.iter()
.map(|utxo| {
if utxo.signing_method == SigningMethod::Taproot {
// Taproot UTXOs scriptPubkeys should be signed as is.
.enumerate()
.map(|(i, utxo)| {
if i == signing_input_index {
// Use the scriptPubkey required to spend this UTXO.
utxo.script_pubkey.clone()
} else {
// Use the original scriptPubkey declared in the unspent output.
// Use the original scriptPubkey declared in the unspent output for other UTXOs
// (different from that we sign at this iteration).
utxo.prevout_script_pubkey.clone()
}
})
Expand Down
74 changes: 74 additions & 0 deletions rust/tw_tests/tests/chains/bitcoin/bitcoin_sign/brc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,77 @@ fn test_bitcoin_sign_brc20_transfer() {
fee: 3000,
});
}

/// Fixes `{"error":"-26: non-mandatory-script-verify-flag (Invalid Schnorr signature)"}` error.
#[test]
fn test_bitcoin_sign_brc20_reveal_with_extra_p2tr_input() {
// bc1puq428nh4eynlqph8gynwdtqg4je0hc03gp2ptgsf4c5ylxz0ll2sd34gk7
let alice_pk_bytes = "8efa479919269076eb331c304fff187b9d7aa60d1f6cd3d6b12a151a52f22582"
.decode_hex()
.unwrap();
let alice_private_key = schnorr::PrivateKey::try_from(alice_pk_bytes.as_slice()).unwrap();
let alice_pubkey = alice_private_key.public().compressed();
let my_address = "bc1puq428nh4eynlqph8gynwdtqg4je0hc03gp2ptgsf4c5ylxz0ll2sd34gk7";

let commit_txid = "164b459a49c5e3a817028df7f4545585874feff3985e48d6ff6792989a4823a8";
let commit_utxo = Proto::Input {
out_point: input::out_point(commit_txid, 0),
value: 546,
sighash_type: SIGHASH_ALL,
claiming_script: input::brc20_inscribe(alice_pubkey.to_vec(), "duna", "0.001"),
..Default::default()
};

// Extra P2TR UTXO is used to cover transaction fee.
let p2tr_utxo = "164b459a49c5e3a817028df7f4545585874feff3985e48d6ff6792989a4823a8";
let extra_p2tr = Proto::Input {
out_point: input::out_point(p2tr_utxo, 1),
value: 11_210,
sighash_type: SIGHASH_ALL,
claiming_script: input::receiver_address(my_address),
..Default::default()
};

let out1 = Proto::Output {
value: 546,
to_recipient: output::to_address(my_address),
};
let change_output = Proto::Output {
value: 0,
to_recipient: output::to_address(my_address),
};

let builder = Proto::TransactionBuilder {
version: Proto::TransactionVersion::V2,
inputs: vec![commit_utxo, extra_p2tr],
outputs: vec![out1],
change_output: Some(change_output),
input_selector: Proto::InputSelector::UseAll,
dust_policy: dust_threshold(DUST),
fee_per_vb: 9,
..Default::default()
};

let signing = Proto::SigningInput {
private_keys: vec![alice_pk_bytes.into()],
chain_info: btc_info(),
// We enable deterministic Schnorr signatures here
dangerous_use_fixed_schnorr_rng: true,
transaction: TransactionOneof::builder(builder),
..Default::default()
};

// https://www.blockchain.com/explorer/transactions/btc/113dfc827e4535dccc6aa7fcff5482b4de0fb2ab70f52c44c12c12bca3be5847
sign::BitcoinSignHelper::new(&signing)
.coin(CoinType::Bitcoin)
.sign(sign::Expected {
encoded: "02000000000102a823489a989267ffd6485e98f3ef4f87855554f4f78d0217a8e3c5499a454b160000000000ffffffffa823489a989267ffd6485e98f3ef4f87855554f4f78d0217a8e3c5499a454b160100000000ffffffff022202000000000000225120e02aa3cef5c927f006e74126e6ac08acb2fbe1f1405415a209ae284f984fffd52d23000000000000225120e02aa3cef5c927f006e74126e6ac08acb2fbe1f1405415a209ae284f984fffd50340b90b099a8facd5d4e6008990d180f9afeeb07d62452570a6e700ca0f7968577da6113cb201e9ac3584caa04898cdc7113cce4df06604b8f294a3959d216d364f5e0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38003a7b2270223a226272632d3230222c226f70223a227472616e73666572222c227469636b223a2264756e61222c22616d74223a22302e303031227d6821c02146f58256fcc00ef86a0e53fc14e943bbea2c7972b598b58178fdd6fa3ef79201401c5e54a0ead877e52146e42f8d197f4c7be84c7d2479a75f33128f15777584bfec410c3e130b4504fe061991a78365add223a3dfb5ca79a988f9ffcf46039b3100000000",
txid: "113dfc827e4535dccc6aa7fcff5482b4de0fb2ab70f52c44c12c12bca3be5847",
inputs: vec![546, 11_210],
outputs: vec![546, 9_005],
// `vsize` is different from the estimated value due to the signatures der serialization.
vsize: 244,
weight: 975,
fee: 2_205,
});
}
Loading