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

View File

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

View File

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

View File

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