Title: Lattice Attack Script Modified
Post by: krashfire on January 05, 2023, 07:03:38 PM
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.
Title: Re: Lattice Attack Script Modified
Post by: mahurovihamilo on May 06, 2024, 06:38:07 PM
Hi there, This is interesting, but is not quite working for me. After I generate the json file, once I run the lattice.py I get this error:
Loading data from file data7.json Public key data invalid, not on the given SECP256K1 curve.
I think it has to do with the format that the xY coordinates I am putting in is not correct. My question it, where and how you get this XY ( or RS) coordinates from, so that they are in the right format to go in gendata.py?
Thanks for your input
Title: Re: Lattice Attack Script Modified
Post by: COBRAS on May 06, 2024, 08:15:47 PM
KRASH Can you add calculation of privkey to scrypt? pvk = (inv(r) * ( (k*s)-z ) ) % N k = (inv(s) * ( z + r * pvk ) ) % N s = (inv(k) * ( z + r * pvk) ) % N pvk = (inv(r) * ( (k*s)-z ) ) % N r * pvk = ( (k*s)-z ) % N
r , s , z, private Key , k All may be odd or even numbers
Title: Re: Lattice Attack Script Modified
Post by: mahurovihamilo on May 06, 2024, 10:11:18 PM
KRASH Can you add calculation of privkey to scrypt? pvk = (inv(r) * ( (k*s)-z ) ) % N k = (inv(s) * ( z + r * pvk ) ) % N s = (inv(k) * ( z + r * pvk) ) % N pvk = (inv(r) * ( (k*s)-z ) ) % N r * pvk = ( (k*s)-z ) % N
r , s , z, private Key , k All may be odd or even numbers I have added those definitions but I get an error. Is that the right part of the code on the lattice_attack.py for them to go in? THANKS. mahuro@machine1:~/lattice-attack$ python3 lattice_attack.py -f data7.json File "/home/mahuro/lattice-attack/lattice_attack.py", line 41 r * pvk = ( (k*s)-z ) % N ^^^^^^^ SyntaxError: cannot assign to expression here. Maybe you meant '==' instead of '='?
Title: Re: Lattice Attack Script Modified
Post by: mahurovihamilo on May 06, 2024, 10:18:35 PM
Not sure where in the code should it go the definitions you mentioned.
I get another error, but I think I am closer now. I think I simply need to change of private_value to integer, But I am not sure how.
There is a comment in the lattice_attack.py that says how to convert between integer and hex, but it doesnt say where those given equations should go:
# To convert to integer : # if got bytes use : int.from_bytes(bytesvar, bytesorder="big") # if got hex use : int(hexintvar, 16) #
Has anyone got this to actually work? just curious...
Title: Re: Lattice Attack Script Modified
Post by: COBRAS on May 07, 2024, 12:22:23 AM
Not sure where in the code should it go the definitions you mentioned.
I get another error, but I think I am closer now. I think I simply need to change of private_value to integer, But I am not sure how.
There is a comment in the lattice_attack.py that says how to convert between integer and hex, but it doesnt say where those given equations should go:
# To convert to integer : # if got bytes use : int.from_bytes(bytesvar, bytesorder="big") # if got hex use : int(hexintvar, 16) #
Has anyone got this to actually work? just curious...
krossfire know kode, he can do it
Title: Re: Lattice Attack Script Modified
Post by: krashfire on May 07, 2024, 01:16:48 AM
Not sure where in the code should it go the definitions you mentioned.
I get another error, but I think I am closer now. I think I simply need to change of private_value to integer, But I am not sure how.
There is a comment in the lattice_attack.py that says how to convert between integer and hex, but it doesnt say where those given equations should go:
# To convert to integer : # if got bytes use : int.from_bytes(bytesvar, bytesorder="big") # if got hex use : int(hexintvar, 16) #
Has anyone got this to actually work? just curious...
theres no point running this. as the rsz created will not point to the correct private key or public key. ran it a long time ago.
|