Functions for key generation #2214
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -43,8 +43,9 @@ sample_point = (
|
|||
)
|
||||
|
||||
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'
|
||||
# Deterministic addresses with stream 1 and versions 3, 4
|
||||
sample_deterministic_addr3 = 'BM-2DBPTgeSawWYZceFD69AbDT5q4iUWtj1ZN'
|
||||
sample_deterministic_addr4 = 'BM-2cWzSnwjJ7yRP3nLEWUV5LisTZyREWSzUK'
|
||||
sample_daddr3_512 = 18875720106589866286514488037355423395410802084648916523381
|
||||
|
|
|
@ -8,7 +8,7 @@ import unittest
|
|||
from abc import ABCMeta, abstractmethod
|
||||
from binascii import hexlify
|
||||
|
||||
from pybitmessage import highlevelcrypto
|
||||
from pybitmessage import highlevelcrypto, fallback
|
||||
|
||||
|
||||
try:
|
||||
|
@ -17,10 +17,10 @@ except ImportError:
|
|||
RIPEMD160 = None
|
||||
|
||||
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_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(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):
|
||||
"""Verify sample signatures and newly generated ones"""
|
||||
pubkey_hex = hexlify(sample_pubsigningkey)
|
||||
|
|
Reference in New Issue
Block a user