From 9e9b5945fe3de77dabb04874625e7fa38799ba64 Mon Sep 17 00:00:00 2001 From: "nicolas.dorier" Date: Mon, 25 May 2020 06:47:43 +0900 Subject: [PATCH] Ensure the payjoin can generate a high R signature if the payer is sending it --- .../Payments/PayJoin/PayJoinEndpointController.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs b/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs index e8c10766b..0f4d5c928 100644 --- a/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs +++ b/BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs @@ -25,6 +25,7 @@ using BTCPayServer.Data; using NBitcoin.DataEncoders; using Amazon.S3.Model; using BTCPayServer.Logging; +using NBitcoin.Crypto; namespace BTCPayServer.Payments.PayJoin { @@ -234,7 +235,7 @@ namespace BTCPayServer.Payments.PayJoin return BadRequest(CreatePayjoinError("invalid-transaction", $"Provided transaction isn't mempool eligible {mempool.RPCCodeMessage}")); } - + var enforcedLowR = ctx.OriginalTransaction.Inputs.All(IsLowR); var paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike); bool paidSomething = false; Money due = null; @@ -472,7 +473,10 @@ namespace BTCPayServer.Payments.PayJoin var coin = selectedUtxo.AsCoin(derivationSchemeSettings.AccountDerivation); signedInput.UpdateFromCoin(coin); var privateKey = accountKey.Derive(selectedUtxo.KeyPath).PrivateKey; - signedInput.Sign(privateKey); + signedInput.Sign(privateKey, new SigningOptions() + { + EnforceLowR = enforcedLowR + }); signedInput.FinalizeInput(); newTx.Inputs[signedInput.Index].WitScript = newPsbt.Inputs[(int)signedInput.Index].FinalScriptWitness; } @@ -623,5 +627,12 @@ namespace BTCPayServer.Payments.PayJoin } return (Array.Empty(), PayjoinUtxoSelectionType.Unavailable); } + private static bool IsLowR(TxIn txin) + { + IEnumerable pushes = txin.WitScript.PushCount > 0 ? txin.WitScript.Pushes : + txin.ScriptSig.IsPushOnly ? txin.ScriptSig.ToOps().Select(o => o.PushData) : + Array.Empty(); + return pushes.Where(p => ECDSASignature.IsValidDER(p)).All(p => p.Length <= 71); + } } }