2016-11-25 21:53:55 +00:00
|
|
|
# This file is part of the TREZOR project.
|
|
|
|
#
|
|
|
|
# Copyright (C) 2012-2016 Marek Palatinus <slush@satoshilabs.com>
|
|
|
|
# Copyright (C) 2012-2016 Pavol Rusnak <stick@satoshilabs.com>
|
|
|
|
# Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
|
|
|
|
#
|
|
|
|
# This library is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This library is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Lesser General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
|
|
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2014-01-14 13:29:18 +00:00
|
|
|
import hashlib
|
2014-02-01 10:29:44 +00:00
|
|
|
import binascii
|
2016-06-27 21:17:20 +00:00
|
|
|
import struct
|
2016-05-20 17:18:33 +00:00
|
|
|
import sys
|
2014-01-14 13:29:18 +00:00
|
|
|
|
2016-06-27 21:17:20 +00:00
|
|
|
if sys.version_info < (3,):
|
|
|
|
def byteindex(data, index):
|
|
|
|
return ord(data[index])
|
2017-06-23 19:31:42 +00:00
|
|
|
|
2016-06-27 21:17:20 +00:00
|
|
|
def iterbytes(data):
|
2017-06-23 19:31:42 +00:00
|
|
|
return (ord(char) for char in data)
|
2016-06-27 21:17:20 +00:00
|
|
|
else:
|
2017-06-23 19:31:42 +00:00
|
|
|
def byteindex(data, index):
|
|
|
|
return data[index]
|
2016-06-27 21:17:20 +00:00
|
|
|
iterbytes = iter
|
|
|
|
|
2017-06-23 19:31:42 +00:00
|
|
|
|
|
|
|
def Hash(data):
|
|
|
|
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
|
|
|
|
|
2014-01-14 13:29:18 +00:00
|
|
|
|
|
|
|
def hash_160(public_key):
|
|
|
|
md = hashlib.new('ripemd160')
|
|
|
|
md.update(hashlib.sha256(public_key).digest())
|
|
|
|
return md.digest()
|
|
|
|
|
|
|
|
|
|
|
|
def hash_160_to_bc_address(h160, address_type):
|
2016-06-27 21:17:20 +00:00
|
|
|
vh160 = struct.pack('<B', address_type) + h160
|
2014-01-14 13:29:18 +00:00
|
|
|
h = Hash(vh160)
|
|
|
|
addr = vh160 + h[0:4]
|
|
|
|
return b58encode(addr)
|
|
|
|
|
2017-06-23 19:31:42 +00:00
|
|
|
|
2014-01-14 13:29:18 +00:00
|
|
|
def compress_pubkey(public_key):
|
2016-06-27 21:17:20 +00:00
|
|
|
if byteindex(public_key, 0) == 4:
|
|
|
|
return bytes((byteindex(public_key, 64) & 1) + 2) + public_key[1:33]
|
2017-11-06 10:09:54 +00:00
|
|
|
raise ValueError("Pubkey is already compressed")
|
2014-01-14 13:29:18 +00:00
|
|
|
|
2017-06-23 19:31:42 +00:00
|
|
|
|
2014-01-14 13:29:18 +00:00
|
|
|
def public_key_to_bc_address(public_key, address_type, compress=True):
|
|
|
|
if public_key[0] == '\x04' and compress:
|
|
|
|
public_key = compress_pubkey(public_key)
|
|
|
|
|
|
|
|
h160 = hash_160(public_key)
|
|
|
|
return hash_160_to_bc_address(h160, address_type)
|
|
|
|
|
2017-06-23 19:31:42 +00:00
|
|
|
|
2013-12-30 22:34:56 +00:00
|
|
|
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|
|
|
__b58base = len(__b58chars)
|
|
|
|
|
2017-06-23 19:31:42 +00:00
|
|
|
|
2013-12-30 22:34:56 +00:00
|
|
|
def b58encode(v):
|
|
|
|
""" encode v, which is a string of bytes, to base58."""
|
|
|
|
|
2016-05-05 02:57:14 +00:00
|
|
|
long_value = 0
|
2016-06-27 21:17:20 +00:00
|
|
|
for c in iterbytes(v):
|
|
|
|
long_value = long_value * 256 + c
|
2013-12-30 22:34:56 +00:00
|
|
|
|
|
|
|
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
|
2016-06-27 21:17:20 +00:00
|
|
|
for c in iterbytes(v):
|
|
|
|
if c == 0:
|
2013-12-30 22:34:56 +00:00
|
|
|
nPad += 1
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
|
|
|
|
return (__b58chars[0] * nPad) + result
|
|
|
|
|
2017-06-23 19:31:42 +00:00
|
|
|
|
2013-12-30 22:34:56 +00:00
|
|
|
def b58decode(v, length):
|
|
|
|
""" decode v into a string of len bytes."""
|
2016-05-05 02:57:14 +00:00
|
|
|
long_value = 0
|
2013-12-30 22:34:56 +00:00
|
|
|
for (i, c) in enumerate(v[::-1]):
|
|
|
|
long_value += __b58chars.find(c) * (__b58base ** i)
|
|
|
|
|
2016-06-27 21:17:20 +00:00
|
|
|
result = b''
|
2013-12-30 22:34:56 +00:00
|
|
|
while long_value >= 256:
|
|
|
|
div, mod = divmod(long_value, 256)
|
2016-06-27 21:17:20 +00:00
|
|
|
result = struct.pack('B', mod) + result
|
2013-12-30 22:34:56 +00:00
|
|
|
long_value = div
|
2016-06-27 21:17:20 +00:00
|
|
|
result = struct.pack('B', long_value) + result
|
2013-12-30 22:34:56 +00:00
|
|
|
|
|
|
|
nPad = 0
|
|
|
|
for c in v:
|
|
|
|
if c == __b58chars[0]:
|
|
|
|
nPad += 1
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
|
2016-06-27 21:17:20 +00:00
|
|
|
result = b'\x00' * nPad + result
|
2013-12-30 22:34:56 +00:00
|
|
|
if length is not None and len(result) != length:
|
|
|
|
return None
|
|
|
|
|
2016-06-27 21:17:20 +00:00
|
|
|
return result
|
2014-02-01 10:29:44 +00:00
|
|
|
|
2017-06-23 19:31:42 +00:00
|
|
|
|
2014-02-01 10:29:44 +00:00
|
|
|
def monkeypatch_google_protobuf_text_format():
|
|
|
|
# monkeypatching: text formatting of protobuf messages
|
|
|
|
import google.protobuf.text_format
|
|
|
|
import google.protobuf.descriptor
|
|
|
|
|
|
|
|
_oldPrintFieldValue = google.protobuf.text_format.PrintFieldValue
|
|
|
|
|
2015-02-21 11:52:01 +00:00
|
|
|
def _customPrintFieldValue(field, value, out, indent=0, as_utf8=False, as_one_line=False, pointy_brackets=False, float_format=None):
|
2014-03-01 11:08:43 +00:00
|
|
|
if field.type == google.protobuf.descriptor.FieldDescriptor.TYPE_BYTES:
|
|
|
|
_oldPrintFieldValue(field, 'hex(%s)' % binascii.hexlify(value), out, indent, as_utf8, as_one_line)
|
2014-02-01 10:29:44 +00:00
|
|
|
else:
|
|
|
|
_oldPrintFieldValue(field, value, out, indent, as_utf8, as_one_line)
|
|
|
|
|
|
|
|
google.protobuf.text_format.PrintFieldValue = _customPrintFieldValue
|