URI: 
       tbitcoin.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
       tbitcoin.py (23572B)
       ---
            1 # -*- coding: utf-8 -*-
            2 #
            3 # Electrum - lightweight Bitcoin client
            4 # Copyright (C) 2011 thomasv@gitorious
            5 #
            6 # Permission is hereby granted, free of charge, to any person
            7 # obtaining a copy of this software and associated documentation files
            8 # (the "Software"), to deal in the Software without restriction,
            9 # including without limitation the rights to use, copy, modify, merge,
           10 # publish, distribute, sublicense, and/or sell copies of the Software,
           11 # and to permit persons to whom the Software is furnished to do so,
           12 # subject to the following conditions:
           13 #
           14 # The above copyright notice and this permission notice shall be
           15 # included in all copies or substantial portions of the Software.
           16 #
           17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
           18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
           19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
           20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
           21 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
           22 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
           23 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
           24 # SOFTWARE.
           25 
           26 import hashlib
           27 from typing import List, Tuple, TYPE_CHECKING, Optional, Union, Sequence
           28 import enum
           29 from enum import IntEnum, Enum
           30 
           31 from .util import bfh, bh2u, BitcoinException, assert_bytes, to_bytes, inv_dict, is_hex_str
           32 from . import version
           33 from . import segwit_addr
           34 from . import constants
           35 from . import ecc
           36 from .crypto import sha256d, sha256, hash_160, hmac_oneshot
           37 
           38 if TYPE_CHECKING:
           39     from .network import Network
           40 
           41 
           42 ################################## transactions
           43 
           44 COINBASE_MATURITY = 100
           45 COIN = 100000000
           46 TOTAL_COIN_SUPPLY_LIMIT_IN_BTC = 21000000
           47 
           48 NLOCKTIME_MIN = 0
           49 NLOCKTIME_BLOCKHEIGHT_MAX = 500_000_000 - 1
           50 NLOCKTIME_MAX = 2 ** 32 - 1
           51 
           52 # supported types of transaction outputs
           53 # TODO kill these with fire
           54 TYPE_ADDRESS = 0
           55 TYPE_PUBKEY  = 1
           56 TYPE_SCRIPT  = 2
           57 
           58 
           59 class opcodes(IntEnum):
           60     # push value
           61     OP_0 = 0x00
           62     OP_FALSE = OP_0
           63     OP_PUSHDATA1 = 0x4c
           64     OP_PUSHDATA2 = 0x4d
           65     OP_PUSHDATA4 = 0x4e
           66     OP_1NEGATE = 0x4f
           67     OP_RESERVED = 0x50
           68     OP_1 = 0x51
           69     OP_TRUE = OP_1
           70     OP_2 = 0x52
           71     OP_3 = 0x53
           72     OP_4 = 0x54
           73     OP_5 = 0x55
           74     OP_6 = 0x56
           75     OP_7 = 0x57
           76     OP_8 = 0x58
           77     OP_9 = 0x59
           78     OP_10 = 0x5a
           79     OP_11 = 0x5b
           80     OP_12 = 0x5c
           81     OP_13 = 0x5d
           82     OP_14 = 0x5e
           83     OP_15 = 0x5f
           84     OP_16 = 0x60
           85 
           86     # control
           87     OP_NOP = 0x61
           88     OP_VER = 0x62
           89     OP_IF = 0x63
           90     OP_NOTIF = 0x64
           91     OP_VERIF = 0x65
           92     OP_VERNOTIF = 0x66
           93     OP_ELSE = 0x67
           94     OP_ENDIF = 0x68
           95     OP_VERIFY = 0x69
           96     OP_RETURN = 0x6a
           97 
           98     # stack ops
           99     OP_TOALTSTACK = 0x6b
          100     OP_FROMALTSTACK = 0x6c
          101     OP_2DROP = 0x6d
          102     OP_2DUP = 0x6e
          103     OP_3DUP = 0x6f
          104     OP_2OVER = 0x70
          105     OP_2ROT = 0x71
          106     OP_2SWAP = 0x72
          107     OP_IFDUP = 0x73
          108     OP_DEPTH = 0x74
          109     OP_DROP = 0x75
          110     OP_DUP = 0x76
          111     OP_NIP = 0x77
          112     OP_OVER = 0x78
          113     OP_PICK = 0x79
          114     OP_ROLL = 0x7a
          115     OP_ROT = 0x7b
          116     OP_SWAP = 0x7c
          117     OP_TUCK = 0x7d
          118 
          119     # splice ops
          120     OP_CAT = 0x7e
          121     OP_SUBSTR = 0x7f
          122     OP_LEFT = 0x80
          123     OP_RIGHT = 0x81
          124     OP_SIZE = 0x82
          125 
          126     # bit logic
          127     OP_INVERT = 0x83
          128     OP_AND = 0x84
          129     OP_OR = 0x85
          130     OP_XOR = 0x86
          131     OP_EQUAL = 0x87
          132     OP_EQUALVERIFY = 0x88
          133     OP_RESERVED1 = 0x89
          134     OP_RESERVED2 = 0x8a
          135 
          136     # numeric
          137     OP_1ADD = 0x8b
          138     OP_1SUB = 0x8c
          139     OP_2MUL = 0x8d
          140     OP_2DIV = 0x8e
          141     OP_NEGATE = 0x8f
          142     OP_ABS = 0x90
          143     OP_NOT = 0x91
          144     OP_0NOTEQUAL = 0x92
          145 
          146     OP_ADD = 0x93
          147     OP_SUB = 0x94
          148     OP_MUL = 0x95
          149     OP_DIV = 0x96
          150     OP_MOD = 0x97
          151     OP_LSHIFT = 0x98
          152     OP_RSHIFT = 0x99
          153 
          154     OP_BOOLAND = 0x9a
          155     OP_BOOLOR = 0x9b
          156     OP_NUMEQUAL = 0x9c
          157     OP_NUMEQUALVERIFY = 0x9d
          158     OP_NUMNOTEQUAL = 0x9e
          159     OP_LESSTHAN = 0x9f
          160     OP_GREATERTHAN = 0xa0
          161     OP_LESSTHANOREQUAL = 0xa1
          162     OP_GREATERTHANOREQUAL = 0xa2
          163     OP_MIN = 0xa3
          164     OP_MAX = 0xa4
          165 
          166     OP_WITHIN = 0xa5
          167 
          168     # crypto
          169     OP_RIPEMD160 = 0xa6
          170     OP_SHA1 = 0xa7
          171     OP_SHA256 = 0xa8
          172     OP_HASH160 = 0xa9
          173     OP_HASH256 = 0xaa
          174     OP_CODESEPARATOR = 0xab
          175     OP_CHECKSIG = 0xac
          176     OP_CHECKSIGVERIFY = 0xad
          177     OP_CHECKMULTISIG = 0xae
          178     OP_CHECKMULTISIGVERIFY = 0xaf
          179 
          180     # expansion
          181     OP_NOP1 = 0xb0
          182     OP_CHECKLOCKTIMEVERIFY = 0xb1
          183     OP_NOP2 = OP_CHECKLOCKTIMEVERIFY
          184     OP_CHECKSEQUENCEVERIFY = 0xb2
          185     OP_NOP3 = OP_CHECKSEQUENCEVERIFY
          186     OP_NOP4 = 0xb3
          187     OP_NOP5 = 0xb4
          188     OP_NOP6 = 0xb5
          189     OP_NOP7 = 0xb6
          190     OP_NOP8 = 0xb7
          191     OP_NOP9 = 0xb8
          192     OP_NOP10 = 0xb9
          193 
          194     OP_INVALIDOPCODE = 0xff
          195 
          196     def hex(self) -> str:
          197         return bytes([self]).hex()
          198 
          199 
          200 def rev_hex(s: str) -> str:
          201     return bh2u(bfh(s)[::-1])
          202 
          203 
          204 def int_to_hex(i: int, length: int=1) -> str:
          205     """Converts int to little-endian hex string.
          206     `length` is the number of bytes available
          207     """
          208     if not isinstance(i, int):
          209         raise TypeError('{} instead of int'.format(i))
          210     range_size = pow(256, length)
          211     if i < -(range_size//2) or i >= range_size:
          212         raise OverflowError('cannot convert int {} to hex ({} bytes)'.format(i, length))
          213     if i < 0:
          214         # two's complement
          215         i = range_size + i
          216     s = hex(i)[2:].rstrip('L')
          217     s = "0"*(2*length - len(s)) + s
          218     return rev_hex(s)
          219 
          220 def script_num_to_hex(i: int) -> str:
          221     """See CScriptNum in Bitcoin Core.
          222     Encodes an integer as hex, to be used in script.
          223 
          224     ported from https://github.com/bitcoin/bitcoin/blob/8cbc5c4be4be22aca228074f087a374a7ec38be8/src/script/script.h#L326
          225     """
          226     if i == 0:
          227         return ''
          228 
          229     result = bytearray()
          230     neg = i < 0
          231     absvalue = abs(i)
          232     while absvalue > 0:
          233         result.append(absvalue & 0xff)
          234         absvalue >>= 8
          235 
          236     if result[-1] & 0x80:
          237         result.append(0x80 if neg else 0x00)
          238     elif neg:
          239         result[-1] |= 0x80
          240 
          241     return bh2u(result)
          242 
          243 
          244 def var_int(i: int) -> str:
          245     # https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer
          246     # https://github.com/bitcoin/bitcoin/blob/efe1ee0d8d7f82150789f1f6840f139289628a2b/src/serialize.h#L247
          247     # "CompactSize"
          248     assert i >= 0, i
          249     if i<0xfd:
          250         return int_to_hex(i)
          251     elif i<=0xffff:
          252         return "fd"+int_to_hex(i,2)
          253     elif i<=0xffffffff:
          254         return "fe"+int_to_hex(i,4)
          255     else:
          256         return "ff"+int_to_hex(i,8)
          257 
          258 
          259 def witness_push(item: str) -> str:
          260     """Returns data in the form it should be present in the witness.
          261     hex -> hex
          262     """
          263     return var_int(len(item) // 2) + item
          264 
          265 
          266 def _op_push(i: int) -> str:
          267     if i < opcodes.OP_PUSHDATA1:
          268         return int_to_hex(i)
          269     elif i <= 0xff:
          270         return opcodes.OP_PUSHDATA1.hex() + int_to_hex(i, 1)
          271     elif i <= 0xffff:
          272         return opcodes.OP_PUSHDATA2.hex() + int_to_hex(i, 2)
          273     else:
          274         return opcodes.OP_PUSHDATA4.hex() + int_to_hex(i, 4)
          275 
          276 
          277 def push_script(data: str) -> str:
          278     """Returns pushed data to the script, automatically
          279     choosing canonical opcodes depending on the length of the data.
          280     hex -> hex
          281 
          282     ported from https://github.com/btcsuite/btcd/blob/fdc2bc867bda6b351191b5872d2da8270df00d13/txscript/scriptbuilder.go#L128
          283     """
          284     data = bfh(data)
          285     data_len = len(data)
          286 
          287     # "small integer" opcodes
          288     if data_len == 0 or data_len == 1 and data[0] == 0:
          289         return opcodes.OP_0.hex()
          290     elif data_len == 1 and data[0] <= 16:
          291         return bh2u(bytes([opcodes.OP_1 - 1 + data[0]]))
          292     elif data_len == 1 and data[0] == 0x81:
          293         return opcodes.OP_1NEGATE.hex()
          294 
          295     return _op_push(data_len) + bh2u(data)
          296 
          297 
          298 def add_number_to_script(i: int) -> bytes:
          299     return bfh(push_script(script_num_to_hex(i)))
          300 
          301 
          302 def construct_witness(items: Sequence[Union[str, int, bytes]]) -> str:
          303     """Constructs a witness from the given stack items."""
          304     witness = var_int(len(items))
          305     for item in items:
          306         if type(item) is int:
          307             item = script_num_to_hex(item)
          308         elif isinstance(item, (bytes, bytearray)):
          309             item = bh2u(item)
          310         else:
          311             assert is_hex_str(item)
          312         witness += witness_push(item)
          313     return witness
          314 
          315 
          316 def construct_script(items: Sequence[Union[str, int, bytes, opcodes]]) -> str:
          317     """Constructs bitcoin script from given items."""
          318     script = ''
          319     for item in items:
          320         if isinstance(item, opcodes):
          321             script += item.hex()
          322         elif type(item) is int:
          323             script += add_number_to_script(item).hex()
          324         elif isinstance(item, (bytes, bytearray)):
          325             script += push_script(item.hex())
          326         elif isinstance(item, str):
          327             assert is_hex_str(item)
          328             script += push_script(item)
          329         else:
          330             raise Exception(f'unexpected item for script: {item!r}')
          331     return script
          332 
          333 
          334 def relayfee(network: 'Network' = None) -> int:
          335     """Returns feerate in sat/kbyte."""
          336     from .simple_config import FEERATE_DEFAULT_RELAY, FEERATE_MAX_RELAY
          337     if network and network.relay_fee is not None:
          338         fee = network.relay_fee
          339     else:
          340         fee = FEERATE_DEFAULT_RELAY
          341     # sanity safeguards, as network.relay_fee is coming from a server:
          342     fee = min(fee, FEERATE_MAX_RELAY)
          343     fee = max(fee, FEERATE_DEFAULT_RELAY)
          344     return fee
          345 
          346 
          347 # see https://github.com/bitcoin/bitcoin/blob/a62f0ed64f8bbbdfe6467ac5ce92ef5b5222d1bd/src/policy/policy.cpp#L14
          348 DUST_LIMIT_DEFAULT_SAT_LEGACY = 546
          349 DUST_LIMIT_DEFAULT_SAT_SEGWIT = 294
          350 
          351 
          352 def dust_threshold(network: 'Network' = None) -> int:
          353     """Returns the dust limit in satoshis."""
          354     # Change <= dust threshold is added to the tx fee
          355     dust_lim = 182 * 3 * relayfee(network)  # in msat
          356     # convert to sat, but round up:
          357     return (dust_lim // 1000) + (dust_lim % 1000 > 0)
          358 
          359 
          360 def hash_encode(x: bytes) -> str:
          361     return bh2u(x[::-1])
          362 
          363 
          364 def hash_decode(x: str) -> bytes:
          365     return bfh(x)[::-1]
          366 
          367 
          368 ############ functions from pywallet #####################
          369 
          370 def hash160_to_b58_address(h160: bytes, addrtype: int) -> str:
          371     s = bytes([addrtype]) + h160
          372     s = s + sha256d(s)[0:4]
          373     return base_encode(s, base=58)
          374 
          375 
          376 def b58_address_to_hash160(addr: str) -> Tuple[int, bytes]:
          377     addr = to_bytes(addr, 'ascii')
          378     _bytes = DecodeBase58Check(addr)
          379     if len(_bytes) != 21:
          380         raise Exception(f'expected 21 payload bytes in base58 address. got: {len(_bytes)}')
          381     return _bytes[0], _bytes[1:21]
          382 
          383 
          384 def hash160_to_p2pkh(h160: bytes, *, net=None) -> str:
          385     if net is None: net = constants.net
          386     return hash160_to_b58_address(h160, net.ADDRTYPE_P2PKH)
          387 
          388 def hash160_to_p2sh(h160: bytes, *, net=None) -> str:
          389     if net is None: net = constants.net
          390     return hash160_to_b58_address(h160, net.ADDRTYPE_P2SH)
          391 
          392 def public_key_to_p2pkh(public_key: bytes, *, net=None) -> str:
          393     if net is None: net = constants.net
          394     return hash160_to_p2pkh(hash_160(public_key), net=net)
          395 
          396 def hash_to_segwit_addr(h: bytes, witver: int, *, net=None) -> str:
          397     if net is None: net = constants.net
          398     return segwit_addr.encode(net.SEGWIT_HRP, witver, h)
          399 
          400 def public_key_to_p2wpkh(public_key: bytes, *, net=None) -> str:
          401     if net is None: net = constants.net
          402     return hash_to_segwit_addr(hash_160(public_key), witver=0, net=net)
          403 
          404 def script_to_p2wsh(script: str, *, net=None) -> str:
          405     if net is None: net = constants.net
          406     return hash_to_segwit_addr(sha256(bfh(script)), witver=0, net=net)
          407 
          408 def p2wpkh_nested_script(pubkey: str) -> str:
          409     pkh = hash_160(bfh(pubkey))
          410     return construct_script([0, pkh])
          411 
          412 def p2wsh_nested_script(witness_script: str) -> str:
          413     wsh = sha256(bfh(witness_script))
          414     return construct_script([0, wsh])
          415 
          416 def pubkey_to_address(txin_type: str, pubkey: str, *, net=None) -> str:
          417     if net is None: net = constants.net
          418     if txin_type == 'p2pkh':
          419         return public_key_to_p2pkh(bfh(pubkey), net=net)
          420     elif txin_type == 'p2wpkh':
          421         return public_key_to_p2wpkh(bfh(pubkey), net=net)
          422     elif txin_type == 'p2wpkh-p2sh':
          423         scriptSig = p2wpkh_nested_script(pubkey)
          424         return hash160_to_p2sh(hash_160(bfh(scriptSig)), net=net)
          425     else:
          426         raise NotImplementedError(txin_type)
          427 
          428 
          429 # TODO this method is confusingly named
          430 def redeem_script_to_address(txin_type: str, scriptcode: str, *, net=None) -> str:
          431     if net is None: net = constants.net
          432     if txin_type == 'p2sh':
          433         # given scriptcode is a redeem_script
          434         return hash160_to_p2sh(hash_160(bfh(scriptcode)), net=net)
          435     elif txin_type == 'p2wsh':
          436         # given scriptcode is a witness_script
          437         return script_to_p2wsh(scriptcode, net=net)
          438     elif txin_type == 'p2wsh-p2sh':
          439         # given scriptcode is a witness_script
          440         redeem_script = p2wsh_nested_script(scriptcode)
          441         return hash160_to_p2sh(hash_160(bfh(redeem_script)), net=net)
          442     else:
          443         raise NotImplementedError(txin_type)
          444 
          445 
          446 def script_to_address(script: str, *, net=None) -> str:
          447     from .transaction import get_address_from_output_script
          448     return get_address_from_output_script(bfh(script), net=net)
          449 
          450 
          451 def address_to_script(addr: str, *, net=None) -> str:
          452     if net is None: net = constants.net
          453     if not is_address(addr, net=net):
          454         raise BitcoinException(f"invalid bitcoin address: {addr}")
          455     witver, witprog = segwit_addr.decode(net.SEGWIT_HRP, addr)
          456     if witprog is not None:
          457         if not (0 <= witver <= 16):
          458             raise BitcoinException(f'impossible witness version: {witver}')
          459         return construct_script([witver, bytes(witprog)])
          460     addrtype, hash_160_ = b58_address_to_hash160(addr)
          461     if addrtype == net.ADDRTYPE_P2PKH:
          462         script = pubkeyhash_to_p2pkh_script(bh2u(hash_160_))
          463     elif addrtype == net.ADDRTYPE_P2SH:
          464         script = construct_script([opcodes.OP_HASH160, hash_160_, opcodes.OP_EQUAL])
          465     else:
          466         raise BitcoinException(f'unknown address type: {addrtype}')
          467     return script
          468 
          469 
          470 class OnchainOutputType(Enum):
          471     """Opaque types of scriptPubKeys.
          472     In case of p2sh, p2wsh and similar, no knowledge of redeem script, etc.
          473     """
          474     P2PKH = enum.auto()
          475     P2SH = enum.auto()
          476     WITVER0_P2WPKH = enum.auto()
          477     WITVER0_P2WSH = enum.auto()
          478 
          479 
          480 def address_to_hash(addr: str, *, net=None) -> Tuple[OnchainOutputType, bytes]:
          481     """Return (type, pubkey hash / witness program) for an address."""
          482     if net is None: net = constants.net
          483     if not is_address(addr, net=net):
          484         raise BitcoinException(f"invalid bitcoin address: {addr}")
          485     witver, witprog = segwit_addr.decode(net.SEGWIT_HRP, addr)
          486     if witprog is not None:
          487         if witver != 0:
          488             raise BitcoinException(f"not implemented handling for witver={witver}")
          489         if len(witprog) == 20:
          490             return OnchainOutputType.WITVER0_P2WPKH, bytes(witprog)
          491         elif len(witprog) == 32:
          492             return OnchainOutputType.WITVER0_P2WSH, bytes(witprog)
          493         else:
          494             raise BitcoinException(f"unexpected length for segwit witver=0 witprog: len={len(witprog)}")
          495     addrtype, hash_160_ = b58_address_to_hash160(addr)
          496     if addrtype == net.ADDRTYPE_P2PKH:
          497         return OnchainOutputType.P2PKH, hash_160_
          498     elif addrtype == net.ADDRTYPE_P2SH:
          499         return OnchainOutputType.P2SH, hash_160_
          500     raise BitcoinException(f"unknown address type: {addrtype}")
          501 
          502 
          503 def address_to_scripthash(addr: str) -> str:
          504     script = address_to_script(addr)
          505     return script_to_scripthash(script)
          506 
          507 def script_to_scripthash(script: str) -> str:
          508     h = sha256(bfh(script))[0:32]
          509     return bh2u(bytes(reversed(h)))
          510 
          511 def public_key_to_p2pk_script(pubkey: str) -> str:
          512     return construct_script([pubkey, opcodes.OP_CHECKSIG])
          513 
          514 def pubkeyhash_to_p2pkh_script(pubkey_hash160: str) -> str:
          515     return construct_script([
          516         opcodes.OP_DUP,
          517         opcodes.OP_HASH160,
          518         pubkey_hash160,
          519         opcodes.OP_EQUALVERIFY,
          520         opcodes.OP_CHECKSIG
          521     ])
          522 
          523 
          524 __b58chars = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
          525 assert len(__b58chars) == 58
          526 
          527 __b43chars = b'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:'
          528 assert len(__b43chars) == 43
          529 
          530 
          531 class BaseDecodeError(BitcoinException): pass
          532 
          533 
          534 def base_encode(v: bytes, *, base: int) -> str:
          535     """ encode v, which is a string of bytes, to base58."""
          536     assert_bytes(v)
          537     if base not in (58, 43):
          538         raise ValueError('not supported base: {}'.format(base))
          539     chars = __b58chars
          540     if base == 43:
          541         chars = __b43chars
          542     long_value = 0
          543     power_of_base = 1
          544     for c in v[::-1]:
          545         # naive but slow variant:   long_value += (256**i) * c
          546         long_value += power_of_base * c
          547         power_of_base <<= 8
          548     result = bytearray()
          549     while long_value >= base:
          550         div, mod = divmod(long_value, base)
          551         result.append(chars[mod])
          552         long_value = div
          553     result.append(chars[long_value])
          554     # Bitcoin does a little leading-zero-compression:
          555     # leading 0-bytes in the input become leading-1s
          556     nPad = 0
          557     for c in v:
          558         if c == 0x00:
          559             nPad += 1
          560         else:
          561             break
          562     result.extend([chars[0]] * nPad)
          563     result.reverse()
          564     return result.decode('ascii')
          565 
          566 
          567 def base_decode(v: Union[bytes, str], *, base: int, length: int = None) -> Optional[bytes]:
          568     """ decode v into a string of len bytes."""
          569     # assert_bytes(v)
          570     v = to_bytes(v, 'ascii')
          571     if base not in (58, 43):
          572         raise ValueError('not supported base: {}'.format(base))
          573     chars = __b58chars
          574     if base == 43:
          575         chars = __b43chars
          576     long_value = 0
          577     power_of_base = 1
          578     for c in v[::-1]:
          579         digit = chars.find(bytes([c]))
          580         if digit == -1:
          581             raise BaseDecodeError('Forbidden character {} for base {}'.format(c, base))
          582         # naive but slow variant:   long_value += digit * (base**i)
          583         long_value += digit * power_of_base
          584         power_of_base *= base
          585     result = bytearray()
          586     while long_value >= 256:
          587         div, mod = divmod(long_value, 256)
          588         result.append(mod)
          589         long_value = div
          590     result.append(long_value)
          591     nPad = 0
          592     for c in v:
          593         if c == chars[0]:
          594             nPad += 1
          595         else:
          596             break
          597     result.extend(b'\x00' * nPad)
          598     if length is not None and len(result) != length:
          599         return None
          600     result.reverse()
          601     return bytes(result)
          602 
          603 
          604 class InvalidChecksum(BaseDecodeError):
          605     pass
          606 
          607 
          608 def EncodeBase58Check(vchIn: bytes) -> str:
          609     hash = sha256d(vchIn)
          610     return base_encode(vchIn + hash[0:4], base=58)
          611 
          612 
          613 def DecodeBase58Check(psz: Union[bytes, str]) -> bytes:
          614     vchRet = base_decode(psz, base=58)
          615     payload = vchRet[0:-4]
          616     csum_found = vchRet[-4:]
          617     csum_calculated = sha256d(payload)[0:4]
          618     if csum_calculated != csum_found:
          619         raise InvalidChecksum(f'calculated {bh2u(csum_calculated)}, found {bh2u(csum_found)}')
          620     else:
          621         return payload
          622 
          623 
          624 # backwards compat
          625 # extended WIF for segwit (used in 3.0.x; but still used internally)
          626 # the keys in this dict should be a superset of what Imported Wallets can import
          627 WIF_SCRIPT_TYPES = {
          628     'p2pkh':0,
          629     'p2wpkh':1,
          630     'p2wpkh-p2sh':2,
          631     'p2sh':5,
          632     'p2wsh':6,
          633     'p2wsh-p2sh':7
          634 }
          635 WIF_SCRIPT_TYPES_INV = inv_dict(WIF_SCRIPT_TYPES)
          636 
          637 
          638 def is_segwit_script_type(txin_type: str) -> bool:
          639     return txin_type in ('p2wpkh', 'p2wpkh-p2sh', 'p2wsh', 'p2wsh-p2sh')
          640 
          641 
          642 def serialize_privkey(secret: bytes, compressed: bool, txin_type: str, *,
          643                       internal_use: bool = False) -> str:
          644     # we only export secrets inside curve range
          645     secret = ecc.ECPrivkey.normalize_secret_bytes(secret)
          646     if internal_use:
          647         prefix = bytes([(WIF_SCRIPT_TYPES[txin_type] + constants.net.WIF_PREFIX) & 255])
          648     else:
          649         prefix = bytes([constants.net.WIF_PREFIX])
          650     suffix = b'\01' if compressed else b''
          651     vchIn = prefix + secret + suffix
          652     base58_wif = EncodeBase58Check(vchIn)
          653     if internal_use:
          654         return base58_wif
          655     else:
          656         return '{}:{}'.format(txin_type, base58_wif)
          657 
          658 
          659 def deserialize_privkey(key: str) -> Tuple[str, bytes, bool]:
          660     if is_minikey(key):
          661         return 'p2pkh', minikey_to_private_key(key), False
          662 
          663     txin_type = None
          664     if ':' in key:
          665         txin_type, key = key.split(sep=':', maxsplit=1)
          666         if txin_type not in WIF_SCRIPT_TYPES:
          667             raise BitcoinException('unknown script type: {}'.format(txin_type))
          668     try:
          669         vch = DecodeBase58Check(key)
          670     except Exception as e:
          671         neutered_privkey = str(key)[:3] + '..' + str(key)[-2:]
          672         raise BaseDecodeError(f"cannot deserialize privkey {neutered_privkey}") from e
          673 
          674     if txin_type is None:
          675         # keys exported in version 3.0.x encoded script type in first byte
          676         prefix_value = vch[0] - constants.net.WIF_PREFIX
          677         try:
          678             txin_type = WIF_SCRIPT_TYPES_INV[prefix_value]
          679         except KeyError as e:
          680             raise BitcoinException('invalid prefix ({}) for WIF key (1)'.format(vch[0])) from None
          681     else:
          682         # all other keys must have a fixed first byte
          683         if vch[0] != constants.net.WIF_PREFIX:
          684             raise BitcoinException('invalid prefix ({}) for WIF key (2)'.format(vch[0]))
          685 
          686     if len(vch) not in [33, 34]:
          687         raise BitcoinException('invalid vch len for WIF key: {}'.format(len(vch)))
          688     compressed = False
          689     if len(vch) == 34:
          690         if vch[33] == 0x01:
          691             compressed = True
          692         else:
          693             raise BitcoinException(f'invalid WIF key. length suggests compressed pubkey, '
          694                                    f'but last byte is {vch[33]} != 0x01')
          695 
          696     if is_segwit_script_type(txin_type) and not compressed:
          697         raise BitcoinException('only compressed public keys can be used in segwit scripts')
          698 
          699     secret_bytes = vch[1:33]
          700     # we accept secrets outside curve range; cast into range here:
          701     secret_bytes = ecc.ECPrivkey.normalize_secret_bytes(secret_bytes)
          702     return txin_type, secret_bytes, compressed
          703 
          704 
          705 def is_compressed_privkey(sec: str) -> bool:
          706     return deserialize_privkey(sec)[2]
          707 
          708 
          709 def address_from_private_key(sec: str) -> str:
          710     txin_type, privkey, compressed = deserialize_privkey(sec)
          711     public_key = ecc.ECPrivkey(privkey).get_public_key_hex(compressed=compressed)
          712     return pubkey_to_address(txin_type, public_key)
          713 
          714 def is_segwit_address(addr: str, *, net=None) -> bool:
          715     if net is None: net = constants.net
          716     try:
          717         witver, witprog = segwit_addr.decode(net.SEGWIT_HRP, addr)
          718     except Exception as e:
          719         return False
          720     return witprog is not None
          721 
          722 def is_b58_address(addr: str, *, net=None) -> bool:
          723     if net is None: net = constants.net
          724     try:
          725         # test length, checksum, encoding:
          726         addrtype, h = b58_address_to_hash160(addr)
          727     except Exception as e:
          728         return False
          729     if addrtype not in [net.ADDRTYPE_P2PKH, net.ADDRTYPE_P2SH]:
          730         return False
          731     return True
          732 
          733 def is_address(addr: str, *, net=None) -> bool:
          734     if net is None: net = constants.net
          735     return is_segwit_address(addr, net=net) \
          736            or is_b58_address(addr, net=net)
          737 
          738 
          739 def is_private_key(key: str, *, raise_on_error=False) -> bool:
          740     try:
          741         deserialize_privkey(key)
          742         return True
          743     except BaseException as e:
          744         if raise_on_error:
          745             raise
          746         return False
          747 
          748 
          749 ########### end pywallet functions #######################
          750 
          751 def is_minikey(text: str) -> bool:
          752     # Minikeys are typically 22 or 30 characters, but this routine
          753     # permits any length of 20 or more provided the minikey is valid.
          754     # A valid minikey must begin with an 'S', be in base58, and when
          755     # suffixed with '?' have its SHA256 hash begin with a zero byte.
          756     # They are widely used in Casascius physical bitcoins.
          757     return (len(text) >= 20 and text[0] == 'S'
          758             and all(ord(c) in __b58chars for c in text)
          759             and sha256(text + '?')[0] == 0x00)
          760 
          761 def minikey_to_private_key(text: str) -> bytes:
          762     return sha256(text)