• R/O
  • HTTP
  • SSH
  • HTTPS

pybtm: 提交

Python3 implementation of the Bytom protocol. https://pypi.org/project/pybtm/


Commit MetaInfo

修订版46f321e2377e2a046a0c854a08bb87cddb200c4b (tree)
时间2019-03-28 12:46:19
作者Chengcheng Zhang <943420582@qq.c...>
CommiterChengcheng Zhang

Log Message

add get_path_from_index

更改概述

差异

--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ pybtm
1515 - [2.10 Sign message](#210-sign-message)
1616 - [2.11 Verify signature](#211-verify-signature)
1717 - [2.12 Create new key](#212-create-new-key)
18+ - [2.13 Create HD path](#213-create-hd-path)
1819
1920 Python3 implementation of the Bytom protocol.
2021
@@ -297,4 +298,18 @@ Return:
297298 'ancient young hurt bone shuffle deposit congress normal crack six boost despair'
298299 >>> r['seed']
299300 'afa3a86bbec2f40bb32833fc6324593824c4fc7821ed32eac1f762b5893e56745f66a6c6f2588b3d627680aa4e0e50efd25065097b3daa8c6a19d606838fe7d4'
300-```
\ No newline at end of file
301+```
302+
303+### 2.13 Create HD path
304+
305+get_path_from_index create HD path.
306+
307+```python
308+>>> from pybtm import receiver
309+>>> account_index_int = 1
310+>>> address_index_int = 1
311+>>> change_bool = True
312+>>> receiver.get_path_from_index(account_index_int, address_index_int, change_bool)
313+{'path': ['2c000000', '99000000', '01000000', '01000000', '01000000'], 'path_str': 'm/44/153/1/1/1'}
314+```
315+
--- a/pybtm/__init__.py
+++ b/pybtm/__init__.py
@@ -1,2 +1,2 @@
11 name = "pybtm"
2-version = "0.0.16"
\ No newline at end of file
2+version = "0.0.17"
\ No newline at end of file
--- /dev/null
+++ b/pybtm/receiver.py
@@ -0,0 +1,174 @@
1+import hashlib
2+from .key import *
3+from .segwit_addr import *
4+from .utils import *
5+
6+# get_path_from_index create xpub path from account key index and current address index
7+# path: purpose(0x2c=44)/coin_type(btm:0x99)/account_index/change(1 or 0)/address_index
8+# You can find more details from: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
9+# You can get more test data from: https://gist.github.com/zcc0721/616eaf337673635fa5c9dd5dbb8dd114
10+# Please attention:
11+# account_index_int >= 1
12+# address_index_int >= 1
13+# change_bool: true or false
14+# test data 1:
15+# account_index_int: 1
16+# address_index_int: 1
17+# change_bool: true
18+# path_list: 2c000000 99000000 01000000 01000000 01000000
19+# test data 2:
20+# account_index_int: 1
21+# address_index_int: 1
22+# change_bool: false
23+# path_list: 2c000000 99000000 01000000 00000000 01000000
24+# test data 3:
25+# account_index_int: 3
26+# address_index_int: 1
27+# change_bool: false
28+# path_list: 2c000000 99000000 03000000 00000000 01000000
29+def get_path_from_index(account_index_int, address_index_int, change_bool):
30+ path_list = ['2c000000', '99000000']
31+ account_index_str = (account_index_int).to_bytes(4, byteorder='little').hex()
32+ path_list.append(account_index_str)
33+ change_str = '0'
34+ if change_bool:
35+ branch_str = (1).to_bytes(4, byteorder='little').hex()
36+ change_str = '1'
37+ else:
38+ branch_str = (0).to_bytes(4, byteorder='little').hex()
39+ path_list.append(branch_str)
40+ address_index_str = (address_index_int).to_bytes(4, byteorder='little').hex()
41+ path_list.append(address_index_str)
42+ path_str = 'm/44/153/' + str(account_index_int) + '/' + change_str + '/' + str(address_index_int)
43+ return {
44+ "path": path_list,
45+ "path_str": path_str
46+ }
47+
48+
49+# get_control_program create control program
50+# You can get more test data from: https://gist.github.com/zcc0721/afa12de04b03b9bfc49985a181ebda80
51+# Please attention:
52+# account_index_int >= 1
53+# address_index_int >= 1
54+# change_bool: true or false
55+# test data 1:
56+# account_index_int: 1
57+# address_index_int: 1
58+# change_bool: false
59+# xpub_str: 3c6664244d2d57168d173c4691dbf8741a67d972b2d3e1b0067eb825e2005d20c5eebd1c26ccad4de5142d7c339bf62cc1fb79a8b3e42a708cd521368dbc9286
60+# control_program_str: 0014052620b86a6d5e07311d5019dffa3864ccc8a6bd
61+# test data 2:
62+# account_index_int: 1
63+# address_index_int: 1
64+# change_bool: true
65+# xpub_str: 3c6664244d2d57168d173c4691dbf8741a67d972b2d3e1b0067eb825e2005d20c5eebd1c26ccad4de5142d7c339bf62cc1fb79a8b3e42a708cd521368dbc9286
66+# control_program: 001478c3aa31753389fcde04d33d0779bdc2840f0ad4
67+# test data 3:
68+# account_index_int: 1
69+# address_index_int: 17
70+# change_bool: true
71+# xpub_str: 3c6664244d2d57168d173c4691dbf8741a67d972b2d3e1b0067eb825e2005d20c5eebd1c26ccad4de5142d7c339bf62cc1fb79a8b3e42a708cd521368dbc9286
72+# control_program: 0014eefb8d0688d7960dfbd79bb3aa1bcaa3ec34415d
73+# test data 4:
74+# account_index_int: 1
75+# address_index_int: 1
76+# change_bool: false
77+# xpub_str: f744493a021b65814ea149118c98aae8d1e217de29fefb7b2024ca341cd834586ee48bbcf1f4ae801ecb8c6784b044fc62a74c58c816d14537e1573c3e20ce79
78+# control_program: 001431f2b90b469e89361225aae370f73e5473b9852b
79+def get_control_program(account_index_int, address_index_int, change_bool, xpub_hexstr):
80+ path_list = get_path_from_index(account_index_int, address_index_int, change_bool)['path']
81+ child_xpub_hexstr = get_child_xpub(xpub_hexstr, path_list)
82+ child_public_key_hexstr = get_public_key(child_xpub_hexstr)
83+ child_public_key_byte = bytes.fromhex(child_public_key_hexstr)
84+
85+ ripemd160 = hashlib.new('ripemd160')
86+ ripemd160.update(child_public_key_byte)
87+ public_key_hash_hexstr = ripemd160.hexdigest()
88+ control_program_hexstr = '0014' + public_key_hash_hexstr
89+ return control_program_hexstr
90+
91+
92+# get_address create address
93+# You can get more test data from: https://gist.github.com/zcc0721/8f52d0a80a0a9f964e9d9d9a50e940c5
94+# Please attention:
95+# network_str: mainnet/testnet/solonet
96+# test data 1:
97+# control_program_str: 001431f2b90b469e89361225aae370f73e5473b9852b
98+# network_str: mainnet
99+# address_str: bm1qx8etjz6xn6ynvy394t3hpae723emnpft3nrwej
100+# test data 2:
101+# control_program_str: 0014eefb8d0688d7960dfbd79bb3aa1bcaa3ec34415d
102+# network_str: mainnet
103+# address_str: bm1qamac6p5g67tqm77hnwe65x7250krgs2avl0nr6
104+# test data 3:
105+# control_program_str: 0014eefb8d0688d7960dfbd79bb3aa1bcaa3ec34415d
106+# network_str: testnet
107+# address_str: tm1qamac6p5g67tqm77hnwe65x7250krgs2agfwhrt
108+# test data 4:
109+# control_program_str: 0014d234314ea1533dee584417ecb922f904b8dd6c6b
110+# network_str: testnet
111+# address_str: tm1q6g6rzn4p2v77ukzyzlktjgheqjud6mrt7emxen
112+# test data 5:
113+# control_program_str: 0014eefb8d0688d7960dfbd79bb3aa1bcaa3ec34415d
114+# network_str: solonet
115+# address_str: sm1qamac6p5g67tqm77hnwe65x7250krgs2adw9jr5
116+# test data 6:
117+# control_program_str: 0014052620b86a6d5e07311d5019dffa3864ccc8a6bd
118+# network_str: solonet
119+# address_str: sm1qq5nzpwr2d40qwvga2qval73cvnxv3f4aa9xzh9
120+def get_address(control_program_hexstr, network_str):
121+ public_key_hash_hexstr = control_program_hexstr[4:]
122+ if network_str == 'mainnet':
123+ hrp = 'bm'
124+ elif network_str == 'testnet':
125+ hrp = 'tm'
126+ else:
127+ hrp = 'sm'
128+ address_str = segwit_addr.encode(hrp, 0, bytes.fromhex(public_key_hash_hexstr))
129+ return address_str
130+
131+
132+# get_new_address create address and address qrcode
133+# test data 1:
134+# xpub_str: 8fde12d7c9d6b6cbfbf344edd42f2ed86ae6270b36bab714af5fd5bb3b54adcec4265f1de85ece50f17534e42016ee9404a11fec94ddfadd4a064d27ef3f3f4c
135+# account_index_int: 1
136+# address_index_int: 1
137+# change_bool: False
138+# network_str: solonet
139+# path: m/44/153/1/0/1
140+# control_program: 00147640f3c34fe4b2b298e54e54a4692a47ce47aa5e
141+# address: sm1qweq08s60ujet9x89fe22g6f2gl8y02j7lgr5v5
142+# address_base64: /9j/4AAQSkZJRgABAQ...
143+# test data 2:
144+# xpub_str: 8fde12d7c9d6b6cbfbf344edd42f2ed86ae6270b36bab714af5fd5bb3b54adcec4265f1de85ece50f17534e42016ee9404a11fec94ddfadd4a064d27ef3f3f4c
145+# account_index_int: 12
146+# address_index_int: 3
147+# change_bool: True
148+# network_str: mainnet
149+# path: m/44/153/12/1/3
150+# control_program: 001458b1477abc46ef81905d25011d36389c0788984b
151+# address: bm1qtzc5w74ugmhcryzay5q36d3cnsrc3xztzw6u4y
152+# address_base64: /9j/4AAQSkZJRgABAQA...
153+# test data 3:
154+# xpub_str: 8fde12d7c9d6b6cbfbf344edd42f2ed86ae6270b36bab714af5fd5bb3b54adcec4265f1de85ece50f17534e42016ee9404a11fec94ddfadd4a064d27ef3f3f4c
155+# account_index_int: 200
156+# address_index_int: 1
157+# change_bool: True
158+# network_str: mainnet
159+# path: m/44/153/200/1/1
160+# control_program: 00144e5c8757c612c21aa2a0c55f1f8e2ab57cfdefca
161+# address: bm1qfewgw47xztpp4g4qc403lr32k470mm724cphhp
162+# address_base64: /9j/4AAQSkZJRgABAQA...
163+def get_new_address(xpub_hexstr, account_index_int, address_index_int, change_bool, network_str):
164+ path_str = get_path_from_index(account_index_int, address_index_int, change_bool)['path_str']
165+ control_program_hexstr = get_control_program(account_index_int, address_index_int, change_bool, xpub_hexstr)
166+ address_str = get_address(control_program_hexstr, network_str)
167+ address_base64 = create_qrcode_base64(address_str)
168+ return {
169+ "path": path_str,
170+ "control_program": control_program_hexstr,
171+ "address": address_str,
172+ "address_base64": address_base64
173+ }
174+
--- /dev/null
+++ b/pybtm/segwit_addr.py
@@ -0,0 +1,125 @@
1+# Copyright (c) 2017 Pieter Wuille
2+#
3+# Permission is hereby granted, free of charge, to any person obtaining a copy
4+# of this software and associated documentation files (the "Software"), to deal
5+# in the Software without restriction, including without limitation the rights
6+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+# copies of the Software, and to permit persons to whom the Software is
8+# furnished to do so, subject to the following conditions:
9+#
10+# The above copyright notice and this permission notice shall be included in
11+# all copies or substantial portions of the Software.
12+#
13+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+# THE SOFTWARE.
20+#
21+# Please Ref: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
22+
23+"""Reference implementation for Bech32 and segwit addresses."""
24+
25+
26+CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
27+
28+
29+def bech32_polymod(values):
30+ """Internal function that computes the Bech32 checksum."""
31+ generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
32+ chk = 1
33+ for value in values:
34+ top = chk >> 25
35+ chk = (chk & 0x1ffffff) << 5 ^ value
36+ for i in range(5):
37+ chk ^= generator[i] if ((top >> i) & 1) else 0
38+ return chk
39+
40+
41+def bech32_hrp_expand(hrp):
42+ """Expand the HRP into values for checksum computation."""
43+ return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
44+
45+
46+def bech32_verify_checksum(hrp, data):
47+ """Verify a checksum given HRP and converted data characters."""
48+ return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1
49+
50+
51+def bech32_create_checksum(hrp, data):
52+ """Compute the checksum values given HRP and data."""
53+ values = bech32_hrp_expand(hrp) + data
54+ polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1
55+ return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
56+
57+
58+def bech32_encode(hrp, data):
59+ """Compute a Bech32 string given HRP and data values."""
60+ combined = data + bech32_create_checksum(hrp, data)
61+ return hrp + '1' + ''.join([CHARSET[d] for d in combined])
62+
63+
64+def bech32_decode(bech):
65+ """Validate a Bech32 string, and determine HRP and data."""
66+ if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
67+ (bech.lower() != bech and bech.upper() != bech)):
68+ return (None, None)
69+ bech = bech.lower()
70+ pos = bech.rfind('1')
71+ if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:
72+ return (None, None)
73+ if not all(x in CHARSET for x in bech[pos+1:]):
74+ return (None, None)
75+ hrp = bech[:pos]
76+ data = [CHARSET.find(x) for x in bech[pos+1:]]
77+ if not bech32_verify_checksum(hrp, data):
78+ return (None, None)
79+ return (hrp, data[:-6])
80+
81+
82+def convertbits(data, frombits, tobits, pad=True):
83+ """General power-of-2 base conversion."""
84+ acc = 0
85+ bits = 0
86+ ret = []
87+ maxv = (1 << tobits) - 1
88+ max_acc = (1 << (frombits + tobits - 1)) - 1
89+ for value in data:
90+ if value < 0 or (value >> frombits):
91+ return None
92+ acc = ((acc << frombits) | value) & max_acc
93+ bits += frombits
94+ while bits >= tobits:
95+ bits -= tobits
96+ ret.append((acc >> bits) & maxv)
97+ if pad:
98+ if bits:
99+ ret.append((acc << (tobits - bits)) & maxv)
100+ elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
101+ return None
102+ return ret
103+
104+
105+def decode(hrp, addr):
106+ """Decode a segwit address."""
107+ hrpgot, data = bech32_decode(addr)
108+ if hrpgot != hrp:
109+ return (None, None)
110+ decoded = convertbits(data[1:], 5, 8, False)
111+ if decoded is None or len(decoded) < 2 or len(decoded) > 40:
112+ return (None, None)
113+ if data[0] > 16:
114+ return (None, None)
115+ if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:
116+ return (None, None)
117+ return (data[0], decoded)
118+
119+
120+def encode(hrp, witver, witprog):
121+ """Encode a segwit address."""
122+ ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5))
123+ if decode(hrp, ret) == (None, None):
124+ return None
125+ return ret
\ No newline at end of file
--- a/pybtm/utils.py
+++ b/pybtm/utils.py
@@ -17,9 +17,7 @@ def create_qrcode_base64(s):
1717 buffered = BytesIO()
1818 img.save(buffered, format="JPEG")
1919 base64_str = pybase64.b64encode(buffered.getvalue()).decode("utf-8")
20- return {
21- "base64": base64_str
22- }
20+ return base64_str
2321
2422
2523 if six.PY3:
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
55
66 setuptools.setup(
77 name="pybtm",
8- version="0.0.16",
8+ version="0.0.17",
99 author="zcc0721",
1010 author_email="zcc0721@foxmail.com",
1111 description="Python3 implementation of the Bytom protocol.",
Show on old repository browser