def tx_get_address_and_utxos(private_key_info, utxo_client, address=None): """ Get information about a private key (or a set of private keys used for multisig). Return (payer_address, payer_utxos) on success. UTXOs will be in BTC, not satoshis! """ if private_key_info is None: # just go with the address unspents = pybitcoin.get_unspents(address, utxo_client) return addr, unspents if is_singlesig(private_key_info): _, payer_address, payer_utxos = virtualchain.analyze_private_key( str(private_key_info), utxo_client) return payer_address, payer_utxos if is_multisig(private_key_info): redeem_script = str(private_key_info['redeem_script']) addr = virtualchain.make_multisig_address(redeem_script) unspents = pybitcoin.get_unspents(addr, utxo_client) return addr, unspents raise ValueError('Invalid private key info')
def test_basic_with_multisig(self): test_zf = """$ORIGIN bar.id $TTL 3600 pubkey TXT "pubkey:data:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" registrar URI 10 1 "bsreg://foo.com:8234" foo TXT "owner={}" "seqn=3" "parts=0" """ my_keys = [keylib.ECPrivateKey() for _ in range(3)] my_pubkeys = [k.public_key().to_hex() for k in my_keys] owner_addr = virtualchain.make_multisig_address(my_pubkeys, 3) test_zf = test_zf.format(owner_addr) domain_name = "bar.id" zf_json = zonefile.decode_name_zonefile(domain_name, test_zf) self.assertEqual(zf_json['$origin'], domain_name) subds = subdomains.parse_zonefile_subdomains(domain_name, zf_json) self.assertEqual(len(subds), 1) sub = subds[0] self.assertEqual(sub.n, 3) self.assertEqual(sub.sig, None) self.assertEqual(sub.subdomain_name, "foo")
def encrypt_private_key_info(privkey_info, password): """ Encrypt private key info. Return {'status': True, 'encrypted_private_key_info': {'address': ..., 'private_key_info': ...}} on success Returns {'error': ...} on error """ ret = {} hex_password = hexlify(password) if is_multisig(privkey_info): ret['address'] = virtualchain.make_multisig_address( privkey_info['redeem_script']) ret['private_key_info'] = encrypt_multisig_info(privkey_info, password) return {'status': True, 'encrypted_private_key_info': ret} elif is_singlesig(privkey_info): ret['address'] = virtualchain.BitcoinPrivateKey( privkey_info).public_key().address() ret['private_key_info'] = aes_encrypt(privkey_info, hex_password) return {'status': True, 'encrypted_private_key_info': ret} else: return {'error': 'Invalid private key info'}
def test_basic_with_multisig(self): test_zf = """$ORIGIN bar.id $TTL 3600 pubkey TXT "pubkey:data:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" registrar URI 10 1 "bsreg://foo.com:8234" foo TXT "owner={}" "seqn=3" "parts=0" """ my_keys = [ keylib.ECPrivateKey() for _ in range(3) ] my_pubkeys = [ k.public_key().to_hex() for k in my_keys ] owner_addr = virtualchain.make_multisig_address(my_pubkeys, 3) test_zf = test_zf.format(owner_addr) domain_name = "bar.id" zf_json = zonefile.decode_name_zonefile(domain_name, test_zf) self.assertEqual(zf_json['$origin'], domain_name) subds = subdomains.parse_zonefile_subdomains(domain_name, zf_json) self.assertEqual(len(subds), 1) sub = subds[0] self.assertEqual(sub.n, 3) self.assertEqual(sub.sig, None) self.assertEqual(sub.subdomain_name, "foo")
def test_sign_verify_multisig(self): my_keys = [keylib.ECPrivateKey() for _ in range(9)] my_pubkeys = [k.public_key().to_hex() for k in my_keys] my_sk_hexes = [k.to_hex() for k in my_keys] blob = "bar_the_foo" hash_hex = binascii.hexlify(hashlib.sha256(blob).digest()) attempted_pairs = [(1, 1), (1, 2), (1, 3), (3, 3), (2, 4), (3, 4), (2, 7), (5, 5)] for m, n in attempted_pairs: script_pubkeys = my_pubkeys[:n] redeem_script = virtualchain.make_multisig_script( script_pubkeys, m) owner_addr = virtualchain.make_multisig_address(script_pubkeys, m) sks_to_use = list(my_sk_hexes[:n]) if m < n: # force 1 failed sig check during verify sks_to_use = sks_to_use[1:] sigb64 = subdomains.sign_multisig(hash_hex, redeem_script, sks_to_use) self.assertTrue(subdomains.verify(owner_addr, blob, sigb64)) # try to mess with the plaintext blob self.assertFalse(subdomains.verify(owner_addr, blob + "0", sigb64)) for m, n in [(2, 3)]: script_pubkeys = my_pubkeys[:n] redeem_script = virtualchain.make_multisig_script( script_pubkeys, m) owner_addr = virtualchain.make_multisig_address(script_pubkeys, m) # try with a wrong redeem script redeem_script_broke = virtualchain.make_multisig_script( script_pubkeys, m - 1) sigb64 = subdomains.sign_multisig(hash_hex, redeem_script_broke, my_sk_hexes) self.assertFalse(subdomains.verify(owner_addr, blob, sigb64))
def test_sign_verify_multisig(self): my_keys = [ keylib.ECPrivateKey() for _ in range(9) ] my_pubkeys = [ k.public_key().to_hex() for k in my_keys ] my_sk_hexes = [ k.to_hex() for k in my_keys ] blob = "bar_the_foo" hash_hex = binascii.hexlify(hashlib.sha256(blob).digest()) attempted_pairs = [(1, 1), (1, 2), (1, 3), (3, 3), (2, 4), (3, 4), (2, 7), (5, 5)] for m, n in attempted_pairs: script_pubkeys = my_pubkeys[:n] redeem_script = virtualchain.make_multisig_script(script_pubkeys, m) owner_addr = virtualchain.make_multisig_address(script_pubkeys, m) sks_to_use = list(my_sk_hexes[:n]) if m < n: # force 1 failed sig check during verify sks_to_use = sks_to_use[1:] sigb64 = subdomains.sign_multisig(hash_hex, redeem_script, sks_to_use) self.assertTrue(subdomains.verify(owner_addr, blob, sigb64)) # try to mess with the plaintext blob self.assertFalse(subdomains.verify(owner_addr, blob + "0", sigb64)) for m, n in [(2, 3)]: script_pubkeys = my_pubkeys[:n] redeem_script = virtualchain.make_multisig_script(script_pubkeys, m) owner_addr = virtualchain.make_multisig_address(script_pubkeys, m) # try with a wrong redeem script redeem_script_broke = virtualchain.make_multisig_script(script_pubkeys, m - 1) sigb64 = subdomains.sign_multisig(hash_hex, redeem_script_broke, my_sk_hexes) self.assertFalse(subdomains.verify(owner_addr, blob, sigb64))
def get_privkey_info_address( privkey_info ): """ Get the address of private key information: * if it's a single private key, then calculate the address. * if it's a multisig info dict, then get the p2sh address """ if privkey_info is None: return None if is_singlesig(privkey_info): return virtualchain.BitcoinPrivateKey(privkey_info).public_key().address() elif is_multisig(privkey_info): return virtualchain.make_multisig_address( privkey_info['redeem_script'] ) else: raise ValueError("Invalid private key info")
def tx_get_address_and_utxos(private_key_info, utxo_client): """ Get information about a private key (or a set of private keys used for multisig). Return (payer_address, payer_utxos) on success. UTXOs will be in BTC, not satoshis! """ if isinstance(private_key_info, (str, unicode)): _, payer_address, payer_utxos = virtualchain.analyze_private_key( str(private_key_info), utxo_client) return payer_address, payer_utxos if isinstance(private_key_info, dict): assert 'redeem_script' in private_key_info assert 'private_keys' in private_key_info redeem_script = str(private_key_info['redeem_script']) addr = virtualchain.make_multisig_address(redeem_script) unspents = pybitcoin.get_unspents(addr, utxo_client) return addr, unspents raise ValueError('Invalid private key info')