def philox(W, N, ctr, key, Nrounds=None): """ W: word length (32, 64) N: number of generated items, 2 or 4 Nrounds: number of rounds (up to 16) inn: counter, array(N, numpy.uint${W}) --- counter k: key, array(N/2, numpy.uint${W}) --- key returns: array(N, numpy.uint${W}) """ assert W in (32, 64) assert N in (2, 4) if Nrounds is None: Nrounds = 10 assert Nrounds <= 16 with ignore_integer_overflow(): for rnd in range(Nrounds): ctr = philox_round(W, N, rnd, ctr, key) return ctr
def threefry(W, N, ctr, key, Nrounds=None): """ W: word length (32, 64) N: number of generated items, 2 or 4 Nrounds: number of rounds (up to 72) ctr: counter, array(N, numpy.uint${W}) key: key, array(N, numpy.uint${W}) returns: array(N, numpy.uint${W}) Note: for W=64, N=4 and Nrounds=72 it is the same as Threefish algorithm from Skein, only without the 128-bit "tweak" which is applied to the key. With this tweak it is possible to upgrade this algorithm from PRNG to QRNG. """ assert W in (32, 64) assert N in (2, 4) if Nrounds is None: Nrounds = 20 dtype = numpy.uint32 if W == 32 else numpy.uint64 if N == 2: assert Nrounds <= 32 ks = numpy.empty(3, dtype) else: assert Nrounds <= 72 ks = numpy.empty(5, dtype) X = numpy.empty(N, dtype) assert ctr.size == key.size == N ks[N] = THREEFRY_KS_PARITY[W] for i in range(N): ks[i] = key[i] X[i] = ctr[i] ks[N] ^= key[i] # Insert initial key before round 0 for i in range(N): X[i] += ks[i] R = THREEFRY_ROTATION[(W, N)] with ignore_integer_overflow(): for rnd in range(Nrounds): # FIXME: In the current version of Random123 (1.06), # there is a bug in R_idx calculation for N == 2, where # R_idx = rnd % 8 if rnd < 20 else (rnd - 4) % 8 # instead of what goes below. # When this bug is fixed, Random123 and this implementation # will start to produce identical results again, # and this comment can be removed. R_idx = rnd % 8 if N == 2: X[0] += X[1] X[1] = threefry_rotate(W, R[R_idx, 0], X[1]) X[1] ^= X[0] else: idx1 = 1 if rnd % 2 == 0 else 3 idx2 = 3 if rnd % 2 == 0 else 1 X[0] += X[idx1] X[idx1] = threefry_rotate(W, R[R_idx, 0], X[idx1]) X[idx1] ^= X[0] X[2] += X[idx2] X[idx2] = threefry_rotate(W, R[R_idx, 1], X[idx2]) X[idx2] ^= X[2] if rnd % 4 == 3: for i in range(N): X[i] += ks[(rnd // 4 + i + 1) % (N + 1)] X[N-1] += dtype(rnd // 4 + 1) return X