P2tr - Vous avez reçu un message d'erreur non obligatoire-script-verify-flag (signature Schnorr invalide) lors d'une transaction de racine pivotante

J'essaie de dépenser une adresse Taproot via un chemin de dépense clé avec la bibliothèque musig2 dans Rust. Cette adresse est regroupée avec 2 propriétaires. Mais j'ai toujours reçu ce message lorsque j'ai diffusé la transaction hexadécimale sur https://blockstream.info/testnet/tx/push

Erreur RPC sendrawtransaction : {"code":-26,"message":"non-mandatory-script-verify-flag (signature Schnorr invalide)"}

La logique pour créer cette transaction est la suivante. Je dois d’abord créer une transaction de dépôt contenant cette adresse agrégée en sortie. Voici le code pour créer l'adresse agrégée :

pub fn Aggregate_pubkeys (owner_pubkey : PublicKey, se_pubkey : PublicKey, ) -> (PublicKey, PublicKey, Address, KeyAggContext) { let secp = Secp256k1::new(); laissez mut pubkeys : Vec = vec ! []; pubkeys.push(owner_pubkey); pubkeys.push(se_pubkey); laissez key_agg_ctx_tw = KeyAggContext::new(pubkeys.clone()) .unwrap() .with_unspendable_taproot_tweak() .unwrap(); laissez Aggregated_pubkey : PublicKey = key_agg_ctx_tw.aggregated_pubkey_untweaked(); laissez Aggregated_pubkey_tw : PublicKey = key_agg_ctx_tw.aggregated_pubkey(); let Aggreged_address = Address::p2tr( &secp, Aggreged_pubkey.x_only_public_key().0, None, Network::Testnet, ); ( Aggreged_pubkey, Aggreged_pubkey_tw, Aggreged_address, key_agg_ctx_tw, ) }

Ensuite, j'utilise la clé pub agrégée pour créer la clé scriptpubkey pour la sortie de la transaction de dépôt :

let agg_scriptpubkey = ScriptBuf::new_p2tr(&secp, agg_pubkey.x_only_public_key().0, None); let utxo = TxOut { valeur : montant ::from_sat (montant), script_pubkey : agg_scriptpubkey, } ;

Aggreged_pubkey_tw et key_agg_ctx_tw sont utilisés pour créer la signature agrégée. Je suis ce document pour créer la signature https://docs.rs/musig2/latest/musig2/

voici le code pour créer la transaction de dépense :

