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 becies_decode(encodedstr): if (encodedstr[:3] != BECIES_MAGIC_BYTES): raise "BECIES magic header not found" encodedstr = encodedstr[3:] flags, o = _from_vli(encodedstr) encodedstr = encodedstr[o:] isaddresses = flags & BECIES_ADDRESSES_FLAG isgroup = flags & BECIES_GROUP_FLAG addresses = [] offsets = [] num_to_activate = None if (isaddresses): num_addresses, o = _from_vli(encodedstr) encodedstr = encodedstr[o:] addresses = [encodedstr[i:i + 20] for i in range(0, num_addresses, 20)] encodedstr = encodedstr[(num_addresses * 20):] if (isgroup): num_to_activate, o = _from_vli(encodedstr) encodedstr = encodedstr[o:] num_offsets, o = _from_vli(encodedstr) offsets = [encodedstr[i:i + n] for i in range(0, num_addresses, 32)] encodedstr = encodedstr[(num_offsets * 32):] ephemeral_pubkey = encodedstr[:33] encodedstr = encodedstr[33:] ephemeral_pubkey = bitcoin.decode_pubkey(ephemeral_pubkey) lcipher, o = _from_vli(encodedstr) encodedstr = encodedstr[o:] ciphertext = encodedstr[:lcipher] encodedstr = encodedstr[o:] tag = encodedstr return ephemeral_pubkey, ciphertext, tag, addresses, num_to_activate, offsets
def __init__(self, public_key): pubkey_points = bitcoin.decode_pubkey(binascii.unhexlify(public_key), 'bin') pubx = pubkey_points[0] puby = pubkey_points[1] edcsa = ECDSA.secp256r1() self.PublicKey = edcsa.Curve.point(pubx, puby) self.PublicKeyHash = Crypto.ToScriptHash(self.PublicKey.encode_point(True), unhex=True)
def __init__(self, private_key: bytes): self.private_key = private_key self.public_key = None bitcoin.change_curve( 115792089210356248762697446949407573530086143415290314195533631308867097853951, 115792089210356248762697446949407573529996955224135760342422259061068512044369, 115792089210356248762697446949407573530086143415290314195533631308867097853948, 41058363725152142129326129780047268409114441015993725554835256314039467401291, 48439561293906451759052585252797914202762949526041747995844080717082404635286, 36134250956749795798585127919587881956611106672985015071877198253568414405109 ) length = len(self.private_key) if length != 32: raise ValueError("Invalid private key") if length == 32: try: pubkey_encoded_not_compressed = bitcoin.privkey_to_pubkey( private_key) pubkey_points = bitcoin.decode_pubkey( pubkey_encoded_not_compressed, 'bin') pubx = pubkey_points[0] puby = pubkey_points[1] self.public_key = cryptography.ECDSA.secp256r1().Curve.point( pubx, puby) except Exception: raise ValueError("Could not determine public key")
def generate_keyfiles(n, m, vf, sf): '''Generate a set of public and private keys for testing. n - the number of OR loops m - the number of keys per loop (note: constant in this crude version) vf - the file path to which to write the verification keys sf - the file path to which to write the signing (private) keys ''' signing_indices = [random.choice(range(m)) for _ in range(n)] priv=[] with open(sf,'wb') as f: for i in range(n): priv.append(os.urandom(32)) f.write(binascii.hexlify(priv[i])+'\n') with open(vf,'wb') as f: for i in range(n): pubkeys = [] for j in range(m): if j==signing_indices[i]: p = btc.privtopub(priv[i]) else: p = btc.privtopub(os.urandom(32)) p = btc.decode_pubkey(p) p = btc.encode_pubkey(p,'bin_compressed') pubkeys.append(binascii.hexlify(p)) f.write(','.join(pubkeys)+'\n')
def __init__(self, priv_key=None): """ Create an instance :param priv_key: a private key """ if priv_key is None: priv_key = bytes(random_bytes(32)) length = len(priv_key) if length != 32: # Just handle 32 byte version raise ValueError("Invalid private key length") self.PrivateKey = bytearray(priv_key[-32:]) #Get last 32 bytes try: pubkey_encoded_not_compressed = bitcoin.privkey_to_pubkey(priv_key) except Exception as e: raise Exception("Could not determine public key") if pubkey_encoded_not_compressed: pubkey_points = bitcoin.decode_pubkey( pubkey_encoded_not_compressed, 'bin') pubx = pubkey_points[0] puby = pubkey_points[1] edcsa = ECDSA.secp256r1() self.PublicKey = edcsa.Curve.point(pubx, puby)
def generate_keyfiles(n, m, vf, sf): '''Generate a set of public and private keys for testing. n - the number of OR loops m - the number of keys per loop (note: constant in this crude version) vf - the file path to which to write the verification keys sf - the file path to which to write the signing (private) keys ''' signing_indices = [random.choice(range(m)) for _ in range(n)] priv = [] with open(sf, 'wb') as f: for i in range(n): priv.append(os.urandom(32)) f.write(binascii.hexlify(priv[i]) + '\n') with open(vf, 'wb') as f: for i in range(n): pubkeys = [] for j in range(m): if j == signing_indices[i]: p = btc.privtopub(priv[i]) else: p = btc.privtopub(os.urandom(32)) p = btc.decode_pubkey(p) p = btc.encode_pubkey(p, 'bin_compressed') pubkeys.append(binascii.hexlify(p)) f.write(','.join(pubkeys) + '\n')
def decode(public_value_compressed_base58): """ Decode the base58 public_value to the decimal x and y values """ public_value_compressed_hex = binascii.hexlify(base58.b58decode(public_value_compressed_base58)) public_value_x, public_value_y = bitcoin.decode_pubkey(public_value_compressed_hex.decode()) return (public_value_x, public_value_y)
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 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 import_keys(vf, sf=None): '''Import the verification keys; one list of pubkeys per loop in hex format, comma separated the first pubkey in each list is to be understood as the input for the connecting node. vf - the path to the file containing verification pubkeys sf - the path to the file containing signing keys, if applicable. Returns: vks - set of verification keys signing_indices - the indices corresponding to the private keys sks - the list of private keys ''' vks = {} with open(vf, 'rb') as f: or_loops = f.readlines() for i, loop in enumerate(or_loops): raw_pks = loop.strip().split(',') vks[i] = [btc.decode_pubkey(pk) for pk in raw_pks] if not sf: return (vks, None, None) #import the signing private keys; #at least one per loop with open(sf, 'rb') as f: raw_sks = f.readlines() sks = [binascii.unhexlify(priv.strip()) for priv in raw_sks] #check that the signing keys have the right configuration if not len(sks) == len(vks): raise Exception("Need " + str(len(vks)) + " signing keys for a valid signature, got " + str(len(sks))) sk_pks = [btc.decode_pubkey(btc.privtopub(sk)) for sk in sks] signing_indices = [] for loop in vks: if not len(set(vks[loop]).intersection(set(sk_pks))) == 1: raise Exception( "Verification key loop does not contain a signing key.") signing_indices.append( [x for x, item in enumerate(vks[loop]) if item in sk_pks][0]) #signing keys have right configuration relative to verification keys. return (vks, signing_indices, sks)
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 __init__(self, priv_key): """ Create an instance. Args: priv_key (bytes): a private key. Raises: ValueError: if the input `priv_key` length is not 32, 96, or 104 if the input `priv_key` length is 32 but the public key still could not be determined """ self.setup_curve() self.PublicKeyHash = None self.PublicKey = None self.PrivateKey = None length = len(priv_key) if length != 32 and length != 96 and length != 104: raise ValueError("Invalid private key") self.PrivateKey = bytearray(priv_key[-32:]) pubkey_encoded_not_compressed = None if length == 32: try: pubkey_encoded_not_compressed = bitcoin.privkey_to_pubkey( priv_key) except Exception: raise ValueError("Could not determine public key") elif length == 96 or length == 104: skip = length - 96 pubkey_encoded_not_compressed = bytearray(b'\x04') + bytearray( priv_key[skip:skip + 64]) if pubkey_encoded_not_compressed: pubkey_points = bitcoin.decode_pubkey( pubkey_encoded_not_compressed, 'bin') pubx = pubkey_points[0] puby = pubkey_points[1] edcsa = ECDSA.secp256r1() self.PublicKey = edcsa.Curve.point(pubx, puby) self.PublicKeyHash = Crypto.ToScriptHash( self.PublicKey.encode_point(True), unhex=True)
def import_keys(vf, sf=None): '''Import the verification keys; one list of pubkeys per loop in hex format, comma separated the first pubkey in each list is to be understood as the input for the connecting node. vf - the path to the file containing verification pubkeys sf - the path to the file containing signing keys, if applicable. Returns: vks - set of verification keys signing_indices - the indices corresponding to the private keys sks - the list of private keys ''' vks = {} with open(vf,'rb') as f: or_loops = f.readlines() for i,loop in enumerate(or_loops): raw_pks = loop.strip().split(',') vks[i] = [btc.decode_pubkey(pk) for pk in raw_pks] if not sf: return (vks, None, None) #import the signing private keys; #at least one per loop with open(sf,'rb') as f: raw_sks = f.readlines() sks = [binascii.unhexlify(priv.strip()) for priv in raw_sks] #check that the signing keys have the right configuration if not len(sks)==len(vks): raise Exception("Need "+str(len(vks))+" signing keys for a valid signature, got "+str(len(sks))) sk_pks = [btc.decode_pubkey(btc.privtopub(sk)) for sk in sks] signing_indices = [] for loop in vks: if not len(set(vks[loop]).intersection(set(sk_pks)))==1: raise Exception("Verification key loop does not contain a signing key.") signing_indices.append([x for x,item in enumerate(vks[loop]) if item in sk_pks][0]) #signing keys have right configuration relative to verification keys. return (vks, signing_indices, sks)
def encrypt(plaintext, pubkey, ephemeral_key=_secure_ephemeral()): optional_shared_info = ('', '') shared_secret = bitcoin.decode_pubkey( bitcoin.multiply(pubkey, ephemeral_key))[1] shared_secret_bin = _int2bin32b(shared_secret) ephemeral_pubkey = bitcoin.privtopub(ephemeral_key) symmetric_key, mac_key = ecies_derive_keys( shared_secret_bin, optional_shared_info0=optional_shared_info[0]) aes = AESCipher(symmetric_key) encrypted_string = aes.encrypt(plaintext) tag = ecies_compute_tag(mac_key=mac_key, encrypted_string=encrypted_string, optional_shared_info1=optional_shared_info[1]) return ephemeral_pubkey, encrypted_string, tag
def becies_shared_secret( private_key, public_key, optional_shared_info0='' ): #we do NOT use http://www.secg.org/sec1-v2.pdf ANSI KDF function, we use pkcs5_pbkdf2_hmac_sha512. It's got more hardening and it's more common and already a part of bitcoin shared_secret_point = bitcoin.multiply(public_key, private_key) shared_secret = bitcoin.decode_pubkey(shared_secret_point)[ 1] #todo: check point at infinity? todo: compressed pubkey? shared_secret_bin = _int2bin32b(shared_secret) salt = 'becies' key = shared_secret_bin + optional_shared_info0 hmac_result = pbkdf2_hmac( _becies_hashname, key, salt=salt + key, iterations=2048 ) #https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki symmetric_key = hmac_result[:(len(hmac_result) // 2)] mac_key = hmac_result[(len(hmac_result) // 2):] return symmetric_key, mac_key
def __init__(self, priv_key): self.setup_curve() length = len(priv_key) if length != 32 and length != 96 and length != 104: raise Exception("Invalid private key") self.PrivateKey = bytearray(priv_key[-32:]) pubkey_encoded_not_compressed = None if length == 32: pubkey_encoded_not_compressed = bitcoin.privkey_to_pubkey(priv_key) elif length == 64 or length == 72: skip = length - 64 pubkey_encoded_not_compressed = bytearray( b'04').hex() + priv_key[skip:] elif length == 96 or length == 104: skip = length - 96 pubkey_encoded_not_compressed = bytearray(b'\x04') + bytearray( priv_key[skip:skip + 64]) if pubkey_encoded_not_compressed: pubkey_points = bitcoin.decode_pubkey( pubkey_encoded_not_compressed, 'bin') pubx = pubkey_points[0] puby = pubkey_points[1] edcsa = ECDSA.secp256r1() self.PublicKey = edcsa.Curve.point(pubx, puby) else: raise Exception("Could not determine public key") self.PublicKeyHash = Crypto.ToScriptHash( self.PublicKey.encode_point(True), unhex=True)
def decrypt(ciphertuple, privkey): optional_shared_info = ('', '') ephemeral_pubkey = ciphertuple[0] encrypted_string = ciphertuple[1] msgtag = ciphertuple[2] shared_secret = bitcoin.decode_pubkey( bitcoin.multiply(privkey, ephemeral_pubkey))[1] #todo: check point at infinity shared_secret_bin = _int2bin32b(shared_secret) symmetric_key, mac_key = ecies_derive_keys( shared_secret_bin, optional_shared_info0=optional_shared_info[0]) tag = ecies_compute_tag(mac_key=mac_key, encrypted_string=encrypted_string, optional_shared_info1=optional_shared_info[1]) if (tag != msgtag): raise "Decryption Failure...tag mismatch. The message may have been tampered with" aes = AESCipher(symmetric_key) return aes.decrypt(encrypted_string)
def decompress_secp256k1_pubkey(data): x, y = decode_pubkey(data, 'bin_compressed') p = ecdsa.ellipticcurve.Point(ecdsa.SECP256k1.curve, x, y) return ecdsa.VerifyingKey.from_public_point(p, ecdsa.SECP256k1)