def test_public_key_from_private_key(self): for priv_details in self.priv_pub_addr: privkey = PrivateKey.from_text(priv_details['priv']) result = privkey.public_key.to_hex() self.assertEqual(priv_details['pub'], result) self.assertEqual(priv_details['txin_type'], 'p2pkh') self.assertEqual(priv_details['compressed'], privkey.is_compressed())
def serialize(self, jsontx): """Create a transaction from json inputs. Inputs must have a redeemPubkey. Outputs must be a list of {'address':address, 'value':satoshi_amount}. """ keypairs = {} inputs = jsontx.get('inputs') outputs = jsontx.get('outputs') locktime = jsontx.get('locktime', 0) for txin in inputs: if txin.get('output'): prevout_hash, prevout_n = txin['output'].split(':') txin['prevout_n'] = int(prevout_n) txin['prevout_hash'] = prevout_hash sec = txin.get('privkey') if sec: privkey = PrivateKey.from_text(sec) txin_type, privkey, compressed = ('p2pkh', privkey.to_bytes(), privkey.is_compressed()) pubkey = privkey.public_key.to_hex() keypairs[pubkey] = privkey, compressed txin['type'] = txin_type txin['x_pubkeys'] = [pubkey] txin['signatures'] = [None] txin['num_sig'] = 1 outputs = [(TYPE_ADDRESS, Address.from_string(x['address']), int(x['value'])) for x in outputs] tx = Transaction.from_io(inputs, outputs, locktime=locktime) tx.sign(keypairs) return tx.as_dict()
def test_import_privkey(self, WIF, pk_string): enc_prvkey_text = pw_encode(WIF, "password") public_key = PrivateKey.from_text(WIF).public_key d = Imported_KeyStore({}) d.import_private_key(1, public_key, enc_prvkey_text) assert d.get_public_key_for_id(1) == public_key assert WIF == d.export_private_key(public_key, "password")
def check_seed(self, seed): secexp = self.stretch_key(seed) master_private_key = PrivateKey(int_to_be_bytes(secexp, 32)) master_public_key = master_private_key.public_key.to_bytes(compressed=False)[1:] if master_public_key != bfh(self.mpk): logger.error('invalid password (mpk) %s %s', self.mpk, master_public_key.hex()) raise InvalidPassword()
class SVRegTestnet(object): """The checkpoint cannot be made until the bitcoin node has at least generated 146 blocks (to calculate the DAA). Blocks are therefore generated until there are at least 200. A new checkpoint at height = 200 is then calculated before allowing anything further to proceed. Note: RegTest overflows the max nBits field, presumably due to a very short time interval between generated blocks. To modify this field would be to change the hash of the header so as a workaround, bitcoinx is monkeypatched to skip the checking of the difficulty target (see HeadersRegtestMod).""" # hardcoded # - WIF private_key: cT3G2vJGRNbpmoCVXYPYv2JbngzwtznLvioPPJXu39jfQeLpDuX5 # - Pubkey hash: mfs8Y8gAwC2vJHCeSXkHs6LF5nu5PA7nxc REGTEST_FUNDS_PRIVATE_KEY: PrivateKey = PrivateKey(bytes.fromhex( 'a2d9803c912ab380c1491d3bd1aaab34ca06742d7885a224ec8d386182d26ed2'), coin=BitcoinRegtest) REGTEST_FUNDS_PRIVATE_KEY_WIF = REGTEST_FUNDS_PRIVATE_KEY.to_WIF() REGTEST_FUNDS_PUBLIC_KEY: PublicKey = REGTEST_FUNDS_PRIVATE_KEY.public_key REGTEST_P2PKH_ADDRESS: P2PKH_Address = REGTEST_FUNDS_PUBLIC_KEY.to_address( ).to_string() # For CI/CD use (restapi will by default reset everything back to empty wallet with this seed) # First receive address: mwv1WZTsrtKf3S9mRQABEeMaNefLbQbKpg REGTEST_DEFAULT_ACCOUNT_SEED = 'tprv8ZgxMBicQKsPd4wsdaJ11eH84eq4hHLX1K6Mx8EQQhJzq8jr25WH1m8hg' \ 'GkCqnksJDCZPZbDoMbQ6QtroyCyn5ZckCmsLeiHDb1MAxhNUHN' MIN_CHECKPOINT_HEIGHT = 0 ADDRTYPE_P2PKH = 111 ADDRTYPE_P2SH = 196 CASHADDR_PREFIX = "bchtest" DEFAULT_PORTS = {'t': '51001', 's': '51002'} DEFAULT_SERVERS = read_json_dict('servers_regtest.json') GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" NAME = 'regtest' BITCOIN_URI_PREFIX = "bitcoin" PAY_URI_PREFIX = "pay" WIF_PREFIX = 0xef BIP276_VERSION = 2 COIN = BitcoinRegtest # Use the following for a chain reset. CHECKPOINT = CheckPoint(bytes.fromhex( '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd' '7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae18' ), height=0, prev_work=0) VERIFICATION_BLOCK_MERKLE_ROOT = None BIP44_COIN_TYPE = 1 BLOCK_EXPLORERS: Dict[str, Tuple[str, Dict[str, str]]] = {} FAUCET_URL = "" KEEPKEY_DISPLAY_COIN_NAME = 'Testnet' # Note: testnet allegedly supported only by unofficial firmware TREZOR_COIN_NAME = 'Bcash Testnet' TWENTY_MINUTE_RULE = True
class SVRegTestnet(object): """The checkpoint cannot be made until the bitcoin node has at least generated 146 blocks (to calculate the DAA). Blocks are therefore generated until there are at least 200. A new checkpoint at height = 200 is then calculated before allowing anything further to proceed. Note: RegTest overflows the max nBits field, presumably due to a very short time interval between generated blocks. To modify this field would be to change the hash of the header so as a workaround, bitcoinx is monkeypatched to skip the checking of the difficulty target (see HeadersRegtestMod).""" # hardcoded # - WIF private_key: cT3G2vJGRNbpmoCVXYPYv2JbngzwtznLvioPPJXu39jfQeLpDuX5 # - Pubkey hash: mfs8Y8gAwC2vJHCeSXkHs6LF5nu5PA7nxc REGTEST_FUNDS_PRIVATE_KEY: PrivateKey = PrivateKey(bytes.fromhex( 'a2d9803c912ab380c1491d3bd1aaab34ca06742d7885a224ec8d386182d26ed2'), coin=BitcoinRegtest) REGTEST_FUNDS_PRIVATE_KEY_WIF = REGTEST_FUNDS_PRIVATE_KEY.to_WIF() REGTEST_FUNDS_PUBLIC_KEY: PublicKey = REGTEST_FUNDS_PRIVATE_KEY.public_key REGTEST_P2PKH_ADDRESS: P2PKH_Address = REGTEST_FUNDS_PUBLIC_KEY.to_address( ).to_string() # For CI/CD use (restapi will by default reset everything back to empty wallet with this seed) REGTEST_DEFAULT_ACCOUNT_SEED = 'tprv8ZgxMBicQKsPd4wsdaJ11eH84eq4hHLX1K6Mx8EQQhJzq8jr25WH1m8hg' \ 'GkCqnksJDCZPZbDoMbQ6QtroyCyn5ZckCmsLeiHDb1MAxhNUHN' MIN_CHECKPOINT_HEIGHT = 200 ADDRTYPE_P2PKH = 111 ADDRTYPE_P2SH = 196 CASHADDR_PREFIX = "bchtest" DEFAULT_PORTS = {'t': '51001', 's': '51002'} DEFAULT_SERVERS = read_json_dict('servers_regtest.json') GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" NAME = 'regtest' URI_PREFIX = "bitcoin" WIF_PREFIX = 0xef BIP276_VERSION = 2 COIN = BitcoinRegtest CHECKPOINT = CheckPoint(bytes.fromhex( '0000002029f1e3df7fda466242b9b56076792ffdb9e5d7ea51610307bc010000000000007ac1fa84' 'ef5f0998232fb01cd6fea2c0199e34218df2fb33e4e80e79d22b6a746994435d41c4021a208bae0a' ), height=123, prev_work=123) VERIFICATION_BLOCK_MERKLE_ROOT = ( '93414acafdef2dad790c456a424a6a261b66771a3426117125d8c13a1c93f10e') BIP44_COIN_TYPE = 1 BLOCK_EXPLORERS: Dict[str, Tuple[str, Dict[str, str]]] = {} FAUCET_URL = "" KEEPKEY_DISPLAY_COIN_NAME = 'Testnet' # Note: testnet allegedly supported only by unofficial firmware TREZOR_COIN_NAME = 'Bcash Testnet' TWENTY_MINUTE_RULE = True
def test_pubkeys_to_address(self, tmp_storage, network): coin = network.COIN privkey = PrivateKey.from_random() WIF = privkey.to_WIF(coin=coin) wallet = ImportedPrivkeyWallet.from_text(tmp_storage, WIF, None) public_key = privkey.public_key pubkey_hex = public_key.to_hex() address = public_key.to_address(coin=coin).to_string() assert wallet.pubkeys_to_address(pubkey_hex) == Address.from_string(address)
def test_P2PKHK_script(self): p = PrivateKey.from_random() PC = p.public_key PU = PC.complement() for P in (PC, PU): script = P.P2PKH_script() data = P.hash160() assert script == ( bytes([OP_DUP, OP_HASH160, len(data)]) + data + bytes([OP_EQUALVERIFY, OP_CHECKSIG]))
def test_pubkeys_to_address(self, tmp_storage, network): coin = network.COIN privkey = PrivateKey.from_random() WIF = privkey.to_WIF(coin=coin) parent_wallet = _TestableParentWallet.as_legacy_wallet_container( tmp_storage) wallet = ImportedPrivkeyWallet.from_text(parent_wallet, WIF) public_key = privkey.public_key pubkey_hex = public_key.to_hex() address = public_key.to_address(coin=coin).to_string() assert wallet.pubkeys_to_address(pubkey_hex) == address_from_string( address)
def test_verify_wrong_addr(): key_priv = PrivateKey.from_arbitrary_bytes(b'123test') key_pub = key_priv.public_key pkh = key_pub.hash160() pkh_0_out_wrong = TxOutput(in_sats - miner_fee, P2PKH_Address(pkh, Bitcoin).to_script()) context = create_input_context(in_sats, acs.locking_script, pkh_0_out_wrong) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) verify_result = acs.unlock(SigHashPreimage(preimage)).verify(context) assert verify_result == False
def test_from_template_bad(self): public_keys = [ PrivateKey.from_random().public_key.to_bytes() for n in range(2) ] with pytest.raises(ValueError): script = P2MultiSig_Output.from_template(pack_byte(1), *public_keys, pack_byte(1)) with pytest.raises(ValueError): script = P2MultiSig_Output.from_template(pack_byte(1), *public_keys, pack_byte(3))
def test_accumulator_multisig_scriptsig_NofM(masks, scripts_hex): for mask in masks: pubkeys = [] signatures = [] for key_index in range(len(mask)): private_key = PrivateKey.from_hex(private_keys_hex[key_index]) pubkeys.append(private_key.public_key) if mask[key_index]: signatures.append(bytes.fromhex(signatures_hex[key_index])) else: signatures.append(NO_SIGNATURE) script = create_script_sig(ScriptType.MULTISIG_ACCUMULATOR, sum(mask), pubkeys, signatures) assert scripts_hex[mask] == script.to_hex()
def test_decrypt_message(self): password = '******' message = b'BitcoinSV' prvkey_text = "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ" enc_prvkey_text = pw_encode(prvkey_text, password) public_key = PrivateKey.from_text(prvkey_text).public_key d = Imported_KeyStore({}) d.import_private_key(1, public_key, enc_prvkey_text) enc_msg = ('QklFMQNkonLnVmRMF3dl+P0rHSbM4lvDPmnE2CFcD+98gGsOe6qtKtmVbCg4' '9bxmT6vfmzl7udrvT81wH1Ri7wZItndtLiNHii6FBNVzoSV/1ZqN3w==') decrypted_message = d.decrypt_message(public_key, enc_msg, password) assert decrypted_message == message
def signtransaction(self, tx, privkey=None, password=None): """Sign a transaction. The wallet keys will be used unless a private key is provided.""" tx = Transaction.from_hex(tx) if privkey: privkey2 = PrivateKey.from_text(privkey) txin_type, privkey2, compressed = ('p2pkh', privkey2.to_bytes(), privkey2.is_compressed()) h160 = hash_160(privkey2.public_key.to_bytes()) x_pubkey = 'fd' + bh2u(b'\x00' + h160) tx.sign({x_pubkey: (privkey2, compressed)}) else: self.wallet.sign_transaction(tx, password) return tx.as_dict()
def test_sign_transaction(self): eckey1 = PrivateKey(bfh('7e1255fddb52db1729fc3ceb21a46f95b8d9fe94cc83425e936a6c5223bb679d')) sig1 = eckey1.sign(bfh('5a548b12369a53faaa7e51b5081829474ebdd9c924b3a8230b69aa0be254cd94'), None) self.assertEqual(bfh('3045022100902a288b98392254cd23c0e9a49ac6d7920f171b8249a48e484b998f1874a2010220723d844826828f092cf400cb210c4fa0b8cd1b9d1a7f21590e78e022ff6476b9'), sig1) eckey2 = PrivateKey(bfh('c7ce8c1462c311eec24dff9e2532ac6241e50ae57e7d1833af21942136972f23')) sig2 = eckey2.sign(bfh('642a2e66332f507c92bda910158dfe46fc10afbf72218764899d3af99a043fac'), None) self.assertEqual(bfh('30440220618513f4cfc87dde798ce5febae7634c23e7b9254a1eabf486be820f6a7c2c4702204fef459393a2b931f949e63ced06888f35e286e446dc46feb24b5b5f81c6ed52'), sig2)
def test_sign_message(self): password = '******' message = 'BitcoinSV' prvkey_text = "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ" enc_prvkey_text = pw_encode(prvkey_text, password) public_key = PrivateKey.from_text(prvkey_text).public_key d = Imported_KeyStore({}) d.import_private_key(1, public_key, enc_prvkey_text) msg_sig = d.sign_message(public_key, message, password) assert msg_sig.hex() == ( '1c26a18cb236e54bbe7e3db56639ef5cbefcf5a2e28850cdd304970832f84031' 'fc073bed1a151f0510e5558a22d23f16ed8032a1b74ffcac05227c053e1a1d8af5' )
def sign(self, keypairs): assert all(isinstance(key, XPublicKey) for key in keypairs) for txin in self.inputs: if txin.is_complete(): continue for j, x_pubkey in enumerate(txin.x_pubkeys): if x_pubkey in keypairs.keys(): logger.debug("adding signature for %s", x_pubkey) sec, compressed = keypairs.get(x_pubkey) txin.signatures[j] = self.sign_txin(txin, sec) if x_pubkey.kind() == 0xfd: pubkey_bytes = PrivateKey(sec).public_key.to_bytes(compressed=compressed) txin.x_pubkeys[j] = XPublicKey(pubkey_bytes) logger.debug("is_complete %s", self.is_complete())
def test_store__write_encrypted(store_class) -> None: privkey = PrivateKey.from_random() wallet_path = tempfile.mktemp() store = store_class(wallet_path, privkey.public_key.to_hex()) assert not store.is_primed() store.put("number", 10) store._write() assert store.is_primed() # This will raise an assertion if there is not locatible data for the JSON lump. store.read_raw_data() assert store.get("number") == 10 store = store_class(wallet_path, privkey.public_key.to_hex()) assert store.is_primed() store.read_raw_data() encrypted_data = store.get_encrypted_data() print(encrypted_data) raw_data = zlib.decompress(privkey.decrypt_message(encrypted_data)) store.load_data(raw_data) assert store.get("number") == 10
def sign(self, keypairs): for i, txin in enumerate(self.inputs()): num = txin['num_sig'] pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) for j, x_pubkey in enumerate(x_pubkeys): signatures = [sig for sig in txin['signatures'] if sig] if len(signatures) == num: # txin is complete break if x_pubkey in keypairs.keys(): logger.debug("adding signature for %s", x_pubkey) sec, compressed = keypairs.get(x_pubkey) sig = self.sign_txin(i, sec) txin['signatures'][j] = sig pubkey = PrivateKey(sec).public_key.to_hex( compressed=compressed) txin['pubkeys'][j] = pubkey # needed for fd keys self._inputs[i] = txin logger.debug("is_complete %s", self.is_complete()) self.raw = self.serialize()
def to_tx_input(txin): prev_hash, prev_idx = txin['output'].split(':') x_pubkeys = [] value = txin.get('value') sec = txin.get('privkey') threshold = 1 if sec: privkey = PrivateKey.from_text(sec) privkey, compressed = privkey.to_bytes(), privkey.is_compressed() x_pubkey = XPublicKey(privkey.public_key.to_hex()) keypairs[x_pubkey] = privkey, compressed x_pubkeys = [x_pubkey] return XTxInput( prev_hash=hex_str_to_hash(prev_hash), prev_idx=int(prev_idx), script_sig=Script(), sequence=0xffffffff, value=value, x_pubkeys=x_pubkeys, address=None, threshold=threshold, signatures=[NO_SIGNATURE] * len(x_pubkeys), )
def test_xpubkey_to_address(): privkey = PrivateKey.from_random() public_key = privkey.public_key x_pubkey = 'fd' + public_key.P2PKH_script().to_hex() assert xpubkey_to_address(x_pubkey) == ( x_pubkey, Address.from_string(public_key.to_address().to_string()))
import pytest import scryptlib.utils import scryptlib.contract from scryptlib.types import Int, PubKey, Sig, SigHashPreimage, Bytes import bitcoinx from bitcoinx import PrivateKey, TxOutput, SigHash, pack_byte, Script, sha256, TxInput key_priv_0 = PrivateKey.from_arbitrary_bytes(b'test123') key_pub_0 = key_priv_0.public_key key_priv_1 = PrivateKey.from_arbitrary_bytes(b'123test') key_pub_1 = key_priv_1.public_key key_priv_2 = PrivateKey.from_arbitrary_bytes(b'te123st') key_pub_2 = key_priv_2.public_key in_sats = 100000 out_sats = 22222 contract = './test/res/tokenUtxo.scrypt' compiler_result = scryptlib.utils.compile_contract(contract) desc = compiler_result.to_desc() Token = scryptlib.contract.build_contract_class(desc) token = Token() def test_verify_split_in_two(): data_part = scryptlib.utils.get_push_item(key_pub_0.to_bytes() + scryptlib.utils.get_push_int(10)[1:] + scryptlib.utils.get_push_int(90)[1:])
import pytest import scryptlib.utils import scryptlib.contract from scryptlib.types import Sig, PubKey, PubKeyHash import bitcoinx from bitcoinx import SigHash, PrivateKey, pack_byte key_priv = PrivateKey.from_arbitrary_bytes(b'test123') key_pub = key_priv.public_key pubkey_hash = key_pub.hash160() wrong_key_priv = PrivateKey.from_arbitrary_bytes(b'somethingelse') wrong_key_pub = wrong_key_priv.public_key contract = './test/res/p2pkh.scrypt' compiler_result = scryptlib.utils.compile_contract(contract) desc = compiler_result.to_desc() P2PKH = scryptlib.contract.build_contract_class(desc) p2pkh_obj = P2PKH(PubKeyHash(pubkey_hash)) context = scryptlib.utils.create_dummy_input_context() sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) input_idx = 0 utxo_satoshis = context.utxo.value sighash = context.tx.signature_hash(input_idx, utxo_satoshis, p2pkh_obj.locking_script, sighash_flag)
def get_private_key(self, pubkey: PublicKey, password: str) -> Tuple[bytes, bool]: '''Returns a (32 byte privkey, is_compressed) pair.''' privkey_text = self.export_private_key(pubkey, password) privkey = PrivateKey.from_text(privkey_text) return privkey.to_bytes(), privkey.is_compressed()
def _mpk_from_hex_seed(cls, hex_seed) -> str: secexp = cls.stretch_key(hex_seed.encode()) master_private_key = PrivateKey(int_to_be_bytes(secexp, 32)) return master_private_key.public_key.to_hex(compressed=False)[2:]
def decrypt_message(self, sequence, message, password: str): privkey, compressed = self.get_private_key(sequence, password) key = PrivateKey(privkey) return key.decrypt_message(message)
def sign_message(self, derivation_path: Sequence[int], message: bytes, password: str): privkey, compressed = self.get_private_key(derivation_path, password) key = PrivateKey(privkey, compressed) return key.sign_message(message)
def _public_key_from_private_key_text(text): return PrivateKey.from_text(text).public_key
def is_private_key(text: str) -> bool: try: PrivateKey.from_text(text) return True except ValueError: return False
def sign_message_with_wif_privkey(wif_privkey, msg): key = PrivateKey.from_WIF(wif_privkey) return key.sign_message(msg)