Fastest bitwise xor between two multibyte binary data variables

后端 未结 7 1816
耶瑟儿~
耶瑟儿~ 2021-01-02 01:05

What is the fastest way to implementat the following logic:

def xor(data, key):
    l = len(key)

    buff = \"\"
    for i in range(0, len(data)):
        b         


        
相关标签:
7条回答
  • 2021-01-02 01:38

    Here's a version that only uses Python built-in and standard modules which seems very fast -- although I haven't compared it to your numpy version. It uses a couple of optimized conversion functions from the Python Cryptography Toolkit as indicated.

    # Part of the Python Cryptography Toolkit
    # found here:
    # http://www.google.com/codesearch/p?hl=en#Y_gnTlD6ECg/trunk/src/gdata/Crypto/Util/number.py&q=lang:python%20%22def%20long_to_bytes%22&sa=N&cd=1&ct=rc
    
    # Improved conversion functions contributed by Barry Warsaw, after
    # careful benchmarking
    
    import struct
    
    def long_to_bytes(n, blocksize=0):
        """long_to_bytes(n:long, blocksize:int) : string
        Convert a long integer to a byte string.
    
        If optional blocksize is given and greater than zero, pad the front of the
        byte string with binary zeros so that the length is a multiple of
        blocksize.
        """
        # after much testing, this algorithm was deemed to be the fastest
        s = ''
        n = long(n)
        pack = struct.pack
        while n > 0:
            s = pack('>I', n & 0xffffffffL) + s
            n = n >> 32
        # strip off leading zeros
        for i in range(len(s)):
            if s[i] != '\000':
                break
        else:
            # only happens when n == 0
            s = '\000'
            i = 0
        s = s[i:]
        # add back some pad bytes.  this could be done more efficiently w.r.t. the
        # de-padding being done above, but sigh...
        if blocksize > 0 and len(s) % blocksize:
            s = (blocksize - len(s) % blocksize) * '\000' + s
        return s
    
    def bytes_to_long(s):
        """bytes_to_long(string) : long
        Convert a byte string to a long integer.
    
        This is (essentially) the inverse of long_to_bytes().
        """
        acc = 0L
        unpack = struct.unpack
        length = len(s)
        if length % 4:
            extra = (4 - length % 4)
            s = '\000' * extra + s
            length = length + extra
        for i in range(0, length, 4):
            acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
        return acc
    
    
    # original code in SO question
    def xor_orig(data, key):
        l = len(key)
    
        buff = ""
        for i in range(0, len(data)):
            buff += chr(ord(data[i]) ^ ord(key[i % l]))
        return buff
    
    # faster pure python version
    def xor_new(data, key):
        import math
    
        # key multiplication in order to match the data length
        key = (key*int( math.ceil(float(len(data))/float(len(key)))))[:len(data)]
    
        # convert key and data to long integers
        key_as_long = bytes_to_long(key)
        data_as_long = bytes_to_long(data)
    
        # xor the numbers together and convert the result back to a byte string
        return long_to_bytes(data_as_long ^ key_as_long)
    
    if __name__=='__main__':
        import random
        import sha
    
        TEST_DATA_LEN = 100000
    
        data = ''.join(chr(random.randint(0, 255)) for i in xrange(TEST_DATA_LEN))
        key = sha.new(data).digest()
    
        assert xor_new(data, key) == xor_orig(data, key)
        print 'done'
    
    0 讨论(0)
提交回复
热议问题