diff options
author | Yesudeep Mangalapilly <yesudeep@gmail.com> | 2011-08-11 12:03:37 +0530 |
---|---|---|
committer | Yesudeep Mangalapilly <yesudeep@gmail.com> | 2011-08-11 12:03:37 +0530 |
commit | a4453c6f8b1f919794e7f3213292d03416eb6d91 (patch) | |
tree | 49e3c5294d511520ca12ef8a5b9df29dd6d2a8ca | |
parent | c19a21bac0fef5691143959d799e5490537fe312 (diff) | |
download | rsa-git-a4453c6f8b1f919794e7f3213292d03416eb6d91.tar.gz |
Adds speed tests for int2bytes and old_int2bytes.
* In the following tests, the first speed test for
each version of Python checked is the new
implementation and the second is the old
implementation.
$ ./speed.sh
int2bytes speed test
python2.5
1000 loops, best of 3: 315 usec per loop
100 loops, best of 3: 4.87 msec per loop
python2.6
10000 loops, best of 3: 170 usec per loop
100 loops, best of 3: 3.34 msec per loop
python2.7
10000 loops, best of 3: 169 usec per loop
100 loops, best of 3: 2.8 msec per loop
python3.2
10000 loops, best of 3: 169 usec per loop
100 loops, best of 3: 3.16 msec per loop
-rw-r--r-- | rsa/transform.py | 71 | ||||
-rwxr-xr-x | speed.sh | 15 | ||||
-rw-r--r-- | tests/test_transform.py | 10 |
3 files changed, 89 insertions, 7 deletions
diff --git a/rsa/transform.py b/rsa/transform.py index 6503cf1..8d3a461 100644 --- a/rsa/transform.py +++ b/rsa/transform.py @@ -21,9 +21,11 @@ From bytes to a number, number to bytes, etc. from __future__ import absolute_import +import types import binascii from struct import pack -from rsa._compat import is_integer, b +from rsa import common +from rsa._compat import is_integer, b, byte ZERO_BYTE = b('\x00') @@ -43,7 +45,7 @@ def bytes2int(raw_bytes): return int(binascii.hexlify(raw_bytes), 16) -def int2bytes(number, block_size=None): +def old_int2bytes(number, block_size=0): r'''Converts a number to a string of bytes. @param number: the number to convert @@ -55,6 +57,65 @@ def int2bytes(number, block_size=None): bytes than fit into the block. + >>> old_int2bytes(123456789) + b'\x07[\xcd\x15' + >>> bytes2int(int2bytes(123456789)) + 123456789 + + >>> old_int2bytes(123456789, 6) + b'\x00\x00\x07[\xcd\x15' + >>> bytes2int(int2bytes(123456789, 128)) + 123456789 + + >>> old_int2bytes(123456789, 3) + Traceback (most recent call last): + ... + OverflowError: Needed 4 bytes for number, but block size is 3 + + ''' + + # Type checking + if not is_integer(number): + raise TypeError("You must pass an integer for 'number', not %s" % + number.__class__) + + if number < 0: + raise ValueError('Negative numbers cannot be used: %i' % number) + + # Do some bounds checking + needed_bytes = common.byte_size(number) + if block_size > 0: + if needed_bytes > block_size: + raise OverflowError('Needed %i bytes for number, but block size ' + 'is %i' % (needed_bytes, block_size)) + + # Convert the number to bytes. + raw_bytes = [] + while number > 0: + raw_bytes.insert(0, byte(number & 0xFF)) + number >>= 8 + + # Pad with zeroes to fill the block + if block_size > 0: + padding = (block_size - needed_bytes) * ZERO_BYTE + else: + padding = b('') + + return padding + b('').join(raw_bytes) + + +def int2bytes(number, block_size=None): + """Converts a number to a string of bytes. + + @param number: the number to convert + @param block_size: the number of bytes to output. If the number encoded to + bytes is less than this, the block will be zero-padded. When not given, + the returned block is not padded. + + @throws OverflowError when block_size is given and the number takes up more + bytes than fit into the block. + + >>> int2bytes(123456789) '\x07[\xcd\x15' >>> bytes2int(int2bytes(123456789)) @@ -69,9 +130,7 @@ def int2bytes(number, block_size=None): Traceback (most recent call last): ... OverflowError: Need 4 bytes for number, but block size is 3 - - ''' - + """ # Type checking if not is_integer(number): raise TypeError("You must pass an integer for 'number', not %s" % @@ -95,7 +154,7 @@ def int2bytes(number, block_size=None): if x != ZERO_BYTE[0]: break - if block_size > 0: + if block_size is not None and block_size > 0: # Bounds checking. We're not doing this up-front because the # most common use case is not specifying a chunk size. In the worst # case, the number will already have been converted to bytes above. diff --git a/speed.sh b/speed.sh new file mode 100755 index 0000000..17f1ea4 --- /dev/null +++ b/speed.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +echo "int2bytes speed test" +echo "python2.5" +python2.5 -mtimeit -s'from rsa.transform import int2bytes; n = 1<<4096' 'int2bytes(n)' +python2.5 -mtimeit -s'from rsa.transform import old_int2bytes; n = 1<<4096' 'old_int2bytes(n)' +echo "python2.6" +python2.6 -mtimeit -s'from rsa.transform import int2bytes; n = 1<<4096' 'int2bytes(n)' +python2.6 -mtimeit -s'from rsa.transform import old_int2bytes; n = 1<<4096' 'old_int2bytes(n)' +echo "python2.7" +python2.7 -mtimeit -s'from rsa.transform import int2bytes; n = 1<<4096' 'int2bytes(n)' +python2.7 -mtimeit -s'from rsa.transform import old_int2bytes; n = 1<<4096' 'old_int2bytes(n)' +echo "python3.2" +python3 -mtimeit -s'from rsa.transform import int2bytes; n = 1<<4096' 'int2bytes(n)' +python3 -mtimeit -s'from rsa.transform import old_int2bytes; n = 1<<4096' 'old_int2bytes(n)' diff --git a/tests/test_transform.py b/tests/test_transform.py index ecc1a30..9bd3c6d 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -3,7 +3,7 @@ import unittest2 from rsa._compat import b -from rsa.transform import int2bytes +from rsa.transform import int2bytes, old_int2bytes class Test_integer_to_bytes(unittest2.TestCase): @@ -12,13 +12,21 @@ class Test_integer_to_bytes(unittest2.TestCase): b('\x00\x00\x07[\xcd\x15')) self.assertEqual(int2bytes(123456789, 7), b('\x00\x00\x00\x07[\xcd\x15')) + self.assertEqual(old_int2bytes(123456789, 6), + b('\x00\x00\x07[\xcd\x15')) + self.assertEqual(old_int2bytes(123456789, 7), + b('\x00\x00\x00\x07[\xcd\x15')) def test_raises_OverflowError_when_chunk_size_is_insufficient(self): self.assertRaises(OverflowError, int2bytes, 123456789, 3) self.assertRaises(OverflowError, int2bytes, 299999999999, 4) + self.assertRaises(OverflowError, old_int2bytes, 123456789, 3) + self.assertRaises(OverflowError, old_int2bytes, 299999999999, 4) def test_raises_ValueError_when_negative_integer(self): self.assertRaises(ValueError, int2bytes, -1) + self.assertRaises(ValueError, old_int2bytes, -1) def test_raises_TypeError_when_not_integer(self): self.assertRaises(TypeError, int2bytes, None) + self.assertRaises(TypeError, old_int2bytes, None) |