Functions for key generation #2214

Merged
PeterSurda merged 3 commits from gitea-86 into v0.6 2024-04-17 01:45:22 +02:00
4 changed files with 111 additions and 82 deletions

View File

@ -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')

View File

@ -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)

View File

@ -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

View File

@ -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)