def ringsig_sign_substitute(msghash, priv, pub_xs, pub_ys): # Number of pubkeys n = len(pub_xs) # Create list of pubkeys as (x, y) points pubs = [(pub_xs[i], recover_y(pub_xs[i], bit(pub_ys, i))) for i in range(n)] # My pubkey my_pub = b.decode_pubkey(b.privtopub(priv)) # Compute my index in the pubkey list my_index = 0 while my_index < n: if pubs[my_index] == my_pub: break my_index += 1 assert my_index < n # Compute the signer's I value I = b.multiply(hash_to_pubkey(list(my_pub)), priv) # Select a random ephemeral key k = b.hash_to_int(b.random_key()) # Store the list of intermediate values in the "ring" e = [None] * n # Compute the entry in the ring corresponding to the signer's index kpub = b.privtopub(k) kmulpub = b.multiply(hash_to_pubkey(list(my_pub)), k) orig_left = hash_array([msghash, kpub[0], kpub[1], kmulpub[0], kmulpub[1]]) orig_right = hash_value(orig_left) e[my_index] = {"left": orig_left, "right": orig_right} # Map of intermediate s values (part of the signature) s = [None] * n for i in list(range(my_index + 1, n)) + list(range(my_index + 1)): prev_i = (i - 1) % n # In your position in the ring, set the s value based on your private # knowledge of k; this lets you "invert" the hash function in order to # ensure a consistent ring. At all other positions, select a random s if i == my_index: s[prev_i] = b.add_privkeys( k, b.mul_privkeys(e[prev_i]["right"], priv)) else: s[prev_i] = b.hash_to_int(b.random_key()) # Create the next values in the ring based on the chosen s value pub1 = b.subtract_pubkeys(b.privtopub(s[prev_i]), b.multiply(pubs[i], e[prev_i]["right"])) pub2 = b.subtract_pubkeys( b.multiply(hash_to_pubkey(list(pubs[i])), s[prev_i]), b.multiply(I, e[prev_i]["right"])) left = hash_array([msghash, pub1[0], pub1[1], pub2[0], pub2[1]]) right = hash_value(left) e[i] = {"left": left, "right": right} # Check that the ring is consistent assert (left, right) == (orig_left, orig_right) # Return the first value in the ring, the s values, and the signer's # I value in compressed form return (e[0]["left"], s, I[0], I[1] % 2)
def ringsig_sign_substitute(msghash, priv, pub_xs, pub_ys): # Number of pubkeys n = len(pub_xs) # Create list of pubkeys as (x, y) points pubs = [(pub_xs[i], recover_y(pub_xs[i], bit(pub_ys, i))) for i in range(n)] # My pubkey my_pub = b.decode_pubkey(b.privtopub(priv)) # Compute my index in the pubkey list my_index = 0 while my_index < n: if pubs[my_index] == my_pub: break my_index += 1 assert my_index < n # Compute the signer's I value I = b.multiply(hash_to_pubkey(list(my_pub)), priv) # Select a random ephemeral key k = b.hash_to_int(b.random_key()) # Store the list of intermediate values in the "ring" e = [None] * n # Compute the entry in the ring corresponding to the signer's index kpub = b.privtopub(k) kmulpub = b.multiply(hash_to_pubkey(list(my_pub)), k) orig_left = hash_array([msghash, kpub[0], kpub[1], kmulpub[0], kmulpub[1]]) orig_right = hash_value(orig_left) e[my_index] = {"left": orig_left, "right": orig_right} # Map of intermediate s values (part of the signature) s = [None] * n for i in list(range(my_index + 1, n)) + list(range(my_index + 1)): prev_i = (i - 1) % n # In your position in the ring, set the s value based on your private # knowledge of k; this lets you "invert" the hash function in order to # ensure a consistent ring. At all other positions, select a random s if i == my_index: s[prev_i] = b.add_privkeys(k, b.mul_privkeys(e[prev_i]["right"], priv)) else: s[prev_i] = b.hash_to_int(b.random_key()) # Create the next values in the ring based on the chosen s value pub1 = b.subtract_pubkeys(b.privtopub(s[prev_i]), b.multiply(pubs[i], e[prev_i]["right"])) pub2 = b.subtract_pubkeys(b.multiply(hash_to_pubkey(list(pubs[i])), s[prev_i]), b.multiply(I, e[prev_i]["right"])) left = hash_array([msghash, pub1[0], pub1[1], pub2[0], pub2[1]]) right = hash_value(left) e[i] = {"left": left, "right": right} # Check that the ring is consistent assert (left, right) == (orig_left, orig_right) # Return the first value in the ring, the s values, and the signer's # I value in compressed form return (e[0]["left"], s, I[0], I[1] % 2)
def sign_donation_tx(tx, i, priv): from bitcoin.main import fast_multiply, decode_privkey, G, inv, N from bitcoin.transaction import der_encode_sig k = sign_k hashcode = btc.SIGHASH_ALL i = int(i) if len(priv) <= 33: priv = btc.safe_hexlify(priv) pub = btc.privkey_to_pubkey(priv) address = btc.pubkey_to_address(pub) signing_tx = btc.signature_form( tx, i, btc.mk_pubkey_script(address), hashcode) msghash = btc.bin_txhash(signing_tx, hashcode) z = btc.hash_to_int(msghash) # k = deterministic_generate_k(msghash, priv) r, y = fast_multiply(G, k) s = inv(k, N) * (z + r * decode_privkey(priv)) % N rawsig = 27 + (y % 2), r, s sig = der_encode_sig(*rawsig) + btc.encode(hashcode, 16, 2) # sig = ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = btc.deserialize(tx) txobj["ins"][i]["script"] = btc.serialize_script([sig, pub]) return btc.serialize(txobj)
def sign_donation_tx(tx, i, priv): from bitcoin.main import fast_multiply, decode_privkey, G, inv, N from bitcoin.transaction import der_encode_sig k = sign_k hashcode = btc.SIGHASH_ALL i = int(i) if len(priv) <= 33: priv = btc.safe_hexlify(priv) pub = btc.privkey_to_pubkey(priv) address = btc.pubkey_to_address(pub) signing_tx = btc.signature_form(tx, i, btc.mk_pubkey_script(address), hashcode) msghash = btc.bin_txhash(signing_tx, hashcode) z = btc.hash_to_int(msghash) # k = deterministic_generate_k(msghash, priv) r, y = fast_multiply(G, k) s = inv(k, N) * (z + r * decode_privkey(priv)) % N rawsig = 27 + (y % 2), r, s sig = der_encode_sig(*rawsig) + btc.encode(hashcode, 16, 2) # sig = ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = btc.deserialize(tx) txobj["ins"][i]["script"] = btc.serialize_script([sig, pub]) return btc.serialize(txobj)
def ecdsa_raw_sign_one_to_one(msghash, sender_priv, receiver_pub): z = bitcoin.hash_to_int(msghash) k = bitcoin.deterministic_generate_k(msghash, sender_priv) r, y = bitcoin.fast_multiply(bitcoin.decode_pubkey(receiver_pub), k) s = bitcoin.inv(k, N) * (z + r * bitcoin.decode_privkey(sender_priv)) % N v, r, s = 27 + ((y % 2) ^ (0 if s * 2 < N else 1)), r, s if s * 2 < N else N - s return v, r, s
def ecdsa_raw_verify_one_to_one(msghash, vrs, sender_pub, receiver_priv): v, r, s = vrs w = bitcoin.inv(s, N) z = bitcoin.hash_to_int(msghash) u1, u2 = z * w % N, r * w % N receiver_pub = bitcoin.decode_pubkey(bitcoin.privtopub(receiver_priv)) receiver_sender_shared = bitcoin.fast_multiply( bitcoin.decode_pubkey(sender_pub), bitcoin.decode_privkey(receiver_priv)) u1Qr = bitcoin.fast_multiply(receiver_pub, u1) u2Qs = bitcoin.fast_multiply(receiver_sender_shared, u2) x, y = bitcoin.fast_add(u1Qr, u2Qs) return bool(r == x and (r % N) and (s % N))
def sign(tx_hash: bytes, private_key: str): msg_hash = tx_hash z = bitcoin.hash_to_int(msg_hash) k = bitcoin.deterministic_generate_k(msg_hash, private_key) r, y = bitcoin.fast_multiply(bitcoin.G, k) s = bitcoin.inv(k, bitcoin.N) * ( z + r * bitcoin.decode_privkey(private_key)) % bitcoin.N v, r, s = 27 + ((y % 2) ^ (0 if s * 2 < bitcoin.N else 1) ), r, s if s * 2 < bitcoin.N else bitcoin.N - s if 'compressed' in bitcoin.get_privkey_format(private_key): v += 4 hex_str_r = hex(r)[2:] if len(hex_str_r) < 64: hex_str_r = ((64 - len(hex_str_r)) * "0") + hex_str_r hex_str_s = hex(s)[2:] if len(hex_str_s) < 64: hex_str_s = ((64 - len(hex_str_s)) * "0") + hex_str_s signature = hex_str_r + hex_str_s recovery = v - 27 return signature, recovery
def ecdsa_sign_k(z, d, k): r, y = bitcoin.fast_multiply(bitcoin.G, k) s = bitcoin.inv(k, bitcoin.N) * (z + r * d) % bitcoin.N v, r, s = 27 + ((y % 2) ^ (0 if s * 2 < bitcoin.N else 1) ), r, s if s * 2 < bitcoin.N else bitcoin.N - s return v, r, s # Generate secret key & the corresponding public key and address sk = random.SystemRandom().randrange(1, bitcoin.N) Q = bitcoin.fast_multiply(bitcoin.G, sk) # Sign 2 differents messages with same k signing_k = random.SystemRandom().randrange(1, bitcoin.N) z1 = bitcoin.hash_to_int(hashlib.sha256('first_message').hexdigest()) z2 = bitcoin.hash_to_int(hashlib.sha256('second_message').hexdigest()) v1, r1, s1 = ecdsa_sign_k(z1, sk, signing_k) v2, r2, s2 = ecdsa_sign_k(z2, sk, signing_k) assert r1 == r2 print('+ R used = {:x}'.format(r1)) # Calculate k candidates k_candidates = [(z1 - z2) * bitcoin.inv(s1 - s2, bitcoin.N) % bitcoin.N, (z1 - z2) * bitcoin.inv(s1 + s2, bitcoin.N) % bitcoin.N] for k in k_candidates: priv_key = (s1 * k - z1) * bitcoin.inv(r1, bitcoin.N) % bitcoin.N if bitcoin.fast_multiply(bitcoin.G, priv_key) == Q: print('+ Calc key = {0}'.format(priv_key)) break else:
from bitcoin import fast_add, fast_multiply, G, hash_to_int, inv, N from hashlib import sha256 from random import SystemRandom # Generate secret key & the corresponding public key and address d = SystemRandom().randrange(1, N) Q = fast_multiply(G, d); # Choose a 2 random numbers a = SystemRandom().randrange(1, N) b = SystemRandom().randrange(1, N) # calculate a signature r = fast_add(fast_multiply(G, a), fast_multiply(Q, b))[0] s = r * inv(b, N) # Calculate the hash corresponding to the signature (r,s) h = a * r * inv(b, N) # calculate the hash of the message we want to sign z = hash_to_int(sha256('0xDEADBEEF').hexdigest()) # re-calculate s to sign z s_p = s * (z + d*r) * inv(h + d*r, N) # et voila w = inv(s_p, N) u1, u2 = z*w % N, r*w % N x, y = fast_add(fast_multiply(G, u1), fast_multiply(Q, u2)) assert(r == x and (r % N) and (s_p % N))
def get_z(msg): hash = hashlib.sha256(msg).hexdigest() return bitcoin.hash_to_int(hash)
def fast_substract(a, b): x1, y1 = a x2, y2 = b return fast_add((x1, y1), (x2, -y2)) inv = bitcoin.inv # We don't know d but we can get Q from emitted signatures d = bitcoin.decode_privkey(bitcoin.random_key()) Q = fast_multiply(G, d) # We build up a message to sign msghash = hashlib.sha256('a_random_message').hexdigest() z = bitcoin.hash_to_int(msghash) cpt = 0 while True: cpt = cpt + 1 r = random.SystemRandom().randrange(1, N) s = random.SystemRandom().randrange(1, N / 2) if r == fast_add(fast_multiply(G, z * inv(s, N)), fast_multiply(Q, r * inv(s, N)))[0]: break assert bitcoin.ecdsa_raw_verify(msghash, (27, r, s), Q) print('v={0}\nr={1}\ns={2}'.format(27, r, s)) print('Find after {} attempts.'.format(cpt))