From a6c225114629b1dde1b02442997d35522a486133 Mon Sep 17 00:00:00 2001 From: tecnovert Date: Fri, 3 Oct 2025 10:36:29 +0200 Subject: [PATCH] btc: grind for low-r value signatures to match core --- basicswap/interface/btc.py | 13 ++++++++++++- tests/basicswap/test_xmr.py | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/basicswap/interface/btc.py b/basicswap/interface/btc.py index 57211df..c7b0ab5 100644 --- a/basicswap/interface/btc.py +++ b/basicswap/interface/btc.py @@ -53,6 +53,7 @@ from coincurve.keys import ( PrivateKey, PublicKey, ) +from coincurve.types import ffi from coincurve.ecdsaotves import ( ecdsaotves_enc_sign, ecdsaotves_enc_verify, @@ -1357,7 +1358,17 @@ class BTCInterface(Secp256k1Interface): ) eck = PrivateKey(key_bytes) - return eck.sign(sig_hash, hasher=None) + bytes((SIGHASH_ALL,)) + for i in range(10000): + # Grind for low-R value + if i == 0: + nonce = (ffi.NULL, ffi.NULL) + else: + extra_entropy = i.to_bytes(4, "little") + (b"\0" * 28) + nonce = (ffi.NULL, ffi.new("unsigned char [32]", extra_entropy)) + sig = eck.sign(sig_hash, hasher=None, custom_nonce=nonce) + if len(sig) < 71: + return sig + bytes((SIGHASH_ALL,)) + raise RuntimeError("sign failed.") def signTxOtVES( self, diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index 206bb2f..3914a0c 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -1249,6 +1249,10 @@ class Test(BaseTest): ci.signTx(b, lock_spend_tx, 0, lock_tx_script, amount), lock_tx_script, ] + assert ( + len(witness_stack[1]) <= 71 + ) # Test for low-r, sig size is <= 70 + sighash_type + assert len(witness_stack[2]) <= 71 lock_spend_tx = ci.setTxSignature(lock_spend_tx, witness_stack) tx_decoded = ci.rpc("decoderawtransaction", [lock_spend_tx.hex()]) vsize_actual: int = tx_decoded["vsize"]