# Sage Sandbox

Back to SAGE & cryptology

## Helper functions

Conversion from int or long to raw string and back is discussed on the Python bug tracking list but since the problem is not yet solved, let's see how to make our own helper functions in a clean and fast way: (measures with %timeit of ipython)

```###############################  long2string  ########################################
def long2string(i):
l=[]
while i:
l[0:0]=chr(i&0xff)
i>>=8
return ''.join(l)
long2string(123456789012345678901234)
#46 µs per loop
long2string(1234567890123456789012345)
#51.8 µs per loop
###################################################################################
def long2string(i):
l=[]
while i:
l.append(chr(i&0xff))
i>>=8
return ''.join(l[::-1])
long2string(123456789012345678901234)
#15.1 µs per loop
long2string(1234567890123456789012345)
#16.4 µs per loop
###################################################################################
def long2string(i):
return ''.join([chr(i>>j & 0xFF) for j in range(int(math.log(i,2)//8)<<3,-1,-8)])
long2string(123456789012345678901234)
#15.5 µs per loop
long2string(1234567890123456789012345)
#16.7 µs per loop
###################################################################################
import math
def long2string(i):
return ('%0*x' % (int(math.ceil(math.log(i,2)/8)*2) , i)).decode('hex')
long2string(123456789012345678901234)
#4.77 µs per loop
long2string(1234567890123456789012345)
#4.83 µs per loop
###################################################################################
def long2string(i):
return ('%0*x' % (len(hex(i)) & -2 , i)).decode('hex').lstrip('\x00')
long2string(123456789012345678901234)
#3.64 µs per loop
long2string(1234567890123456789012345)
#3.78 µs per loop
###################################################################################
('%0*x' % (2 * 16 , 123456789012345678901234)).decode('hex')
#2.06 µs per loop
('%0*x' % (2 * 16 , 1234567890123456789012345)).decode('hex')
#2.01 µs per loop
#Ok if you want fixed length buffer, e.g. 16 bytes
###################################################################################
def long2string(i):
s=hex(i)[2:].rstrip('L')
if len(s) % 2:
s='0'+s
return s.decode('hex')
long2string(123456789012345678901234)
#2.88 µs per loop
long2string(1234567890123456789012345)
#3.22 µs per loop
###################################################################################
def long2string(i):
s='0'+hex(long(i))[2:-1]
return s[len(s) % 2:].decode('hex')
long2string(123456789012345678901234)
#3.04 µs per loop
long2string(1234567890123456789012345)
#3.03 µs per loop
###################################################################################
def long2string(i):
s=hex(long(i))[2:-1]
if len(s) % 2:
s='0'+s
return s.decode('hex')
long2string(123456789012345678901234)
#2.75 µs per loop
long2string(1234567890123456789012345)
#3.06 µs per loop
###################################################################################
#If we are sure our argument is a long we can remove the cast in the 2 previous codes:
def long2string(i):
s='0'+hex(i)[2:-1]
return s[len(s) % 2:].decode('hex')
long2string(123456789012345678901234)
#2.66 µs per loop
long2string(1234567890123456789012345)
#2.62 µs per loop
###################################################################################
def long2string(i):
s=hex(i)[2:-1]
if len(s) % 2:
s='0'+s
return s.decode('hex')
long2string(123456789012345678901234)
#2.42 µs per loop
long2string(1234567890123456789012345)
#2.76 µs per loop
###################################################################################
# There is still room ;-)
'1a249b1f10a06c96aff2'.decode('hex')
#990 ns per loop
###################################################################################
###############################  string2long  ########################################
def string2long(s):
i=0
for c in s:
i=(i<<8)+ord(c)
return i
string2long('\x01\x05n\x0f6\xa6D=\xe2\xdfy')
#8.91 µs per loop
###################################################################################
int('\x01\x05n\x0f6\xa6D=\xe2\xdfy'.encode('hex'),16)
#1.64 µs per loop
###################################################################################
long('\x01\x05n\x0f6\xa6D=\xe2\xdfy'.encode('hex'),16)
#1.38 µs per loop
```

## Learning Python

Some code to make some padding functions available. The code is used as a way to learn python, so it contains things that don't make sense or could be done better.

{{#fileanchor: helper.py}}

```from __future__ import division #http://www.python.org/dev/peps/pep-0238/
import math

def roundUp (n, p):
"""Round an integer up to the nearest multiple

A given integer n will be round up to the nearest multiple of p

Example:
>>> roundUp(13,8)
16
"""
return int(math.ceil(n/p)*p)
#return (n+p)/p*p
```

```import random

import sys
from optparse import OptionParser

try:
import helper
except ImportError:
print 'ERROR: helper.py should be placed in the same location as padding.py'
raise ImportError

class BlockOperator:
"""Class for BlockOperator

Only holds a variable blocksize. Class only exist for testing purpose.
"""

def __init__(self, bs=8):
self.blockSize = bs

Inherits from the BlockOperator class

Example:

After changing the source:
"""

#private function has to be accessed by it's public name when using getattr...

#there is no switch statement in python
#discussion with alternatives: http://simonwillison.net/2004/May/7/switch/
elif algo == 'PKCS7':
elif algo == 'ANSI_X923':
elif algo == 'ISO_10126':
raise NotImplementedError()

else:

Input:
self.blockSize: the padded result will be a multiple of the self.blockSize(default=8)
Output:
return a binary string
"""

patternstring = chr(pattern)

length = ord(pattern)
#check if the bytes to be removed are all the same pattern
else:
print 'error: padding pattern not recognized'

#check if the bytes to be removed are all zero
if padded.count('\x00',-length,-1) == length - 1:
else:

pattern1 = ''.join(chr(random.randrange(256)) for x in range(bytesToPad-1))

def main():
usage = "usage: %prog [options] [texttopad]"
parser = OptionParser(usage=usage)
parser.add_option("-b", "--blocksize", dest='blocksize', default=8, help="specify the bloksize", type='int')
(options, args) = parser.parse_args()

if len(args) > 1:
parser.error("Program takes maximum 1 argument")

try:
testbench(args[0].decode('string_escape'),options.blocksize)
except IndexError:
testbench(blocksize=options.blocksize)

for test in testbench: