-
Notifications
You must be signed in to change notification settings - Fork 571
/
Copy pathclass_addressGenerator.py
376 lines (348 loc) · 18.1 KB
/
class_addressGenerator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
"""
A thread for creating addresses
"""
import time
from binascii import hexlify
from six.moves import configparser, queue
import defaults
import highlevelcrypto
import queues
import shared
import state
from addresses import decodeAddress, encodeAddress, encodeVarint
from bmconfigparser import config
from network import StoppableThread
from tr import _translate
class AddressGeneratorException(Exception):
'''Generic AddressGenerator exception'''
pass
class addressGenerator(StoppableThread):
"""A thread for creating addresses"""
name = "addressGenerator"
def stopThread(self):
"""Tell the thread to stop putting a special command to it's queue"""
try:
queues.addressGeneratorQueue.put(("stopThread", "data"))
except queue.Full:
self.logger.error('addressGeneratorQueue is Full')
super(addressGenerator, self).stopThread()
def run(self):
"""
Process the requests for addresses generation
from `.queues.addressGeneratorQueue`
"""
# pylint: disable=too-many-locals,too-many-branches,too-many-statements
# pylint: disable=too-many-nested-blocks
while state.shutdown == 0:
queueValue = queues.addressGeneratorQueue.get()
nonceTrialsPerByte = 0
payloadLengthExtraBytes = 0
live = True
if queueValue[0] == 'createChan':
command, addressVersionNumber, streamNumber, label, \
deterministicPassphrase, live = queueValue
eighteenByteRipe = False
numberOfAddressesToMake = 1
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
elif queueValue[0] == 'joinChan':
command, chanAddress, label, deterministicPassphrase, \
live = queueValue
eighteenByteRipe = False
addressVersionNumber = decodeAddress(chanAddress)[1]
streamNumber = decodeAddress(chanAddress)[2]
numberOfAddressesToMake = 1
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
elif len(queueValue) == 7:
command, addressVersionNumber, streamNumber, label, \
numberOfAddressesToMake, deterministicPassphrase, \
eighteenByteRipe = queueValue
numberOfNullBytesDemandedOnFrontOfRipeHash = \
config.safeGetInt(
'bitmessagesettings',
'numberofnullbytesonaddress',
2 if eighteenByteRipe else 1
)
elif len(queueValue) == 9:
command, addressVersionNumber, streamNumber, label, \
numberOfAddressesToMake, deterministicPassphrase, \
eighteenByteRipe, nonceTrialsPerByte, \
payloadLengthExtraBytes = queueValue
numberOfNullBytesDemandedOnFrontOfRipeHash = \
config.safeGetInt(
'bitmessagesettings',
'numberofnullbytesonaddress',
2 if eighteenByteRipe else 1
)
elif queueValue[0] == 'stopThread':
break
else:
self.logger.error(
'Programming error: A structure with the wrong number'
' of values was passed into the addressGeneratorQueue.'
' Here is the queueValue: %r\n', queueValue)
if addressVersionNumber < 3 or addressVersionNumber > 4:
self.logger.error(
'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 = config.getint(
'bitmessagesettings', 'defaultnoncetrialsperbyte')
if nonceTrialsPerByte < \
defaults.networkDefaultProofOfWorkNonceTrialsPerByte:
nonceTrialsPerByte = \
defaults.networkDefaultProofOfWorkNonceTrialsPerByte
if payloadLengthExtraBytes == 0:
payloadLengthExtraBytes = config.getint(
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
if payloadLengthExtraBytes < \
defaults.networkDefaultPayloadLengthExtraBytes:
payloadLengthExtraBytes = \
defaults.networkDefaultPayloadLengthExtraBytes
if command == 'createRandomAddress':
queues.UISignalQueue.put((
'updateStatusBar',
_translate(
"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
privSigningKey, pubSigningKey = highlevelcrypto.random_keys()
while True:
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
potentialPrivEncryptionKey, potentialPubEncryptionKey = \
highlevelcrypto.random_keys()
ripe = highlevelcrypto.to_ripe(
pubSigningKey, potentialPubEncryptionKey)
if (
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
== b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash
):
break
self.logger.info(
'Generated address with ripe digest: %s', hexlify(ripe))
try:
self.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
address = encodeAddress(
addressVersionNumber, streamNumber, ripe)
privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat(
privSigningKey)
privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat(
potentialPrivEncryptionKey)
config.add_section(address)
config.set(address, 'label', label)
config.set(address, 'enabled', 'true')
config.set(address, 'decoy', 'false')
config.set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte))
config.set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes))
config.set(
address, 'privsigningkey', privSigningKeyWIF.decode())
config.set(
address, 'privencryptionkey',
privEncryptionKeyWIF.decode())
config.save()
# The API and the join and create Chan functionality
# both need information back from the address generator.
queues.apiAddressGeneratorReturnQueue.put(address)
queues.UISignalQueue.put((
'updateStatusBar',
_translate(
"MainWindow",
"Done generating address. Doing work necessary"
" to broadcast it...")
))
queues.UISignalQueue.put(('writeNewAddressToTable', (
label, address, streamNumber)))
shared.reloadMyAddressHashes()
if addressVersionNumber == 3:
queues.workerQueue.put((
'sendOutOrStoreMyV3Pubkey', ripe))
elif addressVersionNumber == 4:
queues.workerQueue.put((
'sendOutOrStoreMyV4Pubkey', address))
elif command in (
'createDeterministicAddresses', 'createChan',
'getDeterministicAddress', 'joinChan'
):
if not deterministicPassphrase:
self.logger.warning(
'You are creating deterministic'
' address(es) using a blank passphrase.'
' Bitmessage will do it but it is rather stupid.')
if command == 'createDeterministicAddresses':
queues.UISignalQueue.put((
'updateStatusBar',
_translate(
"MainWindow",
"Generating %1 new addresses."
).arg(str(numberOfAddressesToMake))
))
signingKeyNonce = 0
encryptionKeyNonce = 1
# We fill out this list no matter what although we only
# need it if we end up passing the info to the API.
listOfNewAddressesToSendOutThroughTheAPI = []
for _ in range(numberOfAddressesToMake):
# This next section is a little bit strange. We're
# going to generate keys over and over until we 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.
startTime = time.time()
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
while True:
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
potentialPrivSigningKey, potentialPubSigningKey = \
highlevelcrypto.deterministic_keys(
deterministicPassphrase,
encodeVarint(signingKeyNonce))
potentialPrivEncryptionKey, potentialPubEncryptionKey = \
highlevelcrypto.deterministic_keys(
deterministicPassphrase,
encodeVarint(encryptionKeyNonce))
signingKeyNonce += 2
encryptionKeyNonce += 2
ripe = highlevelcrypto.to_ripe(
potentialPubSigningKey, potentialPubEncryptionKey)
if (
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
== b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash
):
break
self.logger.info(
'Generated address with ripe digest: %s', hexlify(ripe))
try:
self.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
address = encodeAddress(
addressVersionNumber, streamNumber, ripe)
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:
listOfNewAddressesToSendOutThroughTheAPI.append(
'chan name does not match address')
saveAddressToDisk = False
if command == 'getDeterministicAddress':
saveAddressToDisk = False
if saveAddressToDisk and live:
privSigningKeyWIF = \
highlevelcrypto.encodeWalletImportFormat(
potentialPrivSigningKey)
privEncryptionKeyWIF = \
highlevelcrypto.encodeWalletImportFormat(
potentialPrivEncryptionKey)
try:
config.add_section(address)
addressAlreadyExists = False
except configparser.DuplicateSectionError:
addressAlreadyExists = True
if addressAlreadyExists:
self.logger.info(
'%s already exists. Not adding it again.',
address
)
queues.UISignalQueue.put((
'updateStatusBar',
_translate(
"MainWindow",
"%1 is already in 'Your Identities'."
" Not adding it again."
).arg(address)
))
else:
self.logger.debug('label: %s', label)
config.set(address, 'label', label)
config.set(address, 'enabled', 'true')
config.set(address, 'decoy', 'false')
if command in ('createChan', 'joinChan'):
config.set(address, 'chan', 'true')
config.set(
address, 'noncetrialsperbyte',
str(nonceTrialsPerByte))
config.set(
address, 'payloadlengthextrabytes',
str(payloadLengthExtraBytes))
config.set(
address, 'privsigningkey',
privSigningKeyWIF.decode())
config.set(
address, 'privencryptionkey',
privEncryptionKeyWIF.decode())
config.save()
queues.UISignalQueue.put((
'writeNewAddressToTable',
(label, address, str(streamNumber))
))
listOfNewAddressesToSendOutThroughTheAPI.append(
address)
shared.myECCryptorObjects[ripe] = \
highlevelcrypto.makeCryptor(
hexlify(potentialPrivEncryptionKey))
shared.myAddressesByHash[ripe] = address
tag = highlevelcrypto.double_sha512(
encodeVarint(addressVersionNumber)
+ encodeVarint(streamNumber) + ripe
)[32:]
shared.myAddressesByTag[tag] = address
if addressVersionNumber == 3:
# If this is a chan address,
# the worker thread won't send out
# the pubkey over the network.
queues.workerQueue.put((
'sendOutOrStoreMyV3Pubkey', ripe))
elif addressVersionNumber == 4:
queues.workerQueue.put((
'sendOutOrStoreMyV4Pubkey', address))
queues.UISignalQueue.put((
'updateStatusBar',
_translate(
"MainWindow", "Done generating address")
))
elif saveAddressToDisk and not live \
and not config.has_section(address):
listOfNewAddressesToSendOutThroughTheAPI.append(
address)
# Done generating addresses.
if command in (
'createDeterministicAddresses', 'createChan', 'joinChan'
):
queues.apiAddressGeneratorReturnQueue.put(
listOfNewAddressesToSendOutThroughTheAPI)
elif command == 'getDeterministicAddress':
queues.apiAddressGeneratorReturnQueue.put(address)
else:
raise AddressGeneratorException(
"Error in the addressGenerator thread. Thread was"
+ " given a command it could not understand: " + command)
queues.addressGeneratorQueue.task_done()