Tuesday, October 1, 2024

Problem with developing 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 making an attempt to ship easy transaction with one V1_P2TR enter and one V1_P2TR output, utilizing what I perceive to be a key path spend method, with none scripts. Nonetheless, 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 imagine this element will not be essential to the difficulty).

This 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) -> Consequence<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 deal with = Deal with::p2tr(&secp256k1, public_key, None, Community::Bitcoin);
    let address_script_pubkey = deal with.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 payment = Quantity::from_sat((fee_rate * tx.vsize()).spherical() as u64);
    data!("Price: {:?}", payment.to_sat());
    tx.output[0].worth = utxo.quantity.to_sat() - payment.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("needs 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 related to my node. If I exploit the
shopper.sign_raw_transaction_with_wallet(&tx, None, None)?.hex; perform, which permits the node to exchange my witness with an accurate one, the transaction is accepted. This means that my inputs and outputs are constructed appropriately, and the difficulty probably lies with how I am producing the signature.

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

Might somebody assist me determine what I am doing improper?

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles