signature – Signing taproot key-path transaction from rust-bitcoin

0
62


I am attempting to make a taproot HTLC utilizing rust-bitcoin for an atomic swap protocol. My plan is that within the “pleased case” of my protocol, the cash are spent with the key-path, after which there’s a tapleaf for the “refund” case (after n blocks, the unique proprietor can spend), and a tapleaf with a hashlock.

Assuming I’ve features to construct up the hashlock and timelock scripts, I am constructing some TaprootSpendInfo and a obtain deal with as so:

let taproot_spend_info = TaprootBuilder::new()
        .add_leaf(
            1u8,
            build_hashlock_script(alice_hashlock.as_slice(), &bob.hl_keypair.x_only_public_key().0)
        )
        .anticipate("could not add hashlock leaf")
        .add_leaf(
            1u8,
            build_timelock_script(2, &alice.refund_keypair.x_only_public_key().0)
        )
        .anticipate("Could not add timelock leaf")
        .finalize(
            &secp,
            alice.escrow_keypair.x_only_public_key().0
        )
        .anticipate("Couldn't finalize taproot spend information");

    let alice2bob_addr = Handle::p2tr_tweaked(taproot_spend_info.output_key(), Community::Regtest);

I am going and fund that deal with. Then after I need to spend from that deal with with the key-path, I make a transaction and get the sighash as so:

    let mut keypath_tx = Transaction {
        model: 1,
        lock_time: PackedLockTime::ZERO,
        enter: vec![ TxIn {
            previous_output: OutPoint {
                txid: first_funding_txid,
                vout: 0
            },
            script_sig: script::Builder::new().into_script(), // this might be wrong
            sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
            witness: Witness::new(),
        }],
        output: vec![ TxOut {
            value: Amount::from_btc(0.99).unwrap().to_sat(),
            script_pubkey: miner_address.script_pubkey()
        }]
    };
    let sighash = keypath_tx.signature_hash(0, &script::Builder::new().into_script(), 0x00);
    let hash_to_be_signed = sighash.as_hash();

After which I take that sighash and signal it with libsecp:

    let message = secp256k1::Message::from_slice(&hash_to_be_signed).unwrap();
    let signature = secp.sign_schnorr(&message, &alice.escrow_keypair.secret_key().add_tweak(&taproot_spend_info.tap_tweak().to_scalar()).unwrap().keypair(&secp));
    keypath_tx.enter[0].witness.push(signature.as_ref());

When I attempt to broadcast this transaction, I get an error Invalid Schnorr signature.

I believe I am including the signature to the witness appropriately: BIP341 says that if after eradicating the annex from the witness (if it is there), if there may be one merchandise left, it is interpreted as a key-path spend and the merchandise is interpreted as a signature. So I believe pushing the signature into the in any other case empty witness is the proper factor to do. I additionally checked that the signature is legitimate. That makes me suppose that I am both signing the incorrect factor or that I am not tweaking the personal key appropriately at signing time.

My solely taproot expertise to this point has been with descriptor wallets, so any recommendations on what I am doing incorrect can be enormously appreciated. Thanks!

LEAVE A REPLY

Please enter your comment!
Please enter your name here