A858DE45F56D9BC9 archive

The 32-bit word posts

Six 2011 posts are lists of 32-bit words. Every word is four Next(lo, hi) calls on one seeded System.Random, one call per byte.

Six of A858's 2011 posts are not GUID lists but lists of 8-hex-digit groups: 32-bit words, separated by spaces. The community called them the "32 bit group" posts. Here is the start of iirqk (201107062222):

DC52CB11 DE23AC5B DA0FA919 DE9FED2F DC8C9914 DA54A930 DEB5A026 DD7AB754 ...

Finding: the words are generated, not encrypted, and carry no message. Each word is four consecutive calls to the standard .NET System.Random, one per byte, each with its own fixed range:

byte b0 = (byte)random.Next(0xDA, 0xDF);   // 0xDA..0xDE
byte b1 = (byte)random.Next(0x0F, 0xB8);   // 0x0F..0xB7
byte b2 = (byte)random.Next(0x96, 0xFE);   // 0x96..0xFD
byte b3 = (byte)random.Next(0x0A, 0x79);   // 0x0A..0x78

The Random is seeded with a number from 0 to 999, the current millisecond, exactly like the mask digit of the GUID lists. Given the seed, every word of every one of the six posts comes out exactly: 620 words, 2,480 bytes, no exceptions.

PostTitlePostedBodyWordsGeneratorCalls before word 1Reproduced
ihwxg2011070600002011-07-06unencrypted256new Random(393)2,398✓ every word
iiafz2011070511002011-07-06unencrypted50new Random(699)4✓ every word
iirqk2011070622222011-07-07unencrypted60new Random(107)2✓ every word
jqt3x2011082211162011-08-22unencrypted180new Random(102)6✓ every word
mymne2011120302492011-12-03decrypted42new Random(798)1✓ every word
n1ley2011120519412011-12-05unencrypted32new Random(591)1✓ every word

The site's build regenerates each list from its seed every time it runs; the table above is that result, not a copy of the notebook's. "Calls before word 1" is the number of Random calls that were made, and thrown away, before the first posted word (see below).

The byte ranges

The first thing that stands out in these posts is that every word starts with DA, DB, DC, DD or DE. The other three bytes are restricted too, less visibly. Plotting every byte of every word by position shows four hard-edged bands:

