From ec27f410ea537b2d995513fd061ced783ce27ad9 Mon Sep 17 00:00:00 2001 From: scgbckbone Date: Thu, 18 Jul 2024 12:22:20 +0200 Subject: [PATCH] optimize: drop DER encoding from signature grinding --- releases/Next-ChangeLog.md | 1 + shared/psbt.py | 26 ++++++++++++++++---------- testing/test_sign.py | 1 + 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/releases/Next-ChangeLog.md b/releases/Next-ChangeLog.md index afc2f693..54ec4559 100644 --- a/releases/Next-ChangeLog.md +++ b/releases/Next-ChangeLog.md @@ -6,6 +6,7 @@ This lists the new changes that have not yet been published in a normal release. - Enhancement: Allow JSON files in `NFC File Share` - Enhancement: latest [0.5.0](https://github.com/bitcoin-core/secp256k1/releases/tag/v0.5.0) libsecp256k1 +- Enhancement: Signature grinding optimizations - Bugfix: UI ordered list alignment in Seed Vault menu - Bugfix: Do not alow to import multisig wallet duplicate with only keys shuffled - Bugfix: Do not read whole PSBT into memory when writing finalized transaction diff --git a/shared/psbt.py b/shared/psbt.py index 5e4f3b46..e6879e62 100644 --- a/shared/psbt.py +++ b/shared/psbt.py @@ -1960,22 +1960,28 @@ class psbtObject(psbtProxy): # value that will encode (after DER) into a shorter string. # - saves on miner's fee (which might be expected/required) # - blends in with Bitcoin Core signatures which do this from 0.17.0 - for retry in range(100): - result = ngu.secp256k1.sign(pk, digest, retry).to_bytes() - - # convert signature to DER format + n = 0 # retry num + while True: + # time to produce signature on stm32: ~25100 microseconds + result = ngu.secp256k1.sign(pk, digest, n).to_bytes() #assert len(result) == 65 - r = result[1:33] - s = result[33:65] - der_sig = ser_sig_der(r, s, inp.sighash) - - if len(der_sig) <= 71: + if result[1] < 0x80: + # no need to check for low S value as those are generated by default by secp256k1 lib + # to produce 71 bytes long signature (low S low R value) we need on average 2 retries + # worst case ~25 grinding iterations need to be performed totaling break + n += 1 + + # wait with der serialization after we have low S and low R sig + r = result[1:33] + s = result[33:65] + der_sig = ser_sig_der(r, s, inp.sighash) + # private key no longer required stash.blank_object(pk) stash.blank_object(node) - del pk, node, pu, skp + del pk, node, pu, skp, n inp.added_sig = (which_key, der_sig) diff --git a/testing/test_sign.py b/testing/test_sign.py index a7329563..85f0f042 100644 --- a/testing/test_sign.py +++ b/testing/test_sign.py @@ -3000,6 +3000,7 @@ def test_low_R_grinding(dev, goto_home, microsd_path, press_select, offer_ms_imp reset_seed_words() clear_ms() desc = "sh(sortedmulti(2,[6ba6cfd0/45h]tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9/0/*,[747b698e/45h]tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc/0/*,[7bb026be/45h]tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa/0/*,[0f056943/45h]tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n/0/*))#up0sw2xp" + # PSBT created via fake_ms_txn, grinded in test_ms_sign_myself psbt_fname = "myself-72sig.psbt" with open(f"data/{psbt_fname}", "r") as f: b64psbt = f.read()