How "addDummySigs" in golang when send satoshi from p2tr multisig script?

I have a 2-of-3 multisig taproot script,create like bitcoinjs-lib:https://github.com/bitcoinjs/bitcoinjs-lib/blob/8d9775c20da03ab40ccbb1971251e71d117bcd8b/test/integration/taproot.spec.ts#L531-L593:

builder := txscript.NewScriptBuilder()
for i, pk := range leafPubkeys {
    if i == 0 {
        builder.AddData(pk)
        builder.AddOp(byte(txscript.OP_CHECKSIG))
    } else {
        builder.AddData(pk)
        builder.AddOp(byte(txscript.OP_CHECKSIGADD))
    }
}
builder.AddOp(byte(txscript.OP_1 - 1 + 2))
builder.AddOp(byte(txscript.OP_GREATERTHANOREQUAL))

then create a tx(send satoshi from the script),and two keys sign it.but got "invalid schnorr signatures" when sent to bitcoind. my golang code:

func TestGenTapscript(t *testing.T) {
    signpks := []string{
...
    }
    pks := []string{...}
    tapscript := NewMultisigTaprootScript(pks, 2, 3, &chaincfg.TestNet3Params)

    // build tx
    const utxoHash = "..."
    const utxoVout = 0
    const utxoAmount = 1000000
    const sendAmount = utxoAmount - 1000

    var (
        inputs     []*wire.OutPoint
        nSequences []uint32
        outputs    []*wire.TxOut
    )
    { // output
        ...
        outputs = append(outputs, redeemTxOut)
    }
    { // input
        ...
    }

    // Build PSBT
    packet, err := psbt.New(inputs, outputs, 2, 0, nSequences)
    if err != nil {
        t.Fatal(err)
    }
    packet.Inputs[0].TaprootLeafScript = []*psbt.TaprootTapLeafScript{
        &psbt.TaprootTapLeafScript{
            ControlBlock: tapscript.controlBlock,
            Script:       tapscript.leafScript,
            LeafVersion:  0xc0,
        },
    }

    // update
    updater, err := psbt.NewUpdater(packet)
    if err != nil {
        t.Fatal(err)
    }
    if err := updater.AddInWitnessUtxo(wire.NewTxOut(utxoAmount, tapscript.output), 0); err != nil {
        t.Fatal(err)
    }

    var serializedTx bytes.Buffer
    if err := packet.Serialize(&serializedTx); err != nil {
        t.Fatal(err)
    }
    psbtHex := hex.EncodeToString(serializedTx.Bytes())
    t.Log("psbtHex before sign:", psbtHex)

    // signit
    cu := cuabs.New()
    signedPsbtHex, err := cu.PsbtSign(context.Background(), signpks[0], psbtHex)
    if err != nil {
        t.Fatal(err)
    }
    signedPsbtHex, err = cu.PsbtSign(context.Background(), signpks[2], signedPsbtHex)
    if err != nil {
        t.Fatal(err)
    }
    t.Log("psbtHex after sign:", signedPsbtHex)

    // addDummySigs like bitcoinjs-lib
    psbtBz, _ := hex.DecodeString(signedPsbtHex)
    packet, err = psbt.NewFromRawBytes(bytes.NewReader(psbtBz), false)
    if err != nil {
        t.Fatal(err)
    }

    for index, input := range packet.Inputs {
        for _, pk := range pks {
            pkbz, _ := hex.DecodeString(pk)
            var signed bool
            for _, x := range input.TaprootScriptSpendSig {
                if bytes.Equal(pkbz, x.XOnlyPubKey) {
                    signed = true
                    break
                }
            }
            if !signed {
                packet.Inputs[index].TaprootScriptSpendSig = append(packet.Inputs[index].TaprootScriptSpendSig, &psbt.TaprootScriptSpendSig{
                    XOnlyPubKey: pkbz,
                    LeafHash:    tapscript.tapleafHash,
                    Signature:   nil,
                    SigHash:     0,
                })
            }
        }

        // sigs := packet.Inputs[index].TaprootScriptSpendSig

        // sort.Slice(sigs, func(i, j int) bool {
        //  return bytes.Compare(sigs[i].XOnlyPubKey, sigs[j].XOnlyPubKey) < 0
        // })
        // packet.Inputs[index].TaprootScriptSpendSig = sigs
    }

    {
        var serializedTx bytes.Buffer
        if err := packet.Serialize(&serializedTx); err != nil {
            t.Fatal(err)
        }
        t.Log("psbtHex before finalize", hex.EncodeToString(serializedTx.Bytes()))
    }

    if err = psbt.MaybeFinalizeAll(packet); err != nil {
        t.Fatal(err)
    }
    {
        var serializedTx bytes.Buffer
        if err := packet.Serialize(&serializedTx); err != nil {
            t.Fatal(err)
        }
        t.Log("psbtHex after finalize", hex.EncodeToString(serializedTx.Bytes()))
        
    }
    //extract()
    //broadcast()
}

Use js code,it work. "tapscript.tapleafHash" in golang is equal "leafHash" in js,and "pubkey" is equal. After comparison, it was found that the "psbtHex before finalize" and "psbtHex after finalize" were different. my js code:

const psbt = bitcoin.Psbt.fromHex(signedPsbtHex)
{
  const leafHash = tapleafHash({
    output: leafScript,
    version: LEAF_VERSION_TAPSCRIPT,
  })
  console.log(leafHash.toString('hex'))
  for (const input of psbt.data.inputs) {
    if (!input.tapScriptSig) continue
    const signedPubkeys = input.tapScriptSig.filter((ts) => ts.leafHash.equals(leafHash)).map((ts) => ts.pubkey)
    for (const pubkey of leafPubkeys) {
      if (signedPubkeys.some((sPub) => sPub.equals(pubkey))) continue
      input.tapScriptSig.push({
        // This can be reused for each dummy signature
        leafHash,
        // This is the pubkey that didn't sign
        pubkey,
        // This must be an empty Buffer.
        signature: Buffer.from([]),
      })
    }
  }
} // this code from bitcoinjs-lib

psbt.finalizeAllInputs()
const tx = psbt.extractTransaction()
broadcast(...)


from Recent Questions - Bitcoin Stack Exchange https://ift.tt/ONhg7Yp
via IFTTT

Popular posts from this blog

Do Kwon’s Detention Prolonged Until 2024 As Montenegro Responds To Extradition Requests

Sam Bankman-Fried Trial Begins Tomorrow: 3 Reasons Ex-SEC Official Foresees Conviction

April’s Crypto Game-Changers: 7 Events Set To Drastically Impact The Course Of Digital Currencies