@@ -896,11 +896,9 @@ func (b *batch) publishBatchCoop(ctx context.Context) (btcutil.Amount,
896896 return fee , err , false
897897 }
898898
899- prevOutputFetcher := txscript .NewMultiPrevOutFetcher (prevOuts )
900-
901899 // Attempt to cooperatively sign the batch tx with the server.
902900 err = b .coopSignBatchTx (
903- ctx , packet , sweeps , prevOutputFetcher , prevOuts , psbtBuf ,
901+ ctx , packet , sweeps , prevOuts , psbtBuf . Bytes () ,
904902 )
905903 if err != nil {
906904 return fee , err , false
@@ -942,138 +940,148 @@ func (b *batch) debugLogTx(msg string, tx *wire.MsgTx) {
942940// coopSignBatchTx collects the necessary signatures from the server in order
943941// to cooperatively sweep the funds.
944942func (b * batch ) coopSignBatchTx (ctx context.Context , packet * psbt.Packet ,
945- sweeps []sweep , prevOutputFetcher * txscript. MultiPrevOutFetcher ,
946- prevOuts map [wire. OutPoint ] * wire. TxOut , psbtBuf bytes. Buffer ) error {
943+ sweeps []sweep , prevOuts map [wire. OutPoint ] * wire. TxOut ,
944+ psbt [] byte ) error {
947945
948946 for i , sweep := range sweeps {
949947 sweep := sweep
950948
951- sigHashes := txscript .NewTxSigHashes (
952- packet .UnsignedTx , prevOutputFetcher ,
953- )
954-
955- sigHash , err := txscript .CalcTaprootSignatureHash (
956- sigHashes , txscript .SigHashDefault , packet .UnsignedTx ,
957- i , prevOutputFetcher ,
949+ finalSig , err := b .musig2sign (
950+ ctx , i , sweep , packet .UnsignedTx , prevOuts , psbt ,
958951 )
959952 if err != nil {
960953 return err
961954 }
962955
963- var (
964- signers [][]byte
965- muSig2Version input.MuSig2Version
966- )
967-
968- // Depending on the MuSig2 version we either pass 32 byte
969- // Schnorr public keys or normal 33 byte public keys.
970- if sweep .protocolVersion >= loopdb .ProtocolVersionMuSig2 {
971- muSig2Version = input .MuSig2Version100RC2
972- signers = [][]byte {
973- sweep .htlcKeys .SenderInternalPubKey [:],
974- sweep .htlcKeys .ReceiverInternalPubKey [:],
975- }
976- } else {
977- muSig2Version = input .MuSig2Version040
978- signers = [][]byte {
979- sweep .htlcKeys .SenderInternalPubKey [1 :],
980- sweep .htlcKeys .ReceiverInternalPubKey [1 :],
981- }
956+ packet .UnsignedTx .TxIn [i ].Witness = wire.TxWitness {
957+ finalSig ,
982958 }
959+ }
983960
984- htlcScript , ok := sweep .htlc .HtlcScript .(* swap.HtlcScriptV3 )
985- if ! ok {
986- return fmt .Errorf ("invalid htlc script version" )
987- }
961+ return nil
962+ }
988963
989- // Now we're creating a local MuSig2 session using the receiver
990- // key's key locator and the htlc's root hash.
991- musig2SessionInfo , err := b .signerClient .MuSig2CreateSession (
992- ctx , muSig2Version ,
993- & sweep .htlcKeys .ClientScriptKeyLocator , signers ,
994- lndclient .MuSig2TaprootTweakOpt (
995- htlcScript .RootHash [:], false ,
996- ),
997- )
998- if err != nil {
999- return fmt .Errorf ("signerClient.MuSig2CreateSession " +
1000- "failed: %w" , err )
1001- }
964+ // musig2sign signs one sweep using musig2.
965+ func (b * batch ) musig2sign (ctx context.Context , inputIndex int , sweep sweep ,
966+ unsignedTx * wire.MsgTx , prevOuts map [wire.OutPoint ]* wire.TxOut ,
967+ psbt []byte ) ([]byte , error ) {
1002968
1003- // With the session active, we can now send the server our
1004- // public nonce and the sig hash, so that it can create it's own
1005- // MuSig2 session and return the server side nonce and partial
1006- // signature.
1007- serverNonce , serverSig , err := b .muSig2SignSweep (
1008- ctx , sweep .protocolVersion , sweep .swapHash ,
1009- sweep .swapInvoicePaymentAddr ,
1010- musig2SessionInfo .PublicNonce [:], psbtBuf .Bytes (),
1011- prevOuts ,
1012- )
1013- if err != nil {
1014- return err
1015- }
969+ prevOutputFetcher := txscript .NewMultiPrevOutFetcher (prevOuts )
1016970
1017- var serverPublicNonce [musig2 .PubNonceSize ]byte
1018- copy (serverPublicNonce [:], serverNonce )
971+ sigHashes := txscript .NewTxSigHashes (unsignedTx , prevOutputFetcher )
1019972
1020- // Register the server's nonce before attempting to create our
1021- // partial signature.
1022- haveAllNonces , err := b .signerClient .MuSig2RegisterNonces (
1023- ctx , musig2SessionInfo .SessionID ,
1024- [][musig2 .PubNonceSize ]byte {serverPublicNonce },
1025- )
1026- if err != nil {
1027- return err
1028- }
973+ sigHash , err := txscript .CalcTaprootSignatureHash (
974+ sigHashes , txscript .SigHashDefault , unsignedTx , inputIndex ,
975+ prevOutputFetcher ,
976+ )
977+ if err != nil {
978+ return nil , err
979+ }
1029980
1030- // Sanity check that we have all the nonces.
1031- if ! haveAllNonces {
1032- return fmt .Errorf ("invalid MuSig2 session: " +
1033- "nonces missing" )
981+ var (
982+ signers [][]byte
983+ muSig2Version input.MuSig2Version
984+ )
985+
986+ // Depending on the MuSig2 version we either pass 32 byte
987+ // Schnorr public keys or normal 33 byte public keys.
988+ if sweep .protocolVersion >= loopdb .ProtocolVersionMuSig2 {
989+ muSig2Version = input .MuSig2Version100RC2
990+ signers = [][]byte {
991+ sweep .htlcKeys .SenderInternalPubKey [:],
992+ sweep .htlcKeys .ReceiverInternalPubKey [:],
993+ }
994+ } else {
995+ muSig2Version = input .MuSig2Version040
996+ signers = [][]byte {
997+ sweep .htlcKeys .SenderInternalPubKey [1 :],
998+ sweep .htlcKeys .ReceiverInternalPubKey [1 :],
1034999 }
1000+ }
10351001
1036- var digest [32 ]byte
1037- copy (digest [:], sigHash )
1002+ htlcScript , ok := sweep .htlc .HtlcScript .(* swap.HtlcScriptV3 )
1003+ if ! ok {
1004+ return nil , fmt .Errorf ("invalid htlc script version" )
1005+ }
10381006
1039- // Since our MuSig2 session has all nonces, we can now create
1040- // the local partial signature by signing the sig hash.
1041- _ , err = b .signerClient .MuSig2Sign (
1042- ctx , musig2SessionInfo .SessionID , digest , false ,
1043- )
1044- if err != nil {
1045- return err
1046- }
1007+ // Now we're creating a local MuSig2 session using the receiver key's
1008+ // key locator and the htlc's root hash.
1009+ keyLocator := & sweep .htlcKeys .ClientScriptKeyLocator
1010+ musig2SessionInfo , err := b .signerClient .MuSig2CreateSession (
1011+ ctx , muSig2Version , keyLocator , signers ,
1012+ lndclient .MuSig2TaprootTweakOpt (htlcScript .RootHash [:], false ),
1013+ )
1014+ if err != nil {
1015+ return nil , fmt .Errorf ("signerClient.MuSig2CreateSession " +
1016+ "failed: %w" , err )
1017+ }
10471018
1048- // Now combine the partial signatures to use the final combined
1049- // signature in the sweep transaction's witness.
1050- haveAllSigs , finalSig , err := b .signerClient .MuSig2CombineSig (
1051- ctx , musig2SessionInfo .SessionID , [][]byte {serverSig },
1052- )
1053- if err != nil {
1054- return err
1055- }
1019+ // With the session active, we can now send the server our
1020+ // public nonce and the sig hash, so that it can create it's own
1021+ // MuSig2 session and return the server side nonce and partial
1022+ // signature.
1023+ serverNonce , serverSig , err := b .muSig2SignSweep (
1024+ ctx , sweep .protocolVersion , sweep .swapHash ,
1025+ sweep .swapInvoicePaymentAddr ,
1026+ musig2SessionInfo .PublicNonce [:], psbt , prevOuts ,
1027+ )
1028+ if err != nil {
1029+ return nil , err
1030+ }
10561031
1057- if ! haveAllSigs {
1058- return fmt .Errorf ("failed to combine signatures" )
1059- }
1032+ var serverPublicNonce [musig2 .PubNonceSize ]byte
1033+ copy (serverPublicNonce [:], serverNonce )
10601034
1061- // To be sure that we're good, parse and validate that the
1062- // combined signature is indeed valid for the sig hash and the
1063- // internal pubkey.
1064- err = b . verifySchnorrSig (
1065- htlcScript . TaprootKey , sigHash , finalSig ,
1066- )
1067- if err != nil {
1068- return err
1069- }
1035+ // Register the server's nonce before attempting to create our
1036+ // partial signature.
1037+ haveAllNonces , err := b . signerClient . MuSig2RegisterNonces (
1038+ ctx , musig2SessionInfo . SessionID ,
1039+ [][ musig2 . PubNonceSize ] byte { serverPublicNonce } ,
1040+ )
1041+ if err != nil {
1042+ return nil , err
1043+ }
10701044
1071- packet .UnsignedTx .TxIn [i ].Witness = wire.TxWitness {
1072- finalSig ,
1073- }
1045+ // Sanity check that we have all the nonces.
1046+ if ! haveAllNonces {
1047+ return nil , fmt .Errorf ("invalid MuSig2 session: " +
1048+ "nonces missing" )
10741049 }
10751050
1076- return nil
1051+ var digest [32 ]byte
1052+ copy (digest [:], sigHash )
1053+
1054+ // Since our MuSig2 session has all nonces, we can now create
1055+ // the local partial signature by signing the sig hash.
1056+ _ , err = b .signerClient .MuSig2Sign (
1057+ ctx , musig2SessionInfo .SessionID , digest , false ,
1058+ )
1059+ if err != nil {
1060+ return nil , err
1061+ }
1062+
1063+ // Now combine the partial signatures to use the final combined
1064+ // signature in the sweep transaction's witness.
1065+ haveAllSigs , finalSig , err := b .signerClient .MuSig2CombineSig (
1066+ ctx , musig2SessionInfo .SessionID , [][]byte {serverSig },
1067+ )
1068+ if err != nil {
1069+ return nil , err
1070+ }
1071+
1072+ if ! haveAllSigs {
1073+ return nil , fmt .Errorf ("failed to combine signatures" )
1074+ }
1075+
1076+ // To be sure that we're good, parse and validate that the
1077+ // combined signature is indeed valid for the sig hash and the
1078+ // internal pubkey.
1079+ err = b .verifySchnorrSig (htlcScript .TaprootKey , sigHash , finalSig )
1080+ if err != nil {
1081+ return nil , err
1082+ }
1083+
1084+ return finalSig , nil
10771085}
10781086
10791087// updateRbfRate updates the fee rate we should use for the new batch
0 commit comments