Simplify handling RIPEMD160 #2235

Merged
PeterSurda merged 1 commits from gitea-89 into v0.6 2024-05-21 02:32:14 +02:00
6 changed files with 55 additions and 47 deletions

View File

@ -1,7 +1,7 @@
""" """
A thread for creating addresses A thread for creating addresses
""" """
import hashlib
import time import time
from binascii import hexlify from binascii import hexlify
@ -14,7 +14,6 @@ import shared
import state import state
from addresses import decodeAddress, encodeAddress, encodeVarint from addresses import decodeAddress, encodeAddress, encodeVarint
from bmconfigparser import config from bmconfigparser import config
from fallback import RIPEMD160Hash
from network import StoppableThread from network import StoppableThread
from tr import _translate from tr import _translate
@ -133,9 +132,8 @@ class addressGenerator(StoppableThread):
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1 numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
potentialPrivEncryptionKey, potentialPubEncryptionKey = \ potentialPrivEncryptionKey, potentialPubEncryptionKey = \
highlevelcrypto.random_keys() highlevelcrypto.random_keys()
sha = hashlib.new('sha512') ripe = highlevelcrypto.to_ripe(
sha.update(pubSigningKey + potentialPubEncryptionKey) pubSigningKey, potentialPubEncryptionKey)
ripe = RIPEMD160Hash(sha.digest()).digest()
if ( if (
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash] ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
== b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash == b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash
@ -244,10 +242,8 @@ class addressGenerator(StoppableThread):
signingKeyNonce += 2 signingKeyNonce += 2
encryptionKeyNonce += 2 encryptionKeyNonce += 2
sha = hashlib.new('sha512') ripe = highlevelcrypto.to_ripe(
sha.update( potentialPubSigningKey, potentialPubEncryptionKey)
potentialPubSigningKey + potentialPubEncryptionKey)
ripe = RIPEMD160Hash(sha.digest()).digest()
if ( if (
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash] ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
== b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash == b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash

View File

@ -28,7 +28,6 @@ from addresses import (
encodeAddress, encodeVarint, varintDecodeError encodeAddress, encodeVarint, varintDecodeError
) )
from bmconfigparser import config from bmconfigparser import config
from fallback import RIPEMD160Hash
from helper_sql import ( from helper_sql import (
sql_ready, sql_timeout, SqlBulkExecute, sqlExecute, sqlQuery) sql_ready, sql_timeout, SqlBulkExecute, sqlExecute, sqlQuery)
from network import knownnodes from network import knownnodes
@ -300,23 +299,20 @@ class objectProcessor(threading.Thread):
'(within processpubkey) payloadLength less than 146.' '(within processpubkey) payloadLength less than 146.'
' Sanity check failed.') ' Sanity check failed.')
readPosition += 4 readPosition += 4
publicSigningKey = data[readPosition:readPosition + 64] pubSigningKey = '\x04' + data[readPosition:readPosition + 64]
# Is it possible for a public key to be invalid such that trying to # Is it possible for a public key to be invalid such that trying to
# encrypt or sign with it will cause an error? If it is, it would # encrypt or sign with it will cause an error? If it is, it would
# be easiest to test them here. # be easiest to test them here.
readPosition += 64 readPosition += 64
publicEncryptionKey = data[readPosition:readPosition + 64] pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
if len(publicEncryptionKey) < 64: if len(pubEncryptionKey) < 65:
return logger.debug( return logger.debug(
'publicEncryptionKey length less than 64. Sanity check' 'publicEncryptionKey length less than 64. Sanity check'
' failed.') ' failed.')
readPosition += 64 readPosition += 64
# The data we'll store in the pubkeys table. # The data we'll store in the pubkeys table.
dataToStore = data[20:readPosition] dataToStore = data[20:readPosition]
sha = hashlib.new('sha512') ripe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey)
sha.update(
'\x04' + publicSigningKey + '\x04' + publicEncryptionKey)
ripe = RIPEMD160Hash(sha.digest()).digest()
if logger.isEnabledFor(logging.DEBUG): if logger.isEnabledFor(logging.DEBUG):
logger.debug( logger.debug(
@ -324,7 +320,7 @@ class objectProcessor(threading.Thread):
'\nripe %s\npublicSigningKey in hex: %s' '\nripe %s\npublicSigningKey in hex: %s'
'\npublicEncryptionKey in hex: %s', '\npublicEncryptionKey in hex: %s',
addressVersion, streamNumber, hexlify(ripe), addressVersion, streamNumber, hexlify(ripe),
hexlify(publicSigningKey), hexlify(publicEncryptionKey) hexlify(pubSigningKey), hexlify(pubEncryptionKey)
) )
address = encodeAddress(addressVersion, streamNumber, ripe) address = encodeAddress(addressVersion, streamNumber, ripe)
@ -354,9 +350,9 @@ class objectProcessor(threading.Thread):
' Sanity check failed.') ' Sanity check failed.')
return return
readPosition += 4 readPosition += 4
publicSigningKey = '\x04' + data[readPosition:readPosition + 64] pubSigningKey = '\x04' + data[readPosition:readPosition + 64]
readPosition += 64 readPosition += 64
publicEncryptionKey = '\x04' + data[readPosition:readPosition + 64] pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
readPosition += 64 readPosition += 64
specifiedNonceTrialsPerByteLength = decodeVarint( specifiedNonceTrialsPerByteLength = decodeVarint(
data[readPosition:readPosition + 10])[1] data[readPosition:readPosition + 10])[1]
@ -373,15 +369,13 @@ class objectProcessor(threading.Thread):
signature = data[readPosition:readPosition + signatureLength] signature = data[readPosition:readPosition + signatureLength]
if highlevelcrypto.verify( if highlevelcrypto.verify(
data[8:endOfSignedDataPosition], data[8:endOfSignedDataPosition],
signature, hexlify(publicSigningKey)): signature, hexlify(pubSigningKey)):
logger.debug('ECDSA verify passed (within processpubkey)') logger.debug('ECDSA verify passed (within processpubkey)')
else: else:
logger.warning('ECDSA verify failed (within processpubkey)') logger.warning('ECDSA verify failed (within processpubkey)')
return return
sha = hashlib.new('sha512') ripe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey)
sha.update(publicSigningKey + publicEncryptionKey)
ripe = RIPEMD160Hash(sha.digest()).digest()
if logger.isEnabledFor(logging.DEBUG): if logger.isEnabledFor(logging.DEBUG):
logger.debug( logger.debug(
@ -389,7 +383,7 @@ class objectProcessor(threading.Thread):
'\nripe %s\npublicSigningKey in hex: %s' '\nripe %s\npublicSigningKey in hex: %s'
'\npublicEncryptionKey in hex: %s', '\npublicEncryptionKey in hex: %s',
addressVersion, streamNumber, hexlify(ripe), addressVersion, streamNumber, hexlify(ripe),
hexlify(publicSigningKey), hexlify(publicEncryptionKey) hexlify(pubSigningKey), hexlify(pubEncryptionKey)
) )
address = encodeAddress(addressVersion, streamNumber, ripe) address = encodeAddress(addressVersion, streamNumber, ripe)
@ -588,9 +582,7 @@ class objectProcessor(threading.Thread):
sigHash = highlevelcrypto.double_sha512(signature)[32:] sigHash = highlevelcrypto.double_sha512(signature)[32:]
# calculate the fromRipe. # calculate the fromRipe.
sha = hashlib.new('sha512') ripe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey)
sha.update(pubSigningKey + pubEncryptionKey)
ripe = RIPEMD160Hash(sha.digest()).digest()
fromAddress = encodeAddress( fromAddress = encodeAddress(
sendersAddressVersionNumber, sendersStreamNumber, ripe) sendersAddressVersionNumber, sendersStreamNumber, ripe)
@ -883,9 +875,8 @@ class objectProcessor(threading.Thread):
requiredPayloadLengthExtraBytes) requiredPayloadLengthExtraBytes)
endOfPubkeyPosition = readPosition endOfPubkeyPosition = readPosition
sha = hashlib.new('sha512') calculatedRipe = highlevelcrypto.to_ripe(
sha.update(sendersPubSigningKey + sendersPubEncryptionKey) sendersPubSigningKey, sendersPubEncryptionKey)
calculatedRipe = RIPEMD160Hash(sha.digest()).digest()
if broadcastVersion == 4: if broadcastVersion == 4:
if toRipe != calculatedRipe: if toRipe != calculatedRipe:

