def test_msg_signing(self): msg1 = b'Chancellor on brink of second bailout for banks' msg2 = b'Electrum' def sign_message_with_wif_privkey(wif_privkey, msg): key = PrivateKey.from_WIF(wif_privkey) return key.sign_message(msg) sig1 = sign_message_with_wif_privkey( 'L1TnU2zbNaAqMoVh65Cyvmcjzbrj41Gs9iTLcWbpJCMynXuap6UN', msg1) addr1 = '15hETetDmcXm1mM4sEf7U2KXC9hDHFMSzz' sig2 = sign_message_with_wif_privkey( '5Hxn5C4SQuiV6e62A1MtZmbSeQyrLFhu5uYks62pU5VBUygK2KD', msg2) addr2 = '1GPHVTY8UD9my6jyP4tb2TYJwUbDetyNC6' sig1_b64 = base64.b64encode(sig1) sig2_b64 = base64.b64encode(sig2) self.assertEqual(sig1_b64, b'H/9jMOnj4MFbH3d7t4yCQ9i7DgZU/VZ278w3+ySv2F4yIsdqjsc5ng3kmN8OZAThgyfCZOQxZCWza9V5XzlVY0Y=') self.assertEqual(sig2_b64, b'G84dmJ8TKIDKMT9qBRhpX2sNmR0y5t+POcYnFFJCs66lJmAs3T8A6Sbpx7KA6yTQ9djQMabwQXRrDomOkIKGn18=') self.assertTrue(PublicKey.verify_message_and_address(sig1, msg1, addr1)) self.assertTrue(PublicKey.verify_message_and_address(sig2, msg2, addr2)) self.assertFalse(PublicKey.verify_message_and_address(b'wrong', msg1, addr1)) self.assertFalse(PublicKey.verify_message_and_address(sig2, msg1, addr1))
def from_pubkey(cls, pubkey): '''Returns a P2PKH address from a public key. The public key can be bytes or a hex string.''' if isinstance(pubkey, str): pubkey = PublicKey.from_hex(pubkey) else: pubkey = PublicKey.from_bytes(pubkey) return cls(hash_160(pubkey.to_bytes()), cls.ADDR_P2PKH)
def _is_public_key_valid(self, hex: str) -> bool: try: PublicKey.from_hex(hex) return True except (ValueError, TypeError): # ValueError <- PublicKey.from_hex() # TypeError <- PublicKey() return False
def multisig_script(cls, m, pubkeys): '''Returns the script for a pay-to-multisig transaction.''' n = len(pubkeys) if not 1 <= m <= n <= 15: raise ScriptError( '{:d} of {:d} multisig script not possible'.format(m, n)) for pubkey in pubkeys: PublicKey.from_bytes(pubkey) # Can be compressed or not # See https://bitcoin.org/en/developer-guide # 2 of 3 is: OP_2 pubkey1 pubkey2 pubkey3 OP_3 OP_CHECKMULTISIG return (bytes([Ops.OP_1 + m - 1]) + b''.join(cls.push_data(pubkey) for pubkey in pubkeys) + bytes([Ops.OP_1 + n - 1, Ops.OP_CHECKMULTISIG]))
def get_master_public_key(self, bip32_path): self.checkDevice() # bip32_path is of the form 44'/0'/1' # S-L-O-W - we don't handle the fingerprint directly, so compute # it manually from the previous node # This only happens once so it's bearable #self.get_client() # prompt for the PIN before displaying the dialog if necessary #self.handler.show_message("Computing master public key") splitPath = bip32_path.split('/') if splitPath[0] == 'm': splitPath = splitPath[1:] bip32_path = bip32_path[2:] fingerprint = 0 if len(splitPath) > 1: prevPath = "/".join(splitPath[0:len(splitPath) - 1]) nodeData = self.dongleObject.getWalletPublicKey(prevPath) publicKey = compress_public_key(nodeData['publicKey']) h = hashlib.new('ripemd160') h.update(hashlib.sha256(publicKey).digest()) fingerprint = unpack(">I", h.digest()[0:4])[0] nodeData = self.dongleObject.getWalletPublicKey(bip32_path) publicKey = bytes(compress_public_key(nodeData['publicKey'])) depth = len(splitPath) lastChild = splitPath[len(splitPath) - 1].split('\'') childnum = int(lastChild[0]) if len( lastChild) == 1 else 0x80000000 | int(lastChild[0]) derivation = BIP32Derivation( chain_code=nodeData['chainCode'], depth=depth, parent_fingerprint=pack_be_uint32(fingerprint), n=childnum) return BIP32PublicKey(PublicKey.from_bytes(publicKey), derivation, Net.COIN)
def test_to_address_compressed(self): pubkey_hex = '036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) address = output.to_address() assert isinstance(address, P2PKH_Address) assert address.to_string() == '16ZbRYV2f1NNuNQ9FDYyUMC2d1cjGS2G3L'
def _write(self): if threading.currentThread().isDaemon(): logger.error('daemon thread cannot write wallet') return if not self.modified: return s = json.dumps(self.data, indent=4, sort_keys=True) if self.pubkey: c = zlib.compress(s.encode()) s = PublicKey.from_hex(self.pubkey).encrypt_message_to_base64(c) temp_path = "%s.tmp.%s" % (self.path, os.getpid()) with open(temp_path, "w", encoding='utf-8') as f: f.write(s) f.flush() os.fsync(f.fileno()) mode = os.stat(self.path).st_mode if self.file_exists( ) else stat.S_IREAD | stat.S_IWRITE # perform atomic write on POSIX systems try: os.rename(temp_path, self.path) except: os.remove(self.path) os.rename(temp_path, self.path) os.chmod(self.path, mode) self._file_exists = True self.raw = s logger.debug("saved '%s'", self.path) self.modified = False
def _convert_version_14(self) -> None: # convert imported wallets for 3.0 if not self._is_upgrade_method_needed(13, 13): return if self.get('wallet_type') == 'imported': addresses = self.get('addresses') if type(addresses) is list: addresses = dict([(x, None) for x in addresses]) self.put('addresses', addresses) elif self.get('wallet_type') == 'standard': if self.get('keystore').get('type') == 'imported': addresses = set(self.get('addresses').get('receiving')) pubkeys = self.get('keystore').get('keypairs').keys() assert len(addresses) == len(pubkeys) d = {} for pubkey in pubkeys: addr = PublicKey.from_hex(pubkey).to_address( coin=Net.COIN).to_string() assert addr in addresses d[addr] = { 'pubkey': pubkey, 'redeem_script': None, 'type': 'p2pkh' } self.put('addresses', d) self.put('pubkeys', None) self.put('wallet_type', 'imported') self.put('seed_version', 14)
def do_send(self, window: 'ElectrumWindow', account: AbstractAccount, tx: Transaction) -> None: def on_done(window, future): try: future.result() except Exception as exc: window.on_exception(exc) else: window.show_message('\n'.join(( _("Your transaction was sent to the cosigning pool."), _("Open your cosigner wallet to retrieve it."), ))) def send_message(): server.put(item.keyhash_hex, message) account_id = account.get_id() for item in self._items: if self._is_theirs(window, account_id, item, tx): raw_tx_bytes = json.dumps(tx.to_dict()).encode() public_key = PublicKey.from_bytes(item.pubkey_bytes) message = public_key.encrypt_message_to_base64(raw_tx_bytes) WaitingDialog(item.window, _('Sending transaction to cosigning pool...'), send_message, on_done=partial(on_done, item.window))
def sign_message(self, sequence, message, password): sig = None try: message = message.encode('utf8') inputPath = self.get_derivation() + "/%d/%d" % sequence msg_hash = sha256d(msg_magic(message)) inputHash = msg_hash.hex() hasharray = [] hasharray.append({'hash': inputHash, 'keypath': inputPath}) hasharray = json.dumps(hasharray) msg = b'{"sign":{"meta":"sign message", "data":%s}}' % hasharray.encode( 'utf8') dbb_client = self.plugin.get_client(self) if not dbb_client.is_paired(): raise Exception(_("Bitbox does not appear to be connected.")) reply = dbb_client.hid_send_encrypt(msg) self.handler.show_message( _("Signing message ...") + "\n\n" + _("To continue, touch the Digital Bitbox's blinking light for " "3 seconds.") + "\n\n" + _("To cancel, briefly touch the blinking light or wait for the timeout." )) # Send twice, first returns an echo for smart verification (not implemented) reply = dbb_client.hid_send_encrypt(msg) self.handler.finished() if 'error' in reply: raise Exception(reply['error']['message']) if 'sign' not in reply: raise Exception(_("Bitbox did not sign the message.")) siginfo = reply['sign'][0] compact_sig = bytes.fromhex(siginfo['sig']) if 'recid' in siginfo: recids = [int(siginfo['recid'], 16)] else: recids = range(4) for recid in recids: # firmware > v2.1.1 message_sig = bytes([recid + 27]) + compact_sig try: pubkey = PublicKey.from_signed_message( message_sig, message) except Exception: logger.exception( f"If Digital Bitbox signing failed, this may be why") continue if pubkey.verify_message(message_sig, message): return message_sig raise RuntimeError( _("Unable to sign as Bitbox failed to provide a valid signature" )) except Exception as e: self.give_error(e) return sig
def test_to_script_bytes(self): pubkey_hex = '0363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) raw = output.to_script_bytes() assert isinstance(raw, bytes) assert raw == push_item(bytes.fromhex(pubkey_hex)) + pack_byte(OP_CHECKSIG)
def get_tx_derivations(self, tx): keypairs = {} for txin_index, txin in enumerate(tx.inputs()): sigs = txin['signatures'] x_pubkeys = txin['x_pubkeys'] # Remove pubkeys that have already signed used = set() sig_idx = len(sigs) - 1 pub_idx = len(x_pubkeys) - 1 pre_hash = tx.preimage_hash(txin_index) while sig_idx >= 0: sig = sigs[sig_idx] sig_idx -= 1 if sig is not None: sig = bytes.fromhex(sig)[:-1] while pub_idx >= 0: x_pubkey = x_pubkeys[pub_idx] public_key = PublicKey.from_hex( xpubkey_to_pubkey(x_pubkey)) used.add(x_pubkey) if public_key.verify_der_signature( sig, pre_hash, None): break pub_idx -= 1 pub_idx -= 1 for x_pubkey in x_pubkeys: if x_pubkey in used: continue derivation = self.get_pubkey_derivation(x_pubkey) if not derivation: continue keypairs[x_pubkey] = derivation return keypairs
def get_pubkey_derivation(self, x_pubkey): if x_pubkey[0:2] in ['02', '03', '04']: pubkey = PublicKey.from_hex(x_pubkey) if pubkey in self.keypairs: return pubkey elif x_pubkey[0:2] == 'fd': addr = _script_to_address(x_pubkey[2:]) return self.address_to_pubkey(addr)
def test_to_script(self): pubkey_hex = '0363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) S = output.to_script() assert isinstance(S, Script) assert S == output.to_script_bytes() assert isinstance(classify_output_script(S, Bitcoin), P2PK_Output)
def createmultisig(self, threshold, pubkeys): """Create multisig address""" assert isinstance(pubkeys, list), (type(threshold), type(pubkeys)) public_keys = [PublicKey.from_hex(pubkey) for pubkey in sorted(pubkeys)] output = P2MultiSig_Output(public_keys, threshold) redeem_script = output.to_script_bytes() address = P2SH_Address(hash160(redeem_script)).to_string() return {'address':address, 'redeemScript':redeem_script.hex()}
def __init__(self, d): Software_KeyStore.__init__(self) keypairs = d.get('keypairs', {}) self.keypairs = { PublicKey.from_hex(pubkey): enc_privkey for pubkey, enc_privkey in keypairs.items() } self._sorted = None
def load_state(self, keyinstance_rows: List[KeyInstanceRow]) -> None: self._keypairs.clear() self._public_keys.clear() for row in keyinstance_rows: data = json.loads(row.derivation_data) public_key = PublicKey.from_hex(data['pub']) self._public_keys[row.keyinstance_id] = public_key self._keypairs[public_key] = cast(str, data['prv'])
def test_update_password(self): keystore = Imported_KeyStore() keystore._keypairs = { PublicKey.from_hex(a): b for a, b in keypairs_dict.items() } keystore.update_password('new password', 'password') pubkey = list(keystore._keypairs.keys())[0] assert keystore.export_private_key(pubkey, 'new password') == ( 'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617') with pytest.raises(AssertionError): keystore.update_password('', 'new password')
def test_raw_public_keys(self, raw_hex, coin): public_key = PublicKey.from_hex(raw_hex) x_pubkey = XPublicKey.from_hex(raw_hex) # assert x_pubkey.to_bytes() == bytes.fromhex(raw_hex) # assert x_pubkey.to_hex() == raw_hex assert not x_pubkey.is_bip32_key() assert x_pubkey.to_public_key() == public_key assert x_pubkey.to_address() == public_key.to_address(coin=coin) assert x_pubkey.to_address().coin() is coin
def to_public_key(self) -> Union[BIP32PublicKey, PublicKey]: '''Returns a PublicKey instance or an Address instance.''' kind = self.kind() if self._pubkey_bytes is not None: return PublicKey.from_bytes(self._pubkey_bytes) elif self._bip32_xpub is not None: assert self._derivation_path is not None result = bip32_key_from_string(self._bip32_xpub) for n in self._derivation_path: result = result.child(n) return result elif self._old_mpk is not None: assert self._derivation_path is not None path = self._derivation_path pubkey = PublicKey.from_bytes(pack_byte(4) + self._old_mpk) # pylint: disable=unsubscriptable-object delta = double_sha256(f'{path[1]}:{path[0]}:'.encode() + self._old_mpk) return pubkey.add(delta) raise ValueError("invalid key data")
def test_to_address_uncompressed(self): pubkey_hex = ( '046d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e' '2487e6222a6664e079c8edf7518defd562dbeda1e7593dfd7f0be285880a24dab' ) pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) address = output.to_address() assert isinstance(address, P2PKH_Address) assert address.to_string() == '1G9f5Kdd5A8MeBN8jduUNfcAXUVvtFxVhP'
def test_signatures(filename): tx, values, pk_scripts = read_json_tx(filename) for input_index, (value, pk_script, txin) in enumerate(zip(values, pk_scripts, tx.inputs)): signature, pubkey = txin.script_sig.ops() pubkey = PublicKey.from_bytes(pubkey) signature_hash = tx.signature_hash(input_index, value, pk_script, SigHash(signature[-1])) assert pubkey.verify_der_signature(signature[:-1], signature_hash, None)
def test_old_keystore(self, raw_hex, public_key_hex, coin): public_key = PublicKey.from_hex(public_key_hex) assert public_key.is_compressed() is False x_pubkey = XPublicKey.from_hex(raw_hex) # assert x_pubkey.to_bytes() == bytes.fromhex(raw_hex) # assert x_pubkey.to_hex() == raw_hex assert not x_pubkey.is_bip32_key() assert x_pubkey.to_public_key() == public_key assert x_pubkey.to_public_key().is_compressed() is False assert x_pubkey.to_address() == public_key.to_address(coin=coin) assert x_pubkey.to_address().coin() is coin
def get_master_public_key(self, bip32_path, creating=False): address_n = bip32_decompose_chain_string(bip32_path) with self.run_flow(creating_wallet=creating): node = trezorlib.btc.get_public_node(self.client, address_n).node self.used() derivation = BIP32Derivation(chain_code=node.chain_code, depth=node.depth, parent_fingerprint=pack_be_uint32( node.fingerprint), n=node.child_num) return BIP32PublicKey(PublicKey.from_bytes(node.public_key), derivation, Net.COIN)
def get_master_public_key(self, bip32_path): address_n = bip32_decompose_chain_string(bip32_path) creating = False node = self.get_public_node(address_n, creating).node self.used() derivation = BIP32Derivation(chain_code=node.chain_code, depth=node.depth, parent_fingerprint=pack_be_uint32( node.fingerprint), n=node.child_num) return BIP32PublicKey(PublicKey.from_bytes(node.public_key), derivation, Net.COIN)
def to_public_key(self): '''Returns a PublicKey instance or an Address instance.''' kind = self.kind() if kind in {0x02, 0x03, 0x04}: return PublicKey.from_bytes(self.raw) if kind == 0xff: return self._bip32_public_key() if kind == 0xfe: return self._old_keystore_public_key() assert kind == 0xfd result = classify_output_script(Script(self.raw[1:]), Net.COIN) assert isinstance(result, Address) return result
def get_master_public_key(self, bip32_path: str, creating: bool = False) -> BIP32PublicKey: address_n = bip32_decompose_chain_string(bip32_path) # This will be cleared by the wrapper around `get_public_node`. self.creating_wallet = creating node = self.get_public_node(address_n).node self.used() derivation = BIP32Derivation(chain_code=node.chain_code, depth=node.depth, parent_fingerprint=pack_be_uint32( node.fingerprint), n=node.child_num) return BIP32PublicKey(PublicKey.from_bytes(node.public_key), derivation, Net.COIN)
def _write(self) -> bytes: # We pack as JSON before encrypting, so can't just put in the generic key value store, # as that is unencrypted and would just be JSON values in the DB. s = json.dumps(self._data, indent=4, sort_keys=True) if self._pubkey: c = zlib.compress(s.encode()) raw = PublicKey.from_hex(self._pubkey).encrypt_message(c) else: raw = s.encode() self._db_values.set("jsondata", raw) self._primed = True return raw
def get_preimage_script(self, txin): _type = txin['type'] if _type == 'p2pkh': return txin['address'].to_script_bytes().hex() elif _type == 'p2sh': pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) return multisig_script(pubkeys, txin['num_sig']) elif _type == 'p2pk': output = P2PK_Output(PublicKey.from_hex(txin['pubkeys'][0])) return output.to_script_bytes().hex() elif _type == 'unknown': # this approach enables most P2SH smart contracts # (but take care if using OP_CODESEPARATOR) return txin['scriptCode'] else: raise RuntimeError('Unknown txin type', _type)
def xpubkey_to_address(x_pubkey): if x_pubkey[0:2] == 'fd': address = _script_to_address(x_pubkey[2:]) return x_pubkey, address if x_pubkey[0:2] in ['02', '03', '04']: pubkey = x_pubkey elif x_pubkey[0:2] == 'ff': xpub, s = BIP32_KeyStore.parse_xpubkey(x_pubkey) pubkey = BIP32_KeyStore.get_pubkey_from_xpub(xpub, s) elif x_pubkey[0:2] == 'fe': mpk, s = Old_KeyStore.parse_xpubkey(x_pubkey) pubkey = Old_KeyStore.get_pubkey_from_mpk(mpk, s[0], s[1]) else: raise Exception("Cannot parse pubkey") if pubkey: address = PublicKey.from_hex(pubkey).to_address(coin=Net.COIN) return pubkey, address