How to change 1 bit from a string python?
<p>I generate a 64 bits random string using <code>os.urandom(8)</code>. Next, I want to randomly change the value of one bit of the string getting the bit to change first <code>x = random.getrandbits(6)</code> and doing the XOR operation for that bit like this <code>rand_string ^= 1 &lt;&lt; x</code> but this last operation gives me the following error: <code>TypeError: unsupported operand type(s) for ^=: 'str' and 'long'</code></p>

<p>It's important to me to generate a random binary string because I want to cipher it <code>cipher.encrypt(rand_string)</code> and only takes plain-text for parameters. I don't use <code>random.getrandbits(64)</code> because it returns a long but it doesn't match the 64 bits size block that I want.</p>

<p>Besides, I want to measure the hamming distance between the strings (should give me 1 because I only changed one bit) but I'm afraid that the algorithm I found is not valid to me because it compares the characters representations instead of comparing bit-level:</p>

<pre><code>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))
</code></pre>

<p>So there are two questions:</p>

<p>How could I change randomly a bit of my binary string?</p>

<p>Is the above algorithm valid for my purposes? If it is not, how could I measure the Hamming Distance at bit-level?</p>

<p>I assume there's a typo in your question. As Jonas Wielicki says, <code>os.random</code> doesn't exist; presumably you meant <code>os.urandom</code>. Yes, it's a Good Idea to use the system's random source for crypto work, but using <code>os.urandom</code> directly isn't so convenient. Fortunately, the <code>random</code> module provides an interface to<code>os.urandom</code>: the <code>SystemRandom</code> class.</p>

<p>Doing bit-twiddling of multi-byte byte objects is possible in Python, although it is somewhat fiddly (especially in Python 2). It's much easier to do this sort of thing with Python integers. You can certainly get 64 random bits using the <code>getrandbits</code> method, although of course it's possible that some of those leading bits are zero bits.</p>

<p>Here's some code that runs on Python 2 or Python 3 that generates a random 64 bit number, flips one of its bits, and then computes the Hamming distance between the original number &amp; the number with the flipped bit (which is of course 1). </p>

<pre><code>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 &lt;&lt; bitnum)
    print('bits1: {:016x}'.format(bits1))

    hamming = bincount(bits0 ^ bits1)
    print('Hamming distance: {}\n'.format(hamming))
</code></pre>

<p><strong>typical output</strong></p>

<pre><code>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
</code></pre>

<p>There are faster ways to compute the number of 1 bits in a Python integer, but <code>bincount</code> is reasonably fast (and faster than a Python implementation of the well-known algorithm by Kernighan); see <a href="http://stackoverflow.com/q/9829578/4014959">fast way of counting non-zero bits in python</a> for other methods.</p>

<p>If you need to convert <code>bits0</code> to a bytes object that's easy in Python 3: just use the <code>.to_bytes</code> method, eg</p>

<pre><code>bytes0 = bits0.to_bytes(8, 'big')    
</code></pre>

<p>If you need to use Python 2, converting an integer to a string and converting a string to an integer takes a little more work. Here's a demo, using a modified version of the above code.</p>

<pre><code>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 &amp; 0xff))
        n &gt;&gt;= 8
    return ''.join(result[::-1])

def bytes_to_int(bs):
    n = 0
    for b in bs:
        n = (n &lt;&lt; 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))
</code></pre>

<p><strong>typical output</strong></p>

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

bits0: c2c77e02969d3ebc
bytes: '\xc2\xc7~\x02\x96\x9d&gt;\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
</code></pre>

python python-2.7 random bit-manipulation