Ejemplo n.º 1
0
    def extract_shared_random(self, block_hash):
        if block_hash == self.dag.genesis_block().get_hash():
            return 0

        private_keys = self.get_private_keys_for_epoch(block_hash)
        public_keys = self.get_public_keys_for_epoch(block_hash)
        published_private_keys = self.filter_out_skipped_public_keys(
            private_keys, public_keys)
        random_pieces_list = self.get_random_splits_for_epoch(block_hash)

        # self.log("pubkeys")
        # for _, public_key in public_keys.items():
        # self.log(Keys.to_visual_string(public_key))
        # self.log("privkeys converted")
        private_key_count = 0  # amount of sent keys
        matching_keys_count = 0  # amount of keys which have matching pubkeys
        for key in published_private_keys:
            if not key:
                # self.log("None")
                continue
            pubkey = Private.publickey(key)
            # self.log(Keys.to_visual_string(pubkey))
            private_key_count += 1
            if Keys.to_bytes(pubkey) in public_keys.values():
                matching_keys_count += 1

        pubkey_count = len(public_keys)
        self.log("pubkey count", pubkey_count, "privkey count",
                 private_key_count, "of them matching", matching_keys_count)

        half_of_pubkeys = int(pubkey_count / 2) + 1
        half_of_privkeys = int(private_key_count / 2) + 1

        # TODO we should have a special handling for when not enough keys was sent for each round
        assert pubkey_count > 1, "Not enough public keys to decrypt random"
        assert private_key_count > 1, "Not enough private keys to decrypt random"
        assert pubkey_count >= half_of_privkeys, "Not enough public keys to decrypt random"
        assert private_key_count >= half_of_pubkeys, "Not enough private keys to decrypt random"
        assert matching_keys_count >= half_of_pubkeys, "Not enough matching keys in epoch"
        assert matching_keys_count >= half_of_privkeys, "Not enough matching keys in epoch"

        ordered_private_keys_count = len(
            private_keys)  # total amount of both sent and unsent keys
        randoms_list = []
        for random_pieces in random_pieces_list:
            assert ordered_private_keys_count >= len(
                random_pieces
            ), "Amount of splits must match amount of public keys"
            random = decode_random(
                random_pieces, Keys.list_from_bytes(published_private_keys))
            randoms_list.append(random)

        seed = sum_random(randoms_list)
        return seed
    def test_encryption_and_decryption(self):
        private_keys = []
        public_keys = []
        for i in range(0, 5):
            private = Private.generate()
            private_keys.append(private)
            public_keys.append(Private.publickey(private))

        raw_private_keys = Keys.list_to_bytes(private_keys)
        decoded_private_keys = Keys.list_from_bytes(raw_private_keys)

        random_bytes = os.urandom(32)
        random_value = int.from_bytes(random_bytes, byteorder='big')
        splits = split_secret(random_bytes, 3, 5)
        encoded_splits = encode_splits(splits, public_keys)
        decoded_random = decode_random(encoded_splits, decoded_private_keys)

        self.assertEqual(random_value, decoded_random)
    def test_decryption_failure(self):
        private_keys = []
        public_keys = []
        for i in range(0, 5):
            private = Private.generate()
            private_keys.append(private)
            public_keys.append(Private.publickey(private))

        raw_private_keys = Keys.list_to_bytes(private_keys)
        decoded_private_keys = Keys.list_from_bytes(raw_private_keys)

        random_bytes = os.urandom(32)
        random_value = int.from_bytes(random_bytes, byteorder='big')
        splits = split_secret(random_bytes, 3, 5)
        encoded_splits = encode_splits(splits, public_keys)
        encoded_splits[2] = os.urandom(len(
            encoded_splits[2]))  #corrupt one of the splits
        encoded_splits[4] = os.urandom(len(
            encoded_splits[4]))  #corrupt another split
        decoded_random = decode_random(encoded_splits, decoded_private_keys)

        self.assertEqual(random_value, decoded_random)
    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)