From 5c1dcc56457a3cae4680a9ce3a3d1366f75fe551 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 9 Dec 2021 19:37:15 +0200 Subject: [PATCH] Define functions for generating keys in the highlevelcrypto --- src/class_addressGenerator.py | 36 ++++------ src/highlevelcrypto.py | 132 +++++++++++++++++++--------------- 2 files changed, 90 insertions(+), 78 deletions(-) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index c32c3994..929ac364 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -16,7 +16,6 @@ from addresses import decodeAddress, encodeAddress, encodeVarint from bmconfigparser import config from fallback import RIPEMD160Hash from network import StoppableThread -from pyelliptic.openssl import OpenSSL from tr import _translate @@ -129,17 +128,13 @@ class addressGenerator(StoppableThread): # the \x00 or \x00\x00 bytes thus making the address shorter. startTime = time.time() numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0 - potentialPrivSigningKey = OpenSSL.rand(32) - potentialPubSigningKey = highlevelcrypto.pointMult( - potentialPrivSigningKey) + privSigningKey, pubSigningKey = highlevelcrypto.random_keys() while True: numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1 - potentialPrivEncryptionKey = OpenSSL.rand(32) - potentialPubEncryptionKey = highlevelcrypto.pointMult( - potentialPrivEncryptionKey) + potentialPrivEncryptionKey, potentialPubEncryptionKey = \ + highlevelcrypto.random_keys() sha = hashlib.new('sha512') - sha.update( - potentialPubSigningKey + potentialPubEncryptionKey) + sha.update(pubSigningKey + potentialPubEncryptionKey) ripe = RIPEMD160Hash(sha.digest()).digest() if ( ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash] @@ -164,7 +159,7 @@ class addressGenerator(StoppableThread): addressVersionNumber, streamNumber, ripe) privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat( - potentialPrivSigningKey) + privSigningKey) privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat( potentialPrivEncryptionKey) @@ -238,18 +233,15 @@ class addressGenerator(StoppableThread): numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0 while True: numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1 - potentialPrivSigningKey = hashlib.sha512( - deterministicPassphrase - + encodeVarint(signingKeyNonce) - ).digest()[:32] - potentialPrivEncryptionKey = hashlib.sha512( - deterministicPassphrase - + encodeVarint(encryptionKeyNonce) - ).digest()[:32] - potentialPubSigningKey = highlevelcrypto.pointMult( - potentialPrivSigningKey) - potentialPubEncryptionKey = highlevelcrypto.pointMult( - potentialPrivEncryptionKey) + potentialPrivSigningKey, potentialPubSigningKey = \ + highlevelcrypto.deterministic_keys( + deterministicPassphrase, + encodeVarint(signingKeyNonce)) + potentialPrivEncryptionKey, potentialPubEncryptionKey = \ + highlevelcrypto.deterministic_keys( + deterministicPassphrase, + encodeVarint(encryptionKeyNonce)) + signingKeyNonce += 2 encryptionKeyNonce += 2 sha = hashlib.new('sha512') diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index e497c31c..d7af85de 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -17,10 +17,10 @@ from pyelliptic import arithmetic as a __all__ = [ - 'decodeWalletImportFormat', 'encodeWalletImportFormat', - 'double_sha512', 'calculateInventoryHash', + 'decodeWalletImportFormat', 'deterministic_keys', + 'double_sha512', 'calculateInventoryHash', 'encodeWalletImportFormat', 'encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'randomBytes', - 'sign', 'verify'] + 'random_keys', 'sign', 'verify'] # WIF (uses arithmetic ): @@ -74,6 +74,77 @@ def calculateInventoryHash(data): return double_sha512(data)[:32] +# Keys + +def random_keys(): + """Return a pair of keys, private and public""" + priv = randomBytes(32) + pub = pointMult(priv) + return priv, pub + + +def deterministic_keys(passphrase, nonce): + """Generate keys from *passphrase* and *nonce* (encoded as varint)""" + priv = hashlib.sha512(passphrase + nonce).digest()[:32] + pub = pointMult(priv) + return priv, pub + + +def hexToPubkey(pubkey): + """Convert a pubkey from hex to binary""" + pubkey_raw = a.changebase(pubkey[2:], 16, 256, minlen=64) + pubkey_bin = b'\x02\xca\x00 ' + pubkey_raw[:32] + b'\x00 ' + pubkey_raw[32:] + return pubkey_bin + + +def privToPub(privkey): + """Converts hex private key into hex public key""" + private_key = a.changebase(privkey, 16, 256, minlen=32) + public_key = pointMult(private_key) + return hexlify(public_key) + + +def pointMult(secret): + """ + Does an EC point multiplication; turns a private key into a public key. + + Evidently, this type of error can occur very rarely: + + >>> File "highlevelcrypto.py", line 54, in pointMult + >>> group = OpenSSL.EC_KEY_get0_group(k) + >>> WindowsError: exception: access violation reading 0x0000000000000008 + """ + while True: + try: + k = OpenSSL.EC_KEY_new_by_curve_name( + OpenSSL.get_curve('secp256k1')) + priv_key = OpenSSL.BN_bin2bn(secret, 32, None) + group = OpenSSL.EC_KEY_get0_group(k) + pub_key = OpenSSL.EC_POINT_new(group) + + OpenSSL.EC_POINT_mul(group, pub_key, priv_key, None, None, None) + OpenSSL.EC_KEY_set_private_key(k, priv_key) + OpenSSL.EC_KEY_set_public_key(k, pub_key) + + size = OpenSSL.i2o_ECPublicKey(k, None) + mb = OpenSSL.create_string_buffer(size) + OpenSSL.i2o_ECPublicKey(k, OpenSSL.byref(OpenSSL.pointer(mb))) + + return mb.raw + + except Exception: + import traceback + import time + traceback.print_exc() + time.sleep(0.2) + finally: + OpenSSL.EC_POINT_free(pub_key) + OpenSSL.BN_free(priv_key) + OpenSSL.EC_KEY_free(k) + + +# Encryption + def makeCryptor(privkey, curve='secp256k1'): """Return a private `.pyelliptic.ECC` instance""" private_key = a.changebase(privkey, 16, 256, minlen=32) @@ -84,26 +155,12 @@ def makeCryptor(privkey, curve='secp256k1'): return cryptor -def hexToPubkey(pubkey): - """Convert a pubkey from hex to binary""" - pubkey_raw = a.changebase(pubkey[2:], 16, 256, minlen=64) - pubkey_bin = b'\x02\xca\x00 ' + pubkey_raw[:32] + b'\x00 ' + pubkey_raw[32:] - return pubkey_bin - - def makePubCryptor(pubkey): """Return a public `.pyelliptic.ECC` instance""" pubkey_bin = hexToPubkey(pubkey) return pyelliptic.ECC(curve='secp256k1', pubkey=pubkey_bin) -def privToPub(privkey): - """Converts hex private key into hex public key""" - private_key = a.changebase(privkey, 16, 256, minlen=32) - public_key = pointMult(private_key) - return hexlify(public_key) - - def encrypt(msg, hexPubkey): """Encrypts message with hex public key""" return pyelliptic.ECC(curve='secp256k1').encrypt( @@ -120,6 +177,8 @@ def decryptFast(msg, cryptor): return cryptor.decrypt(msg) +# Signatures + def _choose_digest_alg(name): """ Choose openssl digest constant by name raises ValueError if not appropriate @@ -160,42 +219,3 @@ def verify(msg, sig, hexPubkey, digestAlg=None): sig, msg, digest_alg=_choose_digest_alg(digestAlg)) except: return False - - -def pointMult(secret): - """ - Does an EC point multiplication; turns a private key into a public key. - - Evidently, this type of error can occur very rarely: - - >>> File "highlevelcrypto.py", line 54, in pointMult - >>> group = OpenSSL.EC_KEY_get0_group(k) - >>> WindowsError: exception: access violation reading 0x0000000000000008 - """ - while True: - try: - k = OpenSSL.EC_KEY_new_by_curve_name( - OpenSSL.get_curve('secp256k1')) - priv_key = OpenSSL.BN_bin2bn(secret, 32, None) - group = OpenSSL.EC_KEY_get0_group(k) - pub_key = OpenSSL.EC_POINT_new(group) - - OpenSSL.EC_POINT_mul(group, pub_key, priv_key, None, None, None) - OpenSSL.EC_KEY_set_private_key(k, priv_key) - OpenSSL.EC_KEY_set_public_key(k, pub_key) - - size = OpenSSL.i2o_ECPublicKey(k, None) - mb = OpenSSL.create_string_buffer(size) - OpenSSL.i2o_ECPublicKey(k, OpenSSL.byref(OpenSSL.pointer(mb))) - - return mb.raw - - except Exception: - import traceback - import time - traceback.print_exc() - time.sleep(0.2) - finally: - OpenSSL.EC_POINT_free(pub_key) - OpenSSL.BN_free(priv_key) - OpenSSL.EC_KEY_free(k)