0x000x200x400x600x800xA00xC00xE00xFFbyte 0: Next(0xDA, 0xDF) gives 0xDA–0xDE; observed 0xDA–0xDE over 620 wordsbyte 0byte 0 = 0xDA: 131 wordsbyte 0 = 0xDB: 133 wordsbyte 0 = 0xDC: 109 wordsbyte 0 = 0xDD: 131 wordsbyte 0 = 0xDE: 116 wordsbyte 1: Next(0x0F, 0xB8) gives 0x0F–0xB7; observed 0x0F–0xB7 over 620 wordsbyte 1byte 1 = 0x0F: 8 wordsbyte 1 = 0x10: 4 wordsbyte 1 = 0x11: 4 wordsbyte 1 = 0x12: 6 wordsbyte 1 = 0x13: 6 wordsbyte 1 = 0x14: 2 wordsbyte 1 = 0x15: 3 wordsbyte 1 = 0x16: 4 wordsbyte 1 = 0x17: 2 wordsbyte 1 = 0x18: 6 wordsbyte 1 = 0x19: 3 wordsbyte 1 = 0x1A: 4 wordsbyte 1 = 0x1B: 4 wordsbyte 1 = 0x1C: 5 wordsbyte 1 = 0x1D: 2 wordsbyte 1 = 0x1E: 3 wordsbyte 1 = 0x1F: 2 wordsbyte 1 = 0x20: 5 wordsbyte 1 = 0x21: 4 wordsbyte 1 = 0x22: 2 wordsbyte 1 = 0x23: 6 wordsbyte 1 = 0x24: 5 wordsbyte 1 = 0x25: 7 wordsbyte 1 = 0x26: 4 wordsbyte 1 = 0x27: 1 wordsbyte 1 = 0x28: 2 wordsbyte 1 = 0x29: 9 wordsbyte 1 = 0x2A: 5 wordsbyte 1 = 0x2B: 8 wordsbyte 1 = 0x2C: 3 wordsbyte 1 = 0x2D: 5 wordsbyte 1 = 0x2E: 10 wordsbyte 1 = 0x2F: 3 wordsbyte 1 = 0x30: 3 wordsbyte 1 = 0x31: 5 wordsbyte 1 = 0x32: 2 wordsbyte 1 = 0x33: 3 wordsbyte 1 = 0x34: 2 wordsbyte 1 = 0x35: 5 wordsbyte 1 = 0x36: 7 wordsbyte 1 = 0x37: 2 wordsbyte 1 = 0x38: 3 wordsbyte 1 = 0x39: 3 wordsbyte 1 = 0x3A: 6 wordsbyte 1 = 0x3B: 4 wordsbyte 1 = 0x3C: 3 wordsbyte 1 = 0x3D: 2 wordsbyte 1 = 0x3E: 5 wordsbyte 1 = 0x3F: 7 wordsbyte 1 = 0x40: 2 wordsbyte 1 = 0x41: 1 wordsbyte 1 = 0x42: 5 wordsbyte 1 = 0x43: 5 wordsbyte 1 = 0x44: 4 wordsbyte 1 = 0x45: 3 wordsbyte 1 = 0x46: 3 wordsbyte 1 = 0x47: 3 wordsbyte 1 = 0x48: 5 wordsbyte 1 = 0x49: 4 wordsbyte 1 = 0x4A: 2 wordsbyte 1 = 0x4B: 5 wordsbyte 1 = 0x4C: 6 wordsbyte 1 = 0x4D: 5 wordsbyte 1 = 0x4E: 6 wordsbyte 1 = 0x4F: 6 wordsbyte 1 = 0x50: 3 wordsbyte 1 = 0x51: 6 wordsbyte 1 = 0x52: 4 wordsbyte 1 = 0x53: 5 wordsbyte 1 = 0x54: 5 wordsbyte 1 = 0x55: 2 wordsbyte 1 = 0x56: 2 wordsbyte 1 = 0x57: 1 wordsbyte 1 = 0x58: 4 wordsbyte 1 = 0x59: 3 wordsbyte 1 = 0x5A: 5 wordsbyte 1 = 0x5B: 2 wordsbyte 1 = 0x5C: 1 wordsbyte 1 = 0x5D: 1 wordsbyte 1 = 0x5E: 2 wordsbyte 1 = 0x5F: 2 wordsbyte 1 = 0x60: 3 wordsbyte 1 = 0x61: 1 wordsbyte 1 = 0x62: 4 wordsbyte 1 = 0x63: 3 wordsbyte 1 = 0x64: 3 wordsbyte 1 = 0x65: 3 wordsbyte 1 = 0x66: 4 wordsbyte 1 = 0x67: 4 wordsbyte 1 = 0x68: 5 wordsbyte 1 = 0x69: 2 wordsbyte 1 = 0x6A: 3 wordsbyte 1 = 0x6B: 7 wordsbyte 1 = 0x6C: 5 wordsbyte 1 = 0x6D: 3 wordsbyte 1 = 0x6E: 3 wordsbyte 1 = 0x6F: 2 wordsbyte 1 = 0x70: 2 wordsbyte 1 = 0x71: 2 wordsbyte 1 = 0x72: 4 wordsbyte 1 = 0x73: 5 wordsbyte 1 = 0x74: 2 wordsbyte 1 = 0x75: 3 wordsbyte 1 = 0x76: 4 wordsbyte 1 = 0x77: 2 wordsbyte 1 = 0x78: 4 wordsbyte 1 = 0x79: 1 wordsbyte 1 = 0x7A: 2 wordsbyte 1 = 0x7B: 5 wordsbyte 1 = 0x7C: 4 wordsbyte 1 = 0x7D: 5 wordsbyte 1 = 0x7E: 2 wordsbyte 1 = 0x7F: 3 wordsbyte 1 = 0x80: 6 wordsbyte 1 = 0x81: 4 wordsbyte 1 = 0x82: 5 wordsbyte 1 = 0x83: 7 wordsbyte 1 = 0x84: 2 wordsbyte 1 = 0x85: 6 wordsbyte 1 = 0x86: 5 wordsbyte 1 = 0x87: 1 wordsbyte 1 = 0x88: 1 wordsbyte 1 = 0x89: 4 wordsbyte 1 = 0x8A: 4 wordsbyte 1 = 0x8B: 6 wordsbyte 1 = 0x8C: 4 wordsbyte 1 = 0x8D: 7 wordsbyte 1 = 0x8E: 1 wordsbyte 1 = 0x8F: 3 wordsbyte 1 = 0x92: 3 wordsbyte 1 = 0x93: 4 wordsbyte 1 = 0x94: 6 wordsbyte 1 = 0x96: 1 wordsbyte 1 = 0x97: 2 wordsbyte 1 = 0x98: 2 wordsbyte 1 = 0x99: 2 wordsbyte 1 = 0x9A: 5 wordsbyte 1 = 0x9B: 8 wordsbyte 1 = 0x9C: 2 wordsbyte 1 = 0x9D: 3 wordsbyte 1 = 0x9E: 2 wordsbyte 1 = 0x9F: 4 wordsbyte 1 = 0xA0: 3 wordsbyte 1 = 0xA2: 4 wordsbyte 1 = 0xA3: 3 wordsbyte 1 = 0xA4: 3 wordsbyte 1 = 0xA5: 3 wordsbyte 1 = 0xA6: 2 wordsbyte 1 = 0xA7: 3 wordsbyte 1 = 0xA8: 3 wordsbyte 1 = 0xA9: 5 wordsbyte 1 = 0xAA: 4 wordsbyte 1 = 0xAB: 4 wordsbyte 1 = 0xAC: 5 wordsbyte 1 = 0xAD: 3 wordsbyte 1 = 0xAE: 3 wordsbyte 1 = 0xAF: 4 wordsbyte 1 = 0xB0: 2 wordsbyte 1 = 0xB1: 3 wordsbyte 1 = 0xB2: 1 wordsbyte 1 = 0xB3: 3 wordsbyte 1 = 0xB4: 5 wordsbyte 1 = 0xB5: 5 wordsbyte 1 = 0xB6: 6 wordsbyte 1 = 0xB7: 6 wordsbyte 2: Next(0x96, 0xFE) gives 0x96–0xFD; observed 0x96–0xFD over 620 wordsbyte 2byte 2 = 0x96: 4 wordsbyte 2 = 0x97: 4 wordsbyte 2 = 0x98: 5 wordsbyte 2 = 0x99: 4 wordsbyte 2 = 0x9A: 3 wordsbyte 2 = 0x9B: 8 wordsbyte 2 = 0x9C: 6 wordsbyte 2 = 0x9D: 4 wordsbyte 2 = 0x9E: 6 wordsbyte 2 = 0x9F: 9 wordsbyte 2 = 0xA0: 6 wordsbyte 2 = 0xA1: 9 wordsbyte 2 = 0xA2: 7 wordsbyte 2 = 0xA3: 9 wordsbyte 2 = 0xA4: 7 wordsbyte 2 = 0xA5: 8 wordsbyte 2 = 0xA6: 9 wordsbyte 2 = 0xA7: 3 wordsbyte 2 = 0xA8: 6 wordsbyte 2 = 0xA9: 9 wordsbyte 2 = 0xAA: 5 wordsbyte 2 = 0xAB: 3 wordsbyte 2 = 0xAC: 8 wordsbyte 2 = 0xAD: 6 wordsbyte 2 = 0xAE: 1 wordsbyte 2 = 0xAF: 7 wordsbyte 2 = 0xB0: 6 wordsbyte 2 = 0xB1: 8 wordsbyte 2 = 0xB2: 4 wordsbyte 2 = 0xB3: 7 wordsbyte 2 = 0xB4: 10 wordsbyte 2 = 0xB5: 8 wordsbyte 2 = 0xB6: 10 wordsbyte 2 = 0xB7: 3 wordsbyte 2 = 0xB8: 4 wordsbyte 2 = 0xB9: 4 wordsbyte 2 = 0xBA: 15 wordsbyte 2 = 0xBB: 5 wordsbyte 2 = 0xBC: 6 wordsbyte 2 = 0xBD: 7 wordsbyte 2 = 0xBE: 7 wordsbyte 2 = 0xBF: 4 wordsbyte 2 = 0xC0: 5 wordsbyte 2 = 0xC1: 8 wordsbyte 2 = 0xC2: 9 wordsbyte 2 = 0xC3: 9 wordsbyte 2 = 0xC4: 4 wordsbyte 2 = 0xC5: 6 wordsbyte 2 = 0xC6: 6 wordsbyte 2 = 0xC7: 6 wordsbyte 2 = 0xC8: 4 wordsbyte 2 = 0xC9: 7 wordsbyte 2 = 0xCA: 4 wordsbyte 2 = 0xCB: 8 wordsbyte 2 = 0xCC: 8 wordsbyte 2 = 0xCD: 3 wordsbyte 2 = 0xCE: 6 wordsbyte 2 = 0xCF: 7 wordsbyte 2 = 0xD0: 4 wordsbyte 2 = 0xD1: 2 wordsbyte 2 = 0xD2: 7 wordsbyte 2 = 0xD3: 2 wordsbyte 2 = 0xD4: 7 wordsbyte 2 = 0xD5: 6 wordsbyte 2 = 0xD6: 9 wordsbyte 2 = 0xD7: 4 wordsbyte 2 = 0xD8: 6 wordsbyte 2 = 0xD9: 10 wordsbyte 2 = 0xDA: 5 wordsbyte 2 = 0xDB: 4 wordsbyte 2 = 0xDC: 3 wordsbyte 2 = 0xDD: 6 wordsbyte 2 = 0xDE: 6 wordsbyte 2 = 0xDF: 7 wordsbyte 2 = 0xE0: 10 wordsbyte 2 = 0xE1: 5 wordsbyte 2 = 0xE2: 4 wordsbyte 2 = 0xE3: 4 wordsbyte 2 = 0xE4: 4 wordsbyte 2 = 0xE5: 4 wordsbyte 2 = 0xE6: 3 wordsbyte 2 = 0xE7: 4 wordsbyte 2 = 0xE8: 9 wordsbyte 2 = 0xE9: 6 wordsbyte 2 = 0xEA: 6 wordsbyte 2 = 0xEB: 8 wordsbyte 2 = 0xEC: 10 wordsbyte 2 = 0xED: 3 wordsbyte 2 = 0xEE: 7 wordsbyte 2 = 0xEF: 5 wordsbyte 2 = 0xF0: 7 wordsbyte 2 = 0xF1: 8 wordsbyte 2 = 0xF2: 6 wordsbyte 2 = 0xF3: 3 wordsbyte 2 = 0xF4: 5 wordsbyte 2 = 0xF5: 3 wordsbyte 2 = 0xF6: 6 wordsbyte 2 = 0xF7: 8 wordsbyte 2 = 0xF8: 7 wordsbyte 2 = 0xF9: 4 wordsbyte 2 = 0xFA: 7 wordsbyte 2 = 0xFB: 1 wordsbyte 2 = 0xFC: 6 wordsbyte 2 = 0xFD: 5 wordsbyte 3: Next(0x0A, 0x79) gives 0x0A–0x78; observed 0x0A–0x78 over 620 wordsbyte 3byte 3 = 0x0A: 6 wordsbyte 3 = 0x0B: 5 wordsbyte 3 = 0x0C: 9 wordsbyte 3 = 0x0D: 8 wordsbyte 3 = 0x0E: 6 wordsbyte 3 = 0x0F: 8 wordsbyte 3 = 0x10: 5 wordsbyte 3 = 0x11: 10 wordsbyte 3 = 0x12: 3 wordsbyte 3 = 0x13: 3 wordsbyte 3 = 0x14: 4 wordsbyte 3 = 0x15: 7 wordsbyte 3 = 0x16: 6 wordsbyte 3 = 0x17: 8 wordsbyte 3 = 0x18: 5 wordsbyte 3 = 0x19: 4 wordsbyte 3 = 0x1A: 4 wordsbyte 3 = 0x1B: 2 wordsbyte 3 = 0x1C: 2 wordsbyte 3 = 0x1D: 7 wordsbyte 3 = 0x1E: 8 wordsbyte 3 = 0x1F: 2 wordsbyte 3 = 0x20: 6 wordsbyte 3 = 0x21: 4 wordsbyte 3 = 0x22: 7 wordsbyte 3 = 0x23: 12 wordsbyte 3 = 0x24: 6 wordsbyte 3 = 0x25: 1 wordsbyte 3 = 0x26: 6 wordsbyte 3 = 0x27: 7 wordsbyte 3 = 0x28: 6 wordsbyte 3 = 0x29: 6 wordsbyte 3 = 0x2A: 4 wordsbyte 3 = 0x2B: 9 wordsbyte 3 = 0x2C: 7 wordsbyte 3 = 0x2D: 4 wordsbyte 3 = 0x2E: 4 wordsbyte 3 = 0x2F: 3 wordsbyte 3 = 0x30: 11 wordsbyte 3 = 0x31: 6 wordsbyte 3 = 0x32: 4 wordsbyte 3 = 0x33: 5 wordsbyte 3 = 0x34: 4 wordsbyte 3 = 0x35: 7 wordsbyte 3 = 0x36: 7 wordsbyte 3 = 0x37: 7 wordsbyte 3 = 0x38: 4 wordsbyte 3 = 0x39: 4 wordsbyte 3 = 0x3A: 4 wordsbyte 3 = 0x3B: 3 wordsbyte 3 = 0x3C: 5 wordsbyte 3 = 0x3D: 10 wordsbyte 3 = 0x3E: 8 wordsbyte 3 = 0x3F: 9 wordsbyte 3 = 0x40: 7 wordsbyte 3 = 0x41: 3 wordsbyte 3 = 0x42: 3 wordsbyte 3 = 0x43: 4 wordsbyte 3 = 0x44: 6 wordsbyte 3 = 0x45: 4 wordsbyte 3 = 0x46: 5 wordsbyte 3 = 0x47: 6 wordsbyte 3 = 0x48: 6 wordsbyte 3 = 0x49: 5 wordsbyte 3 = 0x4A: 10 wordsbyte 3 = 0x4B: 4 wordsbyte 3 = 0x4C: 4 wordsbyte 3 = 0x4D: 5 wordsbyte 3 = 0x4E: 5 wordsbyte 3 = 0x4F: 1 wordsbyte 3 = 0x50: 6 wordsbyte 3 = 0x51: 5 wordsbyte 3 = 0x52: 7 wordsbyte 3 = 0x53: 6 wordsbyte 3 = 0x54: 5 wordsbyte 3 = 0x55: 4 wordsbyte 3 = 0x56: 2 wordsbyte 3 = 0x57: 9 wordsbyte 3 = 0x58: 7 wordsbyte 3 = 0x59: 9 wordsbyte 3 = 0x5A: 3 wordsbyte 3 = 0x5B: 7 wordsbyte 3 = 0x5C: 7 wordsbyte 3 = 0x5D: 4 wordsbyte 3 = 0x5E: 6 wordsbyte 3 = 0x5F: 7 wordsbyte 3 = 0x60: 6 wordsbyte 3 = 0x61: 5 wordsbyte 3 = 0x62: 5 wordsbyte 3 = 0x63: 3 wordsbyte 3 = 0x64: 3 wordsbyte 3 = 0x65: 3 wordsbyte 3 = 0x66: 6 wordsbyte 3 = 0x67: 6 wordsbyte 3 = 0x68: 3 wordsbyte 3 = 0x69: 10 wordsbyte 3 = 0x6A: 8 wordsbyte 3 = 0x6B: 6 wordsbyte 3 = 0x6C: 7 wordsbyte 3 = 0x6D: 6 wordsbyte 3 = 0x6E: 7 wordsbyte 3 = 0x6F: 2 wordsbyte 3 = 0x70: 4 wordsbyte 3 = 0x71: 3 wordsbyte 3 = 0x72: 3 wordsbyte 3 = 0x73: 10 wordsbyte 3 = 0x74: 4 wordsbyte 3 = 0x75: 7 wordsbyte 3 = 0x76: 11 wordsbyte 3 = 0x77: 4 wordsbyte 3 = 0x78: 4 words
Every byte of all 620 words in the 6 posts, by position. The shaded band is the range of the Next(lo, hi) call for that byte; bars are how often each value occurs. Hover for counts.

