Ejemplo n.º 1
0
 def test_seek_negative_position(self):
     """
     Test that seeking to a negative position raises an error.
     """
     bitstream = BitStream()
     self.assertRaises(SeekOutOfRangeError, bitstream.seek, -1)
     # An invalid seek(...) call should not move the position indicator.
     self.assertEqual(bitstream.get_current_pos(), 0)
Ejemplo n.º 2
0
 def test_seek_negative_position(self):
     """
     Test that seeking to a negative position raises an error.
     """
     bitstream = BitStream()
     self.assertRaises(SeekOutOfRangeError, bitstream.seek, -1)
     # An invalid seek(...) call should not move the position indicator.
     self.assertEqual(bitstream.get_current_pos(), 0)
Ejemplo n.º 3
0
 def test_bitstream_constructor(self):
     """
     Test that creating an empty bitstream succeeds.
     """
     bitstream = BitStream()
     # An empty bitstream has length 0 ...
     self.assertEqual(bitstream.get_length(), 0)
     # ...and has its current position marker at position 0.
     self.assertEqual(bitstream.get_current_pos(), 0)
Ejemplo n.º 4
0
 def test_bitstream_constructor(self):
     """
     Test that creating an empty bitstream succeeds.
     """
     bitstream = BitStream()
     # An empty bitstream has length 0 ...
     self.assertEqual(bitstream.get_length(), 0)
     # ...and has its current position marker at position 0.
     self.assertEqual(bitstream.get_current_pos(), 0)
Ejemplo n.º 5
0
 def test_get_hex_invalid_length(self):
     """
     Test that trying to read a number of bits that is not a multiple of 4 
     as hex data raises an exception.
     """
     bitstream = BitStream()
     bitstream.put_hex("DfF7CE69fF5478A") # 15 digits, 60 bits
     bitstream.seek(0)
     self.assertRaises(ValueError, 
                       bitstream.get_hex, 47) # read 11.75 hex digits?
Ejemplo n.º 6
0
 def test_get_base64_invalid_length(self):
     """
     Test that trying to read a number of bits that is not a multiple of 8 
     as base64 data raises an exception.
     """
     bitstream = BitStream()
     bitstream.put_base64("Zm9vYmE=") # 40 bits
     bitstream.seek(0)
     self.assertRaises(ValueError, 
                       bitstream.get_base64, 26) # read 3.25 bytes?
Ejemplo n.º 7
0
    def test_stress(self):
        """
        Stress test BitStream by writings lots of numbers of different bit 
        sizes and reading them back.
        """
        # num_writes = 10000
        num_writes = 1000
        min_bit_length = 1
        max_bit_length = 8192

        # Generate the numbers
        nums = []
        total_bit_length = 0
        for i in range(0, num_writes):
            bit_length = random.randint(min_bit_length, max_bit_length)
            total_bit_length += bit_length
            val = random.randint(0, 2**bit_length - 1)
            nums.append({"bit_length": bit_length, "value": val})

        # Write them to a BitStream object
        bitstream = BitStream()
        for num in nums:
            bitstream.put_num(num["value"], num["bit_length"])

        # Check the BitStream length and current position
        self.assertEquals(bitstream.get_length(), total_bit_length)
        self.assertEquals(bitstream.get_current_pos(), total_bit_length)

        # Read all numbers back
        bitstream.seek(0)
        for num in nums:
            self.assertEquals(bitstream.get_num(num["bit_length"]),
                              num["value"])
Ejemplo n.º 8
0
 def test_string_character_zero(self):
     """
     Test that we are handling character zero ('\\0') correctly.
     """
     bitstream = BitStream()
     bitstream.put_string("Evil \0String.")  # 13 chars/bytes
     self.assertEquals(bitstream.get_length(), 13 * 8)
     bitstream.seek(0)
     self.assertEquals(bitstream.get_string(bitstream.get_length()),
                       "Evil \0String.")
Ejemplo n.º 9
0
 def test_stress(self):
     """
     Stress test BitStream by writings lots of numbers of different bit 
     sizes and reading them back.
     """
     # num_writes = 10000
     num_writes = 1000
     min_bit_length = 1
     max_bit_length = 8192
     
     # Generate the numbers
     nums = []
     total_bit_length = 0
     for i in range(0, num_writes):
         bit_length = random.randint(min_bit_length, max_bit_length)
         total_bit_length += bit_length
         val = random.randint(0, 2**bit_length - 1)
         nums.append({"bit_length" : bit_length, "value" : val})
         
     # Write them to a BitStream object
     bitstream = BitStream()
     for num in nums:
         bitstream.put_num(num["value"], num["bit_length"])
         
     # Check the BitStream length and current position
     self.assertEquals(bitstream.get_length(),total_bit_length)
     self.assertEquals(bitstream.get_current_pos(),total_bit_length)
     
     # Read all numbers back
     bitstream.seek(0)
     for num in nums:
         self.assertEquals(bitstream.get_num(num["bit_length"]),num["value"])
Ejemplo n.º 10
0
 def test_put_num_negative_length(self):
     """
     Test that put_num raises an exception when passed negative integer 
     values as its bit_length argument.
     """
     bitstream = BitStream()
     val = random.randint(-128, -1)
     self.assertRaises(ValueError, bitstream.put_num, 23, val)
Ejemplo n.º 11
0
 def test_put_byte_negative(self):
     """
     Test that put_byte raises an exception when passed negative integer   
     values as its argument.
     """
     bitstream = BitStream()
     val = random.randint(-2**8 + 1, -1)
     self.assertRaises(ValueError, bitstream.put_byte, val)
Ejemplo n.º 12
0
 def test_string_character_zero(self):
     """
     Test that we are handling character zero ('\\0') correctly.
     """
     bitstream = BitStream()
     bitstream.put_string("Evil \0String.") # 13 chars/bytes
     self.assertEquals(bitstream.get_length(),13*8)
     bitstream.seek(0)
     self.assertEquals(bitstream.get_string(bitstream.get_length()),    
                       "Evil \0String.")
Ejemplo n.º 13
0
    def test_hex_basic(self):
        """
        This method tests put_hex's and get_hex's basic functionality.
        """
        bitstream = BitStream()

        # Generate a random string of hex digits, ie: ('0'-'9'|'a'-'f'|'A'-'F')*
        valid_hex_digits = "0123456789abcdefABCDEF"
        num_digits = 50
        digits = ""
        for i in range(0, num_digits):
            digits += random.choice(valid_hex_digits)

        # Put those digits in the BitStream...
        bitstream.put_hex(digits)

        # ...and get them back
        bitstream.seek(0)
        read_digits = bitstream.get_hex(len(digits) *
                                        4)  # 1 hex digit == 4 bits

        # Check that the hexadecimal digits were recovered correctly
        # Note that case information may be lost. Comparison must be case
        # insensitive (ie. 'a9Bc' and 'A9bC' are equal)
        self.assertEqual(read_digits.lower(), digits.lower())
