Example #1
0
    def get_random_senders_pubkeys(self, epoch_hash):
        selected_epoch_validators = self.get_validators(epoch_hash)
        epoch_random_indexes = self.get_randomizers_indexes(epoch_hash)
        validators = []
        for i in Epoch.get_round_range(1, Round.SECRETSHARE):
            index = epoch_random_indexes[i - 1]
            validators.append(selected_epoch_validators[index])

        return validators
Example #2
0
    def get_ordered_signers_pubkeys_for_round(self, epoch_hash, round_type):
        selected_epoch_validators = self.get_validators(epoch_hash)

        epoch_signers_indexes = self.get_signers_indexes(epoch_hash)
        validators = []
        for i in Epoch.get_round_range(1, round_type):
            index = epoch_signers_indexes[i - 1]
            validators.append(selected_epoch_validators[index])

        return validators
Example #3
0
    def get_ordered_randomizers_pubkeys_for_round(self, epoch_hash,
                                                  round_type):
        selected_epoch_validators = self.get_validators(epoch_hash)

        if round_type == Round.PUBLIC or round_type == Round.PRIVATE:
            epoch_random_indexes = self.get_signers_indexes(epoch_hash)
            round_type = Round.PRIVATE

            validators = []
            for i in Epoch.get_round_range(1, round_type):
                index = epoch_random_indexes[i - 1]
                validators.append(selected_epoch_validators[index])

            return validators

        elif round_type == Round.SECRETSHARE:
            return self.get_secret_sharers(epoch_hash)
        elif round_type == Round.COMMIT or round_type == Round.REVEAL:
            return self.get_commiters(epoch_hash)

        assert False, "No randomizers exist for this round type!"
    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_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)
    def test_maliciously_send_negative_and_positive_gossip(self):
        Time.use_test_time()
        Time.set_current_time(1)

        private_keys = BlockSigners()
        private_keys = private_keys.block_signers

        validators = Validators()
        validators.validators = Validators.read_genesis_validators_from_file()
        validators.signers_order = [0] + [1] + [2] + [3] + [
            4
        ] + [5] * Epoch.get_duration()
        validators.randomizers_order = [0] * Epoch.get_duration()

        signer_index = 0
        for i in Epoch.get_round_range(1, Round.PRIVATE):
            validators.signers_order[i] = signer_index
            signer_index += 1

        network = Network()

        node0 = Node(genesis_creation_time=1,
                     node_id=0,
                     network=network,
                     block_signer=private_keys[0],
                     validators=validators,
                     behaviour=Behaviour())

        network.register_node(node0)

        behavior = Behaviour(
        )  # this node maliciously send positive and negative gossip
        behavior.malicious_send_negative_gossip_count = 1
        behavior.malicious_send_positive_gossip_count = 1
        node1 = Node(genesis_creation_time=1,
                     node_id=1,
                     network=network,
                     block_signer=private_keys[1],
                     validators=validators,
                     behaviour=behavior)
        network.register_node(node1)

        node2 = Node(genesis_creation_time=1,
                     node_id=2,
                     network=network,
                     block_signer=private_keys[2],
                     validators=validators,
                     behaviour=Behaviour())
        network.register_node(node2)

        node3 = Node(genesis_creation_time=1,
                     node_id=3,
                     network=network,
                     block_signer=private_keys[3],
                     validators=validators,
                     behaviour=Behaviour())
        network.register_node(node3)

        node4 = Node(genesis_creation_time=1,
                     node_id=4,
                     network=network,
                     block_signer=private_keys[4],
                     validators=validators,
                     behaviour=Behaviour())
        network.register_node(node4)

        node5 = Node(genesis_creation_time=1,
                     node_id=5,
                     network=network,
                     block_signer=private_keys[5],
                     validators=validators,
                     behaviour=Behaviour())
        network.register_node(node5)

        helper = TestHelper(network)

        Time.advance_to_next_timeslot()  # current block number 1
        node0.step()  # create and sign block
        # validate block created and broadcasted
        # validate mempool is empty
        # validate tx by hash is empty
        helper.list_validator(self, network.nodes,
                              ['dag.blocks_by_number.length'], 2)
        helper.list_validator(self, network.nodes, ['mempool.gossips.length'],
                              0)
        # validate 2 public key tx
        helper.list_validator(self, network.nodes,
                              ['dag.transactions_by_hash.length'], 1)

        # on one step sends +and- (add test for different steps ?)
        node1.step(
        )  # ! maliciously sand positive and negative gossip (request by genesis 0 block)
        # all node receive positive gossip
        # txs for now only in mempool (not in block)
        helper.list_validator(self, network.nodes,
                              ['dag.blocks_by_number.length'], 2)
        # all nodes has 1-gossip and 6+gossips (1-gossip and 6+gossip from (0,1,2,3,4,5))
        helper.list_validator(self, network.nodes, ['mempool.gossips.length'],
                              7)
        helper.list_validator(self, network.nodes,
                              ['dag.transactions_by_hash.length'], 1)

        node2.step()
        node3.step()
        node4.step()
        node5.step()
        # after all steps situation same
        helper.list_validator(self, network.nodes,
                              ['dag.blocks_by_number.length'], 2)
        helper.list_validator(self, network.nodes, ['mempool.gossips.length'],
                              7)
        helper.list_validator(self, network.nodes,
                              ['dag.transactions_by_hash.length'], 1)

        Time.advance_to_next_timeslot()  # current block number 2
        node0.step()  # do nothing
        node1.step(
        )  # is validator by order (need to marge mempool and provide block)
        # in current case node will penaltize SELF !!!
        helper.list_validator(self, network.nodes,
                              ['dag.blocks_by_number.length'], 3)
        helper.list_validator(self, network.nodes, ['mempool.gossips.length'],
                              0)
        # tx_s
        # 3 - public key tx
        # 1 - negative gossip tx
        # 6 - positive gossip txs
        # 1 - penalty tx
        # total = 11 txs
        if ROUND_DURATION > 6:  # total 6 nodes in test
            public_key_tx_count = 6
        else:
            public_key_tx_count = ROUND_DURATION
        negative_gossip_tx_count = 1
        positive_gossips_tx_count = 6
        penalty_tx_count = 1
        tx_total_count = public_key_tx_count + negative_gossip_tx_count + positive_gossips_tx_count + penalty_tx_count

        helper.list_validator(self, network.nodes,
                              ['dag.transactions_by_hash.length'],
                              tx_total_count)

        node2.step()
        node3.step()
        node4.step()
        node5.step()
        # validate that all keeps the same
        helper.list_validator(self, network.nodes,
                              ['dag.blocks_by_number.length'], 3)
        helper.list_validator(self, network.nodes, ['mempool.gossips.length'],
                              0)
        helper.list_validator(self, network.nodes,
                              ['dag.transactions_by_hash.length'],
                              tx_total_count)
        # verify that node1 is steel in validators list
        helper.list_validator(self, network.nodes,
                              ['permissions.epoch_validators.length'],
                              GENESIS_VALIDATORS_COUNT)

        Time.advance_to_next_timeslot()  # current block number 3
        node0.step()  # do nothing
        node1.step()  # do nothing
        node2.step()  # provide block
        node3.step()
        node4.step()
        node5.step()

        # validate new block by node2
        helper.list_validator(self, network.nodes,
                              ['dag.blocks_by_number.length'], 4)
        # verify that node1 is steel in validators list until epoch end
        helper.list_validator(self, network.nodes,
                              ['permissions.epoch_validators.length'],
                              GENESIS_VALIDATORS_COUNT)

        for i in range(5, ROUND_DURATION * 6 + 1):
            Time.advance_to_next_timeslot()
            if i == ROUND_DURATION * 6 + 1:
                node0.step()
            node0.step()
            node1.step()
            node2.step()
            node3.step()
            node4.step()
            node5.step()
            if i == ROUND_DURATION * 6 + 1:
                # ! chek up validators list on new epoch upcoming
                # TODO sometimes fall for unknoun reason
                # self.list_validator(network.nodes, ['dag.blocks_by_number.length'], i)
                for node in network.nodes:
                    if len(node.dag.blocks_by_number) != i - 1:
                        print('BLOCK_NUMBER : ' + str(i))
                        print('node id:' + str(node.node_id) +
                              " dag.block_by_number:" +
                              str(len(node1.dag.blocks_by_number)))

                helper.list_validator(self, network.nodes,
                                      ['permissions.epoch_validators.length'],
                                      GENESIS_VALIDATORS_COUNT - 1)
                # TODO nodes recalculates 2 times ?
                helper.list_validator(
                    self, network.nodes,
                    ['permissions.epoch_validators.epoch0.length'],
                    GENESIS_VALIDATORS_COUNT - 1)
                # maybe 20 (on default block time and round duration)
                helper.list_validator(
                    self, network.nodes,
                    ['permissions.epoch_validators.epoch1.length'],
                    GENESIS_VALIDATORS_COUNT - 1)