Each band is uniformly filled and stops dead at both ends, which is what Next(lo, hi) produces: an integer from lo up to, but not including, hi, all equally likely. The ends are not guesses from the observed minimum and maximum. Each bound was varied by ±8 and only the values above make every word come out right; 0xFE and 0x79 in particular are the only upper bounds that work, even though 0xFD and 0x78 are the largest values seen.

The ranges are the same in all six posts, from July to December 2011, so they are constants in the program, not values it drew.

Finding the seed

System.Random(seed) is deterministic: the same seed always gives the same sequence. So the test is simple. For each seed from 0 to 999, and each number of skipped calls from 0 to 3,000, generate words and compare them to the post. Every post fits exactly one (seed, skip) pair, and fits it for every word.

A chance fit is not plausible. One word has 5 × 169 × 104 × 111 ≈ 9.75 million possible values, so a random seed matches a single word with probability about 1 in 10 million; even the shortest list here (32 words) is astronomically beyond chance.

The order of the four calls matters too. An earlier attempt at these posts had the word boundary two calls too early, which made bytes 2 and 3 look like they did not fit. With the boundary in the right place, the byte order is simply the call order.

The discarded calls

Before its first word, each post's Random has already been used a few times:

The two-call preamble is the same in all four 2011 posts, so it is part of the program: some value drawn before the words, perhaps a size or format choice, or a random delay. What exactly it is cannot be told from two numbers that appear nowhere in the posts.

