def create_reconciliation(seed, algorithm, key_size, error_rate):
    Key.set_random_seed(seed)
    Shuffle.set_random_seed(seed + 1)
    correct_key = Key.create_random_key(key_size)
    noisy_key = correct_key.copy(error_rate, Key.ERROR_METHOD_EXACT)
    mock_classical_channel = MockClassicalChannel(correct_key)
    reconciliation = Reconciliation(algorithm, mock_classical_channel,
                                    noisy_key, error_rate)
    return (reconciliation, correct_key)
Beispiel #2
0
def test_get_key_index():
    Key.set_random_seed(77711)
    Shuffle.set_random_seed(77712)
    key = Key.create_random_key(6)
    assert key.__str__() == "110101"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->0 1->5 2->1 3->4 4->2 5->3"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    block = blocks[0]
    assert block.get_key_index(1) == 5
Beispiel #3
0
def test_str():
    Key.set_random_seed(55511)
    Shuffle.set_random_seed(55522)
    key = Key.create_random_key(4)
    assert key.__str__() == "1010"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->1 1->2 2->3 3->0"
    blocks = Block.create_covering_blocks(key, shuffle, 5)
    assert len(blocks) == 1
    assert blocks[0].__str__() == "0101"
Beispiel #4
0
def test_repr():
    Key.set_random_seed(4441)
    Shuffle.set_random_seed(4442)
    key = Key.create_random_key(4)
    assert key.__repr__() == "Key: 1111"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == "Shuffle: 0->3 1->2 2->1 3->0"
    blocks = Block.create_covering_blocks(key, shuffle, 5)
    assert len(blocks) == 1
    assert blocks[0].__repr__() == "Block: 0->3=1 1->2=1 2->1=1 3->0=1"
Beispiel #5
0
def test_get_size():
    Key.set_random_seed(5551)
    Shuffle.set_random_seed(5552)
    key = Key.create_random_key(65)
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    blocks = Block.create_covering_blocks(key, shuffle, 30)
    assert len(blocks) == 3
    assert blocks[0].get_size() == 30
    assert blocks[1].get_size() == 30
    assert blocks[2].get_size() == 5
Beispiel #6
0
def test_get_key_indexes():
    Key.set_random_seed(55593)
    Shuffle.set_random_seed(55594)
    key = Key.create_random_key(6)
    assert key.__str__() == "010011"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->4 1->5 2->2 3->3 4->0 5->1"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    assert len(blocks) == 2
    assert blocks[0].get_key_indexes() == [4, 5, 2]
    assert blocks[1].get_key_indexes() == [3, 0, 1]
Beispiel #7
0
def test_get_shuffle():
    Key.set_random_seed(55591)
    Shuffle.set_random_seed(55592)
    key = Key.create_random_key(6)
    assert key.__str__() == "001000"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->5 1->3 2->4 3->0 4->1 5->2"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    assert len(blocks) == 2
    assert blocks[0].get_shuffle() == shuffle
    assert blocks[1].get_shuffle() == shuffle
Beispiel #8
0
def test_get_end_index():
    Key.set_random_seed(55577)
    Shuffle.set_random_seed(55588)
    key = Key.create_random_key(6)
    assert key.__str__() == "100000"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->4 1->0 2->5 3->2 4->3 5->1"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    assert len(blocks) == 2
    assert blocks[0].get_end_index() == 3
    assert blocks[1].get_end_index() == 6
Beispiel #9
0
def test_get_start_index():
    Key.set_random_seed(55555)
    Shuffle.set_random_seed(55566)
    key = Key.create_random_key(6)
    assert key.__str__() == "001100"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->2 1->1 2->0 3->5 4->3 5->4"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    assert len(blocks) == 2
    assert blocks[0].get_start_index() == 0
    assert blocks[1].get_start_index() == 3
Beispiel #10
0
def test_lt():
    Key.set_random_seed(55533)
    Shuffle.set_random_seed(55544)
    key = Key.create_random_key(6)
    assert key.__str__() == "001101"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->3 1->2 2->4 3->5 4->1 5->0"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    assert len(blocks) == 2
    assert (blocks[0] < blocks[1]) or (blocks[1] < blocks[0])
    # pylint:disable=comparison-with-itself
    assert not blocks[0] < blocks[0]