View File

@ -15,12 +15,13 @@ import pyelliptic
from pyelliptic import OpenSSL from pyelliptic import OpenSSL
from pyelliptic import arithmetic as a from pyelliptic import arithmetic as a
from fallback import RIPEMD160Hash
__all__ = [ __all__ = [
'decodeWalletImportFormat', 'deterministic_keys', 'decodeWalletImportFormat', 'deterministic_keys',
'double_sha512', 'calculateInventoryHash', 'encodeWalletImportFormat', 'double_sha512', 'calculateInventoryHash', 'encodeWalletImportFormat',
'encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'randomBytes', 'encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'randomBytes',
'random_keys', 'sign', 'verify'] 'random_keys', 'sign', 'to_ripe', 'verify']
# WIF (uses arithmetic ): # WIF (uses arithmetic ):
@ -64,6 +65,16 @@ def randomBytes(n):
# Hashes # Hashes
def _bm160(data):
"""RIPEME160(SHA512(data)) -> bytes"""
return RIPEMD160Hash(hashlib.sha512(data).digest()).digest()
def to_ripe(signing_key, encryption_key):
"""Convert two public keys to a ripe hash"""
return _bm160(signing_key + encryption_key)
def double_sha512(data): def double_sha512(data):
"""Binary double SHA512 digest""" """Binary double SHA512 digest"""
return hashlib.sha512(hashlib.sha512(data).digest()).digest() return hashlib.sha512(hashlib.sha512(data).digest()).digest()