The 599 skipped words of ihwxg say more. The program generated about 600 words on the same Random before the 256 it posted, and none of those 600 were ever posted. A fresh new Random() per post could not do that, so the instance lived across several runs of the tool: seeded once, by the millisecond, when the tool started, and then reused. The same pattern, a long-lived Random whose earlier draws are invisible, is what later lets the count RNG identify A858's posting runs.

Two later variants

Neither the word counts (60, 50, 180, 256, 42, 32) nor the seeds carry any visible meaning. Like the GUID lists, these posts are filler: the output of a random generator whose only real inputs are the time and the program's constants.

Check it yourself

This script uses the same .NET Random port as the mask digit page, fetches a post from Arctic Shift and regenerates it. Run it with no arguments for iirqk, or give the post, seed and number of skipped calls from the table, e.g. ihwxg 393 2398.

import json, sys, urllib.request

def net_random(seed):
    # .NET Framework System.Random(seed), enough for seeds 0..999
    M = 2147483647
    sa = [0] * 56
    mj = 161803398 - seed
    sa[55], mk = mj, 1
    for i in range(1, 55):
        ii = 21 * i % 55
        sa[ii], mk, mj = mk, (mj - mk) % M, mk
    for _ in range(4):
        for i in range(1, 56):
            sa[i] = (sa[i] - sa[1 + (i + 30) % 55]) % M
    a, b = 0, 21
    while True:
        a = a % 55 + 1
        b = b % 55 + 1
        sa[a] = (sa[a] - sa[b]) % M
        yield sa[a] / M

RANGES = [(0xDA, 0xDF), (0x0F, 0xB8), (0x96, 0xFE), (0x0A, 0x79)]

def words(seed, skip, n):
    rng = net_random(seed)
    for _ in range(skip):
        next(rng)
    # Random.Next(lo, hi) = lo + (int)(Sample() * (hi - lo))
    return [''.join(f'{int(next(rng) * (hi - lo)) + lo:02X}' for lo, hi in RANGES) for _ in range(n)]

post, seed, skip = (sys.argv[1], int(sys.argv[2]), int(sys.argv[3])) if len(sys.argv) > 3 else ('iirqk', 107, 2)
url = f'https://arctic-shift.photon-reddit.com/api/posts/ids?ids={post}&fields=selftext'
req = urllib.request.Request(url, headers={'User-Agent': 'a858-word-check'})
posted = json.load(urllib.request.urlopen(req))['data'][0]['selftext'].split()
made = words(seed, skip, len(posted))
print(len(posted), 'words; first three:', posted[:3], made[:3])
print('identical' if made == posted else 'different')

It works directly on the four unencrypted 2011 posts. For mymne, use the decrypted text from its JSON file on this site; for n1ley, compare only the words before 00000000.