def sign_raw_data(raw_data, privatekey): """ Sign a string of data. Returns signature as a base64 string """ data_hash = get_data_hash(raw_data) pk = ECPrivateKey(privatekey) pk_hex = pk.to_hex() # force uncompressed if len(pk_hex) > 64: pk = ECPrivateKey(privkey[:64]) priv = pk.to_hex() pub = pk.public_key().to_hex() assert len(pub[2:].decode('hex')) == ecdsa.SECP256k1.verifying_key_length, "BUG: Invalid key decoding" sk = ecdsa.SigningKey.from_string(priv.decode('hex'), curve=ecdsa.SECP256k1) sig_bin = sk.sign_digest(data_hash.decode('hex'), sigencode=ecdsa.util.sigencode_der) # enforce low-s sig_r, sig_s = ecdsa.util.sigdecode_der( sig_bin, ecdsa.SECP256k1.order ) if sig_s * 2 >= ecdsa.SECP256k1.order: log.debug("High-S to low-S") sig_s = ecdsa.SECP256k1.order - sig_s sig_bin = ecdsa.util.sigencode_der( sig_r, sig_s, ecdsa.SECP256k1.order ) # sanity check vk = ecdsa.VerifyingKey.from_string(pub[2:].decode('hex'), curve=ecdsa.SECP256k1) assert vk.verify_digest(sig_bin, data_hash.decode('hex'), sigdecode=ecdsa.util.sigdecode_der), "Failed to verify signature ({}, {})".format(sig_r, sig_s) return base64.b64encode( bitcoin.encode_sig( None, sig_r, sig_s ).decode('hex') )
def sign_token(claim, signing_private_key, subject, issuer=None, signing_algorithm="ES256K"): if signing_algorithm != 'ES256K': raise ValueError("Signing algorithm not supported") private_key_object = ECPrivateKey(signing_private_key) public_key_hex = private_key_object.public_key().to_hex() if not issuer: issuer = {"publicKey": public_key_hex} current_time = datetime.datetime.now() payload = { "claim": claim, "subject": subject, "issuer": issuer, "issuedAt": current_time.isoformat(), "expiresAt": current_time.replace(current_time.year + 1).isoformat() } token_signer = TokenSigner() token = token_signer.sign(payload, private_key_object.to_pem()) return token
def sign_token_records(profile_components, parent_private_key, signing_algorithm="ES256K"): """ Function for iterating through a list of profile components and signing separate individual profile tokens. """ if signing_algorithm != "ES256K": raise ValueError("Signing algorithm not supported") token_records = [] for profile_component in profile_components: private_key = ECPrivateKey(parent_private_key) public_key = private_key.public_key() subject = {"publicKey": public_key.to_hex()} token = sign_token(profile_component, private_key.to_hex(), subject, signing_algorithm=signing_algorithm) token_record = wrap_token(token) token_record["parentPublicKey"] = public_key.to_hex() token_records.append(token_record) return token_records
def setUp(self): self.master_private_key = ECPrivateKey(compressed=True) self.profile_components = [{ "name": "Naval Ravikant" }, { "birthDate": "1980-01-01" }]
def scenario( wallets, **kw ): global wallet_keys, wallet_keys_2, error, index_file_data, resource_data empty_key = ECPrivateKey().to_hex() wallet_keys = testlib.ysi_client_initialize_wallet( "0123456789abcdef", wallets[1].privkey, wallets[2].privkey, wallets[0].privkey) test_proxy = testlib.TestAPIProxy() ysi_client.set_default_proxy( test_proxy ) testlib.ysi_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey ) testlib.next_block( **kw ) testlib.ysi_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey ) testlib.next_block( **kw ) testlib.ysi_namespace_ready( "test", wallets[1].privkey ) testlib.next_block( **kw ) # tell serialization-checker that value_hash can be ignored here print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash" sys.stdout.flush() testlib.next_block( **kw ) config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None) config_dir = os.path.dirname(config_path) conf = ysi_client.get_config(config_path) assert conf api_pass = conf['api_password'] # let's do a withdraw of all res = testlib.ysi_REST_call('POST', '/v1/wallet/balance', None, api_pass=api_pass, data= { 'address' : virtualchain.get_privkey_address(empty_key), }) if 'error' in res['response']: res['test'] = 'Failed to perform withdraw' print json.dumps(res) error = True return False for i in xrange (0, 1): testlib.next_block( **kw ) print 'Waiting for the withdraw to go through' res = testlib.ysi_REST_call('GET', '/v1/wallet/balance/0', None, api_pass=api_pass) if 'error' in res['response']: res['test'] = 'Failed to get wallet balance' print json.dumps(res) error = True return False res = testlib.ysi_REST_call('GET', '/v1/wallet/balance/0', None, api_pass=api_pass) if 'error' in res['response']: res['test'] = 'Failed to get wallet balance' print json.dumps(res) error = True return False
def decrypt_multisig_info(enc_multisig_info, password): """ Given an encrypted multisig info dict, decrypt the sensitive fields. Returns {'private_keys': ..., 'redeem_script': ..., **other_fields} Return {'error': ...} on error """ multisig_info = { 'private_keys': None, 'redeem_script': None, } hex_password = hexlify(password) assert is_encrypted_multisig( enc_multisig_info), 'Invalid encrypted multisig keys' multisig_info['private_keys'] = [] for enc_pk in enc_multisig_info['encrypted_private_keys']: pk = None try: pk = aes_decrypt(enc_pk, hex_password) virtualchain.BitcoinPrivateKey(pk) except Exception as e: if BLOCKSTACK_TEST: log.exception(e) return { 'error': 'Invalid password; failed to decrypt private key in multisig wallet' } multisig_info['private_keys'].append(ECPrivateKey(pk).to_hex()) redeem_script = None enc_redeem_script = enc_multisig_info['encrypted_redeem_script'] try: redeem_script = aes_decrypt(enc_redeem_script, hex_password) except Exception as e: if BLOCKSTACK_TEST: log.exception(e) return { 'error': 'Invalid password; failed to decrypt redeem script in multisig wallet' } multisig_info['redeem_script'] = redeem_script # preserve any other information in the multisig info for k, v in enc_multisig_info.items(): if k not in ['encrypted_private_keys', 'encrypted_redeem_script']: multisig_info[k] = v return multisig_info
def load_data_pubkey_for_new_zonefile( wallet_keys={}, config_path=CONFIG_PATH ): """ Find the right public key to use for data when creating a new zonefile. If the wallet has a data keypair defined, use that. Otherwise, fall back to the owner public key """ data_pubkey = None if 'data_privkey' in wallet_keys and wallet_keys['data_privkey'] is not None: data_pubkey = ECPrivateKey(wallet_keys['data_privkey']).public_key().to_hex() elif 'data_pubkey' in wallet_keys: data_pubkey = wallet_keys['data_pubkey'] return data_pubkey
def make_wallet(password, config_path=CONFIG_PATH, payment_privkey_info=None, owner_privkey_info=None, data_privkey_info=None, test_legacy=False, encrypt=True): """ Make a new, encrypted wallet structure. The owner and payment keys will be 2-of-3 multisig key bundles. The data keypair will be a single-key bundle. Return the new wallet on success. Return {'error': ...} on failure """ if test_legacy and not BLOCKSTACK_TEST: raise Exception("Not in testing but tried to make a legacy wallet") # default to 2-of-3 multisig key info if data isn't given payment_privkey_info = virtualchain.make_multisig_wallet( 2, 3 ) if payment_privkey_info is None and not test_legacy else payment_privkey_info owner_privkey_info = virtualchain.make_multisig_wallet( 2, 3 ) if owner_privkey_info is None and not test_legacy else owner_privkey_info data_privkey_info = ECPrivateKey().to_wif( ) if data_privkey_info is None and not test_legacy else data_privkey_info new_wallet = _make_encrypted_wallet_data(password, payment_privkey_info, owner_privkey_info, data_privkey_info, test_legacy=test_legacy) if 'error' in new_wallet: return new_wallet # sanity check if not test_legacy: jsonschema.validate(new_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT) if encrypt: return new_wallet # decrypt and return wallet_info = decrypt_wallet(new_wallet, password, config_path=config_path) assert 'error' not in wallet_info, "Failed to decrypt new wallet: {}".format( wallet_info['error']) return wallet_info['wallet']
def ecdsa_private_key(privkey_str=None): """ Make a private key, but enforce the following rule: * unless the key's hex encoding specifically ends in '01', treat it as uncompressed. """ compressed = False if privkey_str is not None: assert isinstance(privkey_str, (str, unicode)) privkey_str = str(privkey_str) if privkey_str is None or keylib.key_formatting.get_privkey_format(privkey_str).endswith('compressed'): compressed = True return ECPrivateKey(privkey_str, compressed=compressed)
def decrypt_private_key_info(privkey_info, password): """ Decrypt a particular private key info bundle. It can be either a single-signature private key, or a multisig key bundle. Return {'address': ..., 'private_key_info': ...} on success. Return {'error': ...} on error. """ hex_password = hexlify(password) ret = {} if is_encrypted_multisig(privkey_info): ret = decrypt_multisig_info(privkey_info, password) if 'error' in ret: return { 'error': 'Failed to decrypt multisig wallet: {}'.format(ret['error']) } # sanity check if 'redeem_script' not in ret: return {'error': 'Invalid multisig wallet: missing redeem_script'} if 'private_keys' not in ret: return {'error': 'Invalid multisig wallet: missing private_keys'} return { 'address': virtualchain.make_p2sh_address(ret['redeem_script']), 'private_key_info': ret } if is_encrypted_singlesig(privkey_info): try: pk = aes_decrypt(privkey_info, hex_password) pk = ECPrivateKey(pk).to_hex() except Exception as e: if BLOCKSTACK_TEST: log.exception(e) return {'error': 'Invalid password'} return { 'address': virtualchain.BitcoinPrivateKey(pk).public_key().address(), 'private_key_info': pk } return {'error': 'Invalid encrypted private key info'}
def load_data_pubkey_for_new_zonefile(wallet_keys={}, config_path=CONFIG_PATH): """ Find the right public key to use for data when creating a new zonefile. If the wallet has a data keypair defined, use that. Otherwise, fall back to the owner public key """ data_pubkey = None data_privkey = wallet_keys.get('data_privkey', None) if data_privkey is not None: # force compressed data_pubkey = ECPrivateKey(data_privkey, compressed=True).public_key().to_hex() return data_pubkey data_pubkey = wallet_keys.get('data_pubkey', None) return data_pubkey
def load_signing_key(signing_key, crypto_backend=default_backend()): """ Optional: crypto backend object from the "cryptography" python library """ if not isinstance(crypto_backend, (Backend, MultiBackend)): raise ValueError('backend must be a valid Backend object') if isinstance(signing_key, EllipticCurvePrivateKey): return signing_key elif isinstance(signing_key, (str, unicode)): invalid_strings = [b'-----BEGIN PUBLIC KEY-----'] invalid_string_matches = [ string_value in signing_key for string_value in invalid_strings ] if any(invalid_string_matches): raise ValueError( 'Signing key must be a private key, not a public key.') if is_hex(signing_key): try: private_key_pem = ECPrivateKey(signing_key).to_pem() except: pass else: try: return load_pem_private_key(private_key_pem, password=None, backend=crypto_backend) except: raise InvalidPrivateKeyError() try: return load_der_private_key(signing_key, password=None, backend=crypto_backend) except Exception as e: traceback.print_exc() raise InvalidPrivateKeyError() else: try: return load_pem_private_key(signing_key, password=None, backend=crypto_backend) except: raise InvalidPrivateKeyError() else: raise ValueError('Signing key must be in string or unicode format.')
def get_data_privkey(user_zonefile, wallet_keys=None, config_path=CONFIG_PATH): """ Get the user's data private key. Use the private key that corresponds to the data public key in their zonefile. (If the have a designated data public key, use the data private key. If they don't, use the owner private key). Return None if not set """ from .wallet import get_wallet from .user import user_zonefile_data_pubkey try: data_pubkey = user_zonefile_data_pubkey(user_zonefile) except ValueError: log.error("Multiple pubkeys defined") return None if data_pubkey is None: log.error("No data public key defined") return None wallet = None if wallet_keys is not None: if not wallet_keys.has_key( 'data_privkey') or wallet_keys['data_privkey'] is None: log.error("No data private key set") return None wallet = wallet_keys else: wallet = get_wallet(config_path=CONFIG_PATH) assert wallet is not None if not wallet.has_key('data_privkey') or ECPrivateKey( wallet['data_privkey']).public_key().to_hex() != data_pubkey: # data private key doesn't match zonefile log.error("Data private key does not match zonefile") return None else: # zonefile matches data privkey return wallet['data_privkey']
def setUp(self): self.private_key_hex = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b22901' self.public_key_hex = '027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69' self.sample_payload = {"issuedAt": "1440713414.19"} self.multiple_private_keys = [ '99eca4792e019686f2b115d65224c72431d1dc361a1bacbf46daf0ed194ea07c01', '43baf5d14516a295f8883425bb0b35de7e08ab126965c5775cf7a5956d2eb6b801' ] self.multiple_public_keys = [ ECPrivateKey(pk).public_key().to_hex() for pk in self.multiple_private_keys ] self.multiple_invalid_public_keys_1 = [ self.public_key_hex, self.multiple_public_keys[0] ] self.multiple_invalid_public_keys_2 = [ self.public_key_hex, self.multiple_public_keys[1], self.multiple_public_keys[0] ]
def encrypt_wallet(wallet, password, test_legacy=False): """ Encrypt the wallet. Return the encrypted dict on success Return {'error': ...} on error """ if test_legacy: assert BLOCKSTACK_TEST, 'test_legacy only works in test mode' # must be conformant to the current schema if not test_legacy: jsonschema.validate(wallet, WALLET_SCHEMA_CURRENT) payment_privkey_info = wallet.get('payment_privkey', None) owner_privkey_info = wallet.get('owner_privkey', None) data_privkey_info = wallet.get('data_privkey', None) if not is_singlesig(data_privkey_info): log.error('Invalid data private key') return {'error': 'Invalid data private key'} if not is_singlesig_hex(data_privkey_info): data_privkey_info = ECPrivateKey(data_privkey_info).to_hex() encrypted_wallet = _make_encrypted_wallet_data(password, payment_privkey_info, owner_privkey_info, data_privkey_info, test_legacy=test_legacy) if 'error' in encrypted_wallet: return encrypted_wallet # sanity check if not test_legacy: jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT) return encrypted_wallet
def test_private_key_to_public_key_conversion(self): priv = ECPrivateKey(self.reference['hex_private_key'], compressed=False) pub = priv.public_key() self.assertEqual(pub.to_hex(), self.reference['hex_public_key']) self.assertEqual(pub.address(), self.reference['address'])
def setUp(self): self.private_key = ECPrivateKey( self.ref['wif_private_key'], compressed=False) self.assertEqual(self.private_key_from_wif.to_hex(), self.ref['hex_private_key'])
def test_private_key_from_wif(self): self.private_key_from_wif = ECPrivateKey( self.reference['wif_private_key'], compressed=False) self.assertEqual(self.private_key.to_hex(), self.private_key_from_wif.to_hex())
def setUp(self): self.private_key = ECPrivateKey(self.reference['hex_private_key'], compressed=False)
def make_wallet_keys(data_privkey=None, owner_privkey=None, payment_privkey=None): """ For testing. DO NOT USE """ ret = { 'owner_privkey': None, 'data_privkey': None, 'payment_privkey': None, } if data_privkey is not None: if not is_singlesig(data_privkey): raise ValueError('Invalid data key info') pk_data = virtualchain.BitcoinPrivateKey(data_privkey).to_hex() ret['data_privkey'] = pk_data if owner_privkey is not None: if is_multisig(owner_privkey): pks = [ virtualchain.BitcoinPrivateKey(pk).to_hex() for pk in owner_privkey['private_keys'] ] m, pubs = virtualchain.parse_multisig_redeemscript( owner_privkey['redeem_script']) ret['owner_privkey'] = virtualchain.make_multisig_info(m, pks) ret['owner_addresses'] = [ret['owner_privkey']['address']] elif is_singlesig(owner_privkey): pk_owner = virtualchain.BitcoinPrivateKey(owner_privkey).to_hex() ret['owner_privkey'] = pk_owner ret['owner_addresses'] = [ virtualchain.BitcoinPrivateKey( pk_owner).public_key().address() ] else: raise ValueError('Invalid owner key info') if payment_privkey is None: return ret if is_multisig(payment_privkey): pks = [ virtualchain.BitcoinPrivateKey(pk).to_hex() for pk in payment_privkey['private_keys'] ] m, pubs = virtualchain.parse_multisig_redeemscript( payment_privkey['redeem_script']) ret['payment_privkey'] = virtualchain.make_multisig_info(m, pks) ret['payment_addresses'] = [ret['payment_privkey']['address']] elif is_singlesig(payment_privkey): pk_payment = virtualchain.BitcoinPrivateKey(payment_privkey).to_hex() ret['payment_privkey'] = pk_payment ret['payment_addresses'] = [ virtualchain.BitcoinPrivateKey(pk_payment).public_key().address() ] else: raise ValueError('Invalid payment key info') ret['data_pubkey'] = ECPrivateKey( ret['data_privkey']).public_key().to_hex() ret['data_pubkeys'] = [ret['data_pubkey']] return ret
) return ret # legacy compat: use the master private key to generate child keys. # If the specific key they are purposed for is not defined in the wallet, # then they are used in its place. # This is because originally, the master private key was used to derive # the owner, payment, and data private keys; not all wallets define # these keys separately (and have instead relied on us being able to # generate them from the master private key). child = wallet.get_child_keypairs(count=3, include_privkey=True) payment_keypair = child[0] owner_keypair = child[1] data_keypair = child[2] data_pubkey = ECPrivateKey(data_keypair[1]).public_key().to_hex() multisig = False curr_height = get_block_height(config_path=config_path) if curr_height >= config.EPOCH_HEIGHT_MINIMUM: # safe to use multisig multisig = True ret = {} keynames = ['payment', 'owner', 'data'] for i in xrange(0, len(keynames)): keyname = keynames[i] keyname_privkey = "%s_privkey" % keyname keyname_addresses = "%s_addresses" % keyname
def unlock_wallet(password=None, config_dir=CONFIG_DIR, wallet_path=None): """ Unlock the wallet. Save the wallet to the RPC daemon on success. If this wallet is in legacy format, then it will be migrated to the latest format and the legacy copy backed up. Return {'status': True, 'addresses': ...} on success return {'error': ...} on error """ config_path = os.path.join(config_dir, CONFIG_FILENAME) if wallet_path is None: wallet_path = os.path.join(config_dir, WALLET_FILENAME) if is_wallet_unlocked(config_dir): return {'status': True} else: try: if password is None: password = getpass("Enter wallet password: "******"r") as f: data = f.read() data = json.loads(data) wallet = decrypt_wallet(data, password, config_path=config_path) if 'error' in wallet: log.error("Failed to decrypt wallet: %s" % wallet['error']) return wallet # may need to migrate data_pubkey into wallet.json _, _, onfile_data_pubkey = get_addresses_from_file( wallet_path=wallet_path) if onfile_data_pubkey is None: # make a data keypair (always the third child (index 2) of the HDWallet) w = HDWallet(wallet['hex_privkey']) child = w.get_child_keypairs(count=3, include_privkey=True) data_keypair = child[2] wallet['data_privkey'] = data_keypair[1] wallet['data_pubkeys'] = [ ECPrivateKey(data_keypair[1]).public_key().to_hex() ] wallet['data_pubkey'] = wallet['data_pubkeys'][0] # set addresses wallet['payment_addresses'] = [ get_privkey_info_address(wallet['payment_privkey']) ] wallet['owner_addresses'] = [ get_privkey_info_address(wallet['owner_privkey']) ] # save! encrypted_wallet = make_wallet( password, hex_privkey=wallet['hex_privkey'], payment_privkey=wallet['payment_privkey'], owner_privkey=wallet['owner_privkey'], data_privkey=wallet['data_privkey'], config_path=config_path) if 'error' in encrypted_wallet: log.error("Failed to make wallet: %s" % encrypted_wallet['error']) return encrypted_wallet write_wallet(encrypted_wallet, path=wallet_path + ".tmp") legacy_path = wallet_path + ".legacy" if os.path.exists(wallet_path): if not os.path.exists(legacy_path): shutil.move(wallet_path, legacy_path) else: i = 1 while os.path.exists(legacy_path): legacy_path = wallet_path + ".legacy.%s" % i i += 1 shutil.move(wallet_path, legacy_path) shutil.move(wallet_path + ".tmp", wallet_path) log.debug( "Migrated wallet %s (legacy wallet backed up to %s)" % (wallet_path, legacy_path)) # save! try: res = save_keys_to_memory([ wallet['payment_addresses'][0], wallet['payment_privkey'] ], [wallet['owner_addresses'][0], wallet['owner_privkey'] ], [wallet['data_pubkeys'][0], wallet['data_privkey']], config_dir=config_dir) except KeyError, ke: if os.environ.get("BLOCKSACK_DEBUG", None) == "1": log.error( "data: %s\n" % simplejson.dumps(wallet, indent=4, sort_keys=True)) raise if 'error' in res: return res addresses = { "payment_address": wallet['payment_addresses'][0], "owner_address": wallet['owner_addresses'][0], "data_pubkey": wallet['data_pubkeys'][0] } return {'status': True, "addresses": addresses} except KeyboardInterrupt: return {'error': 'Interrupted'}
def test_random_private_key(self): private_key = ECPrivateKey() self.assertTrue(isinstance(private_key, ECPrivateKey))
def scenario(wallets, **kw): global wallet_keys, wallet_keys_2, error, index_file_data, resource_data empty_key = ECPrivateKey().to_hex() wallet_keys = testlib.ysi_client_initialize_wallet("0123456789abcdef", empty_key, empty_key, empty_key) test_proxy = testlib.TestAPIProxy() ysi_client.set_default_proxy(test_proxy) testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.ysi_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.ysi_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) # tell serialization-checker that value_hash can be ignored here print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash" sys.stdout.flush() testlib.next_block(**kw) config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None) config_dir = os.path.dirname(config_path) conf = ysi_client.get_config(config_path) assert conf api_pass = conf['api_password'] payment_key = wallets[1].privkey # make zonefile for recipient driver_urls = ysi_client.storage.make_mutable_data_urls( 'bar.test', use_only=['dht', 'disk']) zonefile = ysi_client.zonefile.make_empty_zonefile('bar.test', wallets[4].pubkey_hex, urls=driver_urls) zonefile_txt = ysi_zones.make_zone_file(zonefile, origin='bar.test', ttl=3600) no_key_postage = {'name': 'bar.test', 'zonefile': zonefile_txt} key_postage = dict(no_key_postage) key_postage['payment_key'] = payment_key key_postage['owner_key'] = new_key res = testlib.ysi_REST_call('POST', '/v1/names', None, api_pass=api_pass, data=no_key_postage) if 'error' not in res['response']: print "Successfully registered user with should-have-been-bad keys" print res return False # let's do a small withdraw res = testlib.ysi_REST_call( 'POST', '/v1/wallet/balance', None, api_pass=api_pass, data={ 'address': virtualchain.get_privkey_address(empty_key), 'amount': int(1e4), 'payment_key': payment_key }) if 'error' in res['response']: res['test'] = 'Failed to perform withdraw' print json.dumps(res) error = True return False for i in xrange(0, 1): testlib.next_block(**kw) print 'Waiting for the withdraw to go through' res = testlib.ysi_REST_call('GET', '/v1/wallet/balance/0', None, api_pass=api_pass) if 'error' in res['response']: res['test'] = 'Failed to get wallet balance' print json.dumps(res) error = True return False if int(res['response']['balance']['satoshis']) <= 0: res['test'] = 'Wallet balance did not increment!' print json.dumps(res) error = True return False res = testlib.ysi_REST_call('POST', '/v1/names', None, api_pass=api_pass, data=key_postage) if 'error' in res['response']: res['test'] = 'Failed to register user' print json.dumps(res) error = True return False print "Registering bar.test" for i in xrange(0, 6): testlib.next_block(**kw) if not res: return False # wait for the preorder to get confirmed for i in xrange(0, 4): testlib.next_block(**kw) # wait for register to go through print 'Wait for register to be submitted' time.sleep(10) # wait for the register to get confirmed for i in xrange(0, 6): testlib.next_block(**kw) res = testlib.verify_in_queue(None, 'bar.test', 'register', None, api_pass=api_pass) if not res: return False for i in xrange(0, 4): testlib.next_block(**kw) print 'Wait for update to be submitted' time.sleep(10) # wait for update to get confirmed for i in xrange(0, 6): testlib.next_block(**kw) res = testlib.verify_in_queue(None, 'bar.test', 'update', None, api_pass=api_pass) if not res: print res print "update error in first update" return False for i in xrange(0, 4): testlib.next_block(**kw) print 'Wait for zonefile to be sent' time.sleep(10) res = testlib.ysi_REST_call("GET", "/v1/names/bar.test", None, api_pass=api_pass) if 'error' in res or res['http_status'] != 200: res['test'] = 'Failed to get name bar.test' print json.dumps(res) return False print res['response'] zonefile_hash = res['response']['zonefile_hash'] # should still be registered if res['response']['status'] != 'registered': print "register not complete" print json.dumps(res) return False # do we have the history for the name? res = testlib.ysi_REST_call("GET", "/v1/names/bar.test/history", None, api_pass=api_pass) if 'error' in res or res['http_status'] != 200: res['test'] = "Failed to get name history for foo.test" print json.dumps(res) return False # valid history? hist = res['response'] if len(hist.keys()) != 3: res['test'] = 'Failed to get update history' res['history'] = hist print json.dumps(res, indent=4, sort_keys=True) return False # get the zonefile res = testlib.ysi_REST_call( "GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), None, api_pass=api_pass) if 'error' in res or res['http_status'] != 200: res['test'] = 'Failed to get name zonefile' print json.dumps(res) return False # same zonefile we put? if res['response']['zonefile'] != zonefile_txt: res['test'] = 'mismatched zonefile, expected\n{}\n'.format( zonefile_txt) print json.dumps(res) return False # okay, now let's try to do an update. # make zonefile for recipient driver_urls = ysi_client.storage.make_mutable_data_urls( 'bar.test', use_only=['http', 'disk']) zonefile = ysi_client.zonefile.make_empty_zonefile('bar.test', wallets[3].pubkey_hex, urls=driver_urls) zonefile_txt = ysi_zones.make_zone_file(zonefile, origin='bar.test', ttl=3600) # let's do this update. res = testlib.ysi_REST_call('PUT', '/v1/names/bar.test/zonefile', None, api_pass=api_pass, data={ 'zonefile': zonefile_txt, 'owner_key': new_key, 'payment_key': payment_key }) if 'error' in res or res['http_status'] != 202: res['test'] = 'Failed to register user' print json.dumps(res) error = True return False else: print "Submitted update!" print res print 'Wait for update to be submitted' time.sleep(10) # wait for update to get confirmed for i in xrange(0, 6): testlib.next_block(**kw) res = testlib.verify_in_queue(None, 'bar.test', 'update', None, api_pass=api_pass) if not res: print "update error in second update" print res return False for i in xrange(0, 4): testlib.next_block(**kw) # wait for zonefile to propagate time.sleep(10) res = testlib.ysi_REST_call("GET", "/v1/names/bar.test", None, api_pass=api_pass) if 'error' in res or res['http_status'] != 200: res['test'] = 'Failed to get name bar.test' print json.dumps(res) return False zonefile_hash = res['response']['zonefile_hash'] # get the zonefile res = testlib.ysi_REST_call( "GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), None, api_pass=api_pass) if 'error' in res or res['http_status'] != 200: res['test'] = 'Failed to get name zonefile' print json.dumps(res) return False # same zonefile we put? if res['response']['zonefile'] != zonefile_txt: res['test'] = 'mismatched zonefile, expected\n{}\n'.format( zonefile_txt) print json.dumps(res) return False
def setUp(self): self.private_key = ECPrivateKey( self.ref['hex_private_key'], compressed=True)
def singlesig_privkey_to_string(privkey_info): """ Convert private key to string """ return ECPrivateKey(privkey_info).to_hex()
assert is_legacy assert keyname in key_defaults, 'BUG: no legacy private key for {}'.format( keyname) default_privkey = key_defaults[keyname] new_wallet[keyname_privkey] = default_privkey new_wallet[keyname_addresses] = [ virtualchain.BitcoinPrivateKey( default_privkey).public_key().address() ] migrated = True # add data keys. Make sure it's *uncompressed* assert new_wallet.has_key('data_privkey') data_pubkey = ECPrivateKey(str( new_wallet['data_privkey'])).public_key().to_hex() if keylib.key_formatting.get_pubkey_format( data_pubkey) == 'hex_compressed': data_pubkey = keylib.key_formatting.decompress(data_pubkey) data_pubkey = str(data_pubkey) new_wallet['data_pubkeys'] = [data_pubkey] new_wallet['data_pubkey'] = data_pubkey new_wallet['version'] = SERIES_VERSION # sanity check--must be decrypted properly try: jsonschema.validate(new_wallet, WALLET_SCHEMA_CURRENT) except ValidationError as e:
def _make_encrypted_wallet_data(password, payment_privkey_info, owner_privkey_info, data_privkey_info, test_legacy=False): """ Lowlevel method to make the encrypted wallet's data, given the decrypted data. """ data = {} enc_payment_info = None enc_owner_info = None enc_data_info = None if not test_legacy: # legacy wallets (which we test for) may omit these. # when running in production, this is prohibited. assert payment_privkey_info assert owner_privkey_info assert data_privkey_info if payment_privkey_info is not None: enc_payment_info = encrypt_private_key_info(payment_privkey_info, password) if 'error' in enc_payment_info: log.error('failed to encrypt payment private key info') return {'error': enc_payment_info['error']} if owner_privkey_info is not None: enc_owner_info = encrypt_private_key_info(owner_privkey_info, password) if 'error' in enc_owner_info: log.error('failed to encrypt owner private key info') return {'error': enc_owner_info['error']} if data_privkey_info is not None: enc_data_info = encrypt_private_key_info(data_privkey_info, password) if 'error' in enc_data_info: log.error('failed to encrypt data private key info') return {'error': enc_data_info['error']} if enc_payment_info is not None: payment_addr = enc_payment_info['encrypted_private_key_info'][ 'address'] enc_payment_info = enc_payment_info['encrypted_private_key_info'][ 'private_key_info'] data['encrypted_payment_privkey'] = enc_payment_info data['payment_addresses'] = [payment_addr] if enc_owner_info is not None: owner_addr = enc_owner_info['encrypted_private_key_info']['address'] enc_owner_info = enc_owner_info['encrypted_private_key_info'][ 'private_key_info'] data['encrypted_owner_privkey'] = enc_owner_info data['owner_addresses'] = [owner_addr] if enc_data_info is not None: enc_data_info = enc_data_info['encrypted_private_key_info'][ 'private_key_info'] data['encrypted_data_privkey'] = enc_data_info data['data_pubkeys'] = [ ECPrivateKey(data_privkey_info).public_key().to_hex() ] data['data_pubkey'] = data['data_pubkeys'][0] data['version'] = SERIES_VERSION return data