View File

@ -20,7 +20,6 @@ from addresses import (
encodeVarint, decodeVarint, decodeAddress, varintDecodeError) encodeVarint, decodeVarint, decodeAddress, varintDecodeError)
from bmconfigparser import config from bmconfigparser import config
from debug import logger from debug import logger
from fallback import RIPEMD160Hash
from helper_sql import sqlExecute from helper_sql import sqlExecute
from network.node import Peer from network.node import Peer
from version import softwareVersion from version import softwareVersion
@ -512,9 +511,9 @@ def decryptAndCheckPubkeyPayload(data, address):
readPosition = 0 readPosition = 0
# bitfieldBehaviors = decryptedData[readPosition:readPosition + 4] # bitfieldBehaviors = decryptedData[readPosition:readPosition + 4]
readPosition += 4 readPosition += 4
publicSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64] pubSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64]
readPosition += 64 readPosition += 64
publicEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64] pubEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64]
readPosition += 64 readPosition += 64
specifiedNonceTrialsPerByteLength = decodeVarint( specifiedNonceTrialsPerByteLength = decodeVarint(
decryptedData[readPosition:readPosition + 10])[1] decryptedData[readPosition:readPosition + 10])[1]
@ -530,7 +529,7 @@ def decryptAndCheckPubkeyPayload(data, address):
signature = decryptedData[readPosition:readPosition + signatureLength] signature = decryptedData[readPosition:readPosition + signatureLength]
if not highlevelcrypto.verify( if not highlevelcrypto.verify(
signedData, signature, hexlify(publicSigningKey)): signedData, signature, hexlify(pubSigningKey)):
logger.info( logger.info(
'ECDSA verify failed (within decryptAndCheckPubkeyPayload)') 'ECDSA verify failed (within decryptAndCheckPubkeyPayload)')
return 'failed' return 'failed'
@ -538,9 +537,7 @@ def decryptAndCheckPubkeyPayload(data, address):
logger.info( logger.info(
'ECDSA verify passed (within decryptAndCheckPubkeyPayload)') 'ECDSA verify passed (within decryptAndCheckPubkeyPayload)')
sha = hashlib.new('sha512') embeddedRipe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey)
sha.update(publicSigningKey + publicEncryptionKey)
embeddedRipe = RIPEMD160Hash(sha.digest()).digest()
if embeddedRipe != ripe: if embeddedRipe != ripe:
# Although this pubkey object had the tag were were looking for # Although this pubkey object had the tag were were looking for
@ -558,7 +555,7 @@ def decryptAndCheckPubkeyPayload(data, address):
'addressVersion: %s, streamNumber: %s\nripe %s\n' 'addressVersion: %s, streamNumber: %s\nripe %s\n'
'publicSigningKey in hex: %s\npublicEncryptionKey in hex: %s', 'publicSigningKey in hex: %s\npublicEncryptionKey in hex: %s',
addressVersion, streamNumber, hexlify(ripe), addressVersion, streamNumber, hexlify(ripe),
hexlify(publicSigningKey), hexlify(publicEncryptionKey) hexlify(pubSigningKey), hexlify(pubEncryptionKey)
) )
t = (address, addressVersion, storedData, int(time.time()), 'yes') t = (address, addressVersion, storedData, int(time.time()), 'yes')