Ejemplo n.º 14
0
 def encrypt_text(self, text, pad_to=None, task_monitor=None):
     """
     Encrypts the given string into a ciphertext object.
     
     Arguments:
         text::string            -- A string to encrypt.
         pad_to::int            -- Minimum size (in bytes) of the resulting 
                                ciphertext. Data will be padded before 
                                encryption to match this size.
         task_monitor::TaskMonitor    -- A task monitor for this task.
     
     Returns:
         ciphertext:Ciphertext    -- A ciphertext object encapsulating the 
                                    encrypted data.
     """
     bitstream = BitStream()
     bitstream.put_string(text)
     return self.encrypt_bitstream(bitstream, pad_to, task_monitor)
Ejemplo n.º 15
0
 def test_put_base64_wrong_type(self):
     """
     Test that put_base64 raises an exception when passed non string values 
     as its argument.
     """
     bitstream = BitStream()
     self.assertRaises(TypeError, bitstream.put_base64, 23234)
     self.assertRaises(TypeError, bitstream.put_base64, 0.1)
     self.assertRaises(TypeError, bitstream.put_base64, object())
Ejemplo n.º 16
0
 def test_put_num_wrong_bit_length(self):
     """
     Test that put_num raises an exception when given incompatible num and 
     bit_length arguments (ie. num >= 2**bit_length)
     """
     bitstream = BitStream()
     self.assertRaises(ValueError, bitstream.put_num, 2**16, 16)
     val = random.randint(2**64 + 1, 2**128)
     self.assertRaises(ValueError, bitstream.put_num, val, 64)
Ejemplo n.º 17
0
    def encrypt_text(self, text, pad_to=None, task_monitor=None):
        """
        Encrypts the given string into a ciphertext object.

        Arguments:
            text::string            -- A string to encrypt.
            pad_to::int            -- Minimum size (in bytes) of the resulting
                                   ciphertext. Data will be padded before
                                   encryption to match this size.
            task_monitor::TaskMonitor    -- A task monitor for this task.

        Returns:
            ciphertext:Ciphertext    -- A ciphertext object encapsulating the
                                       encrypted data.
        """
        bitstream = BitStream()
        bitstream.put_string(text)
        return self.encrypt_bitstream(bitstream, pad_to, task_monitor)
Ejemplo n.º 18
0
 def test_put_byte_to_big(self):
     """
     Test that put_byte raises an exception when passed any integer value 
     > 255 as its argument.
     """
     bitstream = BitStream()
     self.assertRaises(ValueError, bitstream.put_byte, 256)
     val = random.randint(2**8 + 1, 2**32)
     self.assertRaises(ValueError, bitstream.put_byte, val)
Ejemplo n.º 19
0
 def test_put_num_non_integer(self):
     """
     Test that put_num raises an exception when passed non integer values as 
     its num argument.
     """
     bitstream = BitStream()
     self.assertRaises(TypeError, bitstream.put_num, "gato", 16)
     self.assertRaises(TypeError, bitstream.put_num, 0.1, 16)
     self.assertRaises(TypeError, bitstream.put_num, [1, 'a', 3], 16)
     self.assertRaises(TypeError, bitstream.put_num, object(), 16)
Ejemplo n.º 20
0
 def test_put_num_non_integer_length(self):
     """
     Test that put_num raises an exception when passed non integer values as 
     its bit_length argument.
     """
     bitstream = BitStream()
     self.assertRaises(TypeError, bitstream.put_num, 23, "gato")
     self.assertRaises(TypeError, bitstream.put_num, 23, 12.1)
     self.assertRaises(TypeError, bitstream.put_num, 23, [1, 'a', 3])
     self.assertRaises(TypeError, bitstream.put_num, 23, object())
Ejemplo n.º 21
0
 def test_put_byte_non_integer(self):
     """
     Test that put_byte raises an exception when passed non integer values  
     as its argument.
     """
     bitstream = BitStream()
     self.assertRaises(TypeError, bitstream.put_byte, "gato")
     self.assertRaises(TypeError, bitstream.put_byte, 0.1)
     self.assertRaises(TypeError, bitstream.put_byte, [1, 'a', 3])
     self.assertRaises(TypeError, bitstream.put_byte, object())
Ejemplo n.º 22
0
 def test_string_unicode(self):
     """
     Test basic put_string and get_string support for python unicode objects.
     """
     bitstream = BitStream()
     unicode_string = u"ÄäÜüßЯБГДЖЙŁĄŻĘĆŃŚŹてすとアイウエオカキクケコサシスセソタチツテ"
     bitstream.put_string(unicode_string)
     bitstream.seek(0)
     # Note: the string is read back as a "normal" UTF-8 string, unicode
     #       type information is not stored in the bitstream.
     self.assertEquals(bitstream.get_string(bitstream.get_length()),
                       "ÄäÜüßЯБГДЖЙŁĄŻĘĆŃŚŹてすとアイウエオカキクケコサシスセソタチツテ")
Ejemplo n.º 23
0
    def test_get_base64_zero_bits(self):
        """
        Test that reading zero bits from the stream as base64 data results in 
        getting the empty string: \"\".
        """
        bitstream = BitStream()
        self.assertEquals(bitstream.get_base64(0), "")

        # Store some base64 data in the stream.
        bitstream.put_base64("Zm9vYmE=")  # 40 bits

        bitstream.seek(0)
        self.assertEquals(bitstream.get_base64(0), "")
Ejemplo n.º 24
0
 def _encrypted_data_as_bitstream(self):
     """
     Returns the contents of this ciphertext as a BitStream object.
     
     This includes only the encrypted data (gamma and delta components), not 
     the nbits and public key fingerprint metadata.
     
     The components are encoded alternating as follows:
         [gamma[0], delta[0], gamma[1], delta[1], ...]
     with each component represented as a nbits long number.
     
     Returns:
         bitstream::BitStream    -- The gamma and delta components of this 
                                    ciphertext as a bitstream.
     """
     bitstream = BitStream()
     for i in range(0, self.get_length()):
         bitstream.put_num(self.gamma[i], self.nbits)
         bitstream.put_num(self.delta[i], self.nbits)
     return bitstream
