Saturday, July 6, 2024

Subject with establishing an accurate Schnorr Signature for a Taproot transaction

I am experimenting with creating and sending Taproot transactions programmatically and encountered a problem with the Schnorr signature. I am attempting to ship easy transaction with one V1_P2TR enter and one V1_P2TR output, utilizing what I perceive to be a key path spend strategy, with none scripts. Nevertheless, once I try and ship the transaction, my node rejects it with the error:
mandatory-script-verify-flag-failed (Invalid Schnorr signature)

I am utilizing the next dependencies in my Rust undertaking:

bitcoin = { model = "0.30.1", options = ["rand"] }
ord-bitcoincore-rpc = "0.17.1"   # (a forked model of bitcoincore-rpc, although I consider this element shouldn't be essential to the difficulty).

Here is the related a part of my code:

fn create_and_send_tmp_tx(shopper: &Consumer, utxo: &ListUnspentResultEntry, fee_rate: f64, key_pair: &UntweakedKeyPair, address_to: &Deal with) -> Outcome<Txid> {

    let secp256k1 = Secp256k1::new();

    // Verifying that UTXO might be spent by supplied key pair
    let (public_key, _parity) = XOnlyPublicKey::from_keypair(&key_pair);
    let handle = Deal with::p2tr(&secp256k1, public_key, None, Community::Bitcoin);
    let address_script_pubkey = handle.script_pubkey();
    let utxo_script_pubkey = utxo.script_pub_key.clone();
    if ! (address_script_pubkey == utxo_script_pubkey) {
        bail!("Cannot spend utxo");
    }

    let mut tx = Transaction {
        enter: vec![TxIn {
            previous_output: OutPoint {
                txid: utxo.txid,
                vout: utxo.vout,
            },
            script_sig: Builder::new().into_script(),
            witness: Witness::new(),
            sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
        }],
        output: vec![TxOut {
            script_pubkey: address_to.script_pubkey(),
            value: 0,   // tmp value for estimation
        }],
        lock_time: LockTime::ZERO,
        model: 2,
    };

    tx.enter[0].witness.push(
        Signature::from_slice(&[0; SCHNORR_SIGNATURE_SIZE])
            .unwrap()
            .to_vec(),
    );

    let charge = Quantity::from_sat((fee_rate * tx.vsize()).spherical() as u64);
    data!("Payment: {:?}", charge.to_sat());
    tx.output[0].worth = utxo.quantity.to_sat() - charge.to_sat();
    tx.enter[0].witness.clear();

    let prevouts = vec![TxOut {script_pubkey: utxo.script_pub_key.clone(), value: utxo.amount.to_sat()}];

    let mut sighash_cache = SighashCache::new(&tx);
    let sighash = sighash_cache.taproot_key_spend_signature_hash(
        0,
        &Prevouts::All(&prevouts),
        TapSighashType::Default,
    ).anticipate("Didn't compute sighash");

    let msg = secp256k1::Message::from_slice(sighash.as_ref()).anticipate("ought to be cryptographically safe hash");
    let sig = secp256k1.sign_schnorr(&msg, &key_pair);

    tx.enter[0].witness.push(
        Signature {
            sig,
            hash_ty: TapSighashType::Default,
        }
            .to_vec(),
    );

    let signed_tx_bytes = consensus::encode::serialize(&tx);
    // let signed_tx_bytes = shopper.sign_raw_transaction_with_wallet(&tx, None, None)?.hex;

    let txid = match shopper.send_raw_transaction(&signed_tx_bytes) {
        Okay(txid) => txid,
        Err(err) => {
            return Err(anyhow!("Didn't ship transaction: {err}n"))
        }
    };
    data!("Tx despatched: {:?}", txid);
    Okay(txid)
}

The pockets I am utilizing is linked to my node. If I exploit the
shopper.sign_raw_transaction_with_wallet(&tx, None, None)?.hex; perform, which permits the node to interchange my witness with an accurate one, the transaction is accepted. This implies that my inputs and outputs are constructed appropriately, and the difficulty doubtless lies with how I am producing the signature.

I’ve efficiently despatched transactions utilizing a script path spend with an identical strategy, utilizing sighash_cache.taproot_script_spend_signature_hash, with out the node’s intervention in signing.

May somebody assist me establish what I am doing unsuitable?

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles