forked from grazcoin/mastercoin-tools
-
Notifications
You must be signed in to change notification settings - Fork 12
/
msc_utils_bitcoin.py
160 lines (138 loc) · 5.02 KB
/
msc_utils_bitcoin.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
#!/usr/bin/python
#######################################################
# #
# Copyright Masterchain Grazcoin Grimentz 2013-2014 #
# https://github.com/grazcoin/mastercoin-tools #
# https://masterchain.info #
# masterchain@@bitmessage.ch #
# License AGPLv3 #
# #
#######################################################
import json
import hashlib
import re
from ecdsa import curves, ecdsa
# taken from https://github.com/warner/python-ecdsa
from pycoin import encoding
# taken from https://github.com/richardkiss/pycoin
from msc_utils_general import *
blocks_consider_new=3
blocks_consider_mature=6
max_currency_value=21000000
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
def to_satoshi(value):
return int(float(value)*100000000+0.5)
def from_satoshi(value):
float_number=int(value)/100000000.0
return formatted_decimal(float_number)
def from_hex_satoshi(value):
float_number=int(value,16)/100000000.0
return formatted_decimal(float_number)
def b58encode(v):
""" encode v, which is a string of bytes, to base58. """
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += (256**i) * ord(c)
result = ''
while long_value >= __b58base:
div, mod = divmod(long_value, __b58base)
result = __b58chars[mod] + result
long_value = div
result = __b58chars[long_value] + result
# Bitcoin does a little leading-zero-compression:
# leading 0-bytes in the input become leading-1s
nPad = 0
for c in v:
if c == '\0': nPad += 1
else: break
return (__b58chars[0]*nPad) + result
def b58decode(v, length):
""" decode v into a string of len bytes """
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += __b58chars.find(c) * (__b58base**i)
result = ''
while long_value >= 256:
div, mod = divmod(long_value, 256)
result = chr(mod) + result
long_value = div
result = chr(long_value) + result
nPad = 0
for c in v:
if c == __b58chars[0]: nPad += 1
else: break
result = chr(0)*nPad + result
if length is not None and len(result) != length:
return None
return result
def hash_160_to_bc_address(h160):
vh160 = '\x00'+h160 # \x00 is version 0
h3=hashlib.sha256(hashlib.sha256(vh160).digest()).digest()
addr=vh160+h3[0:4]
return b58encode(addr)
def bc_address_to_hash_160(addr):
vh160_with_checksum=b58decode(addr, 25)
return vh160_with_checksum[1:-4]
def get_sha256(string):
return hashlib.sha256(string).hexdigest()
def is_script_multisig(script):
# check that the script looks like:
# m [ pubkey1 ] .. [ hex ] n checkmultisig
return script.endswith('checkmultisig')
def is_script_paytopubkeyhash(script):
# check that the script looks like:
# dup hash160 [ hex ] equalverify checksig
return script.startswith('dup hash160') and script.endswith('equalverify checksig')
def is_pubkey_valid(pubkey):
try:
sec=encoding.binascii.unhexlify(pubkey)
public_pair=encoding.sec_to_public_pair(sec)
return curves.ecdsa.point_is_valid(ecdsa.generator_secp256k1, public_pair[0], public_pair[1])
except:
return False
def get_compressed_pubkey_format(pubkey):
public_pair=encoding.sec_to_public_pair(encoding.binascii.unhexlify(pubkey))
return encoding.binascii.hexlify(encoding.public_pair_to_sec(public_pair))
def get_address_of_pubkey(pubkey):
sha = hashlib.sha256(pubkey.decode('hex')).digest()
h = hashlib.new('ripemd160')
h.update(sha)
h160 = h.digest()
return hash_160_to_bc_address(h160)
def get_nearby_valid_pubkey(pubkey):
valid_pubkey=pubkey
l=len(pubkey)
while not is_pubkey_valid(valid_pubkey):
next=hex(int(valid_pubkey, 16)+1).strip('L').split('0x')[1]
valid_pubkey = next.zfill(l)
return valid_pubkey
def is_valid_hash(h):
value=h.strip()
if len(value) != 64:
return None
res=re.findall(r"[0-9a-fA-F]+", value)
if len(res)==1 and res[0]==value:
return value
return None
def is_valid_bitcoin_address(value):
value = value.strip()
if re.match(r'[a-zA-Z1-9]{27,35}$', value) is None:
return False
version = get_bcaddress_version(value)
if version != None:
return True
return False
def get_bcaddress_version(address):
""" Returns None if address is invalid. Otherwise returns integer version of address. """
addr = b58decode(address,25)
if addr is None: return None
version = addr[0]
checksum = addr[-4:]
vh160 = addr[:-4] # Version plus hash160 is what is checksummed
h3=hashlib.sha256(hashlib.sha256(vh160).digest()).digest()
if h3[0:4] == checksum:
return ord(version)
return None
def is_valid_bitcoin_address_or_pubkey(value):
return is_valid_bitcoin_address(value) or is_pubkey_valid(value)