View File

@ -8,6 +8,7 @@ sample_double_sha512 = unhexlify(
'0592a10584ffabf96539f3d780d776828c67da1ab5b169e9e8aed838aaecc9ed36d49ff14' '0592a10584ffabf96539f3d780d776828c67da1ab5b169e9e8aed838aaecc9ed36d49ff14'
'23c55f019e050c66c6324f53588be88894fef4dcffdb74b98e2b200') '23c55f019e050c66c6324f53588be88894fef4dcffdb74b98e2b200')
sample_bm160 = unhexlify('79a324faeebcbf9849f310545ed531556882487e')
# 500 identical peers: # 500 identical peers:
# 1626611891, 1, 1, 127.0.0.1, 8444 # 1626611891, 1, 1, 127.0.0.1, 8444

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, fallback from pybitmessage import highlevelcrypto
try: try:
@ -17,10 +17,10 @@ except ImportError:
RIPEMD160 = None RIPEMD160 = None
from .samples import ( from .samples import (
sample_deterministic_ripe, sample_double_sha512, sample_hash_data, sample_bm160, sample_deterministic_ripe, sample_double_sha512,
sample_msg, sample_pubsigningkey, sample_pubencryptionkey, sample_hash_data, sample_msg, sample_pubsigningkey,
sample_privsigningkey, sample_privencryptionkey, sample_ripe, sample_pubencryptionkey, sample_privsigningkey, sample_privencryptionkey,
sample_seed, sample_sig, sample_sig_sha1 sample_ripe, sample_seed, sample_sig, sample_sig_sha1
) )
@ -73,6 +73,19 @@ class TestHighlevelcrypto(unittest.TestCase):
highlevelcrypto.double_sha512(sample_hash_data), highlevelcrypto.double_sha512(sample_hash_data),
sample_double_sha512) sample_double_sha512)
def test_bm160(self):
"""Formally check highlevelcrypto._bm160()"""
# pylint: disable=protected-access
self.assertEqual(
highlevelcrypto._bm160(sample_hash_data), sample_bm160)
def test_to_ripe(self):
"""Formally check highlevelcrypto.to_ripe()"""
self.assertEqual(
hexlify(highlevelcrypto.to_ripe(
sample_pubsigningkey, sample_pubencryptionkey)),
sample_ripe)
def test_randomBytes(self): def test_randomBytes(self):
"""Dummy checks for random bytes""" """Dummy checks for random bytes"""
for n in (8, 32, 64): for n in (8, 32, 64):
@ -94,8 +107,7 @@ class TestHighlevelcrypto(unittest.TestCase):
enkey = highlevelcrypto.deterministic_keys(sample_seed, b'+')[1] enkey = highlevelcrypto.deterministic_keys(sample_seed, b'+')[1]
self.assertEqual( self.assertEqual(
sample_deterministic_ripe, sample_deterministic_ripe,
hexlify(fallback.RIPEMD160Hash( hexlify(highlevelcrypto.to_ripe(sigkey, enkey)))
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"""