Ejemplo n.º 25
0
 def _encrypted_data_as_bitstream(self):
     """
     Returns the contents of this ciphertext as a BitStream object.
     
     This includes only the encrypted data (gamma and delta components), not 
     the nbits and public key fingerprint metadata.
     
     The components are encoded alternating as follows:
         [gamma[0], delta[0], gamma[1], delta[1], ...]
     with each component represented as a nbits long number.
     
     Returns:
         bitstream::BitStream    -- The gamma and delta components of this 
                                    ciphertext as a bitstream.
     """
     bitstream = BitStream()
     for i in range(0, self.get_length()):
         bitstream.put_num(self.gamma[i], self.nbits)
         bitstream.put_num(self.delta[i], self.nbits)
     return bitstream
Ejemplo n.º 26
0
    def test_get_hex_zero_bits(self):
        """
        Test that reading zero bits from the stream as hex data results in 
        getting the empty string: \"\".
        """
        bitstream = BitStream()
        self.assertEquals(bitstream.get_hex(0), "")

        # Store some hex data in the stream.
        bitstream.put_hex("DfF7CE69fF5478A")  # 15 digits, 60 bits

        bitstream.seek(0)
        self.assertEquals(bitstream.get_hex(0), "")
Ejemplo n.º 27
0
    def test_get_string_zero_bits(self):
        """
        Test that reading zero bits from the stream as a string results in  
        getting the empty string: \"\".
        """
        bitstream = BitStream()
        self.assertEquals(bitstream.get_string(0), "")

        # Store a string in the stream.
        bitstream.put_string("Hello World!")

        bitstream.seek(0)
        self.assertEquals(bitstream.get_string(0), "")
Ejemplo n.º 28
0
    def test_get_bit_dump_string_zero_bits(self):
        """
        Test that reading zero bits from the stream as a bit dump string 
        results in getting the empty string: \"\".
        """
        bitstream = BitStream()
        self.assertEquals(bitstream.get_bit_dump_string(0), "")

        # Store some bits in the stream.
        bitstream.put_bit_dump_string("0001110101")  # 10 bits

        bitstream.seek(0)
        self.assertEquals(bitstream.get_bit_dump_string(0), "")
Ejemplo n.º 29
0
    def test_put_hex_invalid_format(self):
        """
        Test that put_hex raises an exception when passed any string not of the 
        form ('0'-'9'|'a'-'f'|'A'-'F')*
        """
        bitstream = BitStream()

        # Try some fixed examples
        self.assertRaises(ValueError, bitstream.put_hex, "aF92G2")
        self.assertRaises(ValueError, bitstream.put_hex, "Hello")
        self.assertRaises(ValueError, bitstream.put_hex, "3354 F")
        self.assertRaises(ValueError, bitstream.put_hex, "ケコサシス")

        # Generate a random string conforming to ('0'-'9'|'a'-'f'|'A'-'F')*
        # except for one (ascii) character.
        valid_hex_digits = "0123456789abcdefABCDEF"
        num_digits = 50
        pos_wrong_char = random.randint(1, 48)
        r_invalid_hex_string = ""

        for i in range(0, pos_wrong_char):
            r_invalid_hex_string += random.choice(valid_hex_digits)

        non_hex_char = "0"
        while (non_hex_char in valid_hex_digits):
            non_hex_char = \
               random.choice(string.letters + string.digits + string.whitespace)

        r_invalid_hex_string += non_hex_char

        for i in range(0, num_digits - pos_wrong_char - 1):
            r_invalid_hex_string += random.choice(valid_hex_digits)

        # Try the randomly generated example
        self.assertRaises(ValueError, bitstream.put_hex, r_invalid_hex_string)

        # Calls that throw exceptions should not alter the contents or position
        # of the bitstream:
        self.assertEquals(bitstream.get_length(), 0)
        self.assertEquals(bitstream.get_current_pos(), 0)
Ejemplo n.º 30
0
 def test_put_hex_invalid_format(self):
     """
     Test that put_hex raises an exception when passed any string not of the 
     form ('0'-'9'|'a'-'f'|'A'-'F')*
     """
     bitstream = BitStream()
     
     # Try some fixed examples
     self.assertRaises(ValueError, bitstream.put_hex, "aF92G2")
     self.assertRaises(ValueError, bitstream.put_hex, "Hello")
     self.assertRaises(ValueError, bitstream.put_hex, "3354 F")
     self.assertRaises(ValueError, bitstream.put_hex, "ケコサシス")
     
     # Generate a random string conforming to ('0'-'9'|'a'-'f'|'A'-'F')* 
     # except for one (ascii) character.
     valid_hex_digits = "0123456789abcdefABCDEF"
     num_digits = 50
     pos_wrong_char = random.randint(1,48)
     r_invalid_hex_string = ""
     
     for i in range(0,pos_wrong_char):
         r_invalid_hex_string += random.choice(valid_hex_digits)
     
     non_hex_char = "0"
     while(non_hex_char in valid_hex_digits): 
         non_hex_char = \
            random.choice(string.letters + string.digits + string.whitespace)
     
     r_invalid_hex_string += non_hex_char
         
     for i in range(0,num_digits - pos_wrong_char - 1):
         r_invalid_hex_string += random.choice(valid_hex_digits)
     
     # Try the randomly generated example
     self.assertRaises(ValueError, bitstream.put_hex, r_invalid_hex_string)
                       
     # Calls that throw exceptions should not alter the contents or position 
     # of the bitstream:
     self.assertEquals(bitstream.get_length(),0)
     self.assertEquals(bitstream.get_current_pos(),0)
Ejemplo n.º 31
0
 def test_seek_beyond_eos(self):
     """
     Test that seeking beyond the end of the bitstream results in an 
     exception raised.
     """
     bitstream = BitStream()
     self.assertRaises(SeekOutOfRangeError, bitstream.seek, 1) # empty stream
     # An invalid seek(...) call should not move the position indicator.
     self.assertEqual(bitstream.get_current_pos(), 0)
     
     # Store a 64-bit integer in the stream.
     num = int('00000000000000110101011001010011'
               '00101100001000101000100110101111', 2)
     bitstream.put_num(num, 64)
     
     # Test seeking past 64 bits
     self.assertRaises(SeekOutOfRangeError, bitstream.seek, 65)
     self.assertRaises(SeekOutOfRangeError, bitstream.seek, 
                       random.randint(66,2**128))
                       
     # An invalid seek(...) call should not move the position indicator.
     self.assertEqual(bitstream.get_current_pos(), 64)