Beispiel #11
0
def test_get_and_create_right_sub_block():
    Key.set_random_seed(6667)
    Shuffle.set_random_seed(6668)
    key = Key.create_random_key(12)
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    blocks = Block.create_covering_blocks(key, shuffle, 8)
    assert len(blocks) == 2
    top_block = blocks[0]
    assert top_block.get_right_sub_block() is None
    right_sub_block = top_block.create_right_sub_block()
    assert top_block.get_right_sub_block() is right_sub_block
    right_right_sub_block = right_sub_block.create_right_sub_block()
    assert right_sub_block.get_right_sub_block() is right_right_sub_block
Beispiel #12
0
def test_flip_bit():
    Key.set_random_seed(77713)
    Shuffle.set_random_seed(77714)
    key = Key.create_random_key(6)
    assert key.__str__() == "111100"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->1 1->2 2->4 3->5 4->0 5->3"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    block = blocks[1]
    assert block.__str__() == "011"
    block.flip_bit(4)
    assert key.__str__() == "011100"
    assert block.__str__() == "001"
Beispiel #13
0
def test_get_parent_block():
    Key.set_random_seed(6665)
    Shuffle.set_random_seed(6666)
    key = Key.create_random_key(10)
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    blocks = Block.create_covering_blocks(key, shuffle, 10)
    assert len(blocks) == 1
    top_block = blocks[0]
    assert top_block.get_parent_block() is None
    left_sub_block = top_block.create_left_sub_block()
    assert left_sub_block.get_parent_block() == top_block
    right_sub_block = top_block.create_left_sub_block()
    assert right_sub_block.get_parent_block() == top_block
    left_left_sub_block = left_sub_block.create_left_sub_block()
    assert left_left_sub_block.get_parent_block() == left_sub_block
Beispiel #14
0
def test_repr():
    Key.set_random_seed(2221)
    Shuffle.set_random_seed(2222)
    key = Key.create_random_key(8)
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_KEEP_SAME)
    assert shuffle.__repr__() == "Shuffle: 0->0 1->1 2->2 3->3 4->4 5->5 6->6 7->7"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == "Shuffle: 0->0 1->1 2->6 3->4 4->3 5->2 6->5 7->7"
Beispiel #15
0
def test_str():
    Key.set_random_seed(3331)
    Shuffle.set_random_seed(3332)
    key = Key.create_random_key(8)
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_KEEP_SAME)
    assert shuffle.__str__() == "0->0 1->1 2->2 3->3 4->4 5->5 6->6 7->7"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->0 1->4 2->2 3->6 4->7 5->3 6->1 7->5"
    def _one_biconf_iteration(self):

        self.stats.biconf_iterations += 1

        cascade = self._algorithm.biconf_cascade

        # Randomly select half of the bits in the key. This is exactly the same as doing a new
        # random shuffle of the key and selecting the first half of newly shuffled key.
        key_size = self._reconciled_key.get_size()
        shuffle = Shuffle(key_size, Shuffle.SHUFFLE_RANDOM)
        mid_index = key_size // 2
        chosen_block = Block(self._reconciled_key, shuffle, 0, mid_index, None)
        if cascade:
            self._register_block_key_indexes(chosen_block)

        # Ask Alice what the correct parity of the chosen block is.
        self._schedule_ask_correct_parity(chosen_block, False)

        # If the algorithm wants it, also ask Alice what the correct parity of the complementary
        # block is.
        if self._algorithm.biconf_correct_complement:
            complement_block = Block(self._reconciled_key, shuffle, mid_index,
                                     key_size, None)
            if cascade:
                self._register_block_key_indexes(complement_block)
            self._schedule_ask_correct_parity(complement_block, False)

        # Service all pending correction attempts (potentially including Cascaded ones) and ask
        # parity messages.
        errors_corrected = self._service_all_pending_work(cascade)
        return errors_corrected
Beispiel #17
0
def test_get_and_set_correct_parity():
    Key.set_random_seed(6663)
    Shuffle.set_random_seed(6664)
    key = Key.create_random_key(10)
    assert key.__str__() == "1010111100"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__(
    ) == "0->8 1->5 2->7 3->0 4->2 5->4 6->1 7->3 8->9 9->6"
    blocks = Block.create_covering_blocks(key, shuffle, 10)
    assert len(blocks) == 1
    block = blocks[0]
    assert block.__str__() == "0111110001"
    assert block.get_correct_parity() is None
    block.set_correct_parity(0)
    assert block.get_correct_parity() == 0
    block.set_correct_parity(1)
    assert block.get_correct_parity() == 1
