OSDN Git Service

071f06e6237ee2ea2e6ebaf8534f74870e08b21b
[bytom/bytom-kit.git] / app / model / key.py
1 import random
2 import hashlib
3 import pbkdf2
4 import hmac
5 import ed25519
6
7 # create_key create 128 bits entropy
8 def create_entropy():
9     hex_str = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]
10     entropy_str = ""
11     for _ in range(32):
12         # create interger in range [1,15]
13         num = random.randint(0,15)
14         entropy_str += hex_str[num]
15
16     return entropy_str
17
18 # entropy_to_mnemonic create mnemonic from 128 bits entropy(the entropy_str length is 32)
19 # return 12 mnemonics
20 # verify or get more test data, please ref: https://gist.github.com/zcc0721/63aeb5143807950f7b7051fadc08cef0
21 # test data 1:
22 #   entropy_str: 1db8b283eb4623e749732a341396e0c9
23 #   mnemonic_str: buffalo sheriff path story giraffe victory chair grab cross original return napkin
24 # test data 2:
25 #   entropy_str: 4d33735a9e92f634d22aecbb4044038d
26 #   mnemonic_str: essay oppose stove diamond control bounce emerge frown robust acquire abstract brick
27 # test data 3:
28 #   entropy_str: 089fe9bf0cac76760bc4b131d938669e
29 #   mnemonic_str: ancient young hurt bone shuffle deposit congress normal crack six boost despair
30 def entropy_to_mnemonic(entropy_str):
31     mnemonic_str = ""
32     mnemonic_length = 12
33
34     # create a 12 elements mnemonic_list 
35     mnemonic_list = []
36     for _ in range(mnemonic_length):
37         mnemonic_list.append('')
38
39     entropy_bytes = bytes.fromhex(entropy_str)
40     checksum = hashlib.sha256(entropy_bytes).hexdigest()[:1]
41     new_entropy_str = "0" + entropy_str + checksum
42     new_entropy_bytes = bytes.fromhex(new_entropy_str)
43     new_entropy_int = int.from_bytes(new_entropy_bytes, byteorder='big')
44
45     file = open('./app/model/english_mnemonic.txt', mode='r')
46     word_list = file.readlines()
47     file.close()
48
49     for i in range(11, -1, -1):
50         word_index = new_entropy_int % 2048
51         new_entropy_int = new_entropy_int >> 11
52         mnemonic_list[i] = word_list[word_index]
53
54     for i in range(12):
55         mnemonic_str += mnemonic_list[i][:-1]
56         mnemonic_str += " "
57
58     return mnemonic_str[:-1]
59
60 # mnemonic_to_seed create seed from mnemonic
61 # You can find more details from: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#from-mnemonic-to-seed
62 # You can verify or get more test data from: https://gist.github.com/zcc0721/4918e891073a9ca6c444ec7490298e82
63 # test data 1:
64 #   mnemonic_str: ancient young hurt bone shuffle deposit congress normal crack six boost despair
65 #   seed_str: afa3a86bbec2f40bb32833fc6324593824c4fc7821ed32eac1f762b5893e56745f66a6c6f2588b3d627680aa4e0e50efd25065097b3daa8c6a19d606838fe7d4
66 # test data 2:
67 #   mnemonic_str: rich decrease live pluck friend recipe burden minor similar agent tired horror
68 #   seed_str: b435f948bd3748ede8f9d6f59728d669939e79c6c885667a5c138e05bbabde1de0dcfcbe0c6112022fbbf0da522f4e224a9c2381016380688b51886248b3156f
69 # test data 3:
70 #   mnemonic_str: enough ginger just mutual fit trash loop mule peasant lady market hub
71 #   seed_str: ecc2bbb6c0492873cdbc81edf56bd896d3b644047879840e357be735b7fa7b6f4af1be7b8d71cc649ac4ca3816f9ccaf11bf49f4effb845f3c19e16eaf8bfcda
72 def mnemonic_to_seed(mnemonic_str):
73     password_str = mnemonic_str
74     salt_str = "mnemonic"
75     seed_str = pbkdf2.PBKDF2(password_str, salt_str, iterations=2048, digestmodule=hashlib.sha512, macmodule=hmac).hexread(64)
76
77     return seed_str
78
79 # s_str must be >= 32 bytes long and gets rewritten in place.
80 # This is NOT the same pruning as in Ed25519: it additionally clears the third
81 # highest bit to ensure subkeys do not overflow the second highest bit.
82 def prune_root_scalar(s_str):
83     s_0_int = int.from_bytes(bytes.fromhex(s_str[0:2]), byteorder='big') & 248
84     s_0_str = "%0.2x" % s_0_int
85     new_s_str = s_0_str + s_str[2:]
86     s_31_int = int.from_bytes(bytes.fromhex(new_s_str[62:64]), byteorder='big') & 31
87     s_31_str = "%0.2x" % s_31_int
88     new_s_str = new_s_str[:62] + s_31_str + new_s_str[64:]
89     s_31_int = int.from_bytes(bytes.fromhex(new_s_str[62:64]), byteorder='big') | 64
90     s_31_str = "%0.2x" % s_31_int
91     new_s_str = new_s_str[:62] + s_31_str + new_s_str[64:]
92     
93     return new_s_str
94
95 # seed_to_root_xprv create rootxprv from seed
96 # seed_str length is 512 bits.
97 # root_xprv length is 512 bits.
98 # You can verify or get more test data from: https://gist.github.com/zcc0721/0aa1b971f4bf93d8f67e25f57b8b97ee
99 # test data 1:
100 #   seed_str: afa3a86bbec2f40bb32833fc6324593824c4fc7821ed32eac1f762b5893e56745f66a6c6f2588b3d627680aa4e0e50efd25065097b3daa8c6a19d606838fe7d4
101 #   root_xprv: 302a25c7c0a68a83fa043f594a2db8b44bc871fced553a8a33144b31bc7fb84887c9e75915bb6ba3fd0b9f94a60b7a5897ab9db6a48f888c2559132dba9152b0
102 # test data 2:
103 #   seed_str: b435f948bd3748ede8f9d6f59728d669939e79c6c885667a5c138e05bbabde1de0dcfcbe0c6112022fbbf0da522f4e224a9c2381016380688b51886248b3156f
104 #   root_xprv: 6032adeb967ac5ccbf988cf8190817bf9040c8cfd9cdfe3d5e400effb2946946d478b61cc6be936f367ae769eb1dc65c473ee73cac2eb43cf6d5e7c62b7f0062
105 # test data 3:
106 #   seed_str: ecc2bbb6c0492873cdbc81edf56bd896d3b644047879840e357be735b7fa7b6f4af1be7b8d71cc649ac4ca3816f9ccaf11bf49f4effb845f3c19e16eaf8bfcda
107 #   root_xprv: a01d6b741b0e74b8d0836ac22b675bbf8e108148ef018d1b000aef1a899a134bd316c0f59e7333520ae1a429504073b2773869e95aa95bb3a4fa0ec76744025c
108 def seed_to_root_xprv(seed_str):
109     hc_str = hmac.HMAC(b'Root', bytes.fromhex(seed_str), digestmod=hashlib.sha512).hexdigest()
110     root_xprv_str = prune_root_scalar(hc_str[:64])
111
112     return root_xprv_str
113
114 ##################################################
115 # def xprv_to_xpub(xprv_str):
116 # private_key = ed25519.SigningKey(bytes.fromhex(xprv_str[:64]))
117 # public_key = private_key.get_verifying_key().to_ascii(encoding='hex')
118 # xpub_str = public_key.decode() + xprv_str[64:]
119 #     return xpub_str
120
121 # def xprv_to_hardened_child(xprv_str):