pub async fn create_bk_tx (pool : &PoolWrapper, conn : &NodeConnector, key_agg_ctx : &KeyAggContext, agg_pubkey : &PublicKey, agg_pubkey_tw : &PublicKey, agg_address : &Address, Receiver_address : &str, txid : &str, vout : u32, montant : u64, statechain_id : &str, ) -> Résultat { let secp = Secp256k1::new(); laissez seckey = pool .get_seckey_by_id(&statechain_id) .await .unwrap() .unwrap(); let seckey = SecretKey::from_str(&seckey).unwrap(); // CRÉER UNE TRANSACTION NON SIGNÉE let agg_scriptpubkey = ScriptBuf::new_p2tr(&secp, agg_pubkey.x_only_public_key().0, None); laissez prev_outpoint = OutPoint { txid : txid.parse().unwrap(), vout : vout.into(), }; let input = TxIn { previous_output : prev_outpoint, script_sig : ScriptBuf::default(), séquence : Sequence::ENABLE_RBF_NO_LOCKTIME, témoin : Witness::default(), } ; let output_address = Address::from_str(receiver_address).unwrap(); laissez check_output_address = output_address.require_network(Network::Testnet).unwrap(); laisser dépenser = TxOut { valeur : montant ::from_sat (montant - BASE_TX_FEE), script_pubkey : vérifié_output_address.script_pubkey(), } ; let mut unsigned_tx = Transaction { version : transaction :: Version :: TWO, // Post BIP-68. lock_time : absolu::LockTime::ZERO, // Ignorer le temps de verrouillage. entrée : vec ! // L'entrée va dans l'index 0. sortie : vec ! , // Sorties, l'ordre n'a pas d'importance. } ; let utxo = TxOut { valeur : montant ::from_sat (montant), script_pubkey : agg_scriptpubkey, } ; laissez prévouts = vec ! ; laissez prevouts = Prevouts::All(&prevouts); laissez mut sighasher = SighashCache::new(&mut unsigned_tx); laissez sighash_type = TapSighashType :: All ; laissez sighash = sighasher .taproot_key_spend_signature_hash(0, &prevouts, sighash_type) .expect("échec de la construction de sighash"); let message = soupir.to_string(); laissez parsed_msg = message.clone(); laissez msg_clone = parsed_msg.clone(); let msg = parsed_msg.clone(); // MUSIG 2 POUR CRÉER UNE SIGNATURE SUR LA TRANSACTION NON SIGNÉE let get_nonce_res = statechain::get_nonce(&conn, statechain_id, &signed_statechain_id).await?; // API pour obtenir un nonce du serveur let server_pubnonce = get_nonce_res.server_nonce; laissez nonce_seed = [0xACu8; 32]; let secnonce = SecNonce::build(nonce_seed).with_seckey(seckey).build(); laissez our_public_nonce = secnonce.public_nonce(); laissez public_nonces = [
our_public_nonce,
server_pubnonce.parse::().unwrap(),
]; laissez agg_pubnonce : AggNonce = public_nonces.iter().sum(); let agg_pubnonce_str = agg_pubnonce.to_string(); let our_partial_signature: PartialSignature = musig2::sign_partial( &key_agg_ctx, seckey, secnonce, &agg_pubnonce, message, ) .expect("erreur lors de la création d'une signature partielle"); laissez serialized_key_agg_ctx = key_agg_ctx .to_bytes() .to_hex_string(bitcoin::hex::Case::Lower); let get_sign_res = statechain::get_partial_signature( &conn, &serialized_key_agg_ctx, &statechain_id, &signed_statechain_id, &msg_clone, &agg_pubnonce_str, ) .attendre ?; // API pour demander la signature partielle au serveur let server_signature = get_sign_res.partial_signature; laissez partial_signatures = [
our_partial_signature,
PartialSignature::from_hex(&server_signature).unwrap(),
]; let final_signature: secp256k1::schnorr::Signature = musig2::aggregate_partial_signatures( &key_agg_ctx, &agg_pubnonce, partial_signatures, msg_clone, ) .expect("erreur d'agrégation des signatures"); musig2::verify_single(*agg_pubkey_tw, final_signature, msg) .expect("la signature agrégée doit être valide"); let signature = bitcoin::taproot::Signature { sig: final_signature, hash_ty: sighash_type, }; let mut wit = Witness::new(); esprit.push(signature.to_vec()); *sighasher.witness_mut(0).unwrap() = esprit; let tx = sighasher.into_transaction(); let tx_hex = consensus::encode::serialize_hex(&tx); // la transaction finale à diffuser Ok(()) }

La signature réussit la vérification musig2 mais pas la vérification du nœud. Je pense que le problème peut être lié au message sighash que je demande à signer. Ici, la transaction de dépôt et la transaction de dépense générées à partir du code. Toute pensée ou aide serait immensément appréciée. Merci d'avance !

Dépôt TX Hex: 02000000000101AdBC7F34E1E97D380BE4056B77843588F0BF15549EE6044EEC203D52108DD0C300000000D489A3220000000000222512 1661B27F295BF7BB9D6725A80B17347306675B07000000000000160014C9DA028A0C782CBD1C20210E6A8059220FB190C02473022012292AC94AB0C6561CD4824441201633AC94AB0C6561CD48244412292 C03D1B0ACFC59CF141EE723BA1755B1376D02202BA6003FD635DCA60E68F03B5A0156 3C2B333C12EAA5A7C5986C324543E186B3800000000 SPECT TX HEX: 020000000001010412EF1C75ADF318B320982FB31824D9DA843FC4EC3B80AF12846EC0893B7B4400000000FICT 00000000000000160014C9DA028A0C782CBD1C20210E6A80592210FB190C0141CA1633 3D2E2828409948723180D1BE3A597CA55DF12AEADDDED2008280100000000