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 26import hashlib 27from typing import List, Tuple, TYPE_CHECKING, Optional, Union, Sequence 28import enum 29from enum import IntEnum, Enum 30 31from .util import bfh, bh2u, BitcoinException, assert_bytes, to_bytes, inv_dict, is_hex_str 32from . import version 33from . import segwit_addr 34from . import constants 35from . import ecc 36from .crypto import sha256d, sha256, hash_160, hmac_oneshot 37 38if TYPE_CHECKING: 39 from .network import Network 40 41 42################################## transactions 43 44COINBASE_MATURITY = 100 45COIN = 100000000 46TOTAL_COIN_SUPPLY_LIMIT_IN_BTC = 21000000 47 48NLOCKTIME_MIN = 0 49NLOCKTIME_BLOCKHEIGHT_MAX = 500_000_000 - 1 50NLOCKTIME_MAX = 2 ** 32 - 1 51 52# supported types of transaction outputs 53# TODO kill these with fire 54TYPE_ADDRESS = 0 55TYPE_PUBKEY = 1 56TYPE_SCRIPT = 2 57 58 59class 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 200def rev_hex(s: str) -> str: 201 return bh2u(bfh(s)[::-1]) 202 203 204def 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 220def 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 244def 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 259def 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 266def _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 277def 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 298def make_op_return(x:bytes) -> bytes: 299 return bytes([opcodes.OP_RETURN]) + bytes.fromhex(push_script(x.hex())) 300 301 302def add_number_to_script(i: int) -> bytes: 303 return bfh(push_script(script_num_to_hex(i))) 304 305 306def construct_witness(items: Sequence[Union[str, int, bytes]]) -> str: 307 """Constructs a witness from the given stack items.""" 308 witness = var_int(len(items)) 309 for item in items: 310 if type(item) is int: 311 item = script_num_to_hex(item) 312 elif isinstance(item, (bytes, bytearray)): 313 item = bh2u(item) 314 else: 315 assert is_hex_str(item) 316 witness += witness_push(item) 317 return witness 318 319 320def construct_script(items: Sequence[Union[str, int, bytes, opcodes]]) -> str: 321 """Constructs bitcoin script from given items.""" 322 script = '' 323 for item in items: 324 if isinstance(item, opcodes): 325 script += item.hex() 326 elif type(item) is int: 327 script += add_number_to_script(item).hex() 328 elif isinstance(item, (bytes, bytearray)): 329 script += push_script(item.hex()) 330 elif isinstance(item, str): 331 assert is_hex_str(item) 332 script += push_script(item) 333 else: 334 raise Exception(f'unexpected item for script: {item!r}') 335 return script 336 337 338def relayfee(network: 'Network' = None) -> int: 339 """Returns feerate in sat/kbyte.""" 340 from .simple_config import FEERATE_DEFAULT_RELAY, FEERATE_MAX_RELAY 341 if network and network.relay_fee is not None: 342 fee = network.relay_fee 343 else: 344 fee = FEERATE_DEFAULT_RELAY 345 # sanity safeguards, as network.relay_fee is coming from a server: 346 fee = min(fee, FEERATE_MAX_RELAY) 347 fee = max(fee, FEERATE_DEFAULT_RELAY) 348 return fee 349 350 351# see https://github.com/bitcoin/bitcoin/blob/a62f0ed64f8bbbdfe6467ac5ce92ef5b5222d1bd/src/policy/policy.cpp#L14 352DUST_LIMIT_DEFAULT_SAT_LEGACY = 546 353DUST_LIMIT_DEFAULT_SAT_SEGWIT = 294 354 355 356def dust_threshold(network: 'Network' = None) -> int: 357 """Returns the dust limit in satoshis.""" 358 # Change <= dust threshold is added to the tx fee 359 dust_lim = 182 * 3 * relayfee(network) # in msat 360 # convert to sat, but round up: 361 return (dust_lim // 1000) + (dust_lim % 1000 > 0) 362 363 364def hash_encode(x: bytes) -> str: 365 return bh2u(x[::-1]) 366 367 368def hash_decode(x: str) -> bytes: 369 return bfh(x)[::-1] 370 371 372############ functions from pywallet ##################### 373 374def hash160_to_b58_address(h160: bytes, addrtype: int) -> str: 375 s = bytes([addrtype]) + h160 376 s = s + sha256d(s)[0:4] 377 return base_encode(s, base=58) 378 379 380def b58_address_to_hash160(addr: str) -> Tuple[int, bytes]: 381 addr = to_bytes(addr, 'ascii') 382 _bytes = DecodeBase58Check(addr) 383 if len(_bytes) != 21: 384 raise Exception(f'expected 21 payload bytes in base58 address. got: {len(_bytes)}') 385 return _bytes[0], _bytes[1:21] 386 387 388def hash160_to_p2pkh(h160: bytes, *, net=None) -> str: 389 if net is None: net = constants.net 390 return hash160_to_b58_address(h160, net.ADDRTYPE_P2PKH) 391 392def hash160_to_p2sh(h160: bytes, *, net=None) -> str: 393 if net is None: net = constants.net 394 return hash160_to_b58_address(h160, net.ADDRTYPE_P2SH) 395 396def public_key_to_p2pkh(public_key: bytes, *, net=None) -> str: 397 if net is None: net = constants.net 398 return hash160_to_p2pkh(hash_160(public_key), net=net) 399 400def hash_to_segwit_addr(h: bytes, witver: int, *, net=None) -> str: 401 if net is None: net = constants.net 402 addr = segwit_addr.encode_segwit_address(net.SEGWIT_HRP, witver, h) 403 assert addr is not None 404 return addr 405 406def public_key_to_p2wpkh(public_key: bytes, *, net=None) -> str: 407 if net is None: net = constants.net 408 return hash_to_segwit_addr(hash_160(public_key), witver=0, net=net) 409 410def script_to_p2wsh(script: str, *, net=None) -> str: 411 if net is None: net = constants.net 412 return hash_to_segwit_addr(sha256(bfh(script)), witver=0, net=net) 413 414def p2wpkh_nested_script(pubkey: str) -> str: 415 pkh = hash_160(bfh(pubkey)) 416 return construct_script([0, pkh]) 417 418def p2wsh_nested_script(witness_script: str) -> str: 419 wsh = sha256(bfh(witness_script)) 420 return construct_script([0, wsh]) 421 422def pubkey_to_address(txin_type: str, pubkey: str, *, net=None) -> str: 423 if net is None: net = constants.net 424 if txin_type == 'p2pkh': 425 return public_key_to_p2pkh(bfh(pubkey), net=net) 426 elif txin_type == 'p2wpkh': 427 return public_key_to_p2wpkh(bfh(pubkey), net=net) 428 elif txin_type == 'p2wpkh-p2sh': 429 scriptSig = p2wpkh_nested_script(pubkey) 430 return hash160_to_p2sh(hash_160(bfh(scriptSig)), net=net) 431 else: 432 raise NotImplementedError(txin_type) 433 434 435# TODO this method is confusingly named 436def redeem_script_to_address(txin_type: str, scriptcode: str, *, net=None) -> str: 437 if net is None: net = constants.net 438 if txin_type == 'p2sh': 439 # given scriptcode is a redeem_script 440 return hash160_to_p2sh(hash_160(bfh(scriptcode)), net=net) 441 elif txin_type == 'p2wsh': 442 # given scriptcode is a witness_script 443 return script_to_p2wsh(scriptcode, net=net) 444 elif txin_type == 'p2wsh-p2sh': 445 # given scriptcode is a witness_script 446 redeem_script = p2wsh_nested_script(scriptcode) 447 return hash160_to_p2sh(hash_160(bfh(redeem_script)), net=net) 448 else: 449 raise NotImplementedError(txin_type) 450 451 452def script_to_address(script: str, *, net=None) -> str: 453 from .transaction import get_address_from_output_script 454 return get_address_from_output_script(bfh(script), net=net) 455 456 457def address_to_script(addr: str, *, net=None) -> str: 458 if net is None: net = constants.net 459 if not is_address(addr, net=net): 460 raise BitcoinException(f"invalid bitcoin address: {addr}") 461 witver, witprog = segwit_addr.decode_segwit_address(net.SEGWIT_HRP, addr) 462 if witprog is not None: 463 if not (0 <= witver <= 16): 464 raise BitcoinException(f'impossible witness version: {witver}') 465 return construct_script([witver, bytes(witprog)]) 466 addrtype, hash_160_ = b58_address_to_hash160(addr) 467 if addrtype == net.ADDRTYPE_P2PKH: 468 script = pubkeyhash_to_p2pkh_script(bh2u(hash_160_)) 469 elif addrtype == net.ADDRTYPE_P2SH: 470 script = construct_script([opcodes.OP_HASH160, hash_160_, opcodes.OP_EQUAL]) 471 else: 472 raise BitcoinException(f'unknown address type: {addrtype}') 473 return script 474 475 476class OnchainOutputType(Enum): 477 """Opaque types of scriptPubKeys. 478 In case of p2sh, p2wsh and similar, no knowledge of redeem script, etc. 479 """ 480 P2PKH = enum.auto() 481 P2SH = enum.auto() 482 WITVER0_P2WPKH = enum.auto() 483 WITVER0_P2WSH = enum.auto() 484 485 486def address_to_hash(addr: str, *, net=None) -> Tuple[OnchainOutputType, bytes]: 487 """Return (type, pubkey hash / witness program) for an address.""" 488 if net is None: net = constants.net 489 if not is_address(addr, net=net): 490 raise BitcoinException(f"invalid bitcoin address: {addr}") 491 witver, witprog = segwit_addr.decode_segwit_address(net.SEGWIT_HRP, addr) 492 if witprog is not None: 493 if witver != 0: 494 raise BitcoinException(f"not implemented handling for witver={witver}") 495 if len(witprog) == 20: 496 return OnchainOutputType.WITVER0_P2WPKH, bytes(witprog) 497 elif len(witprog) == 32: 498 return OnchainOutputType.WITVER0_P2WSH, bytes(witprog) 499 else: 500 raise BitcoinException(f"unexpected length for segwit witver=0 witprog: len={len(witprog)}") 501 addrtype, hash_160_ = b58_address_to_hash160(addr) 502 if addrtype == net.ADDRTYPE_P2PKH: 503 return OnchainOutputType.P2PKH, hash_160_ 504 elif addrtype == net.ADDRTYPE_P2SH: 505 return OnchainOutputType.P2SH, hash_160_ 506 raise BitcoinException(f"unknown address type: {addrtype}") 507 508 509def address_to_scripthash(addr: str, *, net=None) -> str: 510 script = address_to_script(addr, net=net) 511 return script_to_scripthash(script) 512 513 514def script_to_scripthash(script: str) -> str: 515 h = sha256(bfh(script))[0:32] 516 return bh2u(bytes(reversed(h))) 517 518def public_key_to_p2pk_script(pubkey: str) -> str: 519 return construct_script([pubkey, opcodes.OP_CHECKSIG]) 520 521def pubkeyhash_to_p2pkh_script(pubkey_hash160: str) -> str: 522 return construct_script([ 523 opcodes.OP_DUP, 524 opcodes.OP_HASH160, 525 pubkey_hash160, 526 opcodes.OP_EQUALVERIFY, 527 opcodes.OP_CHECKSIG 528 ]) 529 530 531__b58chars = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 532assert len(__b58chars) == 58 533 534__b43chars = b'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:' 535assert len(__b43chars) == 43 536 537 538class BaseDecodeError(BitcoinException): pass 539 540 541def base_encode(v: bytes, *, base: int) -> str: 542 """ encode v, which is a string of bytes, to base58.""" 543 assert_bytes(v) 544 if base not in (58, 43): 545 raise ValueError('not supported base: {}'.format(base)) 546 chars = __b58chars 547 if base == 43: 548 chars = __b43chars 549 long_value = 0 550 power_of_base = 1 551 for c in v[::-1]: 552 # naive but slow variant: long_value += (256**i) * c 553 long_value += power_of_base * c 554 power_of_base <<= 8 555 result = bytearray() 556 while long_value >= base: 557 div, mod = divmod(long_value, base) 558 result.append(chars[mod]) 559 long_value = div 560 result.append(chars[long_value]) 561 # Bitcoin does a little leading-zero-compression: 562 # leading 0-bytes in the input become leading-1s 563 nPad = 0 564 for c in v: 565 if c == 0x00: 566 nPad += 1 567 else: 568 break 569 result.extend([chars[0]] * nPad) 570 result.reverse() 571 return result.decode('ascii') 572 573 574def base_decode(v: Union[bytes, str], *, base: int, length: int = None) -> Optional[bytes]: 575 """ decode v into a string of len bytes.""" 576 # assert_bytes(v) 577 v = to_bytes(v, 'ascii') 578 if base not in (58, 43): 579 raise ValueError('not supported base: {}'.format(base)) 580 chars = __b58chars 581 if base == 43: 582 chars = __b43chars 583 long_value = 0 584 power_of_base = 1 585 for c in v[::-1]: 586 digit = chars.find(bytes([c])) 587 if digit == -1: 588 raise BaseDecodeError('Forbidden character {} for base {}'.format(c, base)) 589 # naive but slow variant: long_value += digit * (base**i) 590 long_value += digit * power_of_base 591 power_of_base *= base 592 result = bytearray() 593 while long_value >= 256: 594 div, mod = divmod(long_value, 256) 595 result.append(mod) 596 long_value = div 597 result.append(long_value) 598 nPad = 0 599 for c in v: 600 if c == chars[0]: 601 nPad += 1 602 else: 603 break 604 result.extend(b'\x00' * nPad) 605 if length is not None and len(result) != length: 606 return None 607 result.reverse() 608 return bytes(result) 609 610 611class InvalidChecksum(BaseDecodeError): 612 pass 613 614 615def EncodeBase58Check(vchIn: bytes) -> str: 616 hash = sha256d(vchIn) 617 return base_encode(vchIn + hash[0:4], base=58) 618 619 620def DecodeBase58Check(psz: Union[bytes, str]) -> bytes: 621 vchRet = base_decode(psz, base=58) 622 payload = vchRet[0:-4] 623 csum_found = vchRet[-4:] 624 csum_calculated = sha256d(payload)[0:4] 625 if csum_calculated != csum_found: 626 raise InvalidChecksum(f'calculated {bh2u(csum_calculated)}, found {bh2u(csum_found)}') 627 else: 628 return payload 629 630 631# backwards compat 632# extended WIF for segwit (used in 3.0.x; but still used internally) 633# the keys in this dict should be a superset of what Imported Wallets can import 634WIF_SCRIPT_TYPES = { 635 'p2pkh':0, 636 'p2wpkh':1, 637 'p2wpkh-p2sh':2, 638 'p2sh':5, 639 'p2wsh':6, 640 'p2wsh-p2sh':7 641} 642WIF_SCRIPT_TYPES_INV = inv_dict(WIF_SCRIPT_TYPES) 643 644 645def is_segwit_script_type(txin_type: str) -> bool: 646 return txin_type in ('p2wpkh', 'p2wpkh-p2sh', 'p2wsh', 'p2wsh-p2sh') 647 648 649def serialize_privkey(secret: bytes, compressed: bool, txin_type: str, *, 650 internal_use: bool = False) -> str: 651 # we only export secrets inside curve range 652 secret = ecc.ECPrivkey.normalize_secret_bytes(secret) 653 if internal_use: 654 prefix = bytes([(WIF_SCRIPT_TYPES[txin_type] + constants.net.WIF_PREFIX) & 255]) 655 else: 656 prefix = bytes([constants.net.WIF_PREFIX]) 657 suffix = b'\01' if compressed else b'' 658 vchIn = prefix + secret + suffix 659 base58_wif = EncodeBase58Check(vchIn) 660 if internal_use: 661 return base58_wif 662 else: 663 return '{}:{}'.format(txin_type, base58_wif) 664 665 666def deserialize_privkey(key: str) -> Tuple[str, bytes, bool]: 667 if is_minikey(key): 668 return 'p2pkh', minikey_to_private_key(key), False 669 670 txin_type = None 671 if ':' in key: 672 txin_type, key = key.split(sep=':', maxsplit=1) 673 if txin_type not in WIF_SCRIPT_TYPES: 674 raise BitcoinException('unknown script type: {}'.format(txin_type)) 675 try: 676 vch = DecodeBase58Check(key) 677 except Exception as e: 678 neutered_privkey = str(key)[:3] + '..' + str(key)[-2:] 679 raise BaseDecodeError(f"cannot deserialize privkey {neutered_privkey}") from e 680 681 if txin_type is None: 682 # keys exported in version 3.0.x encoded script type in first byte 683 prefix_value = vch[0] - constants.net.WIF_PREFIX 684 try: 685 txin_type = WIF_SCRIPT_TYPES_INV[prefix_value] 686 except KeyError as e: 687 raise BitcoinException('invalid prefix ({}) for WIF key (1)'.format(vch[0])) from None 688 else: 689 # all other keys must have a fixed first byte 690 if vch[0] != constants.net.WIF_PREFIX: 691 raise BitcoinException('invalid prefix ({}) for WIF key (2)'.format(vch[0])) 692 693 if len(vch) not in [33, 34]: 694 raise BitcoinException('invalid vch len for WIF key: {}'.format(len(vch))) 695 compressed = False 696 if len(vch) == 34: 697 if vch[33] == 0x01: 698 compressed = True 699 else: 700 raise BitcoinException(f'invalid WIF key. length suggests compressed pubkey, ' 701 f'but last byte is {vch[33]} != 0x01') 702 703 if is_segwit_script_type(txin_type) and not compressed: 704 raise BitcoinException('only compressed public keys can be used in segwit scripts') 705 706 secret_bytes = vch[1:33] 707 # we accept secrets outside curve range; cast into range here: 708 secret_bytes = ecc.ECPrivkey.normalize_secret_bytes(secret_bytes) 709 return txin_type, secret_bytes, compressed 710 711 712def is_compressed_privkey(sec: str) -> bool: 713 return deserialize_privkey(sec)[2] 714 715 716def address_from_private_key(sec: str) -> str: 717 txin_type, privkey, compressed = deserialize_privkey(sec) 718 public_key = ecc.ECPrivkey(privkey).get_public_key_hex(compressed=compressed) 719 return pubkey_to_address(txin_type, public_key) 720 721def is_segwit_address(addr: str, *, net=None) -> bool: 722 if net is None: net = constants.net 723 try: 724 witver, witprog = segwit_addr.decode_segwit_address(net.SEGWIT_HRP, addr) 725 except Exception as e: 726 return False 727 return witprog is not None 728 729def is_b58_address(addr: str, *, net=None) -> bool: 730 if net is None: net = constants.net 731 try: 732 # test length, checksum, encoding: 733 addrtype, h = b58_address_to_hash160(addr) 734 except Exception as e: 735 return False 736 if addrtype not in [net.ADDRTYPE_P2PKH, net.ADDRTYPE_P2SH]: 737 return False 738 return True 739 740def is_address(addr: str, *, net=None) -> bool: 741 if net is None: net = constants.net 742 return is_segwit_address(addr, net=net) \ 743 or is_b58_address(addr, net=net) 744 745 746def is_private_key(key: str, *, raise_on_error=False) -> bool: 747 try: 748 deserialize_privkey(key) 749 return True 750 except BaseException as e: 751 if raise_on_error: 752 raise 753 return False 754 755 756########### end pywallet functions ####################### 757 758def is_minikey(text: str) -> bool: 759 # Minikeys are typically 22 or 30 characters, but this routine 760 # permits any length of 20 or more provided the minikey is valid. 761 # A valid minikey must begin with an 'S', be in base58, and when 762 # suffixed with '?' have its SHA256 hash begin with a zero byte. 763 # They are widely used in Casascius physical bitcoins. 764 return (len(text) >= 20 and text[0] == 'S' 765 and all(ord(c) in __b58chars for c in text) 766 and sha256(text + '?')[0] == 0x00) 767 768def minikey_to_private_key(text: str) -> bytes: 769 return sha256(text) 770