2013-06-21 14:44:37 +02:00
import shared
import threading
import time
2013-06-23 21:52:39 +02:00
import sys
2013-06-21 14:44:37 +02:00
from pyelliptic . openssl import OpenSSL
import ctypes
import hashlib
2013-06-23 21:52:39 +02:00
import highlevelcrypto
2013-06-21 14:44:37 +02:00
from addresses import *
2015-01-08 23:11:30 +01:00
from debug import logger
2015-11-24 01:55:17 +01:00
from helper_threading import *
2013-06-21 21:44:28 +02:00
from pyelliptic import arithmetic
2013-06-24 21:51:01 +02:00
import tr
2013-06-21 14:44:37 +02:00
2015-11-24 01:55:17 +01:00
class addressGenerator ( threading . Thread , StoppableThread ) :
2013-06-21 14:44:37 +02:00
def __init__ ( self ) :
# QThread.__init__(self, parent)
2015-11-24 01:55:17 +01:00
threading . Thread . __init__ ( self , name = " addressGenerator " )
self . initStop ( )
def stopThread ( self ) :
try :
shared . addressGeneratorQueue . put ( ( " stopThread " , " data " ) )
except :
pass
super ( addressGenerator , self ) . stopThread ( )
2013-06-21 14:44:37 +02:00
def run ( self ) :
2015-11-24 01:55:17 +01:00
while shared . shutdown == 0 :
2013-06-21 14:44:37 +02:00
queueValue = shared . addressGeneratorQueue . get ( )
nonceTrialsPerByte = 0
payloadLengthExtraBytes = 0
2013-06-26 17:55:33 +02:00
if queueValue [ 0 ] == ' createChan ' :
command , addressVersionNumber , streamNumber , label , deterministicPassphrase = queueValue
eighteenByteRipe = False
numberOfAddressesToMake = 1
2013-09-18 06:04:01 +02:00
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
2013-06-26 17:55:33 +02:00
elif queueValue [ 0 ] == ' joinChan ' :
command , chanAddress , label , deterministicPassphrase = queueValue
eighteenByteRipe = False
2013-07-22 07:10:22 +02:00
addressVersionNumber = decodeAddress ( chanAddress ) [ 1 ]
streamNumber = decodeAddress ( chanAddress ) [ 2 ]
2013-06-26 17:55:33 +02:00
numberOfAddressesToMake = 1
2013-09-18 06:04:01 +02:00
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
2013-06-26 17:55:33 +02:00
elif len ( queueValue ) == 7 :
2013-06-21 14:44:37 +02:00
command , addressVersionNumber , streamNumber , label , numberOfAddressesToMake , deterministicPassphrase , eighteenByteRipe = queueValue
2013-09-21 19:30:46 +02:00
try :
numberOfNullBytesDemandedOnFrontOfRipeHash = shared . config . getint (
' bitmessagesettings ' , ' numberofnullbytesonaddress ' )
except :
if eighteenByteRipe :
numberOfNullBytesDemandedOnFrontOfRipeHash = 2
else :
numberOfNullBytesDemandedOnFrontOfRipeHash = 1 # the default
2013-06-21 14:44:37 +02:00
elif len ( queueValue ) == 9 :
command , addressVersionNumber , streamNumber , label , numberOfAddressesToMake , deterministicPassphrase , eighteenByteRipe , nonceTrialsPerByte , payloadLengthExtraBytes = queueValue
2013-09-21 19:30:46 +02:00
try :
numberOfNullBytesDemandedOnFrontOfRipeHash = shared . config . getint (
' bitmessagesettings ' , ' numberofnullbytesonaddress ' )
except :
if eighteenByteRipe :
numberOfNullBytesDemandedOnFrontOfRipeHash = 2
else :
numberOfNullBytesDemandedOnFrontOfRipeHash = 1 # the default
2015-11-24 01:55:17 +01:00
elif queueValue [ 0 ] == ' stopThread ' :
break
2013-06-21 14:44:37 +02:00
else :
sys . stderr . write (
2013-07-22 07:10:22 +02:00
' Programming error: A structure with the wrong number of values was passed into the addressGeneratorQueue. Here is the queueValue: %s \n ' % repr ( queueValue ) )
2013-09-13 06:27:34 +02:00
if addressVersionNumber < 3 or addressVersionNumber > 4 :
2013-06-21 14:44:37 +02:00
sys . stderr . write (
' Program error: For some reason the address generator queue has been given a request to create at least one version %s address which it cannot do. \n ' % addressVersionNumber )
if nonceTrialsPerByte == 0 :
nonceTrialsPerByte = shared . config . getint (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
if nonceTrialsPerByte < shared . networkDefaultProofOfWorkNonceTrialsPerByte :
nonceTrialsPerByte = shared . networkDefaultProofOfWorkNonceTrialsPerByte
if payloadLengthExtraBytes == 0 :
payloadLengthExtraBytes = shared . config . getint (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
if payloadLengthExtraBytes < shared . networkDefaultPayloadLengthExtraBytes :
payloadLengthExtraBytes = shared . networkDefaultPayloadLengthExtraBytes
2013-09-13 06:27:34 +02:00
if command == ' createRandomAddress ' :
shared . UISignalQueue . put ( (
' updateStatusBar ' , tr . translateText ( " MainWindow " , " Generating one new address " ) ) )
# This next section is a little bit strange. We're going to generate keys over and over until we
# find one that starts with either \x00 or \x00\x00. Then when we pack them into a Bitmessage address,
# we won't store the \x00 or \x00\x00 bytes thus making the
# address shorter.
startTime = time . time ( )
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
potentialPrivSigningKey = OpenSSL . rand ( 32 )
2014-05-21 12:06:20 +02:00
potentialPubSigningKey = highlevelcrypto . pointMult ( potentialPrivSigningKey )
2013-09-13 06:27:34 +02:00
while True :
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix + = 1
potentialPrivEncryptionKey = OpenSSL . rand ( 32 )
2014-05-21 12:06:20 +02:00
potentialPubEncryptionKey = highlevelcrypto . pointMult (
2013-09-13 06:27:34 +02:00
potentialPrivEncryptionKey )
ripe = hashlib . new ( ' ripemd160 ' )
sha = hashlib . new ( ' sha512 ' )
sha . update (
potentialPubSigningKey + potentialPubEncryptionKey )
ripe . update ( sha . digest ( ) )
2013-09-18 06:04:01 +02:00
if ripe . digest ( ) [ : numberOfNullBytesDemandedOnFrontOfRipeHash ] == ' \x00 ' * numberOfNullBytesDemandedOnFrontOfRipeHash :
break
2015-01-08 23:11:30 +01:00
logger . info ( ' Generated address with ripe digest: %s ' % ripe . digest ( ) . encode ( ' hex ' ) )
try :
logger . info ( ' Address generator calculated %s addresses at %s addresses per second before finding one with the correct ripe-prefix. ' % ( numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix , numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / ( time . time ( ) - startTime ) ) )
except ZeroDivisionError :
# The user must have a pretty fast computer. time.time() - startTime equaled zero.
pass
2013-09-13 06:27:34 +02:00
address = encodeAddress ( addressVersionNumber , streamNumber , ripe . digest ( ) )
# An excellent way for us to store our keys is in Wallet Import Format. Let us convert now.
# https://en.bitcoin.it/wiki/Wallet_import_format
privSigningKey = ' \x80 ' + potentialPrivSigningKey
checksum = hashlib . sha256 ( hashlib . sha256 (
privSigningKey ) . digest ( ) ) . digest ( ) [ 0 : 4 ]
privSigningKeyWIF = arithmetic . changebase (
privSigningKey + checksum , 256 , 58 )
privEncryptionKey = ' \x80 ' + potentialPrivEncryptionKey
checksum = hashlib . sha256 ( hashlib . sha256 (
privEncryptionKey ) . digest ( ) ) . digest ( ) [ 0 : 4 ]
privEncryptionKeyWIF = arithmetic . changebase (
privEncryptionKey + checksum , 256 , 58 )
shared . config . add_section ( address )
shared . config . set ( address , ' label ' , label )
shared . config . set ( address , ' enabled ' , ' true ' )
shared . config . set ( address , ' decoy ' , ' false ' )
shared . config . set ( address , ' noncetrialsperbyte ' , str (
nonceTrialsPerByte ) )
shared . config . set ( address , ' payloadlengthextrabytes ' , str (
payloadLengthExtraBytes ) )
shared . config . set (
address , ' privSigningKey ' , privSigningKeyWIF )
shared . config . set (
address , ' privEncryptionKey ' , privEncryptionKeyWIF )
2014-09-15 08:34:33 +02:00
shared . writeKeysFile ( )
2013-09-13 06:27:34 +02:00
# The API and the join and create Chan functionality
# both need information back from the address generator.
2015-12-05 11:18:51 +01:00
shared . apiAddressGeneratorReturnQueue . put ( address )
2013-09-13 06:27:34 +02:00
shared . UISignalQueue . put ( (
' updateStatusBar ' , tr . translateText ( " MainWindow " , " Done generating address. Doing work necessary to broadcast it... " ) ) )
shared . UISignalQueue . put ( ( ' writeNewAddressToTable ' , (
label , address , streamNumber ) ) )
shared . reloadMyAddressHashes ( )
if addressVersionNumber == 3 :
shared . workerQueue . put ( (
' sendOutOrStoreMyV3Pubkey ' , ripe . digest ( ) ) )
elif addressVersionNumber == 4 :
shared . workerQueue . put ( (
' sendOutOrStoreMyV4Pubkey ' , address ) )
elif command == ' createDeterministicAddresses ' or command == ' getDeterministicAddress ' or command == ' createChan ' or command == ' joinChan ' :
if len ( deterministicPassphrase ) == 0 :
sys . stderr . write (
' WARNING: You are creating deterministic address(es) using a blank passphrase. Bitmessage will do it but it is rather stupid. ' )
if command == ' createDeterministicAddresses ' :
2013-06-21 14:44:37 +02:00
shared . UISignalQueue . put ( (
2015-11-25 01:02:17 +01:00
' updateStatusBar ' , tr . translateText ( " MainWindow " , " Generating % 1 new addresses. " ) . arg ( str ( numberOfAddressesToMake ) ) ) )
2013-09-13 06:27:34 +02:00
signingKeyNonce = 0
encryptionKeyNonce = 1
listOfNewAddressesToSendOutThroughTheAPI = [
] # We fill out this list no matter what although we only need it if we end up passing the info to the API.
for i in range ( numberOfAddressesToMake ) :
2013-06-21 14:44:37 +02:00
# This next section is a little bit strange. We're going to generate keys over and over until we
2013-09-13 06:27:34 +02:00
# find one that has a RIPEMD hash that starts with either \x00 or \x00\x00. Then when we pack them
# into a Bitmessage address, we won't store the \x00 or
# \x00\x00 bytes thus making the address shorter.
2013-06-21 14:44:37 +02:00
startTime = time . time ( )
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
while True :
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix + = 1
2013-09-13 06:27:34 +02:00
potentialPrivSigningKey = hashlib . sha512 (
deterministicPassphrase + encodeVarint ( signingKeyNonce ) ) . digest ( ) [ : 32 ]
potentialPrivEncryptionKey = hashlib . sha512 (
deterministicPassphrase + encodeVarint ( encryptionKeyNonce ) ) . digest ( ) [ : 32 ]
2014-05-21 12:06:20 +02:00
potentialPubSigningKey = highlevelcrypto . pointMult (
2013-09-13 06:27:34 +02:00
potentialPrivSigningKey )
2014-05-21 12:06:20 +02:00
potentialPubEncryptionKey = highlevelcrypto . pointMult (
2013-06-21 14:44:37 +02:00
potentialPrivEncryptionKey )
2013-09-13 06:27:34 +02:00
signingKeyNonce + = 2
encryptionKeyNonce + = 2
2013-06-21 14:44:37 +02:00
ripe = hashlib . new ( ' ripemd160 ' )
sha = hashlib . new ( ' sha512 ' )
sha . update (
potentialPubSigningKey + potentialPubEncryptionKey )
ripe . update ( sha . digest ( ) )
2013-09-18 06:04:01 +02:00
if ripe . digest ( ) [ : numberOfNullBytesDemandedOnFrontOfRipeHash ] == ' \x00 ' * numberOfNullBytesDemandedOnFrontOfRipeHash :
break
2013-06-21 14:44:37 +02:00
2015-01-08 23:11:30 +01:00
logger . info ( ' Generated address with ripe digest: %s ' % ripe . digest ( ) . encode ( ' hex ' ) )
try :
logger . info ( ' Address generator calculated %s addresses at %s addresses per second before finding one with the correct ripe-prefix. ' % ( numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix , numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / ( time . time ( ) - startTime ) ) )
except ZeroDivisionError :
# The user must have a pretty fast computer. time.time() - startTime equaled zero.
pass
2013-09-13 06:27:34 +02:00
address = encodeAddress ( addressVersionNumber , streamNumber , ripe . digest ( ) )
2013-06-21 14:44:37 +02:00
2013-09-13 06:27:34 +02:00
saveAddressToDisk = True
# If we are joining an existing chan, let us check to make sure it matches the provided Bitmessage address
if command == ' joinChan ' :
if address != chanAddress :
2015-12-05 11:18:51 +01:00
shared . apiAddressGeneratorReturnQueue . put ( ' chan name does not match address ' )
2013-06-26 17:55:33 +02:00
saveAddressToDisk = False
2013-09-13 06:27:34 +02:00
if command == ' getDeterministicAddress ' :
saveAddressToDisk = False
2013-06-26 17:55:33 +02:00
2013-09-13 06:27:34 +02:00
if saveAddressToDisk :
# An excellent way for us to store our keys is in Wallet Import Format. Let us convert now.
# https://en.bitcoin.it/wiki/Wallet_import_format
privSigningKey = ' \x80 ' + potentialPrivSigningKey
checksum = hashlib . sha256 ( hashlib . sha256 (
privSigningKey ) . digest ( ) ) . digest ( ) [ 0 : 4 ]
privSigningKeyWIF = arithmetic . changebase (
privSigningKey + checksum , 256 , 58 )
2013-06-21 14:44:37 +02:00
2013-09-13 06:27:34 +02:00
privEncryptionKey = ' \x80 ' + \
potentialPrivEncryptionKey
checksum = hashlib . sha256 ( hashlib . sha256 (
privEncryptionKey ) . digest ( ) ) . digest ( ) [ 0 : 4 ]
privEncryptionKeyWIF = arithmetic . changebase (
privEncryptionKey + checksum , 256 , 58 )
2013-06-21 14:44:37 +02:00
2015-01-08 23:11:30 +01:00
2013-09-13 06:27:34 +02:00
try :
shared . config . add_section ( address )
2015-01-08 23:11:30 +01:00
addressAlreadyExists = False
2013-09-13 06:27:34 +02:00
except :
addressAlreadyExists = True
2015-01-08 23:11:30 +01:00
if addressAlreadyExists :
logger . info ( ' %s already exists. Not adding it again. ' % address )
shared . UISignalQueue . put ( (
' updateStatusBar ' , tr . translateText ( " MainWindow " , " % 1 is already in ' Your Identities ' . Not adding it again. " ) . arg ( address ) ) )
else :
logger . debug ( ' label: %s ' % label )
2013-09-13 06:27:34 +02:00
shared . config . set ( address , ' label ' , label )
shared . config . set ( address , ' enabled ' , ' true ' )
shared . config . set ( address , ' decoy ' , ' false ' )
if command == ' joinChan ' or command == ' createChan ' :
shared . config . set ( address , ' chan ' , ' true ' )
shared . config . set ( address , ' noncetrialsperbyte ' , str (
nonceTrialsPerByte ) )
shared . config . set ( address , ' payloadlengthextrabytes ' , str (
payloadLengthExtraBytes ) )
shared . config . set (
address , ' privSigningKey ' , privSigningKeyWIF )
shared . config . set (
address , ' privEncryptionKey ' , privEncryptionKeyWIF )
2014-09-15 08:34:33 +02:00
shared . writeKeysFile ( )
2013-06-21 14:44:37 +02:00
2013-09-13 06:27:34 +02:00
shared . UISignalQueue . put ( ( ' writeNewAddressToTable ' , (
label , address , str ( streamNumber ) ) ) )
listOfNewAddressesToSendOutThroughTheAPI . append (
address )
shared . myECCryptorObjects [ ripe . digest ( ) ] = highlevelcrypto . makeCryptor (
potentialPrivEncryptionKey . encode ( ' hex ' ) )
2013-09-15 03:06:26 +02:00
shared . myAddressesByHash [ ripe . digest ( ) ] = address
tag = hashlib . sha512 ( hashlib . sha512 ( encodeVarint (
addressVersionNumber ) + encodeVarint ( streamNumber ) + ripe . digest ( ) ) . digest ( ) ) . digest ( ) [ 32 : ]
shared . myAddressesByTag [ tag ] = address
2013-09-13 06:27:34 +02:00
if addressVersionNumber == 3 :
2013-06-21 14:44:37 +02:00
shared . workerQueue . put ( (
2013-07-22 07:10:22 +02:00
' sendOutOrStoreMyV3Pubkey ' , ripe . digest ( ) ) ) # If this is a chan address,
# the worker thread won't send out the pubkey over the network.
2013-09-13 06:27:34 +02:00
elif addressVersionNumber == 4 :
shared . workerQueue . put ( (
' sendOutOrStoreMyV4Pubkey ' , address ) )
2015-01-08 23:11:30 +01:00
shared . UISignalQueue . put ( (
' updateStatusBar ' , tr . translateText ( " MainWindow " , " Done generating address " ) ) )
2013-07-22 07:10:22 +02:00
2013-06-21 14:44:37 +02:00
2013-09-13 06:27:34 +02:00
# Done generating addresses.
2015-12-05 11:18:51 +01:00
if command == ' createDeterministicAddresses ' or command == ' joinChan ' or command == ' createChan ' :
shared . apiAddressGeneratorReturnQueue . put (
listOfNewAddressesToSendOutThroughTheAPI )
elif command == ' getDeterministicAddress ' :
shared . apiAddressGeneratorReturnQueue . put ( address )
2013-09-13 06:27:34 +02:00
else :
raise Exception (
" Error in the addressGenerator thread. Thread was given a command it could not understand: " + command )
2015-11-25 01:02:17 +01:00
shared . addressGeneratorQueue . task_done ( )