如何从字符串python中更改1位?

时间:2016-10-16 14:18:18

标签: python python-2.7 random bit-manipulation

我使用os.urandom(8)生成64位随机字符串。接下来,我想随机更改字符串的一位的值,使该位更改为x = random.getrandbits(6)并对该位执行XOR操作,如此rand_string ^= 1 << x,但最后一次操作会给出以下错误:TypeError: unsupported operand type(s) for ^=: 'str' and 'long'

生成随机二进制字符串对我来说很重要,因为我想要对它进行加密cipher.encrypt(rand_string)并且只接受参数的纯文本。我没有使用random.getrandbits(64),因为它返回了一个长的,但它与我想要的64位大小的块不匹配。

此外,我想测量字符串之间的汉明距离(应该给我1,因为我只改变了一位)但我担心我发现的算法对我无效,因为它比较字符表示而不是比较位级:

def hamming_distance(s1, s2):
    # Return the Hamming distance between equal-length sequences
    if len(s1) != len(s2):
        raise ValueError("Undefined for sequences of unequal length")
    return sum(ch1 != ch2 for ch1, ch2 in zip(s1, s2))

所以有两个问题:

我怎么能随机改变我的二进制字符串?

上述算法对我的目的有效吗?如果不是,我怎么能在比特级测量汉明距离?

2 个答案:

答案 0 :(得分:3)

我认为你的问题中存在拼写错误。正如Jonas Wielicki所说,null并不存在;大概你的意思是os.random。是的,使用系统的随机源进行加密工作是一个好主意,但直接使用os.urandom并不方便。幸运的是,os.urandom模块提供了random的接口:os.urandom类。

在Python中可以对多字节字节对象进行比特操作,尽管它有些繁琐(特别是在Python 2中)。使用Python整数来做这类事情要容易得多。您当然可以使用SystemRandom方法获得64个随机位,但当然有些前导位可能是零位。

这里有一些在Python 2或Python 3上运行的代码,它们生成一个随机的64位数字,翻转其中一个位,然后计算原始数字和数字之间的汉明距离。翻转位的数字(当然是1)。

getrandbits

典型输出

import random

# SystemRandom uses os.urandom() 
sysrandom = random.SystemRandom()

def bincount(n):
    return bin(n).count("1")

for _ in range(5):
    bits0 = sysrandom.getrandbits(64)
    print('bits0: {:016x}'.format(bits0))

    bitnum = sysrandom.randint(0, 64)
    print('bitnum: {}'.format(bitnum))

    bits1 = bits0 ^ (1 << bitnum)
    print('bits1: {:016x}'.format(bits1))

    hamming = bincount(bits0 ^ bits1)
    print('Hamming distance: {}\n'.format(hamming))

有更快的方法来计算Python整数中1位的数量,但bits0: a508c77693a0e7d7 bitnum: 32 bits1: a508c77793a0e7d7 Hamming distance: 1 bits0: 9608e25db458a350 bitnum: 3 bits1: 9608e25db458a358 Hamming distance: 1 bits0: f485bd53af91e2dc bitnum: 62 bits1: b485bd53af91e2dc Hamming distance: 1 bits0: 18f6749bc260fcd1 bitnum: 17 bits1: 18f6749bc262fcd1 Hamming distance: 1 bits0: 51b35142c99b6814 bitnum: 54 bits1: 51f35142c99b6814 Hamming distance: 1 相当快(并且比Kernighan的众所周知的算法的Python实现更快);有关其他方法,请参阅fast way of counting non-zero bits in python

如果您需要将bincount转换为Python 3中易于使用的字节对象:只需使用bits0方法,例如

.to_bytes

如果您需要使用Python 2,将整数转换为字符串并将字符串转换为整数需要更多的工作。这是一个演示,使用上述代码的修改版本。

bytes0 = bits0.to_bytes(8, 'big')    

典型输出

from __future__ import print_function
import random
from binascii import hexlify

# SystemRandom uses os.urandom() 
sysrandom = random.SystemRandom()

def bincount(n):
    return bin(n).count("1")

def int_to_bytes(n, size):
    result = []
    for _ in range(size):
        result.append(chr(n & 0xff))
        n >>= 8
    return ''.join(result[::-1])

def bytes_to_int(bs):
    n = 0
    for b in bs:
        n = (n << 8) | ord(b)
    return n

for _ in range(4):
    bits0 = sysrandom.getrandbits(64)
    print('bits0: {0:016x}'.format(bits0))

    bs = int_to_bytes(bits0, 8)
    print('bytes:', repr(bs))
    print('hex:  ', hexlify(bs))

    n = bytes_to_int(bs)
    print('int:   {0:016x}, {1}\n'.format(n, n == bits0))

答案 1 :(得分:0)

我没有看到获得随机位而不是变换的重点。 randInt应该做得恰到好处。此外,如果您想更改单个位,请尝试xor一个字符而不是字符串。如果这不起作用...=chr(ord(char)^x)