Ejemplo n.º 32
0
 def test_string_unicode(self):
     """
     Test basic put_string and get_string support for python unicode objects.
     """
     bitstream = BitStream()
     unicode_string = u"ÄäÜüßЯБГДЖЙŁĄŻĘĆŃŚŹてすとアイウエオカキクケコサシスセソタチツテ"
     bitstream.put_string(unicode_string)
     bitstream.seek(0)
     # Note: the string is read back as a "normal" UTF-8 string, unicode
     #       type information is not stored in the bitstream.
     self.assertEquals(bitstream.get_string(bitstream.get_length()),    
                       "ÄäÜüßЯБГДЖЙŁĄŻĘĆŃŚŹてすとアイウエオカキクケコサシスセソタチツテ")
Ejemplo n.º 33
0
    def test_get_num_zero_bits(self):
        """
        Test that reading zero bits from the stream as a number results in 
        getting the number 0.
        """
        bitstream = BitStream()
        self.assertEquals(bitstream.get_num(0), 0)

        # Store a 64-bit integer in the stream.
        num = int(
            '00000000000000110101011001010011'
            '00101100001000101000100110101111', 2)
        bitstream.put_num(num, 64)

        bitstream.seek(0)
        self.assertEquals(bitstream.get_num(0), 0)
Ejemplo n.º 34
0
    def test_get_string_utf8_read_partial_characters(self):
        """
        Test that it is possible to read "partial" utf-8 characters from the 
        bitstream and that concatenation restores the full character/glyph.
        """
        bitstream = BitStream()
        string = "てすとアイウエオカキクケコサシスセソタチツテ"  # 22 chars, 66 bytes
        bitstream.put_string(string)
        bitstream.seek(0)

        # First read 32 bytes
        readString = bitstream.get_string(32 * 8)
        self.assertEquals(readString, "てすとアイウエオカキ\xef\xbd")
        # Now read the rest
        readString += bitstream.get_string(34 * 8)
        self.assertEquals(readString, "てすとアイウエオカキクケコサシスセソタチツテ")
Ejemplo n.º 35
0
 def test_get_hex_zero_bits(self):
     """
     Test that reading zero bits from the stream as hex data results in 
     getting the empty string: \"\".
     """
     bitstream = BitStream()
     self.assertEquals(bitstream.get_hex(0), "")
     
     # Store some hex data in the stream.
     bitstream.put_hex("DfF7CE69fF5478A") # 15 digits, 60 bits
     
     bitstream.seek(0)
     self.assertEquals(bitstream.get_hex(0), "")
Ejemplo n.º 36
0
 def test_get_bit_dump_string_zero_bits(self):
     """
     Test that reading zero bits from the stream as a bit dump string 
     results in getting the empty string: \"\".
     """
     bitstream = BitStream()
     self.assertEquals(bitstream.get_bit_dump_string(0), "")
     
     # Store some bits in the stream.
     bitstream.put_bit_dump_string("0001110101") # 10 bits
     
     bitstream.seek(0)
     self.assertEquals(bitstream.get_bit_dump_string(0), "")
Ejemplo n.º 37
0
 def test_get_base64_zero_bits(self):
     """
     Test that reading zero bits from the stream as base64 data results in 
     getting the empty string: \"\".
     """
     bitstream = BitStream()
     self.assertEquals(bitstream.get_base64(0), "")
     
     # Store some base64 data in the stream.
     bitstream.put_base64("Zm9vYmE=") # 40 bits
     
     bitstream.seek(0)
     self.assertEquals(bitstream.get_base64(0), "")
Ejemplo n.º 38
0
 def test_get_string_zero_bits(self):
     """
     Test that reading zero bits from the stream as a string results in  
     getting the empty string: \"\".
     """
     bitstream = BitStream()
     self.assertEquals(bitstream.get_string(0), "")
     
     # Store a string in the stream.
     bitstream.put_string("Hello World!")
     
     bitstream.seek(0)
     self.assertEquals(bitstream.get_string(0), "")
Ejemplo n.º 39
0
    def test_put_bit_dump_string_invalid_format(self):
        """
        Test that put_bit_dump_string raises an exception when passed any 
        string not of the form ('0'|'1')*
        """
        bitstream = BitStream()

        # Try some fixed examples
        self.assertRaises(ValueError, bitstream.put_bit_dump_string, "23234")
        self.assertRaises(ValueError, bitstream.put_bit_dump_string, "Hello")
        self.assertRaises(ValueError, bitstream.put_bit_dump_string, "0101 0")
        self.assertRaises(ValueError, bitstream.put_bit_dump_string, "ケコサシス")

        # Generate a random string conforming to ('0'|'1')* except for one
        # (ascii) character.
        num_bits = 50
        pos_wrong_char = random.randint(1, 48)
        r_invalid_bit_string = ""

        for i in range(0, pos_wrong_char):
            r_invalid_bit_string += random.choice(('0', '1'))

        r_invalid_bit_string += \
            random.choice(string.letters + "23456789_-/\\" + string.whitespace)

        for i in range(0, num_bits - pos_wrong_char - 1):
            r_invalid_bit_string += random.choice(('0', '1'))

        # Try the randomly generated example
        self.assertRaises(ValueError, bitstream.put_bit_dump_string,
                          r_invalid_bit_string)

        # Calls that throw exceptions should not alter the contents or position
        # of the bitstream:
        self.assertEquals(bitstream.get_length(), 0)
        self.assertEquals(bitstream.get_current_pos(), 0)
Ejemplo n.º 40
0
    def test_get_base64_beyond_eos(self):
        """
        Test that trying to read beyond the end of the stream raises an 
        exception when calling get_base64(...).
        """
        bitstream = BitStream()

        self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_base64, 8)
        # Current position should not have been changed
        self.assertEquals(bitstream.get_current_pos(), 0)

        bitstream.put_base64("Zm9vYmE=")  # 40 bits
        bitstream.seek(0)
        # Read beyond EOS
        self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_base64, 48)
        # Current position should not have been changed
        self.assertEquals(bitstream.get_current_pos(), 0)
Ejemplo n.º 41
0
    def test_get_byte_beyond_eos(self):
        """
        Test that trying to read beyond the end of the stream raises an 
        exception when calling get_byte(...).
        """
        bitstream = BitStream()

        self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_byte)
        # Current position should not have been changed
        self.assertEquals(bitstream.get_current_pos(), 0)

        bitstream.put_byte(14)
        bitstream.seek(1)
        # Read a single bit beyond EOS
        self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_byte)
        # Current position should not have been changed
        self.assertEquals(bitstream.get_current_pos(), 1)
