def test_private_keys_extraction(self): dag = Dag(0) epoch = Epoch(dag) node_private = Private.generate() prev_hash = dag.genesis_block().get_hash() round_start, round_end = Epoch.get_round_bounds(1, Round.PRIVATE) for i in range(1, round_start): block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * i) signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(i, signed_block) prev_hash = block.get_hash() generated_private_keys = [] for i in range(round_start, round_end): # intentionally skip last block of round generated_private = Private.generate() generated_private_keys.append(Keys.to_bytes(generated_private)) private_key_tx = PrivateKeyTransaction() private_key_tx.key = Keys.to_bytes(generated_private) block = Block() block.system_txs = [private_key_tx] block.prev_hashes = dag.get_top_blocks_hashes() block.timestamp = i * BLOCK_TIME signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(i, signed_block) prev_hash = block.get_hash() ChainGenerator.fill_with_dummies(dag, prev_hash, Epoch.get_round_range(1, Round.FINAL)) epoch_hash = dag.blocks_by_number[ROUND_DURATION * 6 + 1][0].get_hash() extracted_privates = epoch.get_private_keys_for_epoch(epoch_hash) for i in range(0, ROUND_DURATION - 1): self.assertEqual(extracted_privates[i], generated_private_keys[i])
def test_penalty(self): dag = Dag(0) epoch = Epoch(dag) permissions = Permissions(epoch) node_private = Private.generate() initial_validators = Validators.read_genesis_validators_from_file() genesis_hash = dag.genesis_block().get_hash() last_block_number = Epoch.get_epoch_end_block_number(1) prev_hash = ChainGenerator.fill_with_dummies( dag, genesis_hash, range(1, last_block_number)) block = BlockFactory.create_block_with_timestamp( [prev_hash], BLOCK_TIME * last_block_number) tx = PenaltyTransaction() tx.conflicts = [prev_hash] tx.signature = Private.sign(tx.get_hash(), node_private) block.system_txs = [tx] signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(last_block_number, signed_block) initial_validators_order = permissions.get_signers_indexes( genesis_hash) # we substract two here: one because it is last but one block # and one, because epoch starts from 1 validator_index_to_penalize = initial_validators_order[ last_block_number - 2] resulting_validators = permissions.get_validators(block.get_hash()) self.assertNotEqual(len(initial_validators), len(resulting_validators)) initial_validators.pop(validator_index_to_penalize) init_pubkeys = list( map(lambda validator: validator.public_key, initial_validators)) result_pubkeys = list( map(lambda validator: validator.public_key, resulting_validators)) self.assertEqual(init_pubkeys, result_pubkeys)
def test_secret_sharing_rounds(self): dag = Dag(0) epoch = Epoch(dag) dummy_private = Private.generate() signers = [] for i in range(0, ROUND_DURATION + 1): signers.append(Private.generate()) private_keys = [] block_number = 1 genesis_hash = dag.genesis_block().get_hash() prev_hash = genesis_hash signer_index = 0 for i in Epoch.get_round_range(1, Round.PUBLIC): private = Private.generate() private_keys.append(private) signer = signers[signer_index] pubkey_tx = PublicKeyTransaction() pubkey_tx.generated_pubkey = Private.publickey(private) pubkey_tx.pubkey_index = signer_index pubkey_tx.signature = Private.sign( pubkey_tx.get_signing_hash(genesis_hash), signer) block = Block() block.timestamp = i * BLOCK_TIME block.prev_hashes = [prev_hash] block.system_txs = [pubkey_tx] signed_block = BlockFactory.sign_block(block, signer) dag.add_signed_block(i, signed_block) signer_index += 1 prev_hash = block.get_hash() prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.COMMIT)) public_keys = [] for private in private_keys: public_keys.append(Private.publickey(private)) randoms_list = [] expected_random_pieces = [] for i in Epoch.get_round_range(1, Round.SECRETSHARE): random_bytes = os.urandom(32) random_value = int.from_bytes(random_bytes, byteorder='big') split_random_tx = SplitRandomTransaction() splits = split_secret(random_bytes, 2, 3) encoded_splits = encode_splits(splits, public_keys) split_random_tx.pieces = encoded_splits split_random_tx.pubkey_index = 0 expected_random_pieces.append(split_random_tx.pieces) split_random_tx.signature = Private.sign(pubkey_tx.get_hash(), dummy_private) block = Block() block.timestamp = i * BLOCK_TIME block.prev_hashes = [prev_hash] block.system_txs = [split_random_tx] signed_block = BlockFactory.sign_block(block, dummy_private) dag.add_signed_block(i, signed_block) randoms_list.append(random_value) prev_hash = block.get_hash() expected_seed = sum_random(randoms_list) prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.REVEAL)) signer_index = 0 private_key_index = 0 raw_private_keys = [] for i in Epoch.get_round_range(1, Round.PRIVATE): private_key_tx = PrivateKeyTransaction() private_key_tx.key = Keys.to_bytes(private_keys[private_key_index]) raw_private_keys.append(private_key_tx.key) signer = signers[signer_index] block = Block() block.system_txs = [private_key_tx] block.prev_hashes = [prev_hash] block.timestamp = block_number * BLOCK_TIME signed_block = BlockFactory.sign_block(block, signer) dag.add_signed_block(i, signed_block) signer_index += 1 private_key_index += 1 prev_hash = block.get_hash() prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.FINAL)) top_block_hash = dag.get_top_blocks_hashes()[0] random_splits = epoch.get_random_splits_for_epoch(top_block_hash) self.assertEqual(expected_random_pieces, random_splits) restored_randoms = [] for i in range(0, len(random_splits)): random = decode_random(random_splits[i], Keys.list_from_bytes(raw_private_keys)) restored_randoms.append(random) self.assertEqual(randoms_list, restored_randoms) seed = epoch.extract_shared_random(top_block_hash) self.assertEqual(expected_seed, seed)
def test_commit_reveal(self): dag = Dag(0) epoch = Epoch(dag) private = Private.generate() prev_hash = ChainGenerator.fill_with_dummies( dag, dag.genesis_block().get_hash(), Epoch.get_round_range(1, Round.PUBLIC)) randoms_list = [] for i in Epoch.get_round_range(1, Round.COMMIT): random_value = int.from_bytes(os.urandom(32), byteorder='big') randoms_list.append(random_value) expected_seed = sum_random(randoms_list) reveals = [] epoch_hash = dag.genesis_block().get_hash() for i in Epoch.get_round_range(1, Round.COMMIT): rand = randoms_list.pop() random_bytes = rand.to_bytes(32, byteorder='big') commit, reveal = TestEpoch.create_dummy_commit_reveal( random_bytes, epoch_hash) commit_block = BlockFactory.create_block_with_timestamp( [prev_hash], i * BLOCK_TIME) commit_block.system_txs = [commit] signed_block = BlockFactory.sign_block(commit_block, private) dag.add_signed_block(i, signed_block) prev_hash = commit_block.get_hash() reveals.append(reveal) revealing_key = Keys.from_bytes(reveal.key) encrypted_bytes = Public.encrypt(random_bytes, Private.publickey(revealing_key)) decrypted_bytes = Private.decrypt(encrypted_bytes, revealing_key) # TODO check if encryption decryption can work million times in a row self.assertEqual(decrypted_bytes, random_bytes) revealed_value = Private.decrypt(commit.rand, revealing_key) self.assertEqual(revealed_value, random_bytes) # self.assertEqual(len(reveals), ROUND_DURATION) prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.SECRETSHARE)) for i in Epoch.get_round_range(1, Round.REVEAL): reveal_block = BlockFactory.create_block_with_timestamp( [prev_hash], i * BLOCK_TIME) reveal_block.system_txs = [reveals.pop()] signed_block = BlockFactory.sign_block(reveal_block, private) dag.add_signed_block(i, signed_block) prev_hash = reveal_block.get_hash() prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.PRIVATE)) prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.FINAL)) seed = epoch.reveal_commited_random(prev_hash) self.assertEqual(expected_seed, seed)