def f(public_pair): yield ("public_pair_x", '%d' % public_pair[0], None) yield ("public_pair_y", '%d' % public_pair[1], None) yield ("public_pair_x_hex", '%x' % public_pair[0], " x as hex") yield ("public_pair_y_hex", '%x' % public_pair[1], " y as hex") yield ("y_parity", "odd" if (public_pair[1] & 1) else "even", None) key = Key(public_pair=public_pair) yield ("key_pair_as_sec", b2h(key.sec(is_compressed=True)), None) yield ("key_pair_as_sec_uncompressed", b2h(key.sec(is_compressed=False)), " uncompressed") network_name = network.network_name hash160_u = key.hash160(is_compressed=False) hash160_c = key.hash160(is_compressed=True) yield ("hash160", b2h(hash160_c), None) if hash160_c and hash160_u: yield ("hash160_uncompressed", b2h(hash160_u), " uncompressed") address = network.address.for_p2pkh(hash160_c) yield ("address", address, "%s address" % network_name) yield ("%s_address" % network.symbol, address, "legacy") address = key.address(is_compressed=False) yield ("address_uncompressed", address, "%s address uncompressed" % network_name) yield ("%s_address_uncompressed" % network.symbol, address, "legacy") # don't print segwit addresses unless we're sure we have a compressed key if hash160_c and hasattr(network.address, "for_p2pkh_wit"): address_segwit = network.address.for_p2pkh_wit(hash160_c) if address_segwit: # this network seems to support segwit yield ("address_segwit", address_segwit, "%s segwit address" % network_name) yield ("%s_address_segwit" % network.symbol, address_segwit, "legacy") p2sh_script = network.contract.for_p2pkh_wit(hash160_c) p2s_address = network.address.for_p2s(p2sh_script) if p2s_address: yield ("p2sh_segwit", p2s_address, None) p2sh_script_hex = b2h(p2sh_script) yield ("p2sh_segwit_script", p2sh_script_hex, " corresponding p2sh script")
secret_exponent = parse_as_secret_exponent(secret) if secret_exponent: privkey = Key(secret_exponent=secret_exponent) if SEC_RE.match(secret): privkey = Key.from_sec(unhexlify(secret)) else: try: privkey = Key.from_text(secret) except encoding.EncodingError: pass # Define vars automatically from privkey (could be manually, if you had the values) privkey_uncompressed = '%x' % privkey.secret_exponent() pubkey_uncompressed = hexlify(privkey.sec(use_uncompressed=True)) ## # Prepare pubkey for encrypting ## pubkey_bin_tmp = arithmetic.changebase(pubkey_uncompressed[2:], 16, 256, minlen=64) pubkey_bin = '\x02\xca\x00 ' + pubkey_bin_tmp[:32] + '\x00 ' + pubkey_bin_tmp[ 32:] # Optionally you can use unhexlify, but need to add '\x20' after '\x00' #pubkey_bin_tmp = unhexlify(pubkey_uncompressed) #pubkey_bin = '\x02\xca\x00\x20' + pubkey_bin_tmp[1:-32] + '\x00\x20' + pubkey_bin_tmp[-32:]
def test_generate(mode, pdf, dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path): # test UX and operation of the 'bitcoin core' wallet export mx = "Don't make PDF" goto_home() pick_menu_item('Advanced') try: pick_menu_item('Paper Wallets') except: raise pytest.skip('Feature absent') time.sleep(0.1) title, story = cap_story() assert 'pick a random' in story assert 'MANY RISKS' in story need_keypress('y') time.sleep(0.1) if mode == 'segwit': pick_menu_item('Classic Address') pick_menu_item('Segwit/Bech32') time.sleep(0.5) if pdf: assert mx in cap_menu() shutil.copy('../docs/paperwallet.pdf', microsd_path('paperwallet.pdf')) pick_menu_item(mx) need_keypress('y') time.sleep(0.1) title, story = cap_story() assert 'Pick PDF' in story pick_menu_item('paperwallet.pdf') pick_menu_item('GENERATE WALLET') time.sleep(0.1) title, story = cap_story() assert 'Created file' in story story = [i for i in story.split('\n') if i] if not pdf: fname = story[-1] else: fname = story[-2] pdf_name = story[-1] assert pdf_name.endswith('.pdf') assert fname.endswith('.txt') path = microsd_path(fname) with open(path, 'rt') as fp: hdr = None for ln in fp: ln = ln.rstrip() if not ln: continue if ln[0] != ' ': hdr = ln continue if '█' in ln: continue val = ln.strip() if 'Deposit address' in hdr: assert val == fname.split('.', 1)[0].split('-', 1)[0] txt_addr = val if mode != 'segwit': addr = Key.from_text(val) else: hrp, data = bech32_decode(val) decoded = convertbits(data[1:], 5, 8, False)[-20:] assert hrp in {'tb', 'bc' } addr = Key(hash160=bytes(decoded), is_compressed=True, netcode='XTN') elif hdr == 'Private key:': # for QR case assert val == wif elif 'Private key' in hdr and 'WIF=Wallet' in hdr: wif = val k1 = Key.from_text(val) elif 'Private key' in hdr and 'Hex, 32 bytes' in hdr: k2 = Key(secret_exponent=from_bytes_32(a2b_hex(val)), is_compressed=True) elif 'Bitcoin Core command': assert wif in val assert 'importmulti' in val or 'importprivkey' in val else: print(f'{hdr} => {val}') raise ValueError(hdr) assert k1.sec() == k2.sec() assert k1.public_pair() == k2.public_pair() assert addr.address() == k1.address() os.unlink(path) if not pdf: return path = microsd_path(pdf_name) with open(path, 'rb') as fp: d = fp.read() assert wif.encode('ascii') in d assert txt_addr.encode('ascii') in d os.unlink(path)
class KeyPair(object): """ ECDSA key pair. Args: pkey (str): hexadecimal representation of the private key (secret exponent). secret (str): master password. Attributes: keypair (:py:class:`pycoin.key.Key.Key`): BIP0032-style hierarchical wallet. Raises: NotImplementedError when a randomness source is not found. """ def __init__(self, pkey=None, secret=None): if secret is not None: pkey = format( BIP32Node.from_master_secret( secret.encode('utf-8')).secret_exponent(), "064x") elif pkey is None: try: pkey = format( BIP32Node.from_master_secret( urandom(4096)).secret_exponent(), '064x') except NotImplementedError as e: raise ValueError('No randomness source found: %s' % e) self.keypair = Key(secret_exponent=int(pkey, 16)) @property def node_id(self): """(str): NodeID derived from the public key (RIPEMD160 hash of public key).""" return b2h(self.keypair.hash160()) @property def public_key(self): """(str): public key.""" return b2h(self.keypair.sec(use_uncompressed=False)) @property def private_key(self): """(str): private key.""" return format(self.keypair.secret_exponent(), '064x') @property def address(self): """(): base58 encoded bitcoin address version of the nodeID.""" return self.keypair.address(use_uncompressed=False) def sign(self, message, compact=True): """Signs the supplied message with the private key""" if compact: fd = io.BytesIO() stream_bc_string(fd, bytearray('Bitcoin Signed Message:\n', 'ascii')) stream_bc_string(fd, bytearray(message, 'utf-8')) mhash = from_bytes_32(double_sha256(fd.getvalue())) G = generator_secp256k1 n = G.order() k = from_bytes_32(os.urandom(32)) p1 = k * G r = p1.x() if r == 0: raise RuntimeError("amazingly unlucky random number r") s = (numbertheory.inverse_mod(k, n) * (mhash + (self.keypair.secret_exponent() * r) % n)) % n if s == 0: raise RuntimeError("amazingly unlucky random number s") y_odd = p1.y() % 2 assert y_odd in (0, 1) first = 27 + y_odd + ( 4 if not self.keypair._use_uncompressed(False) else 0) sig = binascii.b2a_base64( bytearray([first]) + to_bytes_32(r) + to_bytes_32(s)).strip() if not isinstance(sig, str): # python3 b2a wrongness sig = str(sig, 'ascii') return sig else: return keys.sign_sha256(self.private_key, message)
secret_exponent = parse_as_secret_exponent(secret) if secret_exponent: privkey = Key(secret_exponent=secret_exponent) if SEC_RE.match(secret): privkey = Key.from_sec(unhexlify(secret)) else: try: privkey = Key.from_text(secret) except encoding.EncodingError: pass # Define vars automatically from privkey (could be manually, if you had the values) privkey_uncompressed = '%x' % privkey.secret_exponent() pubkey_uncompressed = hexlify(privkey.sec(use_uncompressed=True)) ## # Prepare pubkey for encrypting ## pubkey_bin_tmp = arithmetic.changebase(pubkey_uncompressed[2:], 16, 256, minlen=64) pubkey_bin = '\x02\xca\x00 '+ pubkey_bin_tmp[:32] + '\x00 ' + pubkey_bin_tmp[32:] # Optionally you can use unhexlify, but need to add '\x20' after '\x00' #pubkey_bin_tmp = unhexlify(pubkey_uncompressed) #pubkey_bin = '\x02\xca\x00\x20' + pubkey_bin_tmp[1:-32] + '\x00\x20' + pubkey_bin_tmp[-32:] ## # Prepare private key for decrypting ##