For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
-
@robinhouston I half expect that somehow to open up a youtube video of Rick Astley...
@RobJLow @robinhouston It should be possible, just needs somebody to work out the seed. (infinite monkeys + typewriter -> Shakespeare)
I'd be really interested in reading how the seed was generated.
-
He's just confessed how he did it!
@robinhouston this is an absolute joy! What a gift.
-
He's just confessed how he did it!
"The generation of random numbers is too important to be left to chance." – Coveyou, R.R. (1969)
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston What an amazing gift!
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston woah ! (and happy birthday !)
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston This is a direct consequence of what the note at the top of Python's "random" module warns about:
"Warning: The pseudo-random generators of this module should not be used for security purposes. For security or cryptographic uses, see the secrets module."
-
@robinhouston This is a direct consequence of what the note at the top of Python's "random" module warns about:
"Warning: The pseudo-random generators of this module should not be used for security purposes. For security or cryptographic uses, see the secrets module."
@ahltorp Well, I certainly wouldn't expect the output to be unpredictable given a known seed! But it's cool that it's possible to derive a seed that forces a specific sequence of outputs like that.
-
@ahltorp Well, I certainly wouldn't expect the output to be unpredictable given a known seed! But it's cool that it's possible to derive a seed that forces a specific sequence of outputs like that.
@robinhouston Yes, any pseudo-number function must produce the same results each time you run it, that is what "function" means in mathematics. But that is not what is normally meant by "predictable".
What the warning is about is that the results of the "random" module are predictable in a very different way. The function is analysable, which means that you can predict it backwards and forwards, skip over steps, etc.
Cryptographically strong functions are not analysable.
-
He's just confessed how he did it!
@robinhouston Super cool! I guess this is only possible because the Mersenne Twister has such a huge state space (2 kB), making it likely that a valid seed exists. I think e.g. the PCG64 generator has only 128 bits of state, so any requested output of that length or longer would not likely be reproducible.
-
@robinhouston This is a direct consequence of what the note at the top of Python's "random" module warns about:
"Warning: The pseudo-random generators of this module should not be used for security purposes. For security or cryptographic uses, see the secrets module."
@ahltorp @robinhouston yes, that’s indeed how it works, but this is still tremendously cool and delightful
-
@ahltorp @robinhouston yes, that’s indeed how it works, but this is still tremendously cool and delightful
@mattiebee @robinhouston The reason the demonstration is cool and delightful is because it plays on our expectations that it should not be possible, or at least very hard.
And in this case it turns out not to be hard, since cryptographically it's just a normal preimage attack on a system designed with no preimage resistance.
Be amazed, and then learn why your expectations were not correct.
-
@robinhouston Super cool! I guess this is only possible because the Mersenne Twister has such a huge state space (2 kB), making it likely that a valid seed exists. I think e.g. the PCG64 generator has only 128 bits of state, so any requested output of that length or longer would not likely be reproducible.
@thomastc @robinhouston It’s only likely that a valid seed exists when using a large internal state, but it’s a little surprising that the process is reversible, because brute force search across seeds would be infeasible.
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston If I stare at it long enough, will my birthdays reverse?.. cuz I'm feelin' pretty freakin' old...
-
@thomastc @robinhouston It’s only likely that a valid seed exists when using a large internal state, but it’s a little surprising that the process is reversible, because brute force search across seeds would be infeasible.
@Colinvparker @thomastc @robinhouston the trick is that, if only a few bits of the output are constrained, then you only have to solve for a state sequence that produces the right constrained bits, and the other bits are free to change. that reduces the complexity of the maths a lot.
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston This sounds like a bigger problem.
-
He's just confessed how he did it!
@robinhouston someone needs to make a quine out of this!
-
He's just confessed how he did it!
@robinhouston oh hey, he supervised one of my projects last year!
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston Ably demonstrating that machine "randomisation", isn't.
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston can you all stop boosting this wonderful thing so that I can send a version of it to my friend for his birthday?
-
For my birthday, my brother-in-law gave me a 4992-digit hex number that, when used as a seed for Python’s random number generator, makes it so that printing a sequence of “random” ASCII characters actually prints a birthday greeting.
I find it rather amazing that this is possible!
This is the program he sent with the seed:
with open("seed.txt", encoding="ascii") as handle:
seed = int(handle.read().strip(), 0)
r = random.Random(seed)
pending = ""
while True:
character = chr(r.randrange(128))
if pending + character == "\x1e\x1f":
break
print(pending, end="")
pending = character
print()@robinhouston A million monkeys writing Python will eventually write Happy Birthday! I love it!
Happy Birthday!