import sys import math import struct import random sys.path.append('/home/dgoddard/tools/z3/build') from z3 import * # xor_shift_128_plus algorithm def xs128p(state0, state1): s1 = state0 & 0xFFFFFFFFFFFFFFFF s0 = state1 & 0xFFFFFFFFFFFFFFFF s1 ^= (s1 << 23) & 0xFFFFFFFFFFFFFFFF s1 ^= (s1 >> 17) & 0xFFFFFFFFFFFFFFFF s1 ^= s0 & 0xFFFFFFFFFFFFFFFF s1 ^= (s0 >> 26) & 0xFFFFFFFFFFFFFFFF state0 = state1 & 0xFFFFFFFFFFFFFFFF state1 = s1 & 0xFFFFFFFFFFFFFFFF generated = (state0 + state1) & 0xFFFFFFFFFFFFFFFF return state0, state1, generated # Symbolic execution of xs128p def sym_xs128p(slvr, sym_state0, sym_state1, generated, browser): s1 = sym_state0 s0 = sym_state1 s1 ^= (s1 << 23) s1 ^= LShR(s1, 17) s1 ^= s0 s1 ^= LShR(s0, 26) sym_state0 = sym_state1 sym_state1 = s1 calc = (sym_state0 + sym_state1) condition = Bool('c%d' % int(generated * random.random())) if browser == 'chrome': impl = Implies(condition, (calc & 0xFFFFFFFFFFFFF) == int(generated)) elif browser == 'firefox' or browser == 'safari': # Firefox and Safari save an extra bit impl = Implies(condition, (calc & 0x1FFFFFFFFFFFFF) == int(generated)) slvr.add(impl) return sym_state0, sym_state1, [condition] def reverse23(val): bot46 = (val ^ (val << 23)) & 0x3fffffffffff original = (val ^ (bot46 << 23)) & 0xFFFFFFFFFFFFFFFF return original def reverse17(val): top34 = (val ^ (val >> 17)) & 0xFFFFFFFFC0000000 top51 = (val ^ (top34 >> 17)) & 0xFFFFFFFFFFFFE000 original = (val ^ (top51 >> 17)) return original def xs128p_backward(state0, state1): prev_state1 = state0 prev_state0 = state1 ^ (state0 >> 26) prev_state0 = prev_state0 ^ state0 prev_state0 = reverse17(prev_state0) prev_state0 = reverse23(prev_state0) generated = (prev_state0 + prev_state1) & 0xFFFFFFFFFFFFFFFF return prev_state0, prev_state1, generated # Print 'last seen' random number # and winning numbers following that. # This was for debugging. We know that Math.random() # is called in the browser zero times (updated) for each page click # in Chrome and once for each page click in Firefox. # Since we have to click once to enter the numbers # and once for Play, we indicate the winning numbers # with an arrow. def power_ball(generated, browser): # for each random number (skip 4 of 5 that we generated) for idx in xrange(len(generated[4:])): # powerball range is 1 to 69 poss = range(1, 70) # base index 4 to skip gen = generated[4+idx:] # get 'last seen' number g0 = gen[0] gen = gen[1:] # make sure we have enough numbers if len(gen) < 6: break print g0 # generate 5 winning numbers nums = [] for jdx in xrange(5): index = int(gen[jdx] * len(poss)) val = poss[index] poss = poss[:index] + poss[index+1:] nums.append(val) # print indicator if idx == 0 and browser == 'chrome': print '--->', elif idx == 2 and browser == 'firefox': print '--->', else: print ' ', # print winning numbers print sorted(nums), # generate / print power number or w/e it's called double = gen[5] val = int(math.floor(double * 26) + 1) print val # Firefox nextDouble(): # (rand_uint64 & ((1 << 53) - 1)) / (1 << 53) # Chrome nextDouble(): # ((rand_uint64 & ((1 << 52) - 1)) | 0x3FF0000000000000) - 1.0 # Safari weakRandom.get(): # (rand_uint64 & ((1 << 53) - 1) * (1.0 / (1 << 53))) def to_double(browser, out): if browser == 'chrome': double_bits = (out & 0xFFFFFFFFFFFFF) | 0x3FF0000000000000 double = struct.unpack('d', struct.pack('