Show Posts
|
Pages: « 1 2 3 4 [5] 6 »
|
i often read keyhunters are interested in public keys because it can speed up cracking process - true? let us look at puzzle-115: pubkey: 0248d313b0398d4923cdca73b8cfa6532b91b96703902fc8b32fd438a3b7cd7f55 address: 1NLbHuJebVwUZ1XqDjsAyfTRUPwDQbemfv if the attacker does not know the range of private key how realistic is it that he can crack the key? if the attacker does know the range of private key how long does take him to crack the key? what is most efficient cracking tool when you have pubkey - kangaroo or bsgs? let us say an attacker knows address public key plus a valid signature does he have better chance now to crack the key? why all people try to hide public key although it should be public in this system to function? please explain 1) yes. very much. 2) i dont need to know the range of the private key. mathematicians, programmers, they think that way. its important to them. for security researchers like myself, we tend to think differently. the range is not important but its how we can emulate the correct RSZ and K nonce to the public key is more important.. by knowing K, we alrdy are one step away from revealing the private key. 3) range not important to us. good,nice info but we usually shelve it. coz we know we just need to know the K value used. 4) the best tool i use so far and extremely efficient is the lattice attack script written by Antoine. You can download it at https://github.com/bitlogik/lattice-attack5) as i found out, nope. u need a little more than that. you got to get to K nonce. Then things are much easier. 6) i am actually trying to prove to my government on why every bitcoin transaction or any other altcoin transaction should not display the public keys and rsz signatures. if we really want bitcoin or any other altcoins to continue to prosper or at least be relevant for another 8 decades, at least, we then need to give out less informations on every transaction. how can we claim, its anonymous or safe when all i need is for you to make 1 transaction and i know your pubkeys and RSZ? im beginning to understand the mathematics deeper..and as i delve further.. i seriously cannot fathom why showing the public keys are ok to most. as thats my first way in to a wallet. im answering you as a Cyber Security Researcher for 18 years. im trained to think and do my work like how a professional hacker would think and do their research. 11 months on ECDSA though. and this has been one of the best research i had done. my new found respect to Mathematicians. i actually enjoyed doing this research so much.
|
|
|
Modified the gen_data.py script in https://github.com/bitlogik/lattice-attack. Now every set of R,S,Z(HASH) Signatures shows the K_Nonce value used. Does not show up in the json file like the other datas though. It's directly on Terminal. Modified full code below. In gen_data.py, don't forget to input your own public keys XY coordinates. #!/usr/bin/env python3
import argparse import random import json
import ecdsa_lib
def generates_signatures(number_sigs, message, kbits, data_type, curve): print("Preparing Data") d_key = random.randrange(ecdsa_lib.curve_n(curve)) print("Private key to be found (as demo) :") print(hex(d_key)) sigs = [] sz_curve = ecdsa_lib.curve_size(curve) kbi = int(2 ** kbits) print(f"Generating {number_sigs} signatures with curve {curve.upper()}") print(f" leaking {kbits} bits for k ({data_type}) ...") if message is not None: msg = message.encode("utf8") # Always hash message provided with SHA2-256, whatever hash_int = ecdsa_lib.sha2_int(msg) for _ in range(number_sigs): if message is None: # Use a random different message for each signature # Note : there is no associated message from the hash # Do not ever that in practice, this is insecure, only here for demo hash_int = random.randrange(ecdsa_lib.curve_n(curve)) # Compute signatures with k (nonce), r, s, hash sig_info = ecdsa_lib.ecdsa_sign_kout(hash_int, d_key, curve) # pack and save data as : r, s, hash, k%(2^bits) (partial k : "kp") sigs.append( { "r": sig_info[0], "s": sig_info[1], "kp": sig_info[2] % kbi if data_type == "MSB" else sig_info[2] >> (sz_curve - kbits), } ) print(f"k_nonce:{sig_info[2]}")
if message is None: sigs[-1]["hash"] = hash_int ret = { "curve": curve.upper(), "public_key": (31504125288796341338541169388783846543997786027594142627385926708036691251730, 29015715595623874326232564738946807912877814040423899127791236573353650594580), "known_type": data_type, "known_bits": kbits, "signatures": sigs, } if message is not None: ret["message"] = list(msg) return ret
if __name__ == "__main__": parser = argparse.ArgumentParser( description="Generate data for ECDSA attack." ) parser.add_argument( "-f", default="data1.json", help="File name output", metavar="fileout", ) parser.add_argument( "-m", help="Message string", metavar="msg", ) parser.add_argument( "-c", default="secp256k1", help="Elliptic curve name", metavar="curve" ) parser.add_argument( "-b", default=8, type=int, help="Number of known bits (at least 4)", metavar="nbits", ) parser.add_argument( "-t", default="MSB", help="bits type : MSB or LSB", metavar="type" ) parser.add_argument( "-n", default=100, type=int, help="Number of signatures to generate", metavar="num", ) arg = parser.parse_args() sigs_data = generates_signatures(arg.n, arg.m, arg.b, arg.t, arg.c) with open(arg.f, "w") as fout: json.dump(sigs_data, fout) print(f"File {arg.f} written with all data.")
Updated the ecdsa_lib.py to include print function for K_Nonce as well. #!/usr/bin/env python3
# Lattice ECDSA Attack : ECDSA and cryptographic library
# Install cryptography # pip3 install cryptography # or # apt install python3-cryptography
import hashlib import secrets
from cryptography.hazmat import backends from cryptography.hazmat.primitives.asymmetric import ec
CURVES_ORDER = { "SECP224R1": int( "2695994666715063979466701508701962594045780771442439172168272236" "8061" ), "SECP256K1": int( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16 ), "SECP256R1": int( "11579208921035624876269744694940757352999695522413576034242225906" "1068512044369" ), "SECP384R1": int( "39402006196394479212279040100143613805079739270465446667946905279" "627659399113263569398956308152294913554433653942643" ), "SECP521R1": int( "68647976601306097149819007990813932172694353001433054093944634591" "85543183397655394245057746333217197532963996371363321113864768612" "440380340372808892707005449" ), }
def inverse_mod(a_num, m_mod): # a_num^-1 mod m_mod, m_mod must be prime # If not used on a prime modulo, # can throw ZeroDivisionError. if a_num < 0 or m_mod <= a_num: a_num = a_num % m_mod i, j = a_num, m_mod x_a, x_b = 1, 0 while i != 1: quot, rem = divmod(j, i) x_rem = x_b - quot * x_a j, i, x_b, x_a = i, rem, x_a, x_rem return x_a % m_mod
def sha2(raw_message): # SHA-2 256 return hashlib.sha256(raw_message).digest()
def bytes_to_int(bytes_data): return int.from_bytes(bytes_data, "big")
def sha2_int(data): return bytes_to_int(sha2(data))
def curve_size(curve_name): # return the curve size (log2 N) from its name string try: curve_obj = getattr(ec, curve_name.upper())() except Exception as exc: raise Exception( f"Unknown curves. Curves names available : {list(CURVES_ORDER.keys())}" ) from exc return curve_obj.key_size
def curve_n(curve_name): # return the curve order "N" from its name string order = CURVES_ORDER.get(curve_name.upper()) if not order: raise Exception( f"Unknown curves. Curves names available : {list(CURVES_ORDER.keys())}" ) return order
def check_publickey(pubkey, curve_str): # Check pubkey (x,y) belongs on the curve try: curve_obj = getattr(ec, curve_str.upper())() except Exception as exc: raise Exception( f"Unknown curves. Curves names available : {list(CURVES_ORDER.keys())}" ) from exc if len(pubkey) != 2: raise Exception( 'Public key data shall be provided as :\n "public_key" : [ x, y ]' ) publickey_obj = ec.EllipticCurvePublicNumbers(pubkey[0], pubkey[1], curve_obj) ret = False try: publickey_obj.public_key(backends.default_backend()) ret = True except ValueError: pass return ret
def privkey_to_pubkey(pv_key_int, curve_name): # Return public point coordinates (Scalar multiplication of pvkey with base point G) ec_backend = getattr(ec, curve_name.upper())() pubkey = ( ec.derive_private_key(pv_key_int, ec_backend, backends.default_backend()) .public_key() .public_numbers() ) return [pubkey.x, pubkey.y]
def ecdsa_sign_kout(z_hash, pvkey, curve_name): # Perform ECDSA, but insecurely return the private k nonce n_mod = curve_n(curve_name) k_nonce = secrets.randbelow(n_mod) r_sig = scalar_mult_x(k_nonce, curve_name) s_sig = inverse_mod(k_nonce, n_mod) * (z_hash + r_sig * pvkey) % n_mod print(f"k_nonce: {k_nonce}") return r_sig, s_sig, k_nonce
def scalar_mult_x(d_scalar, curve): # Scalar multiplication of d with base point G # and return x, like ECDH with G. return privkey_to_pubkey(d_scalar, curve)[0]
With R,S,Z(HASH) & now K nonce revealed, You can now proceed here and input your datas. https://rawcdn.githack.com/nlitsme/bitcoinexplainer/aa50e86e8c72c04a7986f5f7c43bc2f98df94107/ecdsacrack.html to get to the Private key. Wth this, its almost a done deal to get to the private key. Good luck.
|
|
|
I realize that you can't recreate the attack by using the R,S,Z(H) on blockchain.com. I am not sure why. I believe for different software, it can hash the signatures over and over and over again. So technically, we will never know whats the correct R,S,Z(H) Signatures. The Only way is to create the R,S,Z signatures. Which i did by inputting my Public Keys X,Y Coordinates in the full code below. Input import argparse import base64 import functools import json import hashlib import os import tarfile import urllib.request
# Original data set for traces get from :
RESOURCE_URL = ( "https://github.com/orangecertcc/ecdummyrpa/raw/" "main/sample.tar.gz" )
# Helpers from ecdsa_lib
def sha2(raw_message): # SHA-2 256 return hashlib.sha256(raw_message).digest()
def sha2_int(data): return int.from_bytes(sha2(data), "big")
# Special helpers for this case
def sigDER_to_ints(sigDER): lenr = int(sigDER[3]) lens = int(sigDER[5 + lenr]) r = int.from_bytes(sigDER[4 : lenr + 4], "big") s = int.from_bytes(sigDER[lenr + 6 : lenr + 6 + lens], "big") return r, s
def pubkeyPEM_to_X962(PEMstring): PEMparts = PEMstring.split("-----") pubkey_b64 = PEMparts[2].strip("\r\n") # end of DER is X962 public key return base64.b64decode(pubkey_b64)[-65:]
def pubkeyX962_to_intpair(DERpubk): x_int = int.from_bytes(DERpubk[1:33], "big") y_int = int.from_bytes(DERpubk[33:], "big") return [x_int, y_int]
def pubkeyPEM_to_xy(PEMstr): return pubkeyX962_to_intpair(pubkeyPEM_to_X962(PEMstr))
def load_traces(): # Reads traces from this RPA campain # Prepare to an almost compliant with LatticeAttack # But it requires then filtering to compute "kp" from "trace" files = os.listdir("test") nsig = len(files) // 3 print(f"{len(files)} files detected for {nsig} signatures") traces = [] for i in range(nsig): with open(f"test/trace_{i}.txt", "r") as tracef: data_trace = [float(line) for line in tracef] with open(f"test/signature_{i}.bin", "rb") as sigf: DERsig = sigf.read() with open(f"test/message_{i}.txt", "rb") as msgf: msg = msgf.read() trace_data = {} sig_ints = sigDER_to_ints(DERsig) trace_data["hash"] = sha2_int(msg) trace_data["r"] = sig_ints[0] trace_data["s"] = sig_ints[1] trace_data["trace"] = data_trace traces.append(trace_data) return traces
KNOWN_BITS = 7
def mean_compute(table_array): # compute arithmetic mean value to get the height of the valley return functools.reduce(lambda i, j: i + j, table_array) / len(table_array)
def select_sig(sig_candidate): # Filtering the good signatures # mean value < limit # "A valley considerably lower than the others indicating a nonce that has # its 7 least significant bits set to 0." LIMIT = 20 DISCARD_SIZE = 0.25 # Discard first and last 25% = keeps "half" middle trace_len = len(sig_candidate["trace"]) start_idx = int(trace_len * DISCARD_SIZE) trace_interest = sig_candidate["trace"][start_idx : trace_len - start_idx] val = mean_compute(trace_interest) return val < LIMIT
def compute_kp(onesig): # Generate final data objects (with kp) sigout = {} sigout["hash"] = onesig["hash"] sigout["r"] = onesig["r"] sigout["s"] = onesig["s"] sigout["kp"] = [""] return sigout
def get_data_source(res_url): # Get tar gz file at given url and extract files locally # Use this only on known trusted or friendly TAR files, # as this can write files anywhere locally with urllib.request.urlopen( urllib.request.Request(res_url, headers={"User-Agent": "Mozilla"}) ) as remote_data: tardata = tarfile.open(fileobj=remote_data, mode="r:gz") print("Extracting data files ...") tardata.extractall()
if __name__ == "__main__": parser = argparse.ArgumentParser( description="Load ecdummyRPA traces mesurements for ECDSA attack file format." ) parser.add_argument( "-f", default="data.json", help="File name output", metavar="fileout", ) arg = parser.parse_args()
# Test if data were downloaded by testing presence of pubkey file if not os.path.exists("pubkey.pem"): print("Downloading raw data ...") get_data_source(RESOURCE_URL)
print("Loading files ...") sigs_data = load_traces() print("Filtering signatures traces") sigs_data_selected = [compute_kp(asig) for asig in sigs_data if select_sig(asig)] with open("pubkey.pem", "r") as pkf: pubkey_pem = pkf.read() global_data = { "curve": "SECP256k1", "public_key": (Input X here, Input Y here), "known_type": "LSB", "known_bits": KNOWN_BITS, "signatures": sigs_data_selected, } with open(arg.f, "w") as fout: json.dump(global_data, fout) print(f"File {arg.f} written with all data.")
Output "curve": "SECP256K1", "public_key": [ 31504125288796341338541169388783846543997786027594142627385926708036691251730, 29015715595623874326232564738946807912877814040423899127791236573353650594580 ], "known_type": "LSB", "known_bits": 6, "signatures": [ { "r": 17456122099107622875979177060034160065534440309384765110770021588156777535269, "s": 39548918176628970790297874101648966881380966278908886743977542233652364916621, "kp": 20, "hash": 92211084921678517086309436176248290676365250150878786017110534405419087808719 }, { "r": 23913541315081963661847822603754285037803706978735367208728912448433920129361, "s": 92518508463905780686593084152628940334651401106826544410053244574796065086889, "kp": 13, "hash": 21236183650018659484557387187850143636235316156689640733937135357581028327853 },
Massive Credit to Bitlogik for the gen_input.py on https://github.com/bitlogik/lattice-attack then with the R,S,Z(H) signatures given, i input the signatures in the code below. Originally coded by William J. Buchanan And article written here: https://asecuritysite.com/ecc/ecd7Modified by me to allow public keys and RSZ inputs. Input import ecdsa import random import libnum import hashlib import sys
P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 G = ecdsa.SECP256k1.generator order = G.order() priv1 = random.randrange(1,order) Public_key = (31504125288796341338541169388783846543997786027594142627385926708036691251730, 29015715595623874326232564738946807912877814040423899127791236573353650594580)
k = random.randrange(1, 2**127)
msg1="HelloHello" msg2="IamBB" if (len(sys.argv)>1): msg=(sys.argv[1]) # Input R, S Signatures here r = 17456122099107622875979177060034160065534440309384765110770021588156777535269 s = 39548918176628970790297874101648966881380966278908886743977542233652364916621 h = int(hashlib.sha256(msg1.encode()).hexdigest(),base=16)
# Now generate a fault rf = r sf = (libnum.invmod(k,order)*(h+priv1*rf)) % order hf = int(hashlib.sha256(msg2.encode()).hexdigest(),base=16) kf = hf*(s-sf) * libnum.invmod(sf*r-s*rf,order) valinv = libnum.invmod( (sf*r-s*rf),order) dx = (hf*(s-sf)* valinv) % order
print(f"Sig 1 (Good):") print(f" R :{r}") print(f" S1:{s}") print(f" H1:{h}") print(f" K :{k}") print(f" ------------------------------------------------") print(f" ------------------------------------------------") print(f" ------------------------------------------------")
print(f"Sig 2 (Faulty):") print(f" R :{rf}") print(f" S2:{sf}") print(f" H2:{hf}") print(f" K :{kf}")
print (f"\nRecovered private key: {dx}")
Output Sig 1 (Good): R :17456122099107622875979177060034160065534440309384765110770021588156777535269 S1:39548918176628970790297874101648966881380966278908886743977542233652364916621 H1:11209404430005450692776394377220775389388011163944676048947869460159787075727 K :15903292315272842822984172996837488417 ------------------------------------------------ ------------------------------------------------ ------------------------------------------------ Sig 2 (Faulty): R :17456122099107622875979177060034160065534440309384765110770021588156777535269 S2:96338585688289334914636720032979620932082282355556627366484199230071141146598 H2:54726123683982229645080045215760981633879898681032674670062989804976143680540 K :-188432705557505607344590839989163044641633590292582796389468919499880245866943402758495487463160167555366829032436838039969514252512664280259846882814057850528865220835685847937360676866739560844105311285127539338911992423544765060
Recovered private key: 107749115139875514357274396597987236665757310837906895959705889341744968705665
I took one of the RSZ generated and create the same R signature to give out the K value(Which does not matter cause it was randomly generated) and i got the correct Private Key. However, i want to create a different R signature and now try out another attack. (Same nonce K use to sign different message) What should i change at the R here? or What is the correct formula in python? # Now generate a fault rf = r sf = (libnum.invmod(k,order)*(h+priv1*rf)) % order hf = int(hashlib.sha256(msg2.encode()).hexdigest(),base=16) kf = hf*(s-sf) * libnum.invmod(sf*r-s*rf,order) valinv = libnum.invmod( (sf*r-s*rf),order) dx = (hf*(s-sf)* valinv) % order
|
|
|
it is not finished.
try your self. secp256k1 if you add abstract thinking you will see "there are another properties" that you can use.
You should observe the values as output and think what is going on and test it.
a lot of us had make thousend test to verify thousends posiibilities.
some times you must "go away" and create you own pattern , sometimes expand "calculation" for new coeffs.
I still observe and have a good result.
no one on this forum will really share with his knowledge. TRY Harder and be positive.
🥰🥰
|
|
|
What is the formula to calculate private keys if you already have all the R,S,Z(H) K Value? Where d= private_key.
d = (k * s - z) * r -1 mod n Source: https://learnmeabitcoin.com/technical/ecdsa (Why do you need to generate a random point each time? (Mathematical Explanation) thank u so much. Cheers brother.
|
|
|
What is the formula to calculate private keys if you already have all the R,S,Z(H) K Value? Where d= private_key.
|
|
|
can anyone recommend a mass hex to wif convertor that actually works? tried the ones readily available on github, but it dont work.
Did you try this? https://github.com/joesciii/BitcoinKeyConverter, This tool may help you convert hex priv keys to wif offline. Instructions to use it given within the program. Also, dont try too many random convertors online and risk your keys being stolen. just tested this. it works. thanks bro.
|
|
|
So if i were to give my public key x coordinate input, i should only change the G? And leave the rest as is. Ok thank you so much pooya.
Sorry I made a small mistake, P in this code is actually the public key and you should change that if you want to use another key. F is the curve's prime and G is as I said the generator point and is a constant that shouldn't be changed. ok got it pooya. thank you so much.
|
|
|
can anyone recommend a mass hex to wif convertor that actually works? tried the ones readily available on github, but it dont work.
|
|
|
i recreate the attack and modify the code based on this article. https://asecuritysite.com/ecdsa/ecd7it does work in giving out the private keys. import ecdsa import random import libnum import hashlib import sys
P = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 order = N priv1 = 20 G = (31504125288796341338541169388783846543997786027594142627385926708036691251730, 29015715595623874326232564738946807912877814040423899127791236573353650594580)
k = int(input("K:")) if k < 1 or k > 2**127: raise ValueError("Input is out of range")
r = 66117490189936270206987461679613764204679654666049042771015493508015054858077 s = 49674599047379925216583523329074143648157909613025861611589669633503106636260 h = 99349198094759850433167046658148287296315819226051723223179339267006213272520
msg="HelloHello"
# Now generate a fault rf = r sf = (libnum.invmod(k,order)*(h+priv1*rf)) % order hf = int(hashlib.sha256(msg.encode()).hexdigest(),base=16) k = hf*(s-sf) * libnum.invmod(sf*r-s*rf,order) valinv = libnum.invmod( (sf*r-s*rf),order) dx = (hf*(s-sf)* valinv) % order
print(f"k: {k}") print(f"Sig 1 (Good): r1={r}, s1={s}, h1={h}") print(f"Sig 2 (Faulty): r2={rf}, s2={sf}, h2={hf}") print (f"\nRecovered private key: {dx}")
however, the private keys given are not of the targeted wallet address. so nope, your bitcoins are still safe. my inputs could be wrong though, correct me if im wrong. thank u so much. K:2410 k: -8798166015846973725561614309791304655239378187079711764294056475330149015934906772429315822306934901393705779350762680499808112349218839583434901201485582221473728750380597901824590880328183205377959771799530340013137323794330090 Sig 1 (Good): r1=66117490189936270206987461679613764204679654666049042771015493508015054858077, s1=49674599047379925216583523329074143648157909613025861611589669633503106636260, h1=99349198094759850433167046658148287296315819226051723223179339267006213272520 Sig 2 (Faulty): r2=66117490189936270206987461679613764204679654666049042771015493508015054858077, s2=94761076309972293894096285019617727370519309086943504219315190442656806572338, h2=11209404430005450692776394377220775389388011163944676048947869460159787075727
Recovered private key: 37708835787268217211476314887030394677427639753441187644516074530096113903948
|
|
|
yeah..they gave the codes there as well. thank you pooya. appreciate it.
what is the G and P inputs? is P the public keys input? F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) C = EllipticCurve ([F (0), F (7)]) G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) N = FiniteField (C.order()) P = P=-C.lift_x(0x11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c) # block 9 coinbase payout key. def forge(c, a=-1): # Create a forged 'ECDSA' (hashless) signature # set a to something other than -1 to be less obvious a = N(a) R = c*G + int(a)*P s = N(int(R.xy()[0]))/a m = N(c)*N(int(R.xy()[0]))/a print( 'hash1 = %d'%m) print( 'r1 = %d'%(int(R.xy()[0]))) print( 's1 = %d'%s) for c in range(1,10): forge(c)
Mod note: Consecutive posts merged
|
|
|
Do you have a python or sage code I can look at? I'm a security researcher and I really need to see whether I can recreate a valid (not signed) RSZ. It is better to understand the math behind that. Then, you will write that code easily by yourself, and you will go beyond that example. So, a signature is a relation between some public key, and another "signature public key". You start from private key "d" and "signature private key" called "nonce" and often named as "k". You start from "s=(z+rd)/k" relation, rewrite it, and then convert from private to public keys. Then, if you understand it after such conversion, you know everything you need. s=(z+rd)/k sk=z+rd sk-z=rd rd=sk-z d=(sk-z)/r d=(s/r)k-(z/r) Q=d*G R=k*G Q=(s/r)R-(z/r) Then, when you know "Q" on the left side, you can put anything you want on the right side. Just pick two numbers: "s/r" and "z/r". Then, you will get your "R", and "r=R.x" from that, and then "s=(s/r)*r" and "z=(z/r)*r", then you will have a valid (r,s,z) tuple for that public key. Also, you can go beyond that example, and convert it in another direction. So, by choosing some message, you can hash it, then you will get some z. Then, you can pick some (r,s) pair, and generate a valid Q from your (r,s,z) tuple. Then, you will reach some public key, with a valid signature, where you don't know the private key. It is called "public key recovery", and it is why you can type some address, and some signature, and no public key is needed, because it can be calculated. For example: message="Hello World" address="1psPJZYEJrjPtY6kw5Tqtj4mW2yXSSDuH" signature="GwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" Here, nobody knows the private key for 1psPJZYEJrjPtY6kw5Tqtj4mW2yXSSDuH, it is a "trap address", but this signature is valid. So, to sum up: If you understand "Q=(s/r)R-(z/r)", then you know, that you can choose some Q, and get some matching (r,s,z) tuple, or vice versa: you can choose some (r,s,z) tuple, and find some Q by using public key recovery. Understanding this equation is all you need to go in both directions, and build other fake signatures beyond that. Also, for now it is only a nice mathematical trick, you cannot move any real coins with those tricks. ahhh...very clear. Thank You So much.
|
|
|
Example: an attacker has the public keys of a wallet and he recreate/reverse the procedure to get a new RSZ signatures?
Yes, you can recreate a valid RSZ trio for any public key very easily. In fact some people used this method to attempt scamming others into believing they were the "real Satoshi Nakamoto". Keep in mind that Z is the hash of the message not the message and ECC does not work like that, you have to have a message (in bitcoin it is the transactions) not the hash (Z) alone. And no you won't be able to spend anybody else's bitcoins this way ![Wink](https://bitcointalk.org/Smileys/default/wink.gif) Do you have a python or sage code I can look at? I'm a security researcher and I really need to see whether I can recreate a valid (not signed) RSZ.
|
|
|
RSZ thing is related to the signed transaction, it has nothing to do with the public key itself. What do you mean by "public keys of the wallet"? Do you talk about public keys derived from the one master private key using one of derivation path?
I mean the public keys that's shown together with the signed transactions ..like in blockchain.com so it's not possible to recreate the RSZ just from knowing the public keys right?
|
|
|
Is it even possible to recreate the R, S , Z(H) signatures from the public keys?
Example: an attacker has the public keys of a wallet and he recreate/reverse the procedure to get a new RSZ signatures? Maybe my question is illogical to some. Bear with me please.
I'm still learning. Thank you.
|
|
|
You said "crack any wallet" though. Fault attacks can not be used to crack any wallet. They can only be used when you have some amount of control over the system that signs/creates a wallet at the moment of signing/creation.
Alright... Are you here to argue with me on what's the word used or would you like to blame the author for the word used? Have you actually tried this method? I understand your meaning and the general meaning of fault attack. HOWEVER, that's what the author of this website claim it is. SO... despite of the choice of words used.. What or how can I modify this script so that it accepts my r, s, h and public key inputs? #python fault.py Message: Hello k: 2377122631336757091406456643105226705197917127899304611236234685727643570878493 8957571817458862979584232284037410229596452277879610955286764320595345098952800 839149842089242517072957658427855833009982523662157423292631792006806365 Sig 1 (Good): r=41552918092331466876589119583071324014922831660434505150350778883250206623908, s=103219685505031464720805837014021801697332755430913759423777864063262658295904 Sig 2 (Faulty): r=41552918092331466876589119583071324014922831660434505150350778883250206623909, s=30990528248984818891301551608571623728524592243310248921245102910474460702403
Generated private key: 89452984132331904393121726602673115409896713988677951449044374033056235521792
Recovered private key: 89452984132331904393121726602673115409896713988677951449044374033056235521792
|
|
|
Yeah. Agreed. I was thinking the same thing.. Click the link. The author too call it fault attack.
Hmm maYbe I should edit the subject of this topic.
|
|
|
Hi, I was wondering whether anyone had tried Nonce Reuse fault attack on SECP256K1. It seems so much easier to crack any wallet with this attack. Read here> https://asecuritysite.com/ecdsa/ecd7I had tried lattice attack on my wallet address for 5 weeks now. It works but really slow. I am considering starting a new attack for my research. Your inputs are greatly appreciated. How can i modify this script to accept my R,S,H and public keys ? Please help. Thank You so much. ![Cheesy](https://bitcointalk.org/Smileys/default/cheesy.gif) Code is here. import ecdsa import random import libnum import hashlib import sys
G = ecdsa.SECP256k1.generator order = G.order()
priv1 = random.randrange(1,order) Public_key = ecdsa.ecdsa.Public_key(G, G * priv1) d = ecdsa.ecdsa.Private_key(Public_key, priv1)
k = random.randrange(1, 2**127)
msg="Hello"
if (len(sys.argv)>1): msg=(sys.argv[1])
h = int(hashlib.sha256(msg.encode()).hexdigest(),base=16) sig = d.sign(h, k)
r,s = sig.r,sig.s
# Now generate a fault rf = sig.r+1 sf=(libnum.invmod(k,order)*(h+priv1*rf)) % order
k = h*(s-sf) * libnum.invmod(sf*r-s*rf,order)
valinv = libnum.invmod( (sf*r-s*rf),order)
dx =(h*(s-sf)* valinv) % order
print(f"Message: {msg}") print(f"k: {k}")
print(f"Sig 1 (Good): r={r}, s={s}") print(f"Sig 2 (Faulty): r={rf}, s={sf}")
print (f"\nGenerated private key: {priv1}") print (f"\nRecovered private key: {dx}")
Result is here. #python fault.py Message: Hello k: 2377122631336757091406456643105226705197917127899304611236234685727643570878493 8957571817458862979584232284037410229596452277879610955286764320595345098952800 839149842089242517072957658427855833009982523662157423292631792006806365 Sig 1 (Good): r=41552918092331466876589119583071324014922831660434505150350778883250206623908, s=103219685505031464720805837014021801697332755430913759423777864063262658295904 Sig 2 (Faulty): r=41552918092331466876589119583071324014922831660434505150350778883250206623909, s=30990528248984818891301551608571623728524592243310248921245102910474460702403
Generated private key: 89452984132331904393121726602673115409896713988677951449044374033056235521792
Recovered private key: 89452984132331904393121726602673115409896713988677951449044374033056235521792
|
|
|
Some problems with install fpylll
Developer using Ubuntu >= 20.04 So try on Ubuntu 20.04
pip install git+https://github.com/bitlogik/lattice-attack pip install git+https://github.com/fplll/fpylll.git
All command try installs not successful both on os windows and Linux
using conda not successful too conda install -c conda-forge fpylll
all methods include update apt too
sudo add-apt-repository universe sudo apt update sudo apt install python3-fpylll
pip install Cython
all fail
remove sagemath and it will work. somehow fpylll clash with sagemath and it does not run properly. removing sagemath will solve your issue. in debian, #apt remove sagemath #apt update then run your lattice_attack.py again.
|
|
|
Why don't you simply make 100 raw transactions with the same input containing the pubkey, but with different amounts? You should certainly get 100 different RSZ tuples that way. You don't need to use a sample RSZ for this, you just need an input that is associated with the public key you type.
I don't have that much bitcoins to spend. 1. You can create signed raw transaction without broadcasting it, which means you never spend your Bitcoin. 2. You could use Testnet or Regtest network. Although you might need to obtain some coin from faucet (for testnet), perform initial node setup (for regtest) or make small change on your script. oh i did not know that. ok will do. thank you.
|
|
|
|