hive-nectar 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of hive-nectar might be problematic. Click here for more details.

Files changed (86) hide show
  1. hive_nectar-0.0.2.dist-info/METADATA +182 -0
  2. hive_nectar-0.0.2.dist-info/RECORD +86 -0
  3. hive_nectar-0.0.2.dist-info/WHEEL +4 -0
  4. hive_nectar-0.0.2.dist-info/entry_points.txt +2 -0
  5. hive_nectar-0.0.2.dist-info/licenses/LICENSE.txt +23 -0
  6. nectar/__init__.py +32 -0
  7. nectar/account.py +4371 -0
  8. nectar/amount.py +475 -0
  9. nectar/asciichart.py +270 -0
  10. nectar/asset.py +82 -0
  11. nectar/block.py +446 -0
  12. nectar/blockchain.py +1178 -0
  13. nectar/blockchaininstance.py +2284 -0
  14. nectar/blockchainobject.py +221 -0
  15. nectar/blurt.py +563 -0
  16. nectar/cli.py +6285 -0
  17. nectar/comment.py +1217 -0
  18. nectar/community.py +513 -0
  19. nectar/constants.py +111 -0
  20. nectar/conveyor.py +309 -0
  21. nectar/discussions.py +1709 -0
  22. nectar/exceptions.py +149 -0
  23. nectar/hive.py +546 -0
  24. nectar/hivesigner.py +420 -0
  25. nectar/imageuploader.py +72 -0
  26. nectar/instance.py +129 -0
  27. nectar/market.py +1013 -0
  28. nectar/memo.py +449 -0
  29. nectar/message.py +357 -0
  30. nectar/nodelist.py +444 -0
  31. nectar/price.py +557 -0
  32. nectar/profile.py +65 -0
  33. nectar/rc.py +308 -0
  34. nectar/snapshot.py +726 -0
  35. nectar/steem.py +582 -0
  36. nectar/storage.py +53 -0
  37. nectar/transactionbuilder.py +622 -0
  38. nectar/utils.py +545 -0
  39. nectar/version.py +2 -0
  40. nectar/vote.py +557 -0
  41. nectar/wallet.py +472 -0
  42. nectar/witness.py +617 -0
  43. nectarapi/__init__.py +11 -0
  44. nectarapi/exceptions.py +123 -0
  45. nectarapi/graphenerpc.py +589 -0
  46. nectarapi/node.py +178 -0
  47. nectarapi/noderpc.py +229 -0
  48. nectarapi/rpcutils.py +97 -0
  49. nectarapi/version.py +2 -0
  50. nectarbase/__init__.py +14 -0
  51. nectarbase/ledgertransactions.py +75 -0
  52. nectarbase/memo.py +243 -0
  53. nectarbase/objects.py +429 -0
  54. nectarbase/objecttypes.py +22 -0
  55. nectarbase/operationids.py +102 -0
  56. nectarbase/operations.py +1297 -0
  57. nectarbase/signedtransactions.py +48 -0
  58. nectarbase/transactions.py +11 -0
  59. nectarbase/version.py +2 -0
  60. nectargrapheneapi/__init__.py +6 -0
  61. nectargraphenebase/__init__.py +27 -0
  62. nectargraphenebase/account.py +846 -0
  63. nectargraphenebase/aes.py +52 -0
  64. nectargraphenebase/base58.py +192 -0
  65. nectargraphenebase/bip32.py +494 -0
  66. nectargraphenebase/bip38.py +134 -0
  67. nectargraphenebase/chains.py +149 -0
  68. nectargraphenebase/dictionary.py +3 -0
  69. nectargraphenebase/ecdsasig.py +326 -0
  70. nectargraphenebase/objects.py +123 -0
  71. nectargraphenebase/objecttypes.py +6 -0
  72. nectargraphenebase/operationids.py +3 -0
  73. nectargraphenebase/operations.py +23 -0
  74. nectargraphenebase/prefix.py +11 -0
  75. nectargraphenebase/py23.py +38 -0
  76. nectargraphenebase/signedtransactions.py +201 -0
  77. nectargraphenebase/types.py +419 -0
  78. nectargraphenebase/unsignedtransactions.py +283 -0
  79. nectargraphenebase/version.py +2 -0
  80. nectarstorage/__init__.py +38 -0
  81. nectarstorage/base.py +306 -0
  82. nectarstorage/exceptions.py +16 -0
  83. nectarstorage/interfaces.py +237 -0
  84. nectarstorage/masterpassword.py +239 -0
  85. nectarstorage/ram.py +30 -0
  86. nectarstorage/sqlite.py +334 -0