Ejemplo n.º 42
0
    def test_get_hex_beyond_eos(self):
        """
        Test that trying to read beyond the end of the stream raises an 
        exception when calling get_hex(...).
        """
        bitstream = BitStream()

        self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_hex, 1)
        # Current position should not have been changed
        self.assertEquals(bitstream.get_current_pos(), 0)

        bitstream.put_hex("DfF7CE69fF5478A")  # 15 digits, 60 bits
        bitstream.seek(0)
        # Read beyond EOS
        self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_hex, 61)
        # Current position should not have been changed
        self.assertEquals(bitstream.get_current_pos(), 0)
Ejemplo n.º 43
0
 def test_put_bit_dump_string_invalid_format(self):
     """
     Test that put_bit_dump_string raises an exception when passed any 
     string not of the form ('0'|'1')*
     """
     bitstream = BitStream()
     
     # Try some fixed examples
     self.assertRaises(ValueError, bitstream.put_bit_dump_string, "23234")
     self.assertRaises(ValueError, bitstream.put_bit_dump_string, "Hello")
     self.assertRaises(ValueError, bitstream.put_bit_dump_string, "0101 0")
     self.assertRaises(ValueError, bitstream.put_bit_dump_string, "ケコサシス")
     
     # Generate a random string conforming to ('0'|'1')* except for one 
     # (ascii) character.
     num_bits = 50
     pos_wrong_char = random.randint(1,48)
     r_invalid_bit_string = ""
     
     for i in range(0,pos_wrong_char):
         r_invalid_bit_string += random.choice(('0','1'))
         
     r_invalid_bit_string += \
         random.choice(string.letters + "23456789_-/\\" + string.whitespace)
         
     for i in range(0,num_bits - pos_wrong_char - 1):
         r_invalid_bit_string += random.choice(('0','1'))
     
     # Try the randomly generated example
     self.assertRaises(ValueError, bitstream.put_bit_dump_string, 
                       r_invalid_bit_string)
                       
     # Calls that throw exceptions should not alter the contents or position 
     # of the bitstream:
     self.assertEquals(bitstream.get_length(),0)
     self.assertEquals(bitstream.get_current_pos(),0) 
Ejemplo n.º 44
0
 def test_get_base64_invalid_length(self):
     """
     Test that trying to read a number of bits that is not a multiple of 8 
     as base64 data raises an exception.
     """
     bitstream = BitStream()
     bitstream.put_base64("Zm9vYmE=")  # 40 bits
     bitstream.seek(0)
     self.assertRaises(ValueError, bitstream.get_base64,
                       26)  # read 3.25 bytes?
Ejemplo n.º 45
0
 def test_get_hex_invalid_length(self):
     """
     Test that trying to read a number of bits that is not a multiple of 4 
     as hex data raises an exception.
     """
     bitstream = BitStream()
     bitstream.put_hex("DfF7CE69fF5478A")  # 15 digits, 60 bits
     bitstream.seek(0)
     self.assertRaises(ValueError, bitstream.get_hex,
                       47)  # read 11.75 hex digits?
Ejemplo n.º 46
0
    def test_get_string_non_bytable_size(self):
        """
        Test that calling get_string with a bit_length that is not a multiple 
        of 8 raises an exception.
        That is, we cannot read partial bytes as string data.
        """
        bitstream = BitStream()
        bitstream.put_string("Hello World!")
        bitstream.seek(0)

        self.assertRaises(ValueError, bitstream.get_string, 18)

        # Current position should not have been changed
        self.assertEquals(bitstream.get_current_pos(), 0)
Ejemplo n.º 47
0
 def test_get_num_zero_bits(self):
     """
     Test that reading zero bits from the stream as a number results in 
     getting the number 0.
     """
     bitstream = BitStream()
     self.assertEquals(bitstream.get_num(0), 0)
     
     # Store a 64-bit integer in the stream.
     num = int('00000000000000110101011001010011'
               '00101100001000101000100110101111', 2)
     bitstream.put_num(num, 64)
     
     bitstream.seek(0)
     self.assertEquals(bitstream.get_num(0), 0)
Ejemplo n.º 48
0
 def test_get_string_utf8_read_partial_characters(self):
     """
     Test that it is possible to read "partial" utf-8 characters from the 
     bitstream and that concatenation restores the full character/glyph.
     """
     bitstream = BitStream()
     string = "てすとアイウエオカキクケコサシスセソタチツテ" # 22 chars, 66 bytes
     bitstream.put_string(string)
     bitstream.seek(0)
     
     # First read 32 bytes
     readString = bitstream.get_string(32*8)
     self.assertEquals(readString,"てすとアイウエオカキ\xef\xbd") 
     # Now read the rest
     readString += bitstream.get_string(34*8)
     self.assertEquals(readString,"てすとアイウエオカキクケコサシスセソタチツテ") 
Ejemplo n.º 49
0
 def test_get_byte_beyond_eos(self):
     """
     Test that trying to read beyond the end of the stream raises an 
     exception when calling get_byte(...).
     """
     bitstream = BitStream()
     
     self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_byte)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
     
     bitstream.put_byte(14)
     bitstream.seek(1)
     # Read a single bit beyond EOS
     self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_byte)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),1)
Ejemplo n.º 50
0
 def test_get_string_non_bytable_size(self):
     """
     Test that calling get_string with a bit_length that is not a multiple 
     of 8 raises an exception.
     That is, we cannot read partial bytes as string data.
     """
     bitstream = BitStream()
     bitstream.put_string("Hello World!")
     bitstream.seek(0)
     
     self.assertRaises(ValueError, bitstream.get_string, 18)
     
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
Ejemplo n.º 51
0
 def test_get_string_beyond_eos(self):
     """
     Test that trying to read beyond the end of the stream raises an 
     exception when calling get_string(...).
     """
     bitstream = BitStream()
     
     self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_string, 1)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
     
     bitstream.put_string("Hello World!")    # 12 chars/bytes
     bitstream.seek(0)
     # Read beyond EOS
     self.assertRaises(NotEnoughBitsInStreamError, bitstream.get_string, 
                       13*8)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
Ejemplo n.º 52
0
 def test_get_base64_beyond_eos(self):
     """
     Test that trying to read beyond the end of the stream raises an 
     exception when calling get_base64(...).
     """
     bitstream = BitStream()
     
     self.assertRaises(NotEnoughBitsInStreamError, 
                       bitstream.get_base64, 8)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
     
     bitstream.put_base64("Zm9vYmE=") # 40 bits
     bitstream.seek(0)
     # Read beyond EOS
     self.assertRaises(NotEnoughBitsInStreamError, 
                       bitstream.get_base64, 48)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
