【问题标题】:How to change 1 bit from a string python?如何从字符串 python 中更改 1 位?
【发布时间】:2016-10-16 14:18:18
【问题描述】:

我使用os.urandom(8) 生成一个 64 位随机字符串。接下来,我想随机更改字符串的一个位的值,首先要更改该位x = random.getrandbits(6),然后像rand_string ^= 1 << x 那样对该位进行异或运算,但最后一个操作给了我以下错误:TypeError: unsupported operand type(s) for ^=: 'str' and 'long'

生成一个随机二进制字符串对我来说很重要,因为我想对其进行加密cipher.encrypt(rand_string) 并且只接受纯文本作为参数。我不使用 random.getrandbits(64),因为它返回一个 long 但它与我想要的 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))

所以有两个问题:

如何随机更改一些二进制字符串?

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

【问题讨论】:

  • 首先,这是两个不同的问题。其次,我在 python2 或 python3 上都没有os.random,你似乎有一个错字。三、你是用python2还是python3? (第四,您可以自己测试 hamming_distance 部分;只需创建两个字符串对:一对差异在同一个字符但有两个不同的位,一对差异在两个位中分布在两个字符上;观察输出)
  • @JonasWielicki 是的,有一个错字,我的意思是 os.urandom()。我在 python2 上,实际上我无法测试汉明算法,因为我无法按照我想要的方式修改字符串(更改 1 位)。我知道它适用于列表项或字符串。例如,“abcd”和“abcc”给出的汉明距离为 1,但在二进制中,距离更大,因为 c 和 d 表示有不止一位不同。

标签: python python-2.7 random bit-manipulation


【解决方案1】:

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

在 Python 中可以对多字节字节对象进行位旋转,尽管它有些繁琐(尤其是在 Python 2 中)。用 Python 整数做这种事情要容易得多。您当然可以使用getrandbits 方法获得 64 个随机位,当然其中一些前导位可能是零位。

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

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))

典型输出

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

有更快的方法来计算 Python 整数中 1 的位数,但 bincount 相当快(并且比 Kernighan 的著名算法的 Python 实现更快);其他方法见fast way of counting non-zero bits in python

如果您需要将bits0 转换为在Python 3 中很容易的字节对象:只需使用.to_bytes 方法,例如

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

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

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))

典型输出

bits0: 69831968a1b0aff8
bytes: 'i\x83\x19h\xa1\xb0\xaf\xf8'
hex:   69831968a1b0aff8
int:   69831968a1b0aff8, True

bits0: c2c77e02969d3ebc
bytes: '\xc2\xc7~\x02\x96\x9d>\xbc'
hex:   c2c77e02969d3ebc
int:   c2c77e02969d3ebc, True

bits0: e87c78eb3929a76f
bytes: '\xe8|x\xeb9)\xa7o'
hex:   e87c78eb3929a76f
int:   e87c78eb3929a76f, True

bits0: 0d5d796c986ba329
bytes: '\r]yl\x98k\xa3)'
hex:   0d5d796c986ba329
int:   0d5d796c986ba329, True

【讨论】:

  • 感谢您的回答,绝对对我有很大帮助,但我仍然遇到加密函数调用的问题,因为它需要纯文本参数(问题已解决,因为虽然 to_bytes() 没有在 python2.7 上工作我发现了一个类似的函数 -link) 并返回一个字符串,我应该将其转换为字节字符串以便进行 XOR 但bytes1 = to_bytes(encryptedString, 8, 'big') 给了我以下错误TypeError: %x format: a number is required, not str
  • @arkan_18 我已经在我的答案中添加了一些 Python 2 代码来进行 int-> bytes 和 bytes->int 转换。
  • @PM_2Ring 谢谢!最后一个问题......如果这条线给了我错误,那将意味着什么? n == bits0
  • @arkan_18 n == bits0 应该永远为假。我只是把它放在那里以便更容易看到bytes_to_int 给出了正确的结果。
【解决方案2】:

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

【讨论】:

  • 嗯,在密码学领域是有道理的
猜你喜欢
  • 1970-01-01
  • 2014-10-07
  • 1970-01-01
  • 2021-12-05
  • 1970-01-01
  • 2015-07-18
  • 2019-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多