@@ -0,0 +1,494 @@
1
+ #!/usr/bin/env python
2
+ #
3
+ # Copyright 2014 Corgan Labs
4
+ # See LICENSE.txt for distribution terms
5
+ # https://github.com/namuyan/bip32nem/blob/master/bip32nem/BIP32Key.py
6
+
7
+ import codecs
8
+ import hashlib
9
+ import hmac
10
+ import os
11
+ import struct
12
+ from binascii import hexlify, unhexlify
13
+ from hashlib import sha256
14
+
15
+ import ecdsa
16
+ from ecdsa.curves import SECP256k1
17
+ from ecdsa.numbertheory import square_root_mod_prime as sqrt_mod
18
+
19
+ from nectargraphenebase.base58 import base58CheckDecode, base58CheckEncode
20
+ from nectargraphenebase.py23 import py23_bytes
21
+
22
+ VerifyKey = ecdsa.VerifyingKey.from_public_point
23
+ SigningKey = ecdsa.SigningKey.from_string
24
+ PointObject = ecdsa.ellipticcurve.Point # Point class
25
+ CURVE_GEN = ecdsa.ecdsa.generator_secp256k1 # Point class
26
+ CURVE_ORDER = CURVE_GEN.order() # int
27
+ FIELD_ORDER = SECP256k1.curve.p() # int
28
+ INFINITY = ecdsa.ellipticcurve.INFINITY # Point
29
+
30
+ MIN_ENTROPY_LEN = 128 # bits
31
+ BIP32_HARDEN = 0x80000000 # choose from hardened set of child keys
32
+ EX_MAIN_PRIVATE = [
33
+ codecs.decode("0488ade4", "hex")
34
+ ] # Version strings for mainnet extended private keys
35
+ EX_MAIN_PUBLIC = [
36
+ codecs.decode("0488b21e", "hex"),
37
+ codecs.decode("049d7cb2", "hex"),
38
+ ] # Version strings for mainnet extended public keys
39
+ EX_TEST_PRIVATE = [
40
+ codecs.decode("04358394", "hex")
41
+ ] # Version strings for testnet extended private keys
42
+ EX_TEST_PUBLIC = [
43
+ codecs.decode("043587CF", "hex")
44
+ ] # Version strings for testnet extended public keys
45
+
46
+
47
+ def int_to_hex(x):
48
+ return py23_bytes(hex(x)[2:], encoding="utf-8")
49
+
50
+
51
+ def parse_path(nstr, as_bytes=False):
52
+ """"""
53
+ r = list()
54
+ for s in nstr.split("/"):
55
+ if s == "m":
56
+ continue
57
+ elif s.endswith("'") or s.endswith("h"):
58
+ r.append(int(s[:-1]) + BIP32_HARDEN)
59
+ else:
60
+ r.append(int(s))
61
+ if not as_bytes:
62
+ return r
63
+ path = None
64
+ for p in r:
65
+ if path is None:
66
+ path = int_to_hex(p)
67
+ else:
68
+ path += int_to_hex(p)
69
+ return path
70
+
71
+
72
+ class BIP32Key(object):
73
+ # Static initializers to create from entropy or external formats
74
+ #
75
+ @staticmethod
76
+ def fromEntropy(entropy, public=False, testnet=False):
77
+ """Create a BIP32Key using supplied entropy >= MIN_ENTROPY_LEN"""
78
+ if entropy is None:
79
+ entropy = os.urandom(MIN_ENTROPY_LEN // 8) # Python doesn't have os.random()
80
+ if not len(entropy) >= MIN_ENTROPY_LEN // 8:
81
+ raise ValueError(
82
+ "Initial entropy %i must be at least %i bits" % (len(entropy), MIN_ENTROPY_LEN)
83
+ )
84
+ i64 = hmac.new(b"Bitcoin seed", entropy, hashlib.sha512).digest()
85
+ il, ir = i64[:32], i64[32:]
86
+ # FIXME test Il for 0 or less than SECP256k1 prime field order
87
+ key = BIP32Key(
88
+ secret=il, chain=ir, depth=0, index=0, fpr=b"\0\0\0\0", public=False, testnet=testnet
89
+ )
90
+ if public:
91
+ key.SetPublic()
92
+ return key
93
+
94
+ @staticmethod
95
+ def fromExtendedKey(xkey, public=False):
96
+ """
97
+ Create a BIP32Key by importing from extended private or public key string
98
+
99
+ If public is True, return a public-only key regardless of input type.
100
+ """
101
+ # Sanity checks
102
+ # raw = check_decode(xkey)
103
+ raw = unhexlify(base58CheckDecode(xkey, skip_first_bytes=False))
104
+
105
+ if len(raw) != 78:
106
+ raise ValueError("extended key format wrong length")
107
+
108
+ # Verify address version/type
109
+ version = raw[:4]
110
+ if version in EX_MAIN_PRIVATE:
111
+ is_testnet = False
112
+ is_pubkey = False
113
+ elif version in EX_TEST_PRIVATE:
114
+ is_testnet = True
115
+ is_pubkey = False
116
+ elif version in EX_MAIN_PUBLIC:
117
+ is_testnet = False
118
+ is_pubkey = True
119
+ elif version in EX_TEST_PUBLIC:
120
+ is_testnet = True
121
+ is_pubkey = True
122
+ else:
123
+ raise ValueError("unknown extended key version")
124
+
125
+ # Extract remaining fields
126
+ # Python 2.x compatibility
127
+ if type(raw[4]) == int:
128
+ depth = raw[4]
129
+ else:
130
+ depth = ord(raw[4])
131
+ fpr = raw[5:9]
132
+ child = struct.unpack(">L", raw[9:13])[0]
133
+ chain = raw[13:45]
134
+ secret = raw[45:78]
135
+
136
+ # Extract private key or public key point
137
+ if not is_pubkey:
138
+ secret = secret[1:]
139
+ else:
140
+ # Recover public curve point from compressed key
141
+ # Python3 FIX
142
+ lsb = secret[0] & 1 if type(secret[0]) == int else ord(secret[0]) & 1
143
+ x = int.from_bytes(secret[1:], "big")
144
+ ys = (x**3 + 7) % FIELD_ORDER # y^2 = x^3 + 7 mod p
145
+ y = sqrt_mod(ys, FIELD_ORDER)
146
+ if y & 1 != lsb:
147
+ y = FIELD_ORDER - y
148
+ point = PointObject(SECP256k1.curve, x, y)
149
+ secret = VerifyKey(point, curve=SECP256k1)
150
+
151
+ key = BIP32Key(
152
+ secret=secret,
153
+ chain=chain,
154
+ depth=depth,
155
+ index=child,
156
+ fpr=fpr,
157
+ public=is_pubkey,
158
+ testnet=is_testnet,
159
+ )
160
+ if not is_pubkey and public:
161
+ key.SetPublic()
162
+ return key
163
+
164
+ # Normal class initializer
165
+ def __init__(self, secret, chain, depth, index, fpr, public=False, testnet=False):
166
+ """
167
+ Create a public or private BIP32Key using key material and chain code.
168
+
169
+ secret This is the source material to generate the keypair, either a
170
+ 32-byte string representation of a private key, or the ECDSA
171
+ library object representing a public key.
172
+
173
+ chain This is a 32-byte string representation of the chain code
174
+
175
+ depth Child depth; parent increments its own by one when assigning this
176
+
177
+ index Child index
178
+
179
+ fpr Parent fingerprint
180
+
181
+ public If true, this keypair will only contain a public key and can only create
182
+ a public key chain.
183
+ """
184
+
185
+ self.public = public
186
+ if public is False:
187
+ self.k = SigningKey(secret, curve=SECP256k1)
188
+ self.K = self.k.get_verifying_key()
189
+ else:
190
+ self.k = None
191
+ self.K = secret
192
+
193
+ self.C = chain
194
+ self.depth = depth
195
+ self.index = index
196
+ self.parent_fpr = fpr
197
+ self.testnet = testnet
198
+
199
+ # Internal methods not intended to be called externally
200
+ #
201
+ def hmac(self, data):
202
+ """
203
+ Calculate the HMAC-SHA512 of input data using the chain code as key.
204
+
205
+ Returns a tuple of the left and right halves of the HMAC
206
+ """
207
+ i64 = hmac.new(self.C, data, hashlib.sha512).digest()
208
+ return i64[:32], i64[32:]
209
+
210
+ def CKDpriv(self, i):
211
+ """
212
+ Create a child key of index 'i'.
213
+
214
+ If the most significant bit of 'i' is set, then select from the
215
+ hardened key set, otherwise, select a regular child key.
216
+
217
+ Returns a BIP32Key constructed with the child key parameters,
218
+ or None if i index would result in an invalid key.
219
+ """
220
+ # Index as bytes, BE
221
+ i_str = struct.pack(">L", i)
222
+
223
+ # Data to HMAC
224
+ if i & BIP32_HARDEN:
225
+ data = b"\0" + self.k.to_string() + i_str
226
+ else:
227
+ data = self.PublicKey() + i_str
228
+ # Get HMAC of data
229
+ (Il, Ir) = self.hmac(data)
230
+
231
+ # Construct new key material from Il and current private key
232
+ Il_int = int.from_bytes(Il, "big")
233
+ if Il_int > CURVE_ORDER:
234
+ return None
235
+ pvt_int = int.from_bytes(self.k.to_string(), "big")
236
+ k_int = (Il_int + pvt_int) % CURVE_ORDER
237
+ if k_int == 0:
238
+ return None
239
+ secret = k_int.to_bytes(32, "big")
240
+
241
+ # Construct and return a new BIP32Key
242
+ return BIP32Key(
243
+ secret=secret,
244
+ chain=Ir,
245
+ depth=self.depth + 1,
246
+ index=i,
247
+ fpr=self.Fingerprint(),
248
+ public=False,
249
+ testnet=self.testnet,
250
+ )
251
+
252
+ def CKDpub(self, i):
253
+ """
254
+ Create a publicly derived child key of index 'i'.
255
+
256
+ If the most significant bit of 'i' is set, this is
257
+ an error.
258
+
259
+ Returns a BIP32Key constructed with the child key parameters,
260
+ or None if index would result in invalid key.
261
+ """
262
+
263
+ if i & BIP32_HARDEN:
264
+ raise Exception("Cannot create a hardened child key using public child derivation")
265
+
266
+ # Data to HMAC. Same as CKDpriv() for public child key.
267
+ data = self.PublicKey() + struct.pack(">L", i)
268
+
269
+ # Get HMAC of data
270
+ (Il, Ir) = self.hmac(data)
271
+
272
+ # Construct curve point Il*G+K
273
+ Il_int = int.from_bytes(Il, "big")
274
+ if Il_int >= CURVE_ORDER:
275
+ return None
276
+ point = Il_int * CURVE_GEN + self.K.pubkey.point
277
+ if point == INFINITY:
278
+ return None
279
+
280
+ # Retrieve public key based on curve point
281
+ K_i = VerifyKey(point, curve=SECP256k1)
282
+
283
+ # Construct and return a new BIP32Key
284
+ return BIP32Key(
285
+ secret=K_i,
286
+ chain=Ir,
287
+ depth=self.depth + 1,
288
+ index=i,
289
+ fpr=self.Fingerprint(),
290
+ public=True,
291
+ testnet=self.testnet,
292
+ )
293
+
294
+ # Public methods
295
+ #
296
+ def ChildKey(self, i):
297
+ """
298
+ Create and return a child key of this one at index 'i'.
299
+
300
+ The index 'i' should be summed with BIP32_HARDEN to indicate
301
+ to use the private derivation algorithm.
302
+ """
303
+ if self.public is False:
304
+ return self.CKDpriv(i)
305
+ else:
306
+ return self.CKDpub(i)
307
+
308
+ def SetPublic(self):
309
+ """Convert a private BIP32Key into a public one"""
310
+ self.k = None
311
+ self.public = True
312
+
313
+ def PrivateKey(self):
314
+ """Return private key as string"""
315
+ if self.public:
316
+ raise Exception("Publicly derived deterministic keys have no private half")
317
+ else:
318
+ return self.k.to_string()
319
+
320
+ def PublicKey(self):
321
+ """Return compressed public key encoding"""
322
+ padx = self.K.pubkey.point.x().to_bytes(32, "big")
323
+ if self.K.pubkey.point.y() & 1:
324
+ ck = b"\3" + padx
325
+ else:
326
+ ck = b"\2" + padx
327
+ return ck
328
+
329
+ def ChainCode(self):
330
+ """Return chain code as string"""
331
+ return self.C
332
+
333
+ def Identifier(self):
334
+ """Return key identifier as string"""
335
+ cK = self.PublicKey()
336
+ return hashlib.new("ripemd160", sha256(cK).digest()).digest()
337
+
338
+ def Fingerprint(self):
339
+ """Return key fingerprint as string"""
340
+ return self.Identifier()[:4]
341
+
342
+ def Address(self):
343
+ """Return compressed public key address"""
344
+ addressversion = b"\x00" if not self.testnet else b"\x6f"
345
+ # vh160 = addressversion + self.Identifier()
346
+ # return check_encode(vh160)
347
+ payload = hexlify(self.Identifier()).decode("ascii")
348
+ return base58CheckEncode(hexlify(addressversion).decode("ascii"), payload)
349
+
350
+ def P2WPKHoP2SHAddress(self):
351
+ """Return P2WPKH over P2SH segwit address"""
352
+ pk_bytes = self.PublicKey()
353
+ assert len(pk_bytes) == 33 and (
354
+ pk_bytes.startswith(b"\x02") or pk_bytes.startswith(b"\x03")
355
+ ), (
356
+ "Only compressed public keys are compatible with p2sh-p2wpkh addresses. "
357
+ "See https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki."
358
+ )
359
+ pk_hash = hashlib.new("ripemd160", sha256(pk_bytes).digest()).digest()
360
+ push_20 = bytes.fromhex("0014")
361
+ script_sig = push_20 + pk_hash
362
+ address_bytes = hashlib.new("ripemd160", sha256(script_sig).digest()).digest()
363
+ prefix = b"\xc4" if self.testnet else b"\x05"
364
+ # return check_encode(prefix + address_bytes)
365
+ payload = hexlify(address_bytes).decode("ascii")
366
+ return base58CheckEncode(hexlify(prefix).decode("ascii"), payload)
367
+
368
+ def WalletImportFormat(self):
369
+ """Returns private key encoded for wallet import"""
370
+ if self.public:
371
+ raise Exception("Publicly derived deterministic keys have no private half")
372
+ addressversion = b"\x80" if not self.testnet else b"\xef"
373
+ raw = self.k.to_string() + b"\x01" # Always compressed
374
+ # return check_encode(addressversion + raw)
375
+ payload = hexlify(raw).decode("ascii")
376
+ return base58CheckEncode(hexlify(addressversion).decode("ascii"), payload)
377
+
378
+ def ExtendedKey(self, private=True, encoded=True):
379
+ """Return extended private or public key as string, optionally base58 encoded"""
380
+ if self.public is True and private is True:
381
+ raise Exception(
382
+ "Cannot export an extended private key from a public-only deterministic key"
383
+ )
384
+ if not self.testnet:
385
+ version = EX_MAIN_PRIVATE[0] if private else EX_MAIN_PUBLIC[0]
386
+ else:
387
+ version = EX_TEST_PRIVATE[0] if private else EX_TEST_PUBLIC[0]
388
+ depth = bytes(bytearray([self.depth]))
389
+ fpr = self.parent_fpr
390
+ child = struct.pack(">L", self.index)
391
+ chain = self.C
392
+ if self.public is True or private is False:
393
+ data = self.PublicKey()
394
+ else:
395
+ data = b"\x00" + self.PrivateKey()
396
+ raw = version + depth + fpr + child + chain + data
397
+ if not encoded:
398
+ return raw
399
+ else:
400
+ # return check_encode(raw)
401
+ payload = hexlify(chain + data).decode("ascii")
402
+ return base58CheckEncode(
403
+ hexlify(version + depth + fpr + child).decode("ascii"), payload
404
+ )
405
+
406
+ # Debugging methods
407
+ #
408
+ def dump(self):
409
+ """Dump key fields mimicking the BIP0032 test vector format"""
410
+ print(" * Identifier")
411
+ print(" * (hex): ", self.Identifier().hex())
412
+ print(" * (fpr): ", self.Fingerprint().hex())
413
+ print(" * (main addr):", self.Address())
414
+ if self.public is False:
415
+ print(" * Secret key")
416
+ print(" * (hex): ", self.PrivateKey().hex())
417
+ print(" * (wif): ", self.WalletImportFormat())
418
+ print(" * Public key")
419
+ print(" * (hex): ", self.PublicKey().hex())
420
+ print(" * Chain code")
421
+ print(" * (hex): ", self.C.hex())
422
+ print(" * Serialized")
423
+ print(" * (pub hex): ", self.ExtendedKey(private=False, encoded=False).hex())
424
+ print(" * (pub b58): ", self.ExtendedKey(private=False, encoded=True))
425
+ if self.public is False:
426
+ print(" * (prv hex): ", self.ExtendedKey(private=True, encoded=False).hex())
427
+ print(" * (prv b58): ", self.ExtendedKey(private=True, encoded=True))
428
+
429
+
430
+ def test():
431
+ from binascii import a2b_hex
432
+
433
+ # BIP0032 Test vector 1
434
+ entropy = a2b_hex("000102030405060708090A0B0C0D0E0F")
435
+ m = BIP32Key.fromEntropy(entropy)
436
+ print("Test vector 1:")
437
+ print("Master (hex):", entropy.hex())
438
+ print("* [Chain m]")
439
+ m.dump()
440
+
441
+ print("* [Chain m/0h]")
442
+ m = m.ChildKey(0 + BIP32_HARDEN)
443
+ m.dump()
444
+
445
+ print("* [Chain m/0h/1]")
446
+ m = m.ChildKey(1)
447
+ m.dump()
448
+
449
+ print("* [Chain m/0h/1/2h]")
450
+ m = m.ChildKey(2 + BIP32_HARDEN)
451
+ m.dump()
452
+
453
+ print("* [Chain m/0h/1/2h/2]")
454
+ m = m.ChildKey(2)
455
+ m.dump()
456
+
457
+ print("* [Chain m/0h/1/2h/2/1000000000]")
458
+ m = m.ChildKey(1000000000)
459
+ m.dump()
460
+
461
+ # BIP0032 Test vector 2
462
+ entropy = a2b_hex(
463
+ "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a878481"
464
+ "7e7b7875726f6c696663605d5a5754514e4b484542"
465
+ )
466
+ m = BIP32Key.fromEntropy(entropy)
467
+ print("Test vector 2:")
468
+ print("Master (hex):", entropy.hex())
469
+ print("* [Chain m]")
470
+ m.dump()
471
+
472
+ print("* [Chain m/0]")
473
+ m = m.ChildKey(0)
474
+ m.dump()
475
+
476
+ print("* [Chain m/0/2147483647h]")
477
+ m = m.ChildKey(2147483647 + BIP32_HARDEN)
478
+ m.dump()
479
+
480
+ print("* [Chain m/0/2147483647h/1]")
481
+ m = m.ChildKey(1)
482
+ m.dump()
483
+
484
+ print("* [Chain m/0/2147483647h/1/2147483646h]")
485
+ m = m.ChildKey(2147483646 + BIP32_HARDEN)
486
+ m.dump()
487
+
488
+ print("* [Chain m/0/2147483647h/1/2147483646h/2]")
489
+ m = m.ChildKey(2)
490
+ m.dump()
491
+
492
+
493
+ if __name__ == "__main__":
494
+ test()
@@ -0,0 +1,134 @@
1
+ # -*- coding: utf-8 -*-
2
+ import hashlib
3
+ import logging
4
+ import sys
5
+ from binascii import hexlify, unhexlify
6
+
7
+ from .account import PrivateKey
8
+ from .base58 import Base58, base58decode
9
+ from .py23 import py23_bytes, text_type
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+ try:
14
+ from Cryptodome.Cipher import AES
15
+ except ImportError:
16
+ try:
17
+ from Crypto.Cipher import AES
18
+ except ImportError:
19
+ raise ImportError("Missing dependency: pyCryptodome")
20
+
21
+ SCRYPT_MODULE = None
22
+ if not SCRYPT_MODULE:
23
+ try:
24
+ import scrypt
25
+
26
+ SCRYPT_MODULE = "scrypt"
27
+ except ImportError:
28
+ try:
29
+ import pylibscrypt as scrypt
30
+
31
+ SCRYPT_MODULE = "pylibscrypt"
32
+ except ImportError:
33
+ raise ImportError("Missing dependency: scrypt or pylibscrypt")
34
+
35
+ log.debug("Using scrypt module: %s" % SCRYPT_MODULE)
36
+
37
+
38
+ class SaltException(Exception):
39
+ pass
40
+
41
+
42
+ def _encrypt_xor(a, b, aes):
43
+ """Returns encrypt(a ^ b)."""
44
+ a = unhexlify("%0.32x" % (int((a), 16) ^ int(hexlify(b), 16)))
45
+ return aes.encrypt(a)
46
+
47
+
48
+ def encrypt(privkey, passphrase):
49
+ """BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted privkey.
50
+
51
+ :param privkey: Private key
52
+ :type privkey: Base58
53
+ :param str passphrase: UTF-8 encoded passphrase for encryption
54
+ :return: BIP0038 non-ec-multiply encrypted wif key
55
+ :rtype: Base58
56
+
57
+ """
58
+ if isinstance(privkey, str):
59
+ privkey = PrivateKey(privkey)
60
+ else:
61
+ privkey = PrivateKey(repr(privkey))
62
+
63
+ privkeyhex = repr(privkey) # hex
64
+ addr = format(privkey.bitcoin.address, "BTC")
65
+ a = py23_bytes(addr, "ascii")
66
+ salt = hashlib.sha256(hashlib.sha256(a).digest()).digest()[0:4]
67
+ if sys.version < "3":
68
+ if isinstance(passphrase, text_type):
69
+ passphrase = passphrase.encode("utf-8")
70
+
71
+ if SCRYPT_MODULE == "scrypt":
72
+ key = scrypt.hash(passphrase, salt, 16384, 8, 8)
73
+ elif SCRYPT_MODULE == "pylibscrypt":
74
+ key = scrypt.scrypt(py23_bytes(passphrase, "utf-8"), salt, 16384, 8, 8)
75
+ else:
76
+ raise ValueError("No scrypt module loaded")
77
+ (derived_half1, derived_half2) = (key[:32], key[32:])
78
+ aes = AES.new(derived_half2, AES.MODE_ECB)
79
+ encrypted_half1 = _encrypt_xor(privkeyhex[:32], derived_half1[:16], aes)
80
+ encrypted_half2 = _encrypt_xor(privkeyhex[32:], derived_half1[16:], aes)
81
+ " flag byte is forced 0xc0 because Graphene only uses compressed keys "
82
+ payload = b"\x01" + b"\x42" + b"\xc0" + salt + encrypted_half1 + encrypted_half2
83
+ " Checksum "
84
+ checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
85
+ privatkey = hexlify(payload + checksum).decode("ascii")
86
+ return Base58(privatkey)
87
+
88
+
89
+ def decrypt(encrypted_privkey, passphrase):
90
+ """BIP0038 non-ec-multiply decryption. Returns WIF privkey.
91
+
92
+ :param Base58 encrypted_privkey: Private key
93
+ :param str passphrase: UTF-8 encoded passphrase for decryption
94
+ :return: BIP0038 non-ec-multiply decrypted key
95
+ :rtype: Base58
96
+ :raises SaltException: if checksum verification failed (e.g. wrong password)
97
+
98
+ """
99
+
100
+ d = unhexlify(base58decode(encrypted_privkey))
101
+ d = d[2:] # remove trailing 0x01 and 0x42
102
+ flagbyte = d[0:1] # get flag byte
103
+ d = d[1:] # get payload
104
+ if not flagbyte == b"\xc0":
105
+ raise AssertionError("Flagbyte has to be 0xc0")
106
+ salt = d[0:4]
107
+ d = d[4:-4]
108
+ if sys.version < "3":
109
+ if isinstance(passphrase, text_type):
110
+ passphrase = passphrase.encode("utf-8")
111
+ if SCRYPT_MODULE == "scrypt":
112
+ key = scrypt.hash(passphrase, salt, 16384, 8, 8)
113
+ elif SCRYPT_MODULE == "pylibscrypt":
114
+ key = scrypt.scrypt(py23_bytes(passphrase, "utf-8"), salt, 16384, 8, 8)
115
+ else:
116
+ raise ValueError("No scrypt module loaded")
117
+ derivedhalf1 = key[0:32]
118
+ derivedhalf2 = key[32:64]
119
+ encryptedhalf1 = d[0:16]
120
+ encryptedhalf2 = d[16:32]
121
+ aes = AES.new(derivedhalf2, AES.MODE_ECB)
122
+ decryptedhalf2 = aes.decrypt(encryptedhalf2)
123
+ decryptedhalf1 = aes.decrypt(encryptedhalf1)
124
+ privraw = decryptedhalf1 + decryptedhalf2
125
+ privraw = "%064x" % (int(hexlify(privraw), 16) ^ int(hexlify(derivedhalf1), 16))
126
+ wif = Base58(privraw)
127
+ """ Verify Salt """
128
+ privkey = PrivateKey(format(wif, "wif"))
129
+ addr = format(privkey.bitcoin.address, "BTC")
130
+ a = py23_bytes(addr, "ascii")
131
+ saltverify = hashlib.sha256(hashlib.sha256(a).digest()).digest()[0:4]
132
+ if saltverify != salt:
133
+ raise SaltException("checksum verification failed! Password may be incorrect.")
134
+ return wif