Ejemplo n.º 53
0
 def test_get_hex_beyond_eos(self):
     """
     Test that trying to read beyond the end of the stream raises an 
     exception when calling get_hex(...).
     """
     bitstream = BitStream()
     
     self.assertRaises(NotEnoughBitsInStreamError, 
                       bitstream.get_hex, 1)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
     
     bitstream.put_hex("DfF7CE69fF5478A") # 15 digits, 60 bits
     bitstream.seek(0)
     # Read beyond EOS
     self.assertRaises(NotEnoughBitsInStreamError, 
                       bitstream.get_hex, 61)
     # Current position should not have been changed
     self.assertEquals(bitstream.get_current_pos(),0)
Ejemplo n.º 54
0
 def test_num_basic(self):
     """
     Test basic put_num and get_num behavior
     """
     bitstream = BitStream()
     
     # Some parameters
     num_sizes = [4,8,16,32,64,128,256,2839]
     num_writes = 10
     nums = []
     
     # Add num_writes integers of each size to nums:
     for i in range(0,len(num_sizes)):
         max_val = 2**num_sizes[i] - 1
         nums.append([])
         for j in range(0,num_writes):
             # append a random number between 0 and max_val, inclusive
             nums[i].append(random.randint(0, max_val))
              
     # Write all values in nums to the stream
     for i in range(0,len(num_sizes)):
         for j in range(0,num_writes):
             bitstream.put_num(nums[i][j], num_sizes[i])
             
     # Go back to start of the stream
     bitstream.seek(0)
     
     # Sanity check:
     expected_length = 0
     for num_size in num_sizes: expected_length += num_size * num_writes
     self.assertEqual(bitstream.get_length(), expected_length)
             
     # Read them back and compare
     for i in range(0,len(num_sizes)):
         for j in range(0,num_writes):
             n = bitstream.get_num(num_sizes[i])
             self.assertEqual(n, nums[i][j])
Ejemplo n.º 55
0
 def test_bit_dump_string_basic(self):
     """
     This method tests put_bit_dump_string's and get_bit_dump_string's 
     basic functionality.
     """
     bitstream = BitStream()
     
     # Generate a random string of bits, ie: ('0' | '1')*
     num_bits = 50        
     bits = ""
     for i in range(0,num_bits):
         bits += random.choice(('0','1')) # inefficient, but ok for a test.
         
     # Put those bits in the BitStream...
     bitstream.put_bit_dump_string(bits)
     
     # ...and get them back
     bitstream.seek(0)
     read_bits = bitstream.get_bit_dump_string(len(bits))
     
     # Check that the bits were recovered correctly
     self.assertEqual(read_bits, bits)
Ejemplo n.º 56
0
 def test_hex_basic(self):
     """
     This method tests put_hex's and get_hex's basic functionality.
     """
     bitstream = BitStream()
     
     # Generate a random string of hex digits, ie: ('0'-'9'|'a'-'f'|'A'-'F')*
     valid_hex_digits = "0123456789abcdefABCDEF"
     num_digits = 50        
     digits = ""
     for i in range(0,num_digits):
         digits += random.choice(valid_hex_digits)
         
     # Put those digits in the BitStream...
     bitstream.put_hex(digits)
     
     # ...and get them back
     bitstream.seek(0)
     read_digits = bitstream.get_hex(len(digits)*4) # 1 hex digit == 4 bits
     
     # Check that the hexadecimal digits were recovered correctly
     # Note that case information may be lost. Comparison must be case 
     # insensitive (ie. 'a9Bc' and 'A9bC' are equal)
     self.assertEqual(read_digits.lower(), digits.lower())
Ejemplo n.º 57
0
 def encrypt_bitstream(self, bitstream, pad_to=None, task_monitor=None):
     """
     Encrypts the given bitstream into a ciphertext object.
     
     Arguments:
         bitstream::BitStream-- A stream of bits to encrypt 
                                (see BitStream utility class).
         pad_to::int            -- Minimum size (in bytes) of the resulting 
                                ciphertext. Data will be padded before 
                                encryption to match this size.
         task_monitor::TaskMonitor    -- A task monitor for this task.
     
     Returns:
         ciphertext:Ciphertext    -- A ciphertext object encapsulating the 
                                    encrypted data.        
     """
     random = StrongRandom()
     
     ## PART 1
     # First, format the bitstream as per Ciphertext.py Note 001,
     # previous to encryption.
     #     [size (64 bits) | message (size bits) | padding (X bits) ]
     ##
     formated_bitstream = BitStream()
     
     # The first 64 encode the size of the actual data in bits
     SIZE_BLOCK_LENGTH = 64
     size_in_bits = bitstream.get_length()
     
     if(size_in_bits >= 2**SIZE_BLOCK_LENGTH):
         raise ValueError("The size of the bitstream to encrypt is larger " \
                          "than 16 Exabits. The current format for  " \
                          "PloneVote ciphertext only allows encrypting a  " \
                          "maximum of 16 Exabits of information.")
     
     formated_bitstream.put_num(size_in_bits, SIZE_BLOCK_LENGTH)
     
     # We then copy the contents of the original bitstream
     bitstream.seek(0)
     formated_bitstream.put_bitstream_copy(bitstream)
     
     # Finally, we append random data until we reach the desired pad_to 
     # length
     unpadded_length = formated_bitstream.get_length()
     if(pad_to != None and (pad_to * 8) > unpadded_length):
         full_length = pad_to * 8
     else:
         full_length = unpadded_length
     
     padding_left = full_length - unpadded_length
     
     while(padding_left > 1024):
         padding_bits = random.randint(1, 2**1024)
         formated_bitstream.put_num(padding_bits,1024)
         padding_left -= 1024
     
     if(padding_left > 0):
         padding_bits = random.randint(1, 2**padding_left)
         formated_bitstream.put_num(padding_bits, padding_left)
         padding_left = 0
     
     ## PART 2
     # We encrypt the formated bitsteam using ElGamal into a Ciphertext 
     # object.
     # See "Handbook of Applied Cryptography" Algorithm 8.18
     ##
     
     # block_size is the size of each block of bits to encrypt
     # since we can only encrypt messages in [0, p - 1]
     # we should use (nbits - 1) as the block size, where 
     # 2**(nbits - 1) < p < 2**nbits
     
     block_size = self.cryptosystem.get_nbits() - 1
     prime = self.cryptosystem.get_prime()
     generator = self.cryptosystem.get_generator()
     
     # We pull data from the bitstream one block at a time and encrypt it
     formated_bitstream.seek(0)
     ciphertext = \
         Ciphertext(self.cryptosystem.get_nbits(), self.get_fingerprint()) 
     
     plaintext_bits_left = formated_bitstream.get_length()
     
     # Check if we have a task monitor and register with it
     if(task_monitor != None):
         # We will do two tick()s per block to encrypt: one for generating 
         # the gamma component of the ciphertext block and another for the 
         # delta component (those are the two time intensive steps, 
         # because of exponentiation). 
         ticks = math.ceil((1.0 * plaintext_bits_left) / block_size) * 2
         encrypt_task_mon = \
             task_monitor.new_subtask("Encrypt data", expected_ticks = ticks)
     
     while(plaintext_bits_left > 0):
     
         # get next block (message, m, etc) to encrypt
         if(plaintext_bits_left >= block_size):
             block = formated_bitstream.get_num(block_size)
             plaintext_bits_left -= block_size
         else:
             block = formated_bitstream.get_num(plaintext_bits_left)
             # Encrypt as if the stream was filled with random data past its 
             # end, this avoids introducing a 0's gap during decryption to 
             # bitstream
             displacement = block_size - plaintext_bits_left
             block = block << displacement
             padding = random.randint(0, 2**displacement - 1)
             assert (padding / 2**displacement == 0), \
                         "padding should be at most displacement bits long"
             block = block | padding
             plaintext_bits_left = 0
         
         # Select a random integer k, 1 <= k <= p − 2
         k = random.randint(1, prime - 2)
         
         # Compute gamma and delta
         gamma = pow(generator, k, prime)
         if(task_monitor != None): encrypt_task_mon.tick()
         
         delta = (block * pow(self._key, k, prime)) % prime
         if(task_monitor != None): encrypt_task_mon.tick()
         
         # Add this encrypted data portion to the ciphertext object
         ciphertext.append(gamma, delta)
     
     # return the ciphertext object
     return ciphertext
