def get_new_address(signature_tree_height=config.dev.xmss_tree_height, seed=None): # type: (int, str) -> AddressBundle """ Get a new wallet address The address format is a list of two items [address, data structure from random_mss call] :param signature_tree_height: :param address_type: :param seed: :return: a wallet address """ xmss = XMSS(tree_height=signature_tree_height, seed=seed) return AddressBundle(xmss.get_address(), xmss)
def _read_wallet(self): self.address_bundle = [] if not os.path.isfile(self.wallet_dat_filename): return try: with open(self.wallet_dat_filename, "rb") as infile: wallet_store = qrl_pb2.WalletStore() wallet_store.ParseFromString(bytes(infile.read())) self.address_bundle = [] for a in wallet_store.wallets: tmpxmss = XMSS(config.dev.xmss_tree_height, mnemonic2bin(a.mnemonic.strip())) tmpxmss.set_index(a.xmss_index) if a.address.encode() != tmpxmss.get_address(): logger.fatal("Mnemonic and address do not match.") exit(1) self.address_bundle.append(AddressBundle(tmpxmss.get_address(), tmpxmss)) except Exception as e: logger.warning("It was not possible to open the wallet: %s", e)
def test_sign_verify(self): message = "This is a test" message_bin = str2bin(message) xmss_height = 10 seed = bytearray([i for i in range(48)]) xmss = XMSS(xmss_height, seed) pk = xmss.pk() xmss.set_index(1) for i in range(10): self.assertTrue(xmss.get_index() == i + 1) signature = xmss.SIGN(message_bin) self.assertTrue(XMSS.VERIFY(message_bin, signature, pk))
def slave_tx_generate(ctx, src, master, number_of_slaves, access_type, fee, pk, ots_key_index): """ Generates Slave Transaction for the wallet """ try: _, src_xmss = _select_wallet(ctx, src) ots_key_index = validate_ots_index(ots_key_index, src_xmss) src_xmss.set_ots_index(ots_key_index) if src_xmss: address_src_pk = src_xmss.pk else: address_src_pk = pk.encode() master_addr = None if master_addr: master_addr = parse_qaddress(master) fee_shor = _quanta_to_shor(fee) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) slave_xmss = [] slave_pks = [] access_types = [] slave_xmss_seed = [] if number_of_slaves > 100: click.echo("Error: Max Limit for the number of slaves is 100") quit(1) for i in range(number_of_slaves): print("Generating Slave #" + str(i + 1)) xmss = XMSS.from_height(config.dev.xmss_tree_height) slave_xmss.append(xmss) slave_xmss_seed.append(xmss.extended_seed) slave_pks.append(xmss.pk) access_types.append(access_type) print("Successfully Generated Slave %s/%s" % (str(i + 1), number_of_slaves)) try: tx = SlaveTransaction.create(slave_pks=slave_pks, access_types=access_types, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) tx.sign(src_xmss) with open('slaves.json', 'w') as f: json.dump([bin2hstr(src_xmss.address), slave_xmss_seed, tx.to_json()], f) click.echo('Successfully created slaves.json') click.echo('Move slaves.json file from current directory to the mining node inside ~/.qrl/') except Exception as e: click.echo("Unhandled error: {}".format(str(e))) quit(1)
def _upgrade_old_wallet(self): wallet_old_dat_filename = os.path.join(config.user.wallet_path, config.dev.wallet_old_dat_filename) if not os.path.isfile(wallet_old_dat_filename): return False logger.info("Found old wallet format. Upgrading") try: logger.info('Retrieving wallet file') with open(wallet_old_dat_filename, "r") as infile: data = json.load(infile) self.address_bundle = [] for a in data: tmpxmss = XMSS(config.dev.xmss_tree_height, mnemonic2bin(a['mnemonic'].strip())) tmpxmss.set_index(a['index']) self.address_bundle.append(AddressBundle(tmpxmss.get_address().encode(), tmpxmss)) except Exception as e: logger.warning("It was not possible to open the wallet: %s", e) logger.info("Saving in the new format") self.save_wallet()
def test_create2(self): alice_xmss = get_alice_xmss() slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed()) h0 = sha256(b'hashchain_seed') h1 = sha256(h0) h2 = sha256(h1) h3 = sha256(h2) stake_transaction = StakeTransaction.create(activation_blocknumber=0, xmss=alice_xmss, slavePK=slave_xmss.pk(), hashchain_terminator=h3) sv = StakeValidator(100, stake_transaction) self.assertTrue(sv.validate_hash(h0, 2)) self.assertTrue(sv.validate_hash(h2, 0)) self.assertTrue(sv.validate_hash(h2, 0)) self.assertTrue(sv.validate_hash(h1, 1)) self.assertTrue(sv.validate_hash(h0, 2))
def test_xmss_tree(self): # Create seeds from public/private keys seed1, pub1, priv1 = new_keys(S1) xmss_array, x_bms, l_bms, privs, pubs = XMSS._xmss_tree( number_signatures=2, public_SEED=pub1, private_SEED=priv1) # Verify sizes self.assertEqual(len(xmss_array), 2) self.assertEqual(len(x_bms), 5) self.assertEqual(len(l_bms), 14) self.assertEqual(len(privs), 2) self.assertEqual(len(pubs), 2)
def _read_wallet(self): self.address_bundle = [] if not os.path.isfile(self.wallet_dat_filename): upgraded = self._upgrade_old_wallet() if not upgraded: return try: logger.info('Retrieving wallet file') with open(self.wallet_dat_filename, "rb") as infile: wallet_store = qrl_pb2.WalletStore() wallet_store.ParseFromString(bytes(infile.read())) self.address_bundle = [] for a in wallet_store.wallets: tmpxmss = XMSS(config.dev.xmss_tree_height, mnemonic2bin(a.mnemonic.strip())) tmpxmss.set_index(a.xmss_index) if a.address != tmpxmss.get_address(): logger.fatal("Mnemonic and address do not match.") exit(1) self.address_bundle.append( AddressBundle(tmpxmss.get_address().encode(), tmpxmss)) except Exception as e: logger.warning("It was not possible to open the wallet: %s", e)
def _validate_signed_hash(self, height=config.dev.xmss_tree_height): if self.subtype != TX_SUBTYPE_COINBASE and getAddress('Q', self.PK) != self.txfrom: logger.warning('Public key verification failed') return False if not XMSS.VERIFY(message=self.txhash, signature=self.signature, pk=self.PK, height=height): logger.warning('xmss_verify failed') return False return True
def test_get_height_from_sig_size(self): with self.assertRaises(Exception): XMSS.get_height_from_sig_size(2179) with self.assertRaises(Exception): XMSS.get_height_from_sig_size(0) with self.assertRaises(Exception): XMSS.get_height_from_sig_size(-1) height = XMSS.get_height_from_sig_size(3204) self.assertEqual(height, 32) height = XMSS.get_height_from_sig_size(2180) self.assertEqual(height, 0)
def test_sign_verify(self): message = "This is a test" message_bin = str2bin(message) xmss_height = 10 seed = bytearray([i for i in range(48)]) xmss = XMSS(xmss_height, seed) pk = xmss.pk() xmss.set_index(1) for i in range(10): self.assertTrue(xmss.get_index() == i + 1) signature = xmss.SIGN(message_bin) self.assertTrue(XMSS.VERIFY(message_bin, signature, pk))
def test_multi_output_transaction_add_block(self, time_mock): # Test that adding block with a multi-output Transaction updates everybody's balances correctly. self.chain_manager.load(self.genesis_block) extended_seed = "010300cebc4e25553afa0aab899f7838e59e18a48852fa9dfd5" \ "ae78278c371902aa9e6e9c1fa8a196d2dba0cbfd2f2d212d16c" random_xmss = XMSS.from_extended_seed(hstr2bin(extended_seed)) transfer_transaction = TransferTransaction.create( addrs_to=[alice.address, random_xmss.address], amounts=[ 40 * int(config.dev.shor_per_quanta), 59 * int(config.dev.shor_per_quanta) ], fee=1 * config.dev.shor_per_quanta, xmss_pk=bob.pk) transfer_transaction._data.nonce = 1 transfer_transaction.sign(bob) time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create(block_number=1, prev_headerhash=self.genesis_block.headerhash, prev_timestamp=self.genesis_block.timestamp, transactions=[transfer_transaction], miner_address=alice.address) block_1.set_nonces(129, 0) # Uncomment only to determine the correct mining_nonce of above blocks # from qrl.core.PoWValidator import PoWValidator # while not PoWValidator().validate_mining_nonce(self.state, block_1.blockheader, False): # block_1.set_nonces(block_1.mining_nonce + 1) # print(block_1.mining_nonce) self.assertTrue(block_1.validate(self.chain_manager, {})) result = self.chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(self.chain_manager.last_block, block_1) bob_addr_state = self.state.get_address_state(bob.address) alice_addr_state = self.state.get_address_state(alice.address) random_addr_state = self.state.get_address_state(random_xmss.address) self.assertEqual(bob_addr_state.balance, 0) self.assertEqual( alice_addr_state.balance, 140 * int(config.dev.shor_per_quanta) + block_1.block_reward + block_1.fee_reward) self.assertEqual(random_addr_state.balance, 159 * int(config.dev.shor_per_quanta))
def add_slave(self, index, height, number_of_slaves=1, passphrase: str=None, hash_function="shake128", force=False): if not force: if self.encrypted or self.encrypted_partially: raise WalletEncryptionError("Please decrypt all addresses in this wallet before adding a new address!") slaves_xmss = [] for i in range(number_of_slaves): tmp_xmss = XMSS.from_height(height, hash_function) if i == number_of_slaves - 1: tmp_xmss.set_ots_index(UNRESERVED_OTS_INDEX_START) # Start from unreserved ots index slaves_xmss.append(tmp_xmss) self.append_slave(slaves_xmss, passphrase, index) return slaves_xmss
def test_add_vote1(self): alice_xmss = get_alice_xmss() slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed()) headerhash = b'ffff' vote = Vote.create(addr_from=alice_xmss.get_address().encode(), blocknumber=0, headerhash=headerhash, xmss=slave_xmss) vote.sign(slave_xmss) stake_amount = 101.5012 vote_metadata = VoteMetadata() self.assertNotIn(vote.txfrom, vote_metadata.stake_validator_vote) vote_metadata.add_vote(vote=vote, stake_amount=stake_amount) self.assertIn(vote.txfrom, vote_metadata.stake_validator_vote) self.assertEqual(stake_amount, vote_metadata.total_stake_amount)
def create(mining_nonce: int, block_number: int, prevblock_headerhash: bytes, transactions: list, signing_xmss: XMSS, master_address: bytes, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction()]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend([tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash(hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(blocknumber=block_number, mining_nonce=mining_nonce, PK=signing_xmss.pk(), prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block
def add_address_from_seed(self, seed=None) -> str: self.authenticate() words = seed.split() if len(words) == 34: bin_seed = mnemonic2bin(seed) elif len(seed) == 102: bin_seed = hstr2bin(seed) else: raise ValueError("Invalid Seed") address_from_seed = XMSS.from_extended_seed(bin_seed) if self._wallet.get_xmss_by_qaddress(address_from_seed.qaddress, self._passphrase): raise Exception("Address is already in the wallet") self._wallet.append_xmss(address_from_seed) self._encrypt_last_item() self._wallet.save() return address_from_seed.qaddress
def wallet_recover(ctx, seed_type): """ Recovers a wallet from a hexseed or mnemonic (32 words) """ if ctx.obj.remote: click.echo('This command is unsupported for remote wallets') return seed = click.prompt('Please enter your %s' % (seed_type, )) seed = seed.lower().strip() if seed_type == 'mnemonic': words = seed.split() if len(words) != 34: print('You have entered %s words' % (len(words), )) print('Mnemonic seed must contain only 34 words') return bin_seed = mnemonic2bin(seed) else: if len(seed) != 102: print('You have entered hexseed of %s characters' % (len(seed), )) print('Hexseed must be of only 102 characters.') return bin_seed = hstr2bin(seed) walletObj = Wallet(wallet_path=ctx.obj.wallet_path) recovered_xmss = XMSS.from_extended_seed(bin_seed) print('Recovered Wallet Address : %s' % (Wallet._get_Qaddress(recovered_xmss.address), )) for addr in walletObj.address_items: if recovered_xmss.qaddress == addr.qaddress: print('Wallet Address is already in the wallet list') return if click.confirm('Do you want to save the recovered wallet?'): click.echo('Saving...') walletObj.append_xmss(recovered_xmss) walletObj.save() click.echo('Done') _print_addresses(ctx, walletObj.address_items, config.user.wallet_dir)
def get_mining_slave_addresses(args): slaves_filename = os.path.join(config.user.wallet_dir, config.user.slaves_filename) if args.randomizeSlaveXMSS: xmss = XMSS.from_height(config.dev.slave_xmss_height) slaves = [bin2hstr(xmss.address), [xmss.extended_seed], None] write_slaves(slaves_filename, slaves) if not os.path.isfile(slaves_filename): generate_slave_from_input(slaves_filename) slaves = None try: slaves = read_slaves(slaves_filename) except KeyboardInterrupt: quit(1) except Exception as e: logger.error('Exception %s', e) quit(1) return slaves
def _read_wallet(self): self.address_bundle = [] if not os.path.isfile(self.wallet_dat_filename): return try: with open(self.wallet_dat_filename, "rb") as infile: wallet_store = qrl_pb2.WalletStore() wallet_store.ParseFromString(bytes(infile.read())) self.address_bundle = [] for a in wallet_store.wallets: tmpxmss = XMSS.from_extended_seed(mnemonic2bin(a.mnemonic.strip())) tmpxmss.set_ots_index(a.xmss_index) if a.address != bin2hstr(tmpxmss.address).encode(): logger.fatal("Mnemonic and address do not match.") exit(1) self.address_bundle.append(AddressBundle(a.address, tmpxmss)) except Exception as e: logger.warning("It was not possible to open the wallet: %s", e)
def test_add_2(self): destroy_state() with State() as state: with set_wallet_dir("test_wallet"): chain = Chain(state) buffered_chain = BufferedChain(chain) alice_xmss = get_alice_xmss() slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed()) staking_address = bytes(alice_xmss.get_address().encode()) h0 = sha256(b'hashchain_seed') h1 = sha256(h0) with mocked_genesis() as custom_genesis: custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance( address=alice_xmss.get_address(), balance=700000000000000) ]) res = buffered_chain.add_block(block=custom_genesis) self.assertTrue(res) stake_transaction = StakeTransaction.create( activation_blocknumber=1, xmss=alice_xmss, slavePK=slave_xmss.pk(), hashchain_terminator=h1) vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=0, headerhash=custom_genesis.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(0) # FIXME: The test needs private access.. This is an API issue stake_transaction._data.nonce = 1 stake_transaction.sign(alice_xmss) chain.pstate.stake_validators_tracker.add_sv( balance=700000000000000, stake_txn=stake_transaction, blocknumber=1) sv = chain.pstate.stake_validators_tracker.sv_dict[ staking_address] self.assertEqual(0, sv.nonce) tmp_block = Block.create( staking_address=bytes( alice_xmss.get_address().encode()), block_number=1, reveal_hash=h0, prevblock_headerhash=custom_genesis.headerhash, transactions=[stake_transaction], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=alice_xmss, nonce=1) res = buffered_chain.add_block(block=tmp_block) self.assertTrue(res)
def test_add_3(self): destroy_state() with State() as state: with set_wallet_dir("test_wallet"): chain = Chain(state) buffered_chain = BufferedChain(chain) alice_xmss = get_alice_xmss() slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed()) staking_address = bytes(alice_xmss.get_address().encode()) # FIXME: Replace this with a call to create a hash_chain h0 = sha256(b'hashchain_seed') h1 = sha256(h0) h2 = sha256(h1) h3 = sha256(h2) with mocked_genesis() as custom_genesis: custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance( address=alice_xmss.get_address(), balance=700000000000000) ]) res = buffered_chain.add_block(block=GenesisBlock()) self.assertTrue(res) stake_transaction = StakeTransaction.create( activation_blocknumber=1, xmss=alice_xmss, slavePK=slave_xmss.pk(), hashchain_terminator=h3) stake_transaction._data.nonce = 1 # FIXME: The test needs private access.. This is an API issue stake_transaction.sign(alice_xmss) vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=0, headerhash=GenesisBlock().headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(0) chain.pstate.stake_validators_tracker.add_sv( balance=700000000000000, stake_txn=stake_transaction, blocknumber=1) sv = chain.pstate.stake_validators_tracker.sv_dict[ staking_address] self.assertEqual(0, sv.nonce) tmp_block1 = Block.create( staking_address=staking_address, block_number=1, reveal_hash=h2, prevblock_headerhash=GenesisBlock().headerhash, transactions=[stake_transaction], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=1) res = buffered_chain.add_block(block=tmp_block1) self.assertTrue(res) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block1.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=1, headerhash=tmp_block1.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(1) tmp_block2 = Block.create( staking_address=staking_address, block_number=2, reveal_hash=h1, prevblock_headerhash=tmp_block1.headerhash, transactions=[], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=2) res = buffered_chain.add_block(block=tmp_block2) self.assertTrue(res) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block2.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=2, headerhash=tmp_block2.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(2) tmp_block3 = Block.create( staking_address=staking_address, block_number=3, reveal_hash=h0, prevblock_headerhash=tmp_block2.headerhash, transactions=[], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=3) res = buffered_chain.add_block(block=tmp_block3) self.assertTrue(res)
def test_add_4(self): destroy_state() with State() as state: with set_wallet_dir("test_wallet"): chain = Chain(state) buffered_chain = BufferedChain(chain) alice_xmss = get_alice_xmss() slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed()) random_xmss1 = get_random_xmss() random_xmss2 = get_random_xmss() staking_address = bytes(alice_xmss.get_address().encode()) # FIXME: Replace this with a call to create a hash_chain h0 = sha256(b'hashchain_seed') h1 = sha256(h0) h2 = sha256(h1) h3 = sha256(h2) h4 = sha256(h3) with mocked_genesis() as custom_genesis: custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance( address=alice_xmss.get_address(), balance=700000000000000) ]) res = buffered_chain.add_block(block=GenesisBlock()) self.assertTrue(res) stake_transaction = StakeTransaction.create( activation_blocknumber=1, xmss=alice_xmss, slavePK=slave_xmss.pk(), hashchain_terminator=h4) stake_transaction._data.nonce = 1 # FIXME: The test needs private access.. This is an API issue stake_transaction.sign(alice_xmss) vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=0, headerhash=GenesisBlock().headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(0) chain.pstate.stake_validators_tracker.add_sv( balance=700000000000000, stake_txn=stake_transaction, blocknumber=1) sv = chain.pstate.stake_validators_tracker.sv_dict[ staking_address] self.assertEqual(0, sv.nonce) # Token Transaction to create a token for test token_transaction = get_token_transaction( random_xmss1, random_xmss2) token_transaction._data.nonce = 1 token_transaction.sign(random_xmss1) # Transfer Token Transaction transfer_token1 = TransferTokenTransaction.create( addr_from=random_xmss1.get_address().encode(), token_txhash=token_transaction.txhash, addr_to=alice_xmss.get_address().encode(), amount=100000000, fee=1, xmss_pk=random_xmss1.pk(), xmss_ots_index=random_xmss1.get_index()) transfer_token1._data.nonce = 2 transfer_token1.sign(random_xmss1) transfer_token2 = TransferTokenTransaction.create( addr_from=random_xmss2.get_address().encode(), token_txhash=token_transaction.txhash, addr_to=alice_xmss.get_address().encode(), amount=200000000, fee=1, xmss_pk=random_xmss2.pk(), xmss_ots_index=random_xmss2.get_index()) transfer_token2._data.nonce = 1 transfer_token2.sign(random_xmss2) # Transfer Coin Transaction transfer_transaction = TransferTransaction.create( addr_from=random_xmss1.get_address().encode(), addr_to=random_xmss2.get_address().encode(), amount=10, fee=1, xmss_pk=random_xmss1.pk(), xmss_ots_index=random_xmss1.get_index()) transfer_transaction._data.nonce = 3 transfer_transaction.sign(random_xmss1) tmp_block1 = Block.create( staking_address=staking_address, block_number=1, reveal_hash=h3, prevblock_headerhash=GenesisBlock().headerhash, transactions=[stake_transaction, token_transaction], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=1) res = buffered_chain.add_block(block=tmp_block1) self.assertTrue(res) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block1.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=1, headerhash=tmp_block1.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(1) tmp_block2 = Block.create( staking_address=staking_address, block_number=2, reveal_hash=h2, prevblock_headerhash=tmp_block1.headerhash, transactions=[ transfer_token1, transfer_token2, transfer_transaction ], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=2) res = buffered_chain.add_block(block=tmp_block2) self.assertTrue(res) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block2.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=2, headerhash=tmp_block2.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(2) tmp_block3 = Block.create( staking_address=staking_address, block_number=3, reveal_hash=h1, prevblock_headerhash=tmp_block2.headerhash, transactions=[], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=3) res = buffered_chain.add_block(block=tmp_block3) self.assertTrue(res) chain = buffered_chain._chain random_xmss1_state = chain.pstate._get_address_state( random_xmss1.get_address().encode()) random_xmss2_state = chain.pstate._get_address_state( random_xmss2.get_address().encode()) self.assertEqual( random_xmss1_state.tokens[bin2hstr( token_transaction.txhash).encode()], 400000000) self.assertEqual( random_xmss2_state.tokens[bin2hstr( token_transaction.txhash).encode()], 200000000) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block3.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=3, headerhash=tmp_block3.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(3) tmp_block4 = Block.create( staking_address=staking_address, block_number=4, reveal_hash=h0, prevblock_headerhash=tmp_block3.headerhash, transactions=[], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=4) res = buffered_chain.add_block(block=tmp_block4) self.assertTrue(res) token_metadata = buffered_chain.get_token_metadata( token_transaction.txhash) self.assertEqual(token_metadata.token_txhash, token_transaction.txhash) self.assertEqual( len(token_metadata.transfer_token_tx_hashes), 3) self.assertEqual( token_metadata.transfer_token_tx_hashes[0], token_transaction.txhash) random_xmss1_state = chain.pstate._get_address_state( random_xmss1.get_address().encode()) random_xmss2_state = chain.pstate._get_address_state( random_xmss2.get_address().encode()) alice_state = chain.pstate._get_address_state( alice_xmss.get_address().encode()) self.assertEqual( random_xmss1_state.tokens[bin2hstr( token_transaction.txhash).encode()], 300000000) self.assertEqual( random_xmss2_state.tokens[bin2hstr( token_transaction.txhash).encode()], 0) self.assertEqual( alice_state.tokens[bin2hstr( token_transaction.txhash).encode()], 300000000) self.assertEqual(random_xmss1_state.balance, config.dev.default_account_balance - 13) self.assertEqual(random_xmss2_state.balance, config.dev.default_account_balance + 9)
def add_new_address(self, height): tmp_xmss = XMSS.from_height(height) self.append_xmss(tmp_xmss) return tmp_xmss
def get_some_address(idx=0) -> bytes: seed = bytearray([i for i in range(48)]) seed[0] = idx xmss = XMSS(XmssFast(seed, 4)) return xmss.address
def test_multi_output_transaction_add_block(self): with set_data_dir('no_data'): with State() as state: state.get_measurement = MagicMock(return_value=10000000) alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() extended_seed = "010300cebc4e25553afa0aab899f7838e59e18a48852fa9dfd5" \ "ae78278c371902aa9e6e9c1fa8a196d2dba0cbfd2f2d212d16c" random_xmss = XMSS.from_extended_seed(hstr2bin(extended_seed)) transfer_transaction = TransferTransaction.create( addrs_to=[alice_xmss.address, random_xmss.address], amounts=[ 40 * int(config.dev.shor_per_quanta), 59 * int(config.dev.shor_per_quanta) ], fee=1 * config.dev.shor_per_quanta, xmss_pk=bob_xmss.pk) transfer_transaction._data.nonce = 1 transfer_transaction.sign(bob_xmss) genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_boundary = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock( return_value=(tmp_difficulty, tmp_boundary)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[transfer_transaction], miner_address=alice_xmss.address) block_1.set_nonces(274, 0) # Uncomment only to determine the correct mining_nonce of above blocks # from qrl.core.PoWValidator import PoWValidator # while not PoWValidator().validate_mining_nonce(state, block_1.blockheader, False): # block_1.set_nonces(block_1.mining_nonce + 1) # print(block_1.mining_nonce) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) bob_addr_state = state.get_address(bob_xmss.address) alice_addr_state = state.get_address(alice_xmss.address) random_addr_state = state.get_address(random_xmss.address) self.assertEqual(bob_addr_state.balance, 0) self.assertEqual( alice_addr_state.balance, 140 * int(config.dev.shor_per_quanta) + block_1.block_reward + block_1.fee_reward) self.assertEqual(random_addr_state.balance, 159 * int(config.dev.shor_per_quanta))
def slave_tx_generate(ctx, src, addr_from, number_of_slaves, access_type, fee, pk, otsidx): """ Generates Slave Transaction for the wallet """ try: address_src, src_xmss = _select_wallet(ctx, src) if len(addr_from.strip()) == 0: addr_from = address_src if src_xmss: address_src_pk = src_xmss.pk() address_src_otsidx = src_xmss.get_index() else: address_src_pk = pk.encode() address_src_otsidx = int(otsidx) fee_shor = int(fee * 1.e9) except Exception as e: click.echo("Error validating arguments") quit(1) slave_xmss = [] slave_pks = [] access_types = [] slave_xmss_seed = [] if number_of_slaves > 100: click.echo("Error: Max Limit for the number of slaves is 100") quit(1) for i in range(number_of_slaves): print("Generating Slave #"+str(i+1)) xmss = XMSS(config.dev.xmss_tree_height) slave_xmss.append(xmss) slave_xmss_seed.append(xmss.get_seed()) slave_pks.append(xmss.pk()) access_types.append(access_type) print("Successfully Generated Slave %s/%s" % (str(i + 1), number_of_slaves)) channel = grpc.insecure_channel(ctx.obj.node_public_address) stub = qrl_pb2_grpc.PublicAPIStub(channel) # FIXME: This could be problematic. Check slaveTxnReq = qrl_pb2.SlaveTxnReq(address_from=addr_from, slave_pks=slave_pks, access_types=access_types, fee=fee_shor, xmss_pk=address_src_pk, xmss_ots_index=address_src_otsidx) try: slaveTxnResp = stub.GetSlaveTxn(slaveTxnReq, timeout=5) tx = Transaction.from_pbdata(slaveTxnResp.transaction_unsigned) tx.sign(src_xmss) with open('slaves.json', 'w') as f: json.dump([src_xmss.get_address(), slave_xmss_seed, tx.to_json()], f) click.echo('Successfully created slaves.json') click.echo('Move slaves.json file from current directory to the mining node inside ~/.qrl/') except grpc.RpcError as e: click.echo(e.details()) quit(1) except Exception as e: click.echo("Unhandled error: {}".format(str(e))) quit(1)
def get_slave_xmss() -> XMSS: xmss_height = 6 seed = bytes([i + 10 for i in range(48)]) return XMSS(XmssFast(seed, xmss_height))
def get_random_xmss(xmss_height=6) -> XMSS: return XMSS.from_height(xmss_height)
def slave_tx_generate(ctx, src, master, number_of_slaves, access_type, fee, pk, otsidx): """ Generates Slave Transaction for the wallet """ try: _, src_xmss = _select_wallet(ctx, src) src_xmss.set_ots_index(otsidx) if src_xmss: address_src_pk = src_xmss.pk else: address_src_pk = pk.encode() master_addr = _parse_qaddress(master) fee_shor = _shorize(fee) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) slave_xmss = [] slave_pks = [] access_types = [] slave_xmss_seed = [] if number_of_slaves > 100: click.echo("Error: Max Limit for the number of slaves is 100") quit(1) for i in range(number_of_slaves): print("Generating Slave #" + str(i + 1)) xmss = XMSS.from_height(config.dev.xmss_tree_height) slave_xmss.append(xmss) slave_xmss_seed.append(xmss.extended_seed) slave_pks.append(xmss.pk) access_types.append(access_type) print("Successfully Generated Slave %s/%s" % (str(i + 1), number_of_slaves)) # FIXME: This could be problematic. Check slaveTxnReq = qrl_pb2.SlaveTxnReq(slave_pks=slave_pks, access_types=access_types, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) try: stub = ctx.obj.get_stub_public_api() slaveTxnResp = stub.GetSlaveTxn(slaveTxnReq, timeout=5) tx = Transaction.from_pbdata( slaveTxnResp.extended_transaction_unsigned.tx) tx.sign(src_xmss) with open('slaves.json', 'w') as f: json.dump( [bin2hstr(src_xmss.address), slave_xmss_seed, tx.to_json()], f) click.echo('Successfully created slaves.json') click.echo( 'Move slaves.json file from current directory to the mining node inside ~/.qrl/' ) except grpc.RpcError as e: click.echo(e.details()) quit(1) except Exception as e: click.echo("Unhandled error: {}".format(str(e))) quit(1)
def get_bob_xmss(xmss_height=6) -> XMSS: seed = bytes([i + 5 for i in range(48)]) return XMSS(XmssFast(seed, xmss_height))
def test_signature_type(self): xmss_height = 4 seed = bytearray([i for i in range(48)]) xmss = XMSS(XmssFast(seed, xmss_height)) self.assertEqual(0, xmss.signature_type)
def generate_slave_xmss(self, epoch): assert (epoch == self.slave_xmsspool.getCurrentIndex() ) # Verify we are not skipping trees tmp_xmss = self.slave_xmsspool.getNextTree() return XMSS(tmp_xmss.getHeight(), _xmssfast=tmp_xmss)
def test_from_height_custom_hash(self): xmss_height = 4 xmss = XMSS.from_height(xmss_height, "shake128") self.assertEqual('shake128', xmss.hash_function)
transactions.append( create_tx(addrs_to, amounts, signing_xmss, count // output_limit)) addrs_to = [] amounts = [] if addrs_to: transactions.append(create_tx(addrs_to, amounts, signing_xmss, count)) return transactions seed = bytes(hstr2bin(input('Enter extended hexseed: '))) dist_xmss = XMSS.from_extended_seed(seed) transactions = get_migration_transactions(signing_xmss=dist_xmss) block = Block.create(block_number=0, prevblock_headerhash=config.dev.genesis_prev_headerhash, transactions=transactions, miner_address=dist_xmss.address) block.set_nonces(0, 0) block._data.genesis_balance.MergeFrom([ qrl_pb2.GenesisBalance(address=config.dev.coinbase_address, balance=105000000000000000) ])
def test_add_4(self, mock_difficulty_tracker_get): with set_qrl_dir('wallet_ver1'): with State() as state: with mocked_genesis() as custom_genesis: chain_manager = ChainManager(state) chain_manager._difficulty_tracker = Mock() tmp_difficulty = StringToUInt256('2') tmp_target = DifficultyTracker.get_target(tmp_difficulty) mock_difficulty_tracker_get.return_value = [ tmp_difficulty, tmp_target ] alice_xmss = get_alice_xmss() slave_xmss = XMSS( XmssFast(alice_xmss.seed, alice_xmss.height)) random_xmss1 = get_random_xmss() random_kyber1 = Kyber() random_dilithium1 = Dilithium() random_xmss2 = get_random_xmss() random_kyber2 = Kyber() random_dilithium2 = Dilithium() message = b'Hello World How are you?' prf512_seed = b'10192' custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance(address=random_xmss1.address, balance=65000000000000000) ]) custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance(address=random_xmss2.address, balance=65000000000000000) ]) chain_manager.load(custom_genesis) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 lattice_public_key_txn = LatticePublicKey.create( fee=1, kyber_pk=random_kyber1.getPK(), dilithium_pk=random_dilithium1.getPK(), xmss_pk=random_xmss1.pk) lattice_public_key_txn._data.nonce = 1 lattice_public_key_txn.sign(random_xmss1) genesis_block = GenesisBlock() tmp_block1 = Block.create( block_number=1, prev_block_headerhash=genesis_block.headerhash, prev_block_timestamp=genesis_block.timestamp, transactions=[lattice_public_key_txn], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block1.blockheader, False): tmp_block1.set_nonces(tmp_block1.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block1) self.assertTrue(res) # Need to move forward the time to align with block times time_mock.return_value += config.dev.minimum_minting_delay * 2 encrypted_eph_message = create_ephemeral_channel( msg_id=lattice_public_key_txn.txhash, ttl=time_mock.return_value, ttr=0, addr_from=random_xmss2.address, kyber_pk=random_kyber2.getPK(), kyber_sk=random_kyber2.getSK(), receiver_kyber_pk=random_kyber1.getPK(), dilithium_pk=random_dilithium2.getPK(), dilithium_sk=random_dilithium2.getSK(), prf512_seed=prf512_seed, data=message, nonce=1) chain_manager.state.update_ephemeral( encrypted_eph_message) eph_metadata = chain_manager.state.get_ephemeral_metadata( lattice_public_key_txn.txhash) # Decrypting Payload encrypted_eph_message = eph_metadata.encrypted_ephemeral_message_list[ 0] encrypted_payload = encrypted_eph_message.payload random_kyber1.kem_decode( encrypted_eph_message.channel.enc_aes256_symkey) aes_key = bytes(random_kyber1.getMyKey()) myAES = AES(aes_key) decrypted_payload = myAES.decrypt(encrypted_payload) ephemeral_channel_payload = EphemeralChannelPayload.from_json( decrypted_payload) self.assertEqual(ephemeral_channel_payload.prf512_seed, b'10192') self.assertEqual(ephemeral_channel_payload.data, b'Hello World How are you?') # TODO (cyyber): Add Ephemeral Testing code using Naive RNG tmp_block2 = Block.create( block_number=2, prev_block_headerhash=tmp_block1.headerhash, prev_block_timestamp=tmp_block1.timestamp, transactions=[], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block2.blockheader, False): tmp_block2.set_nonces(tmp_block2.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block2) self.assertTrue(res) # Need to move forward the time to align with block times time_mock.return_value += config.dev.minimum_minting_delay * 2 tmp_block3 = Block.create( block_number=3, prev_block_headerhash=tmp_block2.headerhash, prev_block_timestamp=tmp_block1.timestamp, transactions=[], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block3.blockheader, False): tmp_block3.set_nonces(tmp_block3.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block3) self.assertTrue(res) time_mock.return_value += config.dev.minimum_minting_delay tmp_block4 = Block.create( block_number=4, prev_block_headerhash=tmp_block3.headerhash, prev_block_timestamp=tmp_block1.timestamp, transactions=[], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block4.blockheader, False): tmp_block4.set_nonces(tmp_block4.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block4) self.assertTrue(res) address_state = chain_manager.get_address( random_xmss1.address) self.assertEqual( address_state.latticePK_list[0].kyber_pk, lattice_public_key_txn.kyber_pk) self.assertEqual( address_state.latticePK_list[0].dilithium_pk, lattice_public_key_txn.dilithium_pk) self.assertEqual(address_state.address, lattice_public_key_txn.addr_from) random_xmss1_state = chain_manager.get_address( random_xmss1.address) self.assertEqual(64999999999999999, random_xmss1_state.balance)