0

Reference article: https://bertcmiller.com/2021/12/28/glimpse_nonce_reuse.html

Reference repo: https://github.com/Marsh61/ECDSA-Nonce-Reuse-Exploit-Example/blob/master/Attack-Main.py

Objective: Solve for private key with 2 transactions signed with same R

Problem: Unable to get private key

Steps taken

  1. Find 2 tx with same r based on reference article
  2. Note down their r,s values from getTxHash
  3. Get "raw" message signed via https://etherscan.io/getRawTx?tx=
  4. Call attack function which solves the simultaneous equation to obtain private key

Suspected mistakes

  1. Message being hashed is wrong? (Not sure what other value I can use for this?)
from ecdsa.numbertheory import inverse_mod
import ecdsa


def attack(publicKeyOrderInteger, signaturePair1, signaturePair2, messageHash1, messageHash2):
    r1 = signaturePair1[0]
    s1 = signaturePair1[1]
    r2 = signaturePair2[0]
    s2 = signaturePair2[1]

    if (r1 != r2):
        print("ERROR: The signature pairs given are not susceptible to this attack")
        return None

    numerator = (((s2 * messageHash1) % publicKeyOrderInteger) -
                 ((s1 * messageHash2) % publicKeyOrderInteger))
    denominator = inverse_mod(
        r1 * ((s1 - s2) % publicKeyOrderInteger), publicKeyOrderInteger)

    privateKey = numerator * denominator % publicKeyOrderInteger

    return hex(privateKey)


if __name__ == "__main__":
    G = ecdsa.SECP256k1.generator

    # mod N component for secp256k1 which we will be using
    order = G.order()
    print('Order:', order)

    hash1 = 0xb5d2454d7380bfa7ac75ec76f15eecb56e60941429153081fe799fb53a7ff901
    rawHash1 = 0xf9010a0685028fa6ae00830242c294dc42728b0ea910349ed3c6e1c9dc06b5fb591f9880b8a40175b1c4f48c9980411f86fb275b915d5fe29fca6626a646c18787e9bb8b2f653cc995e90000000000000000000000000dcb0cb0120d355cde1ce56040be57add0185baa000000000000000000000000fa9da51631268a30ec3ddd1ccbf46c65fad9925100000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000000a4b125a0f0d7b10f398357f7d140ff2be1bea9165d32238360ad0f82911235868be7c6e1a063ede1f38c2f7eb6163f5885852aaec1cfb5b2919d2fec9a46d6ff1494901392
    r1 = 0xf0d7b10f398357f7d140ff2be1bea9165d32238360ad0f82911235868be7c6e1
    s1 = 0x63ede1f38c2f7eb6163f5885852aaec1cfb5b2919d2fec9a46d6ff1494901392

    hash2 = 0x9e459be7fa9950835a3c2594d3440c684fed05fa8e12e8088cc7776c4afb364c
    rawHash2 = 0xf9010a0b850d9f2bfda68302998894dc42728b0ea910349ed3c6e1c9dc06b5fb591f9880b8a40175b1c40746d52e628dc6698c2da01d2447a365b16008802e350fcaf00ce357b291163b0000000000000000000000000dcb0cb0120d355cde1ce56040be57add0185baa0000000000000000000000009883c9925aca25ad93907616dcbe4900869a9dd6000000000000000000000000000000000000000000000000013fbe85edc90000000000000000000000000000000000000000000000000000000000000000a4b126a0f0d7b10f398357f7d140ff2be1bea9165d32238360ad0f82911235868be7c6e1a0604e4a2cc65d279ae6946cd8fa73a23b6086ea01afa5a46b9aa40685236011ec
    r2 = 0xf0d7b10f398357f7d140ff2be1bea9165d32238360ad0f82911235868be7c6e1
    s2 = 0x604e4a2cc65d279ae6946cd8fa73a23b6086ea01afa5a46b9aa40685236011ec

    resolvedPrivateKey = attack(order, [r1, s1], [r2, s2], rawHash1, rawHash2)
    print('Private key found:', resolvedPrivateKey)

1

1 Answer 1

0

I dont know either how to recover the secret behind this. I already tried contacting the master himself @bertcmiller for the maths, but unfortunately he didnt reply. The only thing I could say is, it has something to do with the points you are creating. Inverse mod has two values 1 and -1, so there are more possibiliies for a private key than the one you print out.

In sum you could create four private keys... [1,1],[1,-1],[-1,1],[-1,-1]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.