Advertisement
A_GUES

Python RNG v8

Jun 22nd, 2023 (edited)
313
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.26 KB | None | 0 0
  1. #!/usr/bin/python3
  2. import z3
  3. import struct
  4. import sys
  5.  
  6.  
  7. """
  8. Solving for seed states in XorShift128+ used in V8
  9. > https://v8.dev/blog/math-random
  10. > https://apechkurov.medium.com/v8-deep-dives-random-thoughts-on-math-random-fb155075e9e5
  11. > https://blog.securityevaluators.com/hacking-the-javascript-lottery-80cc437e3b7f
  12.  
  13. > Tested on Chrome(102.0.5005.61) or Nodejs(v18.2.0.)
  14. """
  15.  
  16. """
  17. Plug in a handful random number sequences from node/chrome
  18. > Array.from(Array(5), Math.random)
  19.  
  20. (Optional) In node, we can specify the seed
  21. > node --random_seed=1337
  22. """
  23. sequence = [
  24.   0.9311600617849973,
  25.   0.3551442693830502,
  26.   0.7923158995678377,
  27.   0.787777942408997,
  28.   0.376372264303491,
  29.   # 0.23137147109312428
  30. ]
  31.  
  32. """
  33. Random numbers generated from xorshift128+ is used to fill an internal entropy pool of size 64
  34. > https://github.com/v8/v8/blob/7a4a6cc6a85650ee91344d0dbd2c53a8fa8dce04/src/numbers/math-random.cc#L35
  35.  
  36. Numbers are popped out in LIFO(Last-In First-Out) manner, hence the numbers presented from the entropy pool are reveresed.
  37. """
  38. sequence = sequence[::-1]
  39.  
  40. solver = z3.Solver()
  41.  
  42. """
  43. Create 64 bit states, BitVec (uint64_t)
  44. > static inline void XorShift128(uint64_t* state0, uint64_t* state1);
  45. > https://github.com/v8/v8/blob/a9f802859bc31e57037b7c293ce8008542ca03d8/src/base/utils/random-number-generator.h#L119
  46. """
  47. se_state0, se_state1 = z3.BitVecs("se_state0 se_state1", 64)
  48.  
  49. for i in range(len(sequence)):
  50.     """
  51.    XorShift128+
  52.    > https://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
  53.    > https://github.com/v8/v8/blob/a9f802859bc31e57037b7c293ce8008542ca03d8/src/base/utils/random-number-generator.h#L119
  54.  
  55.    class V8_BASE_EXPORT RandomNumberGenerator final {
  56.        ...
  57.        static inline void XorShift128(uint64_t* state0, uint64_t* state1) {
  58.            uint64_t s1 = *state0;
  59.            uint64_t s0 = *state1;
  60.            *state0 = s0;
  61.            s1 ^= s1 << 23;
  62.            s1 ^= s1 >> 17;
  63.            s1 ^= s0;
  64.            s1 ^= s0 >> 26;
  65.            *state1 = s1;
  66.        }
  67.        ...
  68.    }
  69.    """
  70.     se_s1 = se_state0
  71.     se_s0 = se_state1
  72.     se_state0 = se_s0
  73.     se_s1 ^= se_s1 << 23
  74.     se_s1 ^= z3.LShR(se_s1, 17)  # Logical shift instead of Arthmetric shift
  75.     se_s1 ^= se_s0
  76.     se_s1 ^= z3.LShR(se_s0, 26)
  77.     se_state1 = se_s1
  78.  
  79.     """
  80.    IEEE 754 double-precision binary floating-point format
  81.    > https://en.wikipedia.org/wiki/Double-precision_floating-point_format
  82.    > https://www.youtube.com/watch?v=p8u_k2LIZyo&t=257s
  83.  
  84.    Sign (1)    Exponent (11)    Mantissa (52)
  85.    [#]         [###########]    [####################################################]
  86.    """
  87.  
  88.     """
  89.    Pack as `double` and re-interpret as unsigned `long long` (little endian)
  90.    > https://stackoverflow.com/a/65377273
  91.    """
  92.     float_64 = struct.pack("d", sequence[i] + 1)
  93.     u_long_long_64 = struct.unpack("<Q", float_64)[0]
  94.  
  95.     """
  96.    # visualize sign, exponent & mantissa
  97.    bits = bin(u_long_long_64)[2:]
  98.    bits = '0' * (64-len(bits)) + bits
  99.    print(f'{bits[0]} {bits[1:12]} {bits[12:]}')
  100.    """
  101.  
  102.     # Get the lower 52 bits (mantissa)
  103.     mantissa = u_long_long_64 & ((1 << 52) - 1)
  104.  
  105.     # Compare Mantissas
  106.     solver.add(int(mantissa) == z3.LShR(se_state0, 12))
  107.  
  108.  
  109. if solver.check() == z3.sat:
  110.     model = solver.model()
  111.  
  112.     states = {}
  113.     for state in model.decls():
  114.         states[state.__str__()] = model[state]
  115.  
  116.     print(states)
  117.  
  118.     state0 = states["se_state0"].as_long()
  119.  
  120.     """
  121.    Extract mantissa
  122.    - Add `1.0` (+ 0x3FF0000000000000) to 52 bits
  123.    - Get the double and Subtract `1` to obtain the random number between [0, 1)
  124.  
  125.    > https://github.com/v8/v8/blob/a9f802859bc31e57037b7c293ce8008542ca03d8/src/base/utils/random-number-generator.h#L111
  126.  
  127.    static inline double ToDouble(uint64_t state0) {
  128.        // Exponent for double values for [1.0 .. 2.0)
  129.        static const uint64_t kExponentBits = uint64_t{0x3FF0000000000000};
  130.        uint64_t random = (state0 >> 12) | kExponentBits;
  131.        return base::bit_cast<double>(random) - 1;
  132.    }
  133.    """
  134.     u_long_long_64 = (state0 >> 12) | 0x3FF0000000000000
  135.     float_64 = struct.pack("<Q", u_long_long_64)
  136.     next_sequence = struct.unpack("d", float_64)[0]
  137.     next_sequence -= 1
  138.  
  139.     print(next_sequence)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement