bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.7k stars 2.11k forks source link

Mandatory-script-verify-flag-failed (Invalid Schnorr signature) #2162

Closed Arunpandiaraja closed 2 months ago

Arunpandiaraja commented 2 months ago

Any help over here?

Error: Mandatory-script-verify-flag-failed (Invalid Schnorr signature)

I have done the taptweak method when i have privatekey and was able to make the transaction work.

But how to do tap tweak and sign the inputs with schnorr signature that i'm getting from MPC TSS network

After generating the preSignTxHash, i'm calling the MPC TSS network to get the signature for the preSignTxHash message, with that signature i'm trying to update the input.

Transaction Hex - 02000000000101a0c8b590d64027b2172bb32d99aba45c66840dabcccfdcdd8f3d53172bccfada0000000000ffffffff0180969800000000002251207a5f02cab5e731e516c5b8727acf92a69fe9aac12eb326afea9c3a724084afa0014099c5d041f5adad9ba7ba94a45270560575ea522af9b20d25af9a8e97287946fd3dcb626c859f674cb4d9c1d70ec2df1ac30579558a16c3d7183b3be0b601a06000000000


export const generatePreSignTxHash = async (txObject) => {
    const network = networks.testnet;
    const psbt = new Psbt({ network });
    try {
      const { utxos, fromAddress, outputAmount, outputs, toAddress, feeRate } = txObject;
      let inputSum = 0;
      const pubKey = process.env.MPC_PUB_KEY;
      utxos.forEach((utxo, index) => {
        inputSum += utxo.value;
        try {
          psbt.addInput({
            hash: utxo.txid,
            index: utxo.vout,
            witnessUtxo: {
              script: address.toOutputScript(fromAddress, network),
              value: utxo.value,
            },
            tapInternalKey: Buffer.from(pubKey ?? '', 'hex'),
          })
        } catch (error) {
          console.error(`Error adding input for txid ${utxo.txid}:`, error)
          throw error
        }
      });

      try {
        outputs.forEach((output) => {
          psbt.addOutput({
            address: output.address,
            value: output.amount,
          })
        });

        const totalOutputAmount = outputs.reduce(
          (sum, output) => sum + output.amount,
          0
        );
        const estimatedFee = feeRate; // Adjust fee calculation as needed
        const changeAmount = inputSum - totalOutputAmount - estimatedFee;

        if (changeAmount > 0) {
          psbt.addOutput({
            address: fromAddress,
            value: changeAmount,
          })
        }
      } catch (error) {
        console.error('Error adding outputs:', error);
        throw error
      }

      const preSignTxHashes = psbt.data.inputs.map((input, index) => {
        const hashType = Transaction.SIGHASH_ALL;
        const transaction = new Transaction()
        const updatedPsbtData = Transaction.fromBuffer(psbt.data.globalMap.unsignedTx.toBuffer());
        const sighash = updatedPsbtData.hashForWitnessV1(
          index,
          [input.witnessUtxo.script],
          [input.witnessUtxo.value],
          hashType
        );
        return `0x${sighash.toString('hex')}`;
      });
      console.log("preSignTxHashes", preSignTxHashes);
      return { preSignTxHashes, psbt };
    } catch (error) {
      console.error('Error generating pre-sign transaction hashes:', error);
    }
};

psbt.data.inputs.forEach((input, index) => {
    const signature = signatures[index];
    const sigBuffer = Buffer.from(signature.sign, 'hex');
    psbt.updateInput(index, {
      tapKeySig: sigBuffer,
    });
jasonandjay commented 2 months ago

Does MPC TSS network support schnorr signature?

Arunpandiaraja commented 2 months ago

Yes @jasonandjay

jasonandjay commented 2 months ago

Transaction broadcast failed shows invalid schnorr signature

I think you should check MPC TSS network, schnorr is not different with ecdsa

It is nothing with this repo, maybe you can ask help from MPC TSS network

Arunpandiaraja commented 2 months ago

But when im trying to verify the schnorr signature its showing valid as signature, code below for verifying the schnorr signature.

preSignTxHashes and generatedSigns getting from the above code.



import sha256 from "sha256"
import * as secp256k1 from 'noble-secp256k1';

 const encMsg = sha256(Buffer.from(preSignTxHashes[0].replace("0x", ""), "hex"));
  const isValid = await verifySchnorrSignature(encMsg, generatedSigns[0].sign);
  console.log("isValid signature", isValid);

export async function verifySchnorrSignature(message, signature) {
  const publicKey = process.env.MPC_PUB_KEY;
  console.log({
    message,
    signature,
    publicKey
  });
  try {
    // Convert hex strings to Uint8Array
    const messageArray = Uint8Array.from(Buffer.from(message, 'hex'));
    const signatureArray = Uint8Array.from(Buffer.from(signature, 'hex'));
    const publicKeyArray = Uint8Array.from(Buffer.from(publicKey, 'hex'));
    // Verify the Schnorr signature
    const isValid = await secp256k1.schnorr.verify(signatureArray, messageArray, publicKeyArray);
    return isValid;
  } catch (error) {
    console.error('Verification error:', error.message);
    return false;
  }
} 
jasonandjay commented 2 months ago

refer to this issue: https://github.com/bitcoinjs/bitcoinjs-lib/issues/2140

you should verify tweak MPC_PUB_KEY,not itself

Arunpandiaraja commented 2 months ago

Ok. Thanks for the response, lemme check