Beispiel #18
0
def test_get_key_index():
    Shuffle.set_random_seed(9992)
    shuffle = Shuffle(6, Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == "Shuffle: 0->5 1->4 2->2 3->0 4->1 5->3"
    assert shuffle.get_key_index(0) == 5
    assert shuffle.get_key_index(1) == 4
    assert shuffle.get_key_index(5) == 3
Beispiel #19
0
def test_calculate_parity():
    Key.set_random_seed(8881)
    Shuffle.set_random_seed(8882)
    key = Key.create_random_key(10)
    assert key.__repr__() == "Key: 1011111100"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == "Shuffle: 0->1 1->4 2->5 3->9 4->6 5->0 6->7 7->2 8->3 9->8"
    assert shuffle.__str__() == "0->1 1->4 2->5 3->9 4->6 5->0 6->7 7->2 8->3 9->8"
    assert shuffle.calculate_parity(key, 0, 10) == 1
    assert shuffle.calculate_parity(key, 4, 8) == 0
    assert shuffle.calculate_parity(key, 1, 2) == 1
Beispiel #20
0
def test_ask_parities():
    Key.set_random_seed(3)
    Shuffle.set_random_seed(77716)
    correct_key = Key.create_random_key(32)
    shuffle = Shuffle(correct_key.get_size(), Shuffle.SHUFFLE_RANDOM)
    blocks = Block.create_covering_blocks(correct_key, shuffle, 8)
    assert len(blocks) == 4
    assert blocks[0].__str__() == "01010011"
    assert blocks[1].__str__() == "01011100"
    assert blocks[2].__str__() == "10110001"
    assert blocks[3].__str__() == "01001110"
    channel = MockClassicalChannel(correct_key)
    channel.start_reconciliation()
    parities = channel.ask_parities(blocks)
    assert parities[0] == 0
    assert parities[1] == 0
    assert parities[2] == 0
    assert parities[3] == 0
    channel.end_reconciliation()
Beispiel #21
0
def test_get_bit():
    Key.set_random_seed(5551)
    Shuffle.set_random_seed(5552)
    key = Key.create_random_key(13)
    assert key.__str__() == "1011010010010"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == ("0->5 1->9 2->3 3->12 4->10 5->6 6->11 7->7 8->0 9->4 "
                                 "10->1 11->2 12->8")
    assert shuffle.get_bit(key, 0) == 1   # Shuffle bit 0 -> Key bit 5 -> Bit value 1
    assert shuffle.get_bit(key, 1) == 0   # Shuffle bit 1 -> Key bit 9 -> Bit value 0
    assert shuffle.get_bit(key, 2) == 1   # Shuffle bit 2 -> Key bit 3 -> Bit value 1
    assert shuffle.get_bit(key, 12) == 1  # Shuffle bit 12 -> Key bit 8 -> Bit value 1
Beispiel #22
0
def test_flip_parity():
    Key.set_random_seed(77715)
    Shuffle.set_random_seed(77716)
    key = Key.create_random_key(6)
    assert key.__str__() == "001010"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == "0->2 1->5 2->0 3->4 4->1 5->3"
    blocks = Block.create_covering_blocks(key, shuffle, 3)
    block = blocks[1]
    assert block.__str__() == "100"
    assert block.get_error_parity() == Block.ERRORS_UNKNOWN
    block.set_correct_parity(0)
    assert block.get_error_parity() == Block.ERRORS_ODD
    block.flip_bit(4)
    assert key.__str__() == "011010"
    assert block.__str__() == "110"
    assert block.get_error_parity() == Block.ERRORS_ODD
    block.flip_parity()
    assert block.get_error_parity() == Block.ERRORS_EVEN
Beispiel #23
0
def test_flip_bit():
    Key.set_random_seed(7771)
    Shuffle.set_random_seed(7772)
    key = Key.create_random_key(6)
    assert key.__repr__() == "Key: 010011"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == "Shuffle: 0->5 1->2 2->4 3->3 4->1 5->0"
    shuffle.flip_bit(key, 0)                    # Shuffle bit 0 -> Key bit 5 -> Bit value 1->0
    assert key.__repr__() == "Key: 010010"
Beispiel #24
0
def test_create_shuffle_keep_same():
    Key.set_random_seed(1111)
    Shuffle.set_random_seed(1112)

    # Empty shuffle.
    key = Key()
    assert key.__str__() == ""
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_KEEP_SAME)
    assert shuffle.__str__() == ""

    # Non-empty shuffle.
    key = Key.create_random_key(8)
    assert key.__str__() == "00101100"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_KEEP_SAME)
    assert shuffle.__str__() == "0->0 1->1 2->2 3->3 4->4 5->5 6->6 7->7"
    for index in range(key.get_size()):
        assert shuffle.get_bit(key, index) == key.get_bit(index)
