def b62encode_naive(raw_bytes, base_bytes=base62.ASCII62_BYTES, _padding=True, _zero_byte=ZERO_BYTE): """ Base62 encodes a sequence of raw bytes. Zero-byte sequences are preserved by default. :param raw_bytes: Raw bytes to encode. :param base_bytes: The character set to use. Defaults to ``ASCII62_CHARSET`` that uses natural ASCII order. :param _padding: (Internal) ``True`` (default) to include prefixed zero-byte sequence padding converted to appropriate representation. :returns: Base-62 encoded bytes. """ if not builtins.is_bytes(raw_bytes): raise TypeError("data must be raw bytes: got %r" % type(raw_bytes).__name__) number = integer.bytes_to_uint(raw_bytes) encoded = EMPTY_BYTE while number > 0: encoded = base_bytes[number % 62] + encoded number //= 62 # The following makes more divmod calls but is 2x faster. # number, remainder = divmod(number, 62) # encoded = _charset[remainder] + encoded if _padding: zero_leading = functional.leading(lambda w: w == _zero_byte[0], raw_bytes) encoded = (base_bytes[0] * zero_leading) + encoded return encoded
def test_zero_bytes(self): self.assertEqual(uint_to_bytes(bytes_to_uint(zero_bytes)), one_zero_byte) self.assertEqual(uint_to_bytes(bytes_to_uint_naive(zero_bytes)), one_zero_byte) self.assertEqual(uint_to_bytes(bytes_to_uint_simple(zero_bytes)), one_zero_byte)
def base_encode(raw_bytes, base, base_bytes, base_zero, padding=True): """ Encodes raw bytes given a base. :param raw_bytes: Raw bytes to encode. :param base: Unsigned integer base. :param base_bytes: The ASCII bytes used in the encoded string. "Character set" or "alphabet". :param base_zero: """ if not is_bytes(raw_bytes): raise TypeError("data must be raw bytes: got %r" % type(raw_bytes).__name__) number = bytes_to_uint(raw_bytes) encoded = EMPTY_BYTE while number > 0: number, remainder = divmod(number, base) encoded = base_bytes[remainder] + encoded if padding: zero_leading = bytes_leading(raw_bytes) encoded = encoded.rjust(len(encoded) + zero_leading, base_zero) return encoded
def base_encode(raw_bytes, base, base_bytes, base_zero, padding=True): """ Encodes raw bytes given a base. :param raw_bytes: Raw bytes to encode. :param base: Unsigned integer base. :param base_bytes: The ASCII bytes used in the encoded string. "Character set" or "alphabet". :param base_zero: """ if not builtins.is_bytes(raw_bytes): raise TypeError("data must be raw bytes: got %r" % type(raw_bytes).__name__) number = integer.bytes_to_uint(raw_bytes) encoded = EMPTY_BYTE while number > 0: number, remainder = divmod(number, base) encoded = base_bytes[remainder] + encoded if padding: zero_leading = builtins.bytes_leading(raw_bytes) encoded = encoded.rjust(len(encoded) + zero_leading, base_zero) return encoded
def test_zero_bytes(self): self.assertEqual(integer.uint_to_bytes(integer.bytes_to_uint(ZERO_BYTES)), ONE_ZERO_BYTE) self.assertEqual(integer.uint_to_bytes(_alt_integer.bytes_to_uint_naive(ZERO_BYTES)), ONE_ZERO_BYTE) self.assertEqual(integer.uint_to_bytes(_alt_integer.bytes_to_uint_simple(ZERO_BYTES)), ONE_ZERO_BYTE)
def test_encoding_and_decoding(self): hello_world = b("\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64") encoded_hello_world = base58.b58encode(hello_world) self.assertEqual(encoded_hello_world, _alt_base.b58encode_naive(hello_world)) self.assertEqual(base58.b58decode(encoded_hello_world), hello_world) self.assertEqual(integer.bytes_to_uint(base58.b58decode(b("16Ho7Hs"))), 3471844090) self.assertEqual( base58.b58encode(integer.uint_to_bytes(3471844090, 5)), b("16Ho7Hs")) self.assertEqual(base58.b58encode(RAW_DATA), ENCODED) self.assertEqual(base58.b58decode(ENCODED), RAW_DATA) self.assertEqual(base58.b58decode(ENCODED_WITH_WHITESPACE), RAW_DATA) self.assertEqual(_alt_base.b58decode_naive(ENCODED), RAW_DATA) self.assertEqual(_alt_base.b58decode_naive(ENCODED_WITH_WHITESPACE), RAW_DATA) self.assertEqual(codec.base58_encode(RAW_DATA), ENCODED) self.assertEqual(codec.base58_decode(ENCODED), RAW_DATA) self.assertEqual(codec.base58_decode(ENCODED_WITH_WHITESPACE), RAW_DATA)
def test_codec_equivalence(self): # Padding bytes are not preserved (it is acceptable here). random_bytes = b("\x00\xbcE\x9a\xda]") expected_bytes = b("\xbcE\x9a\xda]") self.assertEqual(uint_to_bytes(bytes_to_uint(random_bytes)), expected_bytes) self.assertEqual(uint_to_bytes(bytes_to_uint_naive(random_bytes)), expected_bytes) self.assertEqual(uint_to_bytes(bytes_to_uint_simple(random_bytes)), expected_bytes)
def test_codec_equivalence(self): # Padding bytes are not preserved (it is acceptable here). random_bytes = b("\x00\xbcE\x9a\xda]") expected_bytes = b("\xbcE\x9a\xda]") self.assertEqual(integer.uint_to_bytes(integer.bytes_to_uint(random_bytes)), expected_bytes) self.assertEqual(integer.uint_to_bytes(_alt_integer.bytes_to_uint_naive(random_bytes)), expected_bytes) self.assertEqual(integer.uint_to_bytes(_alt_integer.bytes_to_uint_simple(random_bytes)), expected_bytes)
def verify(self, digest, signature_bytes): """ Verifies a signature against that computed by signing the provided data. :param digest: The SHA-1 digest of the data. :param signature_bytes: The signature raw byte string. :returns: ``True`` if the signature matches; ``False`` otherwise. """ return self._verify(digest, integer.bytes_to_uint(signature_bytes))
def decimal_encode(raw_bytes): """ Encodes raw bytes into decimal representation. Leading zero bytes are preserved. Encode your Unicode strings to a byte encoding before decimal-encoding them. :param raw_bytes: Bytes. :returns: Decimal-encoded representation. """ padding = DIGIT_ZERO_BYTE * bytes_leading(raw_bytes) int_val = bytes_to_uint(raw_bytes) if int_val: encoded = padding + str(int_val).encode("ascii") else: encoded = padding return encoded
def test_encoding_and_decoding(self): hello_world = b("\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64") encoded_hello_world = base58.b58encode(hello_world) self.assertEqual(encoded_hello_world, _alt_base.b58encode_naive(hello_world)) self.assertEqual(base58.b58decode(encoded_hello_world), hello_world) self.assertEqual(integer.bytes_to_uint(base58.b58decode(b("16Ho7Hs"))), 3471844090) self.assertEqual(base58.b58encode(integer.uint_to_bytes(3471844090, 5)), b("16Ho7Hs")) self.assertEqual(base58.b58encode(RAW_DATA), ENCODED) self.assertEqual(base58.b58decode(ENCODED), RAW_DATA) self.assertEqual(base58.b58decode(ENCODED_WITH_WHITESPACE), RAW_DATA) self.assertEqual(_alt_base.b58decode_naive(ENCODED), RAW_DATA) self.assertEqual(_alt_base.b58decode_naive(ENCODED_WITH_WHITESPACE), RAW_DATA) self.assertEqual(codec.base58_encode(RAW_DATA), ENCODED) self.assertEqual(codec.base58_decode(ENCODED), RAW_DATA) self.assertEqual(codec.base58_decode(ENCODED_WITH_WHITESPACE), RAW_DATA)
def decimal_encode(raw_bytes): """ Encodes raw bytes into decimal representation. Leading zero bytes are preserved. Encode your Unicode strings to a byte encoding before decimal-encoding them. :param raw_bytes: Bytes. :returns: Decimal-encoded representation. """ padding = DIGIT_ZERO_BYTE * builtins.bytes_leading(raw_bytes) int_val = integer.bytes_to_uint(raw_bytes) if int_val: encoded = padding + str(int_val).encode("ascii") else: encoded = padding return encoded
def test_encoding_and_decoding(self): hello_world = b('\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64') encoded_hello_world = b58encode(hello_world) self.assertEqual(encoded_hello_world, b58encode_naive(hello_world)) self.assertEqual(b58decode(encoded_hello_world), hello_world) self.assertEqual(bytes_to_uint(b58decode(b("16Ho7Hs"))), 3471844090) self.assertEqual(b58encode(uint_to_bytes(3471844090, 5)), b("16Ho7Hs")) self.assertEqual(b58encode(raw_data), encoded) self.assertEqual(b58decode(encoded), raw_data) self.assertEqual(b58decode(encoded_with_whitespace), raw_data) self.assertEqual(b58decode_naive(encoded), raw_data) self.assertEqual(b58decode_naive(encoded_with_whitespace), raw_data) self.assertEqual(base58_encode(raw_data), encoded) self.assertEqual(base58_decode(encoded), raw_data) self.assertEqual(base58_decode(encoded_with_whitespace), raw_data)
def generate_random_uint_exactly(n_bits, rand_func=generate_random_bytes): """ Generates a random unsigned long with ``n_bits`` random bits. :param n_bits: Number of random bits. :param rand_func: Random bytes generator function. :returns: Returns an unsigned long integer with ``n_bits`` random bits. The generated unsigned long integer will be between 2**(n_bits-1) and (2**n_bits)-1 both inclusive. """ # Doesn't perform any floating-point operations. value = bytes_to_uint(generate_random_bits(n_bits, rand_func=rand_func)) #assert(value >= 0 and value < (2L ** n_bits)) # Set the high bit to ensure bit length. #value |= 2 ** (n_bits - 1) value |= 1 << (n_bits - 1) #assert(long_bit_length(value) >= n_bits) return value
def test_correctness_against_base_implementation(self): # Slow test. values = [ 1 << 512, 1 << 8192, 1 << 77, ] for value in values: self.assertEqual(integer.uint_to_bytes(value), _alt_integer.uint_to_bytes_naive(value), "Boom %d" % value) self.assertEqual(_alt_integer.uint_to_bytes_array_based(value), _alt_integer.uint_to_bytes_naive(value), "Boom %d" % value) self.assertEqual(integer.uint_to_bytes(value), _alt_integer.uint_to_bytes_naive_array_based(value), "Boom %d" % value) self.assertEqual(_alt_integer.uint_to_bytes_pycrypto(value), _alt_integer.uint_to_bytes_naive(value), "Boom %d" % value) self.assertEqual(integer.bytes_to_uint(integer.uint_to_bytes(value)), value, "Boom %d" % value)
def test_correctness_against_base_implementation(self): # Slow test. values = [ 1 << 512, 1 << 8192, 1 << 77, ] for value in values: self.assertEqual(uint_to_bytes(value), uint_to_bytes_naive(value), "Boom %d" % value) self.assertEqual(uint_to_bytes_array_based(value), uint_to_bytes_naive(value), "Boom %d" % value) self.assertEqual(uint_to_bytes(value), uint_to_bytes_naive_array_based(value), "Boom %d" % value) self.assertEqual(uint_to_bytes_pycrypto(value), uint_to_bytes_naive(value), "Boom %d" % value) self.assertEqual(bytes_to_uint(uint_to_bytes(value)), value, "Boom %d" % value)
def generate_random_uint_exactly(n_bits, rand_func=generate_random_bytes): """ Generates a random unsigned long with ``n_bits`` random bits. :param n_bits: Number of random bits. :param rand_func: Random bytes generator function. :returns: Returns an unsigned long integer with ``n_bits`` random bits. The generated unsigned long integer will be between 2**(n_bits-1) and (2**n_bits)-1 both inclusive. """ # Doesn't perform any floating-point operations. value = integer.bytes_to_uint( generate_random_bits(n_bits, rand_func=rand_func)) #assert(value >= 0 and value < (2L ** n_bits)) # Set the high bit to ensure bit length. #value |= 2 ** (n_bits - 1) value |= 1 << (n_bits - 1) #assert(long_bit_length(value) >= n_bits) return value
def generate_random_uint_atmost(n_bits, rand_func=generate_random_bytes): """ Generates a random unsigned integer with `n_bits` random bits. :param n_bits: Number of random bits to be generated at most. :param rand_func: Random bytes generator function. :returns: Returns an unsigned long integer with at most `n_bits` random bits. The generated unsigned long integer will be between 0 and (2**n_bits)-1 both inclusive. """ if not builtins.is_integer(n_bits): raise TypeError("unsupported operand type: %r" % type(n_bits).__name__) if n_bits <= 0: raise ValueError("number of bits must be greater than 0.") # Doesn't perform any floating-point operations. quotient, remainder = divmod(n_bits, 8) if remainder: quotient += 1 random_bytes = rand_func(quotient) mask = (1 << n_bits) - 1 return mask & integer.bytes_to_uint(random_bytes)
def test_range(self): for _ in range(999): n_bits = 4 value = integer.bytes_to_uint(random.generate_random_bits(n_bits)) self.assertTrue(value >= 0 and value < (1 << n_bits))