def bmix(self, source, target): """ block mixing function used by smix() uses salsa20/8 core to mix block contents. :arg source: source to read from. should be list of 32*r 4-byte integers (2*r salsa20 blocks). :arg target: target to write to. should be list with same size as source. the existing value of this buffer is ignored. .. warning:: this operates *in place* on target, so source & target should NOT be same list. .. note:: * time cost is ``O(r)`` -- loops 16*r times, salsa20() has ``O(1)`` cost. * memory cost is ``O(1)`` -- salsa20() uses 16 x uint4, all other operations done in-place. """ ## assert source is not target # Y[-1] = B[2r-1], Y[i] = hash( Y[i-1] xor B[i]) # B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ half = self.bmix_half_len # 16*r out of 32*r - start of Y_1 tmp = source[-16:] # 'X' in scrypt source siter = iter(source) j = 0 while j < half: jn = j + 16 target[j:jn] = tmp = salsa20(a ^ b for a, b in izip(tmp, siter)) target[half + j:half + jn] = tmp = salsa20( a ^ b for a, b in izip(tmp, siter)) j = jn
def _bmix_1(self, source, target): """special bmix() method optimized for ``r=1`` case""" B = source[16:] target[:16] = tmp = salsa20(a ^ b for a, b in izip(B, iter(source))) target[16:] = salsa20(a ^ b for a, b in izip(tmp, B))