Beispiel #25
0
def test_get_error_parity():

    # Create the original (sent) key.
    Key.set_random_seed(8881)
    Shuffle.set_random_seed(8882)
    correct_key = Key.create_random_key(16)
    assert correct_key.__repr__() == "Key: 1011111100101110"

    # Create the noisy (received) key, which has 3 errors relative to the original key.
    noisy_key = correct_key.copy(0.1875, Key.ERROR_METHOD_EXACT)
    assert correct_key.__repr__() == "Key: 1011111100101110"
    assert noisy_key.__repr__() == "Key: 1111111110101100"
    # Errors:  ^      ^     ^
    #                   111111
    #         0123456789012345

    # Create a random shuffling.
    shuffle = Shuffle(noisy_key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == (
        "Shuffle: 0->8 1->12 2->6 3->7 4->4 5->10 6->11 7->2 8->1 9->9 "
        "10->15 11->0 12->13 13->3 14->5 15->14")

    # Create a block that covers the entire shuffled noisy key.
    # The block has errors at the following shuffle indexes: 2->6 8->1 14->5
    rx_blocks = Block.create_covering_blocks(noisy_key, shuffle,
                                             noisy_key.get_size())
    assert len(rx_blocks) == 1
    rx_block = rx_blocks[0]
    assert rx_block.__repr__() == (
        "Block: 0->8=1 1->12=1 2->6=1 3->7=1 4->4=1 5->10=1 6->11=0 "
        "7->2=1 8->1=1 9->9=0 10->15=0 11->0=1 12->13=1 13->3=1 14->5=1 "
        "15->14=0")
    assert rx_block.__str__() == "1111110110011110"  # 12 ones -> even parity
    # Errors:  ^   ^^             # 3 errors -> odd number of errors
    #                   111111
    #         0123456789012345
    assert rx_block.get_current_parity() == 0

    # At this point, we have not yet corrected any error in the block.
    assert rx_block.get_error_parity() == Block.ERRORS_UNKNOWN
Beispiel #26
0
def test_create_block():

    # Block covers entire shuffle.
    Key.set_random_seed(2221)
    Shuffle.set_random_seed(2222)
    key = Key.create_random_key(8)
    assert key.__repr__() == "Key: 10111010"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__(
    ) == "Shuffle: 0->0 1->1 2->6 3->4 4->3 5->2 6->5 7->7"
    block = Block(key, shuffle, 3, 6, None)
    assert block.__repr__() == "Block: 3->4=1 4->3=1 5->2=1"
    block = Block(key, shuffle, 0, 8, None)
    assert block.__repr__(
    ) == "Block: 0->0=1 1->1=0 2->6=1 3->4=1 4->3=1 5->2=1 6->5=0 7->7=0"

    # Block covers part of the shuffle.
    block = Block(key, shuffle, 1, 3, None)
    assert block.__repr__() == "Block: 1->1=0 2->6=1"

    # Single bit block.
    block = Block(key, shuffle, 2, 3, None)
    assert block.__repr__() == "Block: 2->6=1"
    def _one_normal_cascade_iteration(self, iteration_nr):

        self.stats.normal_iterations += 1

        # Determine the block size to be used for this iteration, using the rules for this
        # particular algorithm of the Cascade algorithm.
        block_size = self._algorithm.block_size_function(
            self._estimated_bit_error_rate, self._reconciled_key.get_size(),
            iteration_nr)

        # In the first iteration, we don't shuffle the key. In all subsequent iterations we
        # shuffle the key, using a different random shuffling in each iteration.
        if iteration_nr == 1:
            shuffle = Shuffle(self._reconciled_key.get_size(),
                              Shuffle.SHUFFLE_KEEP_SAME)
        else:
            shuffle = Shuffle(self._reconciled_key.get_size(),
                              Shuffle.SHUFFLE_RANDOM)

        # Split the shuffled key into blocks, using the block size that we chose.
        blocks = Block.create_covering_blocks(self._reconciled_key, shuffle,
                                              block_size)

        # For each top-level covering block...
        for block in blocks:

            # Update the key index to block map.
            self._register_block_key_indexes(block)

            # We won't be able to do anything with the top-level covering blocks until we know what
            # the correct parity it.
            self._schedule_ask_correct_parity(block, False)

        # Service all pending correction attempts (including Cascaded ones) and ask parity
        # messages.
        self._service_all_pending_work(True)
Beispiel #28
0
def test_create_shuffle_random():
    Key.set_random_seed(1111)
    Shuffle.set_random_seed(1112)

    # Empty shuffle.
    key = Key()
    assert key.__str__() == ""
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == ""

    # Non-empty shuffle.
    key = Key.create_random_key(16)
    assert key.__str__() == "0010110001010010"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__() == ("0->2 1->9 2->8 3->7 4->3 5->12 6->1 7->5 8->13 "
                                 "9->6 10->0 11->14 12->10 13->4 14->11 15->15")
    key = Key()
    assert key.__str__() == ""
Beispiel #29
0
def test_create_covering_blocks():

    # Prepare key and shuffle.
    Key.set_random_seed(3331)
    Shuffle.set_random_seed(3332)
    key = Key.create_random_key(16)
    assert key.__repr__() == "Key: 0011011001100110"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == (
        "Shuffle: 0->4 1->14 2->5 3->15 4->0 5->1 6->7 7->11 "
        "8->6 9->12 10->13 11->3 12->9 13->8 14->2 15->10")

    # Multiple blocks, last block is partially filled.
    blocks = Block.create_covering_blocks(key, shuffle, 5)
    assert len(blocks) == 4
    assert blocks[0].__repr__(
    ) == "Block: 0->4=0 1->14=1 2->5=1 3->15=0 4->0=0"
    assert blocks[1].__repr__(
    ) == "Block: 5->1=0 6->7=0 7->11=0 8->6=1 9->12=0"
    assert blocks[2].__repr__(
    ) == "Block: 10->13=1 11->3=1 12->9=1 13->8=0 14->2=1"
    assert blocks[3].__repr__() == "Block: 15->10=1"

    # Multiple blocks, last block is fully filled.
    blocks = Block.create_covering_blocks(key, shuffle, 4)
    assert len(blocks) == 4
    assert blocks[0].__repr__() == "Block: 0->4=0 1->14=1 2->5=1 3->15=0"
    assert blocks[1].__repr__() == "Block: 4->0=0 5->1=0 6->7=0 7->11=0"
    assert blocks[2].__repr__() == "Block: 8->6=1 9->12=0 10->13=1 11->3=1"
    assert blocks[3].__repr__() == "Block: 12->9=1 13->8=0 14->2=1 15->10=1"

    # Single block, partially filled.
    key = Key.create_random_key(4)
    assert key.__repr__() == "Key: 1111"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__repr__() == "Shuffle: 0->0 1->1 2->3 3->2"
    blocks = Block.create_covering_blocks(key, shuffle, 5)
    assert len(blocks) == 1
    assert blocks[0].__repr__() == "Block: 0->0=1 1->1=1 2->3=1 3->2=1"

    # Single block, fully filled.
    blocks = Block.create_covering_blocks(key, shuffle, 4)
    assert len(blocks) == 1
    assert blocks[0].__repr__() == "Block: 0->0=1 1->1=1 2->3=1 3->2=1"
Beispiel #30
0
def test_get_current_parity():

    # Even parity block.
    Key.set_random_seed(6661)
    Shuffle.set_random_seed(6662)
    key = Key.create_random_key(10)
    assert key.__str__() == "0111101111"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__(
    ) == "0->1 1->6 2->7 3->8 4->4 5->2 6->0 7->9 8->3 9->5"
    blocks = Block.create_covering_blocks(key, shuffle, 10)
    assert len(blocks) == 1
    block = blocks[0]
    assert block.__str__() == "1111110110"
    assert block.get_current_parity() == 0

    # Odd parity block.
    key = Key.create_random_key(12)
    assert key.__str__() == "010100111101"
    shuffle = Shuffle(key.get_size(), Shuffle.SHUFFLE_RANDOM)
    assert shuffle.__str__(
    ) == "0->7 1->9 2->11 3->2 4->8 5->1 6->6 7->5 8->0 9->10 10->3 11->4"
    blocks = Block.create_covering_blocks(key, shuffle, 12)
    assert len(blocks) == 1
    block = blocks[0]
    assert block.__str__() == "111011100010"
    assert block.get_current_parity() == 1

    # Split block into sub-blocks.
    left_sub_block = block.create_left_sub_block()
    right_sub_block = block.create_right_sub_block()

    # Odd parity sub-block.
    assert left_sub_block.__str__() == "111011"
    assert left_sub_block.get_current_parity() == 1

    # Even parity sub-block.
    assert right_sub_block.__str__() == "100010"
    assert right_sub_block.get_current_parity() == 0