Ejemplo n.º 58
0
 def decrypt_to_bitstream(self, ciphertext, task_monitor=None, force=False):
     """
     Decrypts the given ciphertext into a bitstream.
     
     If the bitstream was originally encrypted with PublicKey.encrypt_X(), 
     then this method returns a bitstream following the format described 
     in Note 001 of the Ciphertext.py file:
         [size (64 bits) | message (size bits) | padding (X bits) ]
     
     Arguments:
         ciphertext::Ciphertext    -- An encrypted Ciphertext object.
         task_monitor::TaskMonitor    -- A task monitor for this task.
         force:bool    -- Set this to true if you wish to force a decryption 
                        attempt, even when the ciphertext's stored public key
                        fingerprint does not match that of the public key 
                        associated with this private key.
     
     Returns:
         bitstream::Bitstream    -- A bitstream containing the unencrypted 
                                    data.
     
     Throws:
         IncompatibleCiphertextError -- The given ciphertext does not appear 
                                        to be decryptable with the selected 
                                        private key.
     """
     # Check that the public key fingerprint stored in the ciphertext 
     # matches the public key associated with this private key.
     if(not force):
         if(ciphertext.nbits != self.cryptosystem.get_nbits()):
             raise IncompatibleCiphertextError("The given ciphertext is " \
                     "not decryptable with the selected private key: " \
                     "incompatible cryptosystem/key sizes.")
         
         if(ciphertext.pk_fingerprint != self.public_key.get_fingerprint()):
             raise IncompatibleCiphertextError("The given ciphertext is " \
                     "not decryptable with the selected private key: " \
                     "public key fingerprint mismatch.")
     
     # We read and decrypt the ciphertext block by block
     # See "Handbook of Applied Cryptography" Algorithm 8.18
     bitstream = BitStream()
     
     block_size = self.cryptosystem.get_nbits() - 1
     prime = self.cryptosystem.get_prime()
     key = self._key
     
     # Check if we have a task monitor and register with it
     if(task_monitor != None):
         # One tick per block
         ticks = ciphertext.get_length()
         decrypt_task_mon = \
             task_monitor.new_subtask("Decrypt data", expected_ticks = ticks)
     
     for gamma, delta in ciphertext:
         assert max(gamma, delta) < 2**(block_size + 1), \
             "The ciphertext object includes blocks larger than the " \
             "expected block size."
         m = (pow(gamma, prime - 1 - key, prime) * delta) % prime
         bitstream.put_num(m, block_size)
         
         if(task_monitor != None): decrypt_task_mon.tick()
         
     return bitstream
	def decrypt_to_bitstream(self, task_monitor=None):
		"""
		Decrypt the ciphertext to a bitstream, using the partial decryptions.
		
		At least (threshold) correctly generated partial decryptions for the 
		ciphertext must be registered with this instance in order for 
		decryption to succeed.
		
		Arguments:
			task_monitor::TaskMonitor	-- A task monitor for this task.
		
		Returns:
			bitstream::Bitstream	-- A bitstream containing the unencrypted 
									   data.
									   
		Throws:
			InsuficientPartialDecryptionsError	-- If there aren't enough 
									partial decryptions registered with this 
									object to perform combined decryption.
		"""
		# Get the indexes of all trustees for which we have a registered
		# partial decryption. We use 1 based indexes here.
		trustee_indexes = []
		for trustee in range(1, self._num_trustees + 1):
			decryption = self._trustees_partial_decryptions[trustee - 1]
			if(decryption != None):
				trustee_indexes.append(trustee)
		
		# Check that we have enough trustees.
		if (len(trustee_indexes) < self._threshold):
			raise InsuficientPartialDecryptionsError("Not enough partial " \
					"decryptions have been registered with this object to " \
					"create a combined decryption. Registered partial " \
					"decryptions: %d. Required partial decryptions " \
					"(threshold): %d." \
					% (len(trustee_indexes), self._threshold))
					
		# We only need threshold trustees, exactly. Select those at random.
		random.shuffle(trustee_indexes)
		trustee_indexes = trustee_indexes[0:self._threshold]
		
		# We get the number of bits and prime for the cryptosystem
		nbits = self.cryptosystem.get_nbits()
		prime = self.cryptosystem.get_prime()
		#  prime = 2q + 1 with q prime by construction (see EGCryptoSystem).
		q = (prime - 1) / 2
		
		# See PublicKey.encrypt_bitstream for why we use nbits - 1 as the block 
		# size.
		block_size = self.cryptosystem.get_nbits() - 1
		
		# We initialize our bitstream
		bitstream = BitStream()
		
		# We pre-calculate the lagrange coefficients for the trustees in Z_{q}
		# for x = 0, to avoid doing so for each block of ciphertext.
		# See below for an explanation of the use of lagrange coefficients.
		lagrange_coeffs = [None for i in range(0,self._num_trustees + 1)]
		for trustee in trustee_indexes:
			lagrange_coeffs[trustee] = \
				_lagrange_coefficient(trustee_indexes, trustee, 0, q)
		
		# For each block of partial decryption/(gamma, delta) pair of ciphertext
		for b_index in range(0, self._ciphertext.get_length()):
			
			# Each partial decryption block is of the form g^{rP(i)}, where 
			# (gamma, delta) = (g^r, m*g^{r2P(0)}).
			#
			# We must first interpolate val=g^{r2P(0)} from the g^{rP(i)}'s.
			# Interpolation of val (LaTeX):
			# $g^{r2P(0)}=g^{\sum_{i\in I}r2P(i)\lambda_{i}(0)}=
			# \prod_{i\in I}\left(g^{rP\left(i\right)}\right)^{2\lambda_{i}(0)}$
			# where \lambda_{i}(0) are the Lagrange Coefficients.
			#
			# Note that the polynomials are in the field Z_{q} where q is such 
			# that p = 2*q + 1 and prime. This allows us to use lagrange 
			# interpolation. However, in order for the whole g^{...} values to 
			# be equal mod p, we need to have the exponents be equal mod (p-1) 
			# (rather than mod q), so we multiply by 2. Remember that this 
			# means that 2P(0) is our private key for the threshold encryption 
			# (although it never gets created by any of the parties), and the 
			# reason why g^2P(0) is the threshold public key.
			#
			# See (TODO: Add reference) for the full explanation
			
			gamma, delta = self._ciphertext[b_index]
			val = 1
			for trustee in trustee_indexes:
				p_decryption = self._trustees_partial_decryptions[trustee - 1]
				
				# Get the value (g^{rP(i)}) of the partial decryption block.
				#  Remember that each PartialDecryptionBlock is an object 
				#  containing both the value of the block and its proof of 
				#  partial decryption
				pd_block = p_decryption[b_index].value
				
				# We get \lambda_{i}(0) in the field Z_{q} for the trustees
				l_coeff = lagrange_coeffs[trustee]
				
				# We assert that the \lambda_{i}(0) was pre-calculated.
				assert (l_coeff != None), "lagrange coefficients for " \
										  "trustees in trustee_indexes " \
										  "should have been pre-calculated."
				
				# factor: $\left(g^{rP\left(i\right)}\right)^{2\lambda_{i}(0)}$
				factor = pow(pd_block, 2*l_coeff, prime)
				
				val = (val*factor) % prime
			
			# We decrypt a block of message as m = delta/val = delta*(val)^{-1}.
			# (val)^{-1} the inverse of val in Z_{p}
			inv_val = pow(val, prime - 2, prime)
			m = (delta*inv_val) % prime
			
			# ... and add it to the bitstream.
			bitstream.put_num(m, block_size)
		
		# Return the decrypted bitstream
		return bitstream
Ejemplo n.º 60
0
	def generate_commitment(self):
		"""
		Generate a ThresholdEncryptionCommitment towards the threshold scheme.
		
		Returns:
			commitment::ThresholdEncryptionCommitment
		
		Throws:
			ThresholdEncryptionSetUpStateError -- If public keys are not loaded.
		"""
		# 0. Verify that all public keys are available for 1-to-1 encryption.
		for trustee in range(0, self._num_trustees):
			pk = self._trustees_simple_public_keys[trustee]
			if(pk == None):
				raise ThresholdEncryptionSetUpStateError(
					"generate_commitment() must only be called after all the " \
					"trustees' public keys have been registered with this " \
					"ThresholdEncryptionSetUp instance. Missing public key " \
					"for trustee %d." % trustee)
		
		# 1. Construct a new random polynomial of degree (threshold - 1)
		# Note: A polynomial of degree (t - 1) is determined by any t 
		# (distinct) points.
		degree = self._threshold - 1
		nbits = self.cryptosystem.get_nbits()
		prime = self.cryptosystem.get_prime()
		generator = self.cryptosystem.get_generator()
		
		#  All calculations inside the polynomial are performed modulus q
		#  where q is such that p = 2*q + 1 (q is prime because of how we 
		#  construct p when generating an EGCryptoSystem).
		#  We do this, because the values of the polynomial coefficients or its 
		#  value at a certain point are always used as the exponent of elements 
		#  in Z_{p}^{*}, and we know:
		#  a = b mod (p - 1) => g^a = g^b mod p
		#  (because g^{a-b} = g^{x(p-1)} = (g^x)^{p-1} = 1 mod p)
		#  We use q and not p - 1, because Z_{q} is a field (because q is 
		#  prime), while the same would not be true for p-1, and we need the 
		#  polynomials to be on a field in order to perform Lagrange 
		#  Interpolation (see ThresholdDecryptionCombinator.decrypt_to_X()). 
		#  This also means that 2*P(0) will be the threshold private key 
		#  (never actually seen directly by the parties), and g^(2*P(0)) 
		#  the threshold public key.
		#  For the full explanation, see: (TODO: Add reference)
		
		q = (prime - 1) / 2
		polynomial = \
			CoefficientsPolynomial.new_random_polynomial(q, degree)
		
		# 2. Generate the public "coefficients" (actually g^coefficient for 
		# each coefficient of the polynomial).
		public_coeficients = []
		for coeff in polynomial.get_coefficients():
			public_coeficients.append(pow(generator, coeff, prime)) 
		
		# 3. Generate the partial private keys for each trustee.
		# The partial private key for trustee j is P_{i}(j+1), with i the   
		# trustee generating the commitment, its full private key is the sum 
		# of the P_{i}(j+1) values generated by all trustees (including its own).
		# We must add 1 to the trustee index, since we want the trustee 
		# indexes in the polynomial to start on 1, while our lists are 0 
		# based.
		# (We must never reveal P(0) as this is the complete private key
		# of the full threshold scheme)
		
		# IMPORTANT: We encrypt each partial private key so that only its 
		# intended recipient may read it.
		enc_partial_priv_keys = []
		for trustee in range(0, self._num_trustees):
			ppriv_key = polynomial(trustee + 1) # P_{i}(j)
			trustee_pk = self._trustees_simple_public_keys[trustee]
			
			# Note that trustee public keys need not use the same cryptosystem 
			# as the threshold encryption. In fact, they might not even have 
			# the same bit length.
			bitstream = BitStream()
			bitstream.put_num(ppriv_key, nbits)
			ciphertext = trustee_pk.encrypt_bitstream(bitstream)
			enc_partial_priv_keys.append(ciphertext)
		
		# 4. Construct a ThresholdEncryptionCommitment object storing this 
		# commitment and return it.
		return ThresholdEncryptionCommitment(self.cryptosystem, 
			self._num_trustees, self._threshold, public_coeficients, 
			enc_partial_priv_keys)