Functions for key generation #2214
|
@ -16,7 +16,6 @@ from addresses import decodeAddress, encodeAddress, encodeVarint
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from fallback import RIPEMD160Hash
|
from fallback import RIPEMD160Hash
|
||||||
from network import StoppableThread
|
from network import StoppableThread
|
||||||
from pyelliptic.openssl import OpenSSL
|
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,17 +128,13 @@ class addressGenerator(StoppableThread):
|
||||||
# the \x00 or \x00\x00 bytes thus making the address shorter.
|
# the \x00 or \x00\x00 bytes thus making the address shorter.
|
||||||
startTime = time.time()
|
startTime = time.time()
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
||||||
potentialPrivSigningKey = OpenSSL.rand(32)
|
privSigningKey, pubSigningKey = highlevelcrypto.random_keys()
|
||||||
potentialPubSigningKey = highlevelcrypto.pointMult(
|
|
||||||
potentialPrivSigningKey)
|
|
||||||
while True:
|
while True:
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
||||||
potentialPrivEncryptionKey = OpenSSL.rand(32)
|
potentialPrivEncryptionKey, potentialPubEncryptionKey = \
|
||||||
potentialPubEncryptionKey = highlevelcrypto.pointMult(
|
highlevelcrypto.random_keys()
|
||||||
potentialPrivEncryptionKey)
|
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
sha.update(
|
sha.update(pubSigningKey + potentialPubEncryptionKey)
|
||||||
potentialPubSigningKey + potentialPubEncryptionKey)
|
|
||||||
ripe = RIPEMD160Hash(sha.digest()).digest()
|
ripe = RIPEMD160Hash(sha.digest()).digest()
|
||||||
if (
|
if (
|
||||||
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
|
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
|
||||||
|
@ -164,7 +159,7 @@ class addressGenerator(StoppableThread):
|
||||||
addressVersionNumber, streamNumber, ripe)
|
addressVersionNumber, streamNumber, ripe)
|
||||||
|
|
||||||
privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat(
|
privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat(
|
||||||
potentialPrivSigningKey)
|
privSigningKey)
|
||||||
privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat(
|
privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat(
|
||||||
potentialPrivEncryptionKey)
|
potentialPrivEncryptionKey)
|
||||||
|
|
||||||
|
@ -238,18 +233,15 @@ class addressGenerator(StoppableThread):
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
||||||
while True:
|
while True:
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
||||||
potentialPrivSigningKey = hashlib.sha512(
|
potentialPrivSigningKey, potentialPubSigningKey = \
|
||||||
deterministicPassphrase
|
highlevelcrypto.deterministic_keys(
|
||||||
+ encodeVarint(signingKeyNonce)
|
deterministicPassphrase,
|
||||||
).digest()[:32]
|
encodeVarint(signingKeyNonce))
|
||||||
potentialPrivEncryptionKey = hashlib.sha512(
|
potentialPrivEncryptionKey, potentialPubEncryptionKey = \
|
||||||
deterministicPassphrase
|
highlevelcrypto.deterministic_keys(
|
||||||
+ encodeVarint(encryptionKeyNonce)
|
deterministicPassphrase,
|
||||||
).digest()[:32]
|
encodeVarint(encryptionKeyNonce))
|
||||||
potentialPubSigningKey = highlevelcrypto.pointMult(
|
|
||||||
potentialPrivSigningKey)
|
|
||||||
potentialPubEncryptionKey = highlevelcrypto.pointMult(
|
|
||||||
potentialPrivEncryptionKey)
|
|
||||||
signingKeyNonce += 2
|
signingKeyNonce += 2
|
||||||
encryptionKeyNonce += 2
|
encryptionKeyNonce += 2
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
|
|
|
@ -17,10 +17,10 @@ from pyelliptic import arithmetic as a
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'decodeWalletImportFormat', 'encodeWalletImportFormat',
|
'decodeWalletImportFormat', 'deterministic_keys',
|
||||||
'double_sha512', 'calculateInventoryHash',
|
'double_sha512', 'calculateInventoryHash', 'encodeWalletImportFormat',
|
||||||
'encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'randomBytes',
|
'encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'randomBytes',
|
||||||
'sign', 'verify']
|
'random_keys', 'sign', 'verify']
|
||||||
|
|
||||||
|
|
||||||
# WIF (uses arithmetic ):
|
# WIF (uses arithmetic ):
|
||||||
|
@ -74,6 +74,77 @@ def calculateInventoryHash(data):
|
||||||
return double_sha512(data)[:32]
|
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'):
|
def makeCryptor(privkey, curve='secp256k1'):
|
||||||
"""Return a private `.pyelliptic.ECC` instance"""
|
"""Return a private `.pyelliptic.ECC` instance"""
|
||||||
private_key = a.changebase(privkey, 16, 256, minlen=32)
|
private_key = a.changebase(privkey, 16, 256, minlen=32)
|
||||||
|
@ -84,26 +155,12 @@ def makeCryptor(privkey, curve='secp256k1'):
|
||||||
return cryptor
|
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):
|
def makePubCryptor(pubkey):
|
||||||
"""Return a public `.pyelliptic.ECC` instance"""
|
"""Return a public `.pyelliptic.ECC` instance"""
|
||||||
pubkey_bin = hexToPubkey(pubkey)
|
pubkey_bin = hexToPubkey(pubkey)
|
||||||
return pyelliptic.ECC(curve='secp256k1', pubkey=pubkey_bin)
|
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):
|
def encrypt(msg, hexPubkey):
|
||||||
"""Encrypts message with hex public key"""
|
"""Encrypts message with hex public key"""
|
||||||
return pyelliptic.ECC(curve='secp256k1').encrypt(
|
return pyelliptic.ECC(curve='secp256k1').encrypt(
|
||||||
|
@ -120,6 +177,8 @@ def decryptFast(msg, cryptor):
|
||||||
return cryptor.decrypt(msg)
|
return cryptor.decrypt(msg)
|
||||||
|
|
||||||
|
|
||||||
|
# Signatures
|
||||||
|
|
||||||
def _choose_digest_alg(name):
|
def _choose_digest_alg(name):
|
||||||
"""
|
"""
|
||||||
Choose openssl digest constant by name raises ValueError if not appropriate
|
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))
|
sig, msg, digest_alg=_choose_digest_alg(digestAlg))
|
||||||
except:
|
except:
|
||||||
return False
|
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)
|
|
||||||
|
|
|
@ -43,8 +43,9 @@ sample_point = (
|
||||||
)
|
)
|
||||||
|
|
||||||
sample_seed = b'TIGER, tiger, burning bright. In the forests of the night'
|
sample_seed = b'TIGER, tiger, burning bright. In the forests of the night'
|
||||||
# Deterministic addresses with stream 1 and versions 3, 4
|
# RIPE hash on step 22 with signing key nonce 42
|
||||||
sample_deterministic_ripe = b'00cfb69416ae76f68a81c459de4e13460c7d17eb'
|
sample_deterministic_ripe = b'00cfb69416ae76f68a81c459de4e13460c7d17eb'
|
||||||
|
# Deterministic addresses with stream 1 and versions 3, 4
|
||||||
sample_deterministic_addr3 = 'BM-2DBPTgeSawWYZceFD69AbDT5q4iUWtj1ZN'
|
sample_deterministic_addr3 = 'BM-2DBPTgeSawWYZceFD69AbDT5q4iUWtj1ZN'
|
||||||
sample_deterministic_addr4 = 'BM-2cWzSnwjJ7yRP3nLEWUV5LisTZyREWSzUK'
|
sample_deterministic_addr4 = 'BM-2cWzSnwjJ7yRP3nLEWUV5LisTZyREWSzUK'
|
||||||
sample_daddr3_512 = 18875720106589866286514488037355423395410802084648916523381
|
sample_daddr3_512 = 18875720106589866286514488037355423395410802084648916523381
|
||||||
|
|
|
@ -8,7 +8,7 @@ import unittest
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
|
||||||
from pybitmessage import highlevelcrypto
|
from pybitmessage import highlevelcrypto, fallback
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -17,10 +17,10 @@ except ImportError:
|
||||||
RIPEMD160 = None
|
RIPEMD160 = None
|
||||||
|
|
||||||
from .samples import (
|
from .samples import (
|
||||||
sample_double_sha512, sample_hash_data,
|
sample_deterministic_ripe, sample_double_sha512, sample_hash_data,
|
||||||
sample_msg, sample_pubsigningkey, sample_pubencryptionkey,
|
sample_msg, sample_pubsigningkey, sample_pubencryptionkey,
|
||||||
sample_privsigningkey, sample_privencryptionkey, sample_ripe,
|
sample_privsigningkey, sample_privencryptionkey, sample_ripe,
|
||||||
sample_sig, sample_sig_sha1
|
sample_seed, sample_sig, sample_sig_sha1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +81,22 @@ class TestHighlevelcrypto(unittest.TestCase):
|
||||||
self.assertNotEqual(len(set(data)), 1)
|
self.assertNotEqual(len(set(data)), 1)
|
||||||
self.assertNotEqual(data, highlevelcrypto.randomBytes(n))
|
self.assertNotEqual(data, highlevelcrypto.randomBytes(n))
|
||||||
|
|
||||||
|
def test_random_keys(self):
|
||||||
|
"""Dummy checks for random keys"""
|
||||||
|
priv, pub = highlevelcrypto.random_keys()
|
||||||
|
self.assertEqual(len(priv), 32)
|
||||||
|
self.assertEqual(highlevelcrypto.pointMult(priv), pub)
|
||||||
|
|
||||||
|
def test_deterministic_keys(self):
|
||||||
|
"""Generate deterministic keys, make ripe and compare it to sample"""
|
||||||
|
# encodeVarint(42) = b'*'
|
||||||
|
sigkey = highlevelcrypto.deterministic_keys(sample_seed, b'*')[1]
|
||||||
|
enkey = highlevelcrypto.deterministic_keys(sample_seed, b'+')[1]
|
||||||
|
self.assertEqual(
|
||||||
|
sample_deterministic_ripe,
|
||||||
|
hexlify(fallback.RIPEMD160Hash(
|
||||||
|
hashlib.sha512(sigkey + enkey).digest()).digest()))
|
||||||
|
|
||||||
def test_signatures(self):
|
def test_signatures(self):
|
||||||
"""Verify sample signatures and newly generated ones"""
|
"""Verify sample signatures and newly generated ones"""
|
||||||
pubkey_hex = hexlify(sample_pubsigningkey)
|
pubkey_hex = hexlify(sample_pubsigningkey)
|
||||||
|
|
Reference in New Issue
Block a user