def setUp(self): p2p_factory = Mock(spec=P2PFactory) p2p_factory.sync_state = SyncState() p2p_factory.num_connections = 23 p2p_factory.pow = Mock() b = Block() self.chain_manager = Mock(spec=ChainManager) self.chain_manager.height = 0 self.chain_manager.get_last_block = MagicMock(return_value=b) self.chain_manager.get_block_header_hash_by_number = MagicMock( return_value=b.headerhash) self.qrlnode = QRLNode(mining_address=b'') self.qrlnode.set_chain_manager(self.chain_manager) self.qrlnode._p2pfactory = p2p_factory self.qrlnode._pow = p2p_factory.pow self.block_header_params = { "dev_config": config.dev, "blocknumber": 10, "prev_headerhash": sha256(b'prevblock'), "prev_timestamp": 1234567890, "hashedtransactions": sha256(b'tx1'), "fee_reward": 1, "seed_height": 0, "seed_hash": None, } self.service = MiningAPIService(self.qrlnode)
def __init__(self, chain): self.blockheader = BlockHeader() self.blockheader.create(chain=chain, blocknumber=0, hashchain_link='genesis', prev_blockheaderhash=sha256(config.dev.genesis_prev_headerhash), hashedtransactions=sha256('0'), reveal_list=[], vote_hashes=[]) self.transactions = [] self.stake = [] self.state = [] package_directory = os.path.dirname(os.path.abspath(__file__)) genesis_data_path = os.path.join(package_directory, 'genesis.yml') with open(genesis_data_path) as f: dataMap = yaml.safe_load(f) genesis_info.update(dataMap['genesis_info']) for key in genesis_info: self.state.append([key, [0, genesis_info[key] * 100000000, []]]) self.stake_list = [] for stake in self.state: self.stake_list.append(stake[0]) self.stake_seed = '1a02aa2cbe25c60f491aeb03131976be2f9b5e9d0bc6b6d9e0e7c7fd19c8a076c29e028f5f3924b4'
def hashchain_reveal(xmss, n=config.dev.blocks_per_epoch, epoch=0): """ :param n: :type xmss: XMSS :param epoch: :type epoch: int :return: """ half = int(config.dev.blocks_per_epoch / 2) x = GEN(xmss._private_SEED, half + epoch, l=32) y = GEN(x, half, l=32) z = GEN(y, half, l=32) z = hexlify(z) z = GEN_range(z, 1, config.dev.hashchain_nums) hc = [] for hash_chain in z: hc.append([hash_chain]) tmp_hc_terminator = [] for hash_chain in hc[:-1]: for x in range(n): hash_chain.append(sha256(hash_chain[-1])) tmp_hc_terminator.append(hash_chain[-1]) for hash_chain in hc[-1:]: for x in range(n + 1): hash_chain.append(sha256(hash_chain[-1])) tmp_hc_terminator.append(hash_chain[-1]) return tmp_hc_terminator
def _verify_auth(auth_route, i_bms, pub, PK): """ verify an XMSS auth root path..requires the xmss authentication route, OTS public key and XMSS public key (containing merkle root, x and l bitmasks) and i regenerate leaf from pub[i] and l_bm, use auth route to navigate up merkle tree to regenerate the root and compare with PK[0] :param auth_route: :param i_bms: :param pub: :param PK: :return: """ root = PK[0] x_bms = PK[1] l_bms = PK[2] leaf = XMSS._l_tree(pub, l_bms) h = len(auth_route) node = None for x in range(h - 1): # last check is simply to confirm root = pair, no need for sha xor.. if i_bms[x][0] == 'L': node = sha256(hex(int(leaf, 16) ^ int(x_bms[i_bms[x][1]], 16))[2:-1] + hex( int(auth_route[x], 16) ^ int(x_bms[i_bms[x][2]], 16))[2:-1]) else: node = sha256(hex(int(auth_route[x], 16) ^ int(x_bms[i_bms[x][0]], 16))[2:-1] + hex( int(leaf, 16) ^ int(x_bms[i_bms[x][1]], 16))[2:-1]) leaf = node if node == root: return True return False
def test_init2(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) self.assertIsNotNone(block_header) # just to avoid warnings
def generate_reboot_hash(self, key, nonce=None, blocknumber=0): reboot_data = [ '2920c8ec34f04f59b7df4284a4b41ca8cbec82ccdde331dd2d64cc89156af653', 0 ] try: reboot_data = self.state.db.get('reboot_data') except: pass if nonce: if reboot_data[1] > nonce: return None, 'Nonce must be greater than or equals to ' + str( reboot_data[1]) + '\r\n' reboot_data[1] = int(nonce) output = sha256(key) for i in range(0, 40000 - reboot_data[1]): output = sha256(output) status, error = self.validate_reboot(output, reboot_data[1]) if not status: return None, error return json.dumps({ 'hash': output, 'nonce': reboot_data[1], 'blocknumber': int(blocknumber) }), "Reboot Initiated\r\n"
def validate_tx(self): if self.subtype != TX_SUBTYPE_TX: return False # FIXME: what does this comment means? # sanity check: this is not how the economy is supposed to work! if self.amount <= 0: logger.info( 'State validation failed for %s because negative or zero', self.txhash) logger.info('Amount %d', self.amount) return False # FIXME: Duplication. Risk of mismatch (create & verification) txhash = sha256( bytes( ''.join(self.txfrom + self.txto + str(self.amount) + str(self.fee)), 'utf-8')) txhash = sha256(txhash + self.pubhash) # cryptographic checks if self.txhash != txhash: return False if not self._validate_signed_hash(): return False return True
def reveal_to_terminator(self, reveal, blocknumber, add_loop=0): tmp = sha256(reveal) epoch = blocknumber // config.dev.blocks_per_epoch for _ in range(blocknumber - (epoch * config.dev.blocks_per_epoch) + add_loop): tmp = sha256(tmp) return tmp
def test_GetBlockMiningCompatible(self): p2p_factory = Mock(spec=P2PFactory) p2p_factory.sync_state = SyncState() p2p_factory.num_connections = 23 p2p_factory.pow = Mock() chain_manager = Mock(spec=ChainManager) chain_manager.height = 0 chain_manager.get_last_block = MagicMock(return_value=Block()) qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow block_header = BlockHeader.create(blocknumber=10, prev_headerhash=sha256(b'prevblock'), prev_timestamp=1234567890, hashedtransactions=sha256(b'tx1'), fee_reward=1) qrlnode.get_blockheader_and_metadata = MagicMock( return_value=[block_header, BlockMetadata()]) service = MiningAPIService(qrlnode) req = qrlmining_pb2.GetBlockMiningCompatibleReq(height=10) answer = service.GetBlockMiningCompatible(request=req, context=None) self.assertEqual(10, answer.blockheader.block_number) self.assertEqual(1, answer.blockheader.reward_fee)
def test_create(self): 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) h2 = sha256(h1) stake_transaction = StakeTransaction.create(activation_blocknumber=0, xmss=alice_xmss, slavePK=slave_xmss.pk(), hashchain_terminator=h2) sv = StakeValidator(100, stake_transaction) self.assertEqual(staking_address, sv.address) self.assertEqual(slave_xmss.pk(), sv.slave_public_key) self.assertEqual(h2, sv.terminator_hash) self.assertEqual(100, sv.balance) self.assertEqual(0, sv.nonce) self.assertFalse(sv.is_banned) self.assertTrue(sv.is_active)
def pos_block_pool(self, n=1.5): """ create a snapshot of the transaction pool to account for network traversal time (probably less than 300ms, but let's give a window of 1.5 seconds). :param n: :return: list of merkle root hashes of the tx pool over last 1.5 seconds """ timestamp = time() start_time = timestamp - n x = self.sorted_tx_pool(start_time) y = self.sorted_tx_pool(timestamp) if not y: # if pool is empty -> return sha256 null return [sha256('')], [[]] elif x == y: # if the pool isnt empty but there is no difference then return the only merkle hash possible.. return [merkle_tx_hash(y)], [y] else: # there is a difference in contents of pool over last 1.5 seconds.. merkle_hashes = [] txhashes = [] if not x: merkle_hashes.append(sha256('')) x = [] txhashes.append(x) else: merkle_hashes.append(merkle_tx_hash(x)) txhashes.append(x) tmp_txhashes = x for tx in reversed(self.transaction_pool): if tx.txhash in y and tx.txhash not in x: tmp_txhashes.append(tx.txhash) tmp_txhashes.sort() merkle_hashes.append(merkle_tx_hash(tmp_txhashes)) txhashes.append(tmp_txhashes) return merkle_hashes, txhashes
def _set_txhash(self): tmptxhash = sha256( self._get_concatenated_fields() ) for index in range(0, len(self.slave_pks)): tmptxhash = sha256(tmptxhash + self.slave_pks[index] + str(self.access_types[index]).encode()) self._data.transaction_hash = tmptxhash
def test_blob(self, time_mock): block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) self.assertEquals( '00501846b24200c31fca7172a7f701ae50322579cfdf1d7777daab4ce6ead70b76debb2c51a1' 'c700000000000000000000000000000000002b80aecec05ad5c7c4f2259c8f69e2966a6ce102', bin2hstr(block_header.mining_blob)) self.assertEquals(config.dev.mining_blob_size, len(block_header.mining_blob))
def _xmss_route(x_bms, x_tree, i=0): # type: (object, object, int) -> tuple """ generate the xmss tree merkle auth route for a given ots key (starts at 0) :param x_bms: :param x_tree: :param i: :return: """ auth_route = [] i_bms = [] nodehash_list = [item for sublist in x_tree for item in sublist] h = len(x_tree) leaf = x_tree[0][i] for x in range(h): if len(x_tree[x]) == 1: # must be at root layer if node == ''.join(x_tree[x]): auth_route.append(''.join(x_tree[x])) else: logger.info('Failed..root') return elif i == len(x_tree[x]) - 1 and leaf in x_tree[ x + 1]: # for an odd node it goes up a level each time until it branches.. i = x_tree[x + 1].index(leaf) n = nodehash_list.index(leaf) nodehash_list[n] = None # stops at first duplicate in list..need next so wipe.. else: n = nodehash_list.index(leaf) # position in the list == bitmask.. if i % 2 == 0: # left leaf, go right.. # logger.info(( 'left' node = sha256(hex(int(leaf, 16) ^ int(x_bms[n], 16))[2:-1] + hex( int(nodehash_list[n + 1], 16) ^ int(x_bms[n + 1], 16))[2:-1]) pair = nodehash_list[n + 1] auth_route.append(pair) i_bms.append(('L', n, n + 1)) elif i % 2 == 1: # right leaf go left.. node = sha256(hex(int(nodehash_list[n - 1], 16) ^ int(x_bms[n - 1], 16))[2:-1] + hex( int(leaf, 16) ^ int(x_bms[n], 16))[2:-1]) pair = nodehash_list[n - 1] auth_route.append(pair) i_bms.append((n - 1, n)) try: x_tree[x + 1].index(node) # confirm node matches a hash in next layer up? except: logger.warning(('Failed at height', str(x))) return leaf = node i = x_tree[x + 1].index(leaf) return auth_route, i_bms
def test_blob(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), sha256(b'txs'), 10) self.assertEquals( '74aa496ffe19107faaf418b720fb5b8446ba4b595c178fcf099c99b3dee99860d788c77910a9ed000000' '000000000000000000e0d022b37421b81b7bbcf5b497fb89408c05c7d713c5e1e5187b02aa9344cf83bb', bin2hstr(block_header.mining_blob)) self.assertEquals(config.dev.mining_blob_size, len(block_header.mining_blob))
def test_create_fails_when_prev_timestamp_is_negative(self, time_mock): # The only way to get it to fail in this mode is to pass a negative timestamp. Which should never happen IRL. time_mock.return_value = 0 b = BlockHeader.create(config.dev, 1, sha256(b'prev'), -10, sha256(b'txs'), 10, seed_height=0, seed_hash=None) self.assertIsNone(b)
def test_blob(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) self.assertEquals( '00501846b24200c31fca7172a7f701ae50322579cfdf1d7777daab4ce6ead70b76debb2c51a1' 'c70000000000000000000000002b80aecec05ad5c7c4f2259c8f69e2966a6ce102d4609af2cd', bin2hstr(block_header.mining_blob)) self.assertEquals(config.dev.mining_blob_size, len(block_header.mining_blob))
def test_addr_tx_hashes(self): with set_data_dir('no_data'): with State() as state: alice_xmss = get_alice_xmss() alice_address = bytes(alice_xmss.get_address().encode()) # FIXME: This needs to be refactored some_hash1 = bin2hstr(sha256(b'some_hash1')).encode() some_hash2 = bin2hstr(sha256(b'some_hash2')).encode() state.update_address_tx_hashes(alice_address, some_hash1) state.update_address_tx_hashes(alice_address, some_hash2) result = state.get_address_tx_hashes(alice_address) self.assertEqual(some_hash1, result[0]) self.assertEqual(some_hash2, result[1])
def test_hash(self, time_mock): block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) header_hash = block_header.generate_headerhash() self.assertEquals( 'ac021e63df860ea930ea9de05e350d3f74af35341688134f92957f1dac3a62fb', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def _set_txhash(self): tmptxhash = sha256( self._get_concatenated_fields() + self._data.token.symbol + self._data.token.name + self._data.token.owner + str(self._data.token.decimals).encode() ) for initial_balance in self._data.token.initial_balances: tmptxhash += initial_balance.address tmptxhash += str(initial_balance.amount).encode() self._data.transaction_hash = sha256(tmptxhash)
def __init__(self, *args, **kwargs): super(TestCoinBase, self).__init__(*args, **kwargs) self.alice = get_alice_xmss() self.alice.set_ots_index(11) self.mock_blockheader = Mock(spec=BlockHeader) self.mock_blockheader.stake_selector = self.alice.address self.mock_blockheader.block_reward = 50 self.mock_blockheader.fee_reward = 40 self.mock_blockheader.prev_blockheaderhash = sha256(b'prev_headerhash') self.mock_blockheader.block_number = 1 self.mock_blockheader.headerhash = sha256(b'headerhash') self.maxDiff = None
def validate_tx(self): if not self.validate_subtype(self.subtype, TX_SUBTYPE_LATTICE): return False txhash = sha256(self.kyber_pk + self.tesla_pk) txhash = sha256(txhash + self.pubhash) if self.txhash != txhash: logger.info('Invalid Txhash') logger.warning('Found: %s Expected: %s', self.txhash, txhash) return False if not self.validate_signed_hash(): return False return True
def test_create_hashchain(self): seed = sha256(b'test_seed') HASHCHAIN_SIZE = 100 hcb = hashchain(seed, 1, HASHCHAIN_SIZE) self.assertIsNotNone(hcb) self.assertEqual(HASHCHAIN_SIZE + 1, len(hcb.hashchain)) # FIXME: Why seed comes as an array of tuples? self.assertEqual( '127f5db0388cd82bd4af80b88e8d68409e1f70fd322f96b3f2aca55b0ade116f', bin2hstr(hcb.seed[0])) self.assertEqual( '1d3b37dedc74980941b3b65640e8d2851658feac0d38196f372ada9c2ac0b077', bin2hstr(hcb.hc_terminator)) self.assertEqual( '1d3b37dedc74980941b3b65640e8d2851658feac0d38196f372ada9c2ac0b077', bin2hstr(hcb.hashchain[-1])) self.assertEqual( '127f5db0388cd82bd4af80b88e8d68409e1f70fd322f96b3f2aca55b0ade116f', bin2hstr(hcb.hashchain[0])) self.assertNotEqual( '127f5db0388cd82bd4af80b88e8d68409e1f70fd322f96b3f2aca55b0ade116f', bin2hstr(hcb.hashchain[1])) self.assertEqual( 'ff7f4850bc6499e08e104c6967ee66e665e57d7e0e429072e646d14e1b92600a', bin2hstr(hcb.hashchain[50]))
def get_hashable_bytes(self): return sha256( self.addr_from + self.fee.to_bytes(8, byteorder='big', signed=False) + self.kyber_pk + self.dilithium_pk )
def test_hash(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), sha256(b'txs'), 10) header_hash = block_header.generate_headerhash() self.assertEquals( '584f898a54269d0651cca3403843d4cdb764e5a31655bf51db39bbf8c4883b01', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def score(stake_address: bytes, reveal_one: bytes, balance: int = 0, seed: bytes = None, verbose: bool = False): if not seed: logger.info('Exception Raised due to seed none in score fn') raise Exception if not balance: logger.info(' balance 0 so score none ') logger.info(' stake_address %s', stake_address) return None # FIXME: Review this reveal_seed = bin2hstr(sha256(str(reveal_one).encode() + str(seed).encode())) score = (Decimal(config.dev.N) - (Decimal(int(reveal_seed, 16)).log10() / Decimal(2).log10())) / Decimal(balance) if verbose: logger.info('=' * 10) logger.info('Score - %s', score) logger.info('reveal_one - %s', reveal_one) logger.info('seed - %s', seed) logger.info('balance - %s', balance) return score
def create(self, xmss, kyber_pk, tesla_pk): self.txfrom = xmss.address self.kyber_pk = kyber_pk self.tesla_pk = tesla_pk self.txhash = sha256(self.kyber_pk + self.tesla_pk) self.process_XMSS(xmss.address, self.txhash, xmss) return self
def test_getBlockByNumber(self): db_state = Mock(spec=State) db_state.get_tx_metadata = MagicMock(return_value=None) db_state.get_block = MagicMock(return_value=None) p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) alice_xmss = get_alice_xmss() b = Block.create(block_number=1, prev_headerhash=sha256(b'reveal'), prev_timestamp=10, transactions=[], miner_address=alice_xmss.address) db_state.get_block_by_number = MagicMock(return_value=b) context = Mock(spec=ServicerContext) request = qrl_pb2.GetBlockByNumberReq(block_number=b.block_number) response = service.GetBlockByNumber(request=request, context=context) context.set_code.assert_not_called() self.assertEqual(1, response.block.header.block_number)
def validate_reboot(self, mhash, nonce): reboot_data = [ '2920c8ec34f04f59b7df4284a4b41ca8cbec82ccdde331dd2d64cc89156af653', 0 ] try: reboot_data_db = self.state.db.get('reboot_data') reboot_data = reboot_data_db except: pass if reboot_data[1] >= nonce: # already used msg = 'nonce in db ' + str(reboot_data[1]) msg += '\nnonce provided ' + str(nonce) return None, msg reboot_data[1] = nonce output = mhash for i in range(0, reboot_data[1]): output = sha256(output) if output != reboot_data[0]: msg = 'expected hash ' + str(reboot_data[0]) msg += '\nhash found ' + str(output) msg += '\nnonce provided ' + str(nonce) + "\n" return None, msg # reboot_data[1] += 1 # self.state.db.put('reboot_data', reboot_data) return True, 'Success'
def validate_hash(self, hash, blocknum, target_chain=config.dev.hashchain_nums - 1, stake_address=None): epoch_blocknum = StakeValidator.get_epoch_blocknum(blocknum) if hash in self.hash_staker: if stake_address and stake_address != self.hash_staker[hash]: return False return True if stake_address: if stake_address not in self.sv_list: return False sv = self.sv_list[stake_address] return sv.validate_hash(hash, blocknum, self.hash_staker, target_chain) tmp = hash count = epoch_blocknum while count >= -1: tmp = sha256(tmp) if tmp in self.hash_staker: stake_address = self.hash_staker[tmp] sv = self.sv_list[stake_address] sv.update(epoch_blocknum, hash, target_chain, self.hash_staker) return True count -= 1 return False
def audit_multisig_addr(qrl_client, addr): """ Validate the multi sig address """ balance = 0 tx_count = 0 bad_tx_count = 0 request_addr = qrl_pb2.GetMultiSigAddressStateReq( address=bytes.fromhex(addr[1:])) response_addr = qrl_client.GetMultiSigAddressState(request_addr) if not response_addr.HasField('state'): logging.error('could not find address {}'.format(addr)) return balance, tx_count, bad_tx_count balance = response_addr.state.balance request_txs = qrl_pb2.GetMultiSigSpendTxsByAddressReq( address=bytes.fromhex(addr[1:]), item_per_page=64, page_number=1, filter_type=qrl_pb2.GetMultiSigSpendTxsByAddressReq.EXECUTED_ONLY) response_txs = qrl_client.GetMultiSigSpendTxsByAddress(request_txs) tx_count = len(response_txs.transactions_detail) for tx_detail in response_txs.transactions_detail: tx = tx_detail.tx if not tx.HasField('multi_sig_spend'): bad_tx_count += 1 logging.error('txhash {} for addr {} does not exist'.format( tx.transaction_hash.hex(), addr)) continue tmptxhash = (tx.master_addr + to_bytes(tx.fee) + tx.multi_sig_spend.multi_sig_address + to_bytes(tx.multi_sig_spend.expiry_block_number) + get_tx_hash(tx.multi_sig_spend)) if not XmssFast.verify(sha256(tmptxhash), tx.signature, tx.public_key): logging.info( 'txhash {} for addr {} failed XmssFast verification'.format( tx.transaction_hash.hex(), addr)) return balance, tx_count, bad_tx_count
def validate_tx(self, chain, blockheader): sv_list = chain.block_chain_buffer.stake_list_get( blockheader.blocknumber) if blockheader.blocknumber > 1 and sv_list[ self.txto].slave_public_key != self.PK: logger.warning('Stake validator doesnt own the Public key') logger.warning('Expected public key %s', sv_list[self.txto].slave_public_key) logger.warning('Found public key %s', self.PK) return False if self.txto != self.txfrom: logger.warning('Non matching txto and txfrom') logger.warning('txto: %s txfrom: %s', self.txto, self.txfrom) return False # FIXME: Duplication. Risk of mismatch (create & verification) txhash = blockheader.prev_blockheaderhash + \ tuple([int(char) for char in str(blockheader.blocknumber)]) + \ blockheader.headerhash # FIXME: This additional transformation happens in a base class txhash = sha256(txhash + self.pubhash) if self.txhash != txhash: logger.warning('Block_headerhash doesnt match') logger.warning('Found: %s', self.txhash) logger.warning('Expected: %s', txhash) return False # Slave XMSS is used to sign COINBASE txn having quite low XMSS height if not self._validate_signed_hash(height=config.dev.slave_xmss_height): return False return True
def create(addr_from, addr_to, amount, fee, xmss_pk, xmss_ots_key): transaction = SimpleTransaction() transaction.txfrom = addr_from transaction.txto = addr_to transaction.amount = int( amount) # FIXME: Review conversions for quantities transaction.fee = int(fee) # FIXME: Review conversions for quantities # FIXME: This is very confusing and can be a security risk # FIXME: Duplication. Risk of mismatch (create & verification) transaction.PK = xmss_pk transaction.ots_key = xmss_ots_key tmppubhash = transaction._get_pubhash() tmptxhash = sha256( bytes( ''.join(transaction.txfrom + transaction.txto + str(transaction.amount) + str(transaction.fee)), 'utf-8')) transaction.txhash = transaction._get_txhash(tmptxhash, tmppubhash) return transaction
def _set_txhash(self): self._data.transaction_hash = sha256( self._get_concatenated_fields() + self._data.coinbase.addr_to + str(self._data.coinbase.amount).encode() + str(self._data.coinbase.block_number).encode() + self._data.coinbase.headerhash )
def test_hashchain_reveal(self): seed = sha256(b'test_seed') self.assertEqual('1d3b37dedc74980941b3b65640e8d2851658feac0d38196f372ada9c2ac0b077', bin2hstr(hashchain_reveal(seed, 1, 100))) self.assertEqual('127f5db0388cd82bd4af80b88e8d68409e1f70fd322f96b3f2aca55b0ade116f', bin2hstr(hashchain_reveal(seed, 1, 0))) self.assertEqual('ff7f4850bc6499e08e104c6967ee66e665e57d7e0e429072e646d14e1b92600a', bin2hstr(hashchain_reveal(seed, 1, 50))) self.assertNotEqual('ff7f4850bc6499e08e104c6967ee66e665e57d7e0e429072e646d14e1b92600a', bin2hstr(hashchain_reveal(seed, 1, 51)))
def test_hashchain_verify(self): seed = sha256(b'test_seed') HASHCHAIN_SIZE = 100 hcb = hashchain(seed, 1, HASHCHAIN_SIZE) self.assertIsNotNone(hcb) self.assertEqual(HASHCHAIN_SIZE + 1, len(hcb.hashchain)) for i, value in enumerate(hcb.hashchain): tmp = sha256_n(value, HASHCHAIN_SIZE - i) logger.info("{:-4} {} {}".format(i, bin2hstr(value), bin2hstr(tmp))) self.assertEqual(hcb.hc_terminator, tmp)
def _calc_hashchain( seed_private: bytes, epoch: int, blocks_per_epoch: int): # FIXME: Move to C++ hc_seed = getHashChainSeed(seed_private, epoch, 1) hc = [bytes(hc_seed[0])] for x in range(blocks_per_epoch): hc.append(sha256(hc[-1])) hc_terminator = hc[-1] return hc_seed, hc, hc_terminator
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 test_create_hashchain(self): seed = sha256(b'test_seed') HASHCHAIN_SIZE = 100 hcb = hashchain(seed, 1, HASHCHAIN_SIZE) self.assertIsNotNone(hcb) self.assertEqual(HASHCHAIN_SIZE + 1, len(hcb.hashchain)) # FIXME: Why seed comes as an array of tuples? self.assertEqual('127f5db0388cd82bd4af80b88e8d68409e1f70fd322f96b3f2aca55b0ade116f', bin2hstr(hcb.seed[0])) self.assertEqual('1d3b37dedc74980941b3b65640e8d2851658feac0d38196f372ada9c2ac0b077', bin2hstr(hcb.hc_terminator)) self.assertEqual('1d3b37dedc74980941b3b65640e8d2851658feac0d38196f372ada9c2ac0b077', bin2hstr(hcb.hashchain[-1])) self.assertEqual('127f5db0388cd82bd4af80b88e8d68409e1f70fd322f96b3f2aca55b0ade116f', bin2hstr(hcb.hashchain[0])) self.assertNotEqual('127f5db0388cd82bd4af80b88e8d68409e1f70fd322f96b3f2aca55b0ade116f', bin2hstr(hcb.hashchain[1])) self.assertEqual('ff7f4850bc6499e08e104c6967ee66e665e57d7e0e429072e646d14e1b92600a', bin2hstr(hcb.hashchain[50]))
def _set_txhash(self): self._data.transaction_hash = sha256( self._get_concatenated_fields() + self._data.latticePK.kyber_pk + self._data.latticePK.dilithium_pk )
def _set_txhash(self): self._data.transaction_hash = sha256( self._get_concatenated_fields() + self._data.message.message_hash )
def _set_txhash(self): self._data.transaction_hash = sha256( self._get_concatenated_fields() + self._data.transfer_token.addr_to + str(self._data.transfer_token.amount).encode() )