On November 2011 Minecraft 1.0 was released,
a
few month later, Searge created modcoder pack
or MCP for short that help to decompile Minecraft.
Not that minecraft was not decompiled before
but the tool started to be made so exploring
the source code was getting easier.
Then time flies, tries were made and in 2012
we find back the first trace of a seed cracking
idea, the user that posted the message, MelaMok
suggested to use 15 slime chunks to get a
48bits seed.
Oh wow only 48bits ?
Well yes, let me recall you how minecraft
generation works, back in alpha and beta it
was solely based on Java Random.
The interesting fact is that java Random use
long type variable which are capable of holding
64 bits number (so up to eighteen quintillion
different numbers) but they use what we call
a mask that wrap up this 64bit range to only
a 48 bit one.
That saves the day
So the effective period of the Java PRNG or
pseudo random number generator is only 284
trillions and since a lot of stuff were using
java random getting a gpu to bruteforce through
the range was the easiest back then
Of course today we have the issue that minecraft
use the full 64bit seed range for the biomes
but they only influence terrain shape and
decorators, the internal LCG for most of the
structure and features has still a period
of 48 bits because it use java random
Let’s talk about slime chunks, they were
introduced back in alpha and the formula hasn’t
been modified since then
The formula is really simple, give it the
2 chunk coordinates and depending of the world
seed it will set a specific slime chunk seed
You then check if nextInt(10) is equal to
0 and that’s it, you got a slime chunk (There
is also further check to make sure the height
is below and that only 1 in 10 attempts give
a slime )
Well all of that is great but you can actually
do a lot more, because all the structure are
seeded in the same fashion, make a temporary
seed then use it to check conditions
Here some examples.
As you can see its very simple, just set the
seed based on the chunk x and z coordinates,
use a different salt depending of the structure,
then call nextInt 2 or 4 times depending of
the structure.
You then get an offset in the region and check
if the chunk chosen at the beginning are the
one decided for the region.
This was figured early on and we have some
traces of it, so we can cite
Taleden April 2013
• github user "pruby" posted a tool using
slime chunks as early as October 2014
• reddit and github user "Badel2" posted
code using slime chunks in December 2017
• reddit user "osmotischen" posted code
using ocean monuments in December 2017
But that was the slow method, cracking 48
bits on gpu still takes between 30min and
12 hours on modern consumer gpu.
So why bothers with it when you have actually
have to only crack 32 of them …
Introduce L64, this was the beginning of scicraft
and the golden age of ZipKrowd, seed finding
was in its infancy but already quite advanced.
Ok disclaimer, I attribute this discovery
to L64 but there is traces that this was independly
discovered before, also this might have not
been only l64 work.
The trick was to use end pillars…
In fact mojang messed up a bit and with those
pillars since 1.9 they are in a fixed pattern,
10 pillar put in a circle with different heights
between 76 and 103,
To decide which order the pillar should go
in mojang used a random shuffle on an ordered
list, so far this is ok, the issue is that
they actually messed up the seeding of it.
You see they seed it like so, they take the
world seed to set up a Java Random Object,
so far this is ok, it looks like structure
seeding , then they take a nextLong (so a
64bit number) then they use it to seed another
random to shuffle the range of integer from
0 to 9, oh yeah I forgot the interesting part
they mask the nextLong result with 0xFFFF
or 2^16-1 or 65535.
Random random = new Random(WorldSeed);
long pillar_seed = random.nextLong() & 65535L;
List list = Lists.newArrayList(ContiguousSet.create(Range.closedOpen(Integer.valueOf(0),
Integer.valueOf(10)), DiscreteDomain.integers()));
Collections.shuffle(list, new Random(pillar_seed));
Why does that matters ? well the second random
Object only has a range of potential seed
of 2^16 (0 to 65535) and that’s bad because
we know the result of that shuffle so we can
reverse back to that pillar_seed in less than
2sec of bruteforce.
( yes I know that factorial 10 is 3628800
and 65536 is lower so there is indeed collisions
but its maximum 3)
Ok but we still need to go back to the worldseed
right ?
Well if you look closely we know
Random random = new Random(WorldSeed); // (WorldSeed
^ multiplier) & mask;
long pillar_seed = random.nextLong() & 65535L;
// ((long)(next(32)) << 32) + next(32); & 65535L
so we know the bottom 16 bit of the second
random call on the random object seeded with
the world seed and reversing a random call
is easy because, let me remind you next is
defined as
nextseed = (oldseed * multiplier + addend)
& mask;
and the multiplicative inverse of the multiplier
0x5DEECE66DL
is 0xdfe05bcb1365 modulo 2^48 -1
and we take the 32 upper bit of that (shift
by 48-32 so 16)
So we can reassemble a full worlseed like
so
currentSeed = (seed << 16u & 0xFFFF00000000)
| (pillar_seed << 16u) |
(seed & 0xFFFF);
currentSeed = ((currentSeed - 0xb) * 0xdfe05bcb1365)
& (unsigned long long) 0xffffffffffff;
currentSeed = ((currentSeed - 0xb) * 0xdfe05bcb1365)
& (unsigned long long) 0xffffffffffff;
currentSeed ^= 0x5DEECE66D;
In this function seed is a 32 bits seed used
to bruteforce on that search space and the
pillar seed is the one matching the pillar
formation seems before, 0xdfe05bcb1365 is
the modular inverse of 0x5DEECE66D (mod 2^48-1).
So if we go from last to first we have the
xor 0x5DEECE66D which is the random mask applied
when we pass a seed to the Random object,
then we go 2 times back in the internal state
of the LCG which is due to the random.nextLong()
call then we assemble the 32 bits seed and
the pillar seed as follows: 16 upper of the
32 | pillar Seed | 16 lower of the 32.
We get a correct worldseed that use the pillar
data
This weird packing is due to how we got the
lower 16 bits of the nextLong which in itself
is two 32 bits packed on which the bottom
one was shifted by 16 so we indeed got the
middle part of the 48 bit worldseed
And that’s was the genius of L64 because
now we only need to iterate over 32bits to
actually get the 48bit of the worldseed since
we now 16 of it.
So we apply that previous function to all
seed between 0 and 2^32-1 and simply check
the resulting 48bits seed with structures.
L64 did exactly that and the program was fast
!... Uhm actually it was slow af, it took
2 hours to finish!
Ok it was only single threaded but still.
Introduce me, Neil in 2018, at that time,
I just discovered scicraft, I was just catching
up on everything when I read something strange,
the l64 finder was dusted off and taleden
made public his repo.
I am sure you all know EarthComputer, well
guess what at that time I beat him to the
punch ;), joking ofc, There was a lot of stuff
to search and well I guess we went from a
friendly competition, turns out I had the
program finished in a week end, and I published
it.
(oh and did you know that was the time he
made enchantment cracker and that a bit later
they discovered the rng manipulation which
technically was under my nose the whole time
but yeah wasn’t looking for it ;)
This was a complete re-implementation of the
l64 cracker but more modern and not in java
(ok it was in python but I went sub 10min!).
Anyway I decided to release to the public
mccracking2 in June 2018 and got swarmed by
ppl that wanted to use that, I clearly didn’t
anticipated, ahah.
Anyway I went through multiple iterations,
each time supporting newer versions, so when
1.13 came out I publish MinecraftSeedCrackingC
in April 2019 , so far nothing much changed,
its still the same stuff of L64 just supporting
more structures.
Anyway fast forward and introduce new players
!
KaptainWutax, this guy decided to tackle the
problem a bit differently, he was wondering
if dungeon could be used to have the full
seed, turns out that yes, unfortunately, this
is still 48 bits to crack (well less because
there is contraints on the height but still)
but we could use it in combinaison with the
16 bits end pillars however as an increasing
number of ppl started to report end dimension
different seed, we had to separate ourself
from the end pillars.
However before going to the good part, let
me go through one notable events, so far to
crack a seed we required exact coordinate
of the structure but we actually can do it
with only images !
Introduce Pewdiepie Seed cracking in July
2019, we didn’t had much but we give it
a try, turns out that, if you combine coolmann
texture finder and a simple gpu kernel you
can do wonders, so in 5 days it was done,
btw skyrising was the one who made and ran
the kernel that found it.
Anyway after we got ripped by Dream (yeah
he didn’t do anything I got more information
from the second guy that contacted me).
Kap made this awesome mod, which I presented
here, while I updated mine to 1.14, he published
his using the same trick as we did but all
inside minecraft.
Then 1.15 came out in December 2019 and the
mod was fully functional.
Ok but that’s still old tech, lets talk
about new tech, but first let me introduce
the man of the Year !
Matthew Bolan, you might know him from speedrunning
or even from being featured inside AntVenom
videos, but me I mostly know him to have introduced
us to lattices.
Basically lattices is just a structure that
can help you to solve a linear system by applying
some bounds on it, I am not going in details
but using a reduction algorithm such as LLL
we can make it so the solution is easy to
find inside a constrained area.
Anyway after packpng project was launched
(see SalC1 video for more details), LattiCG
was born and with it the ability to actually
crack dungeons in few seconds.
Tools to crack the dungeons with it were made
and now its fully integrated in KaptainWutax
mod.
So thanks to Matthew Bolan (and Riley), EarthComputer
and a few others, we have now a tool set to
tackle the java random problems much faster.
But still, we showed that we still needed
data from a real world or a dungeon picture
which is still a bit constraining, let me
introduce you to the even newer gen,
Seed cracking based on Trees, remember guys
dungeon are only the 3 oldest feature/ structure
in Minecraft, trees were actually the first
2.
And as you might have get it, almost everything
is based on java Random…
Anyway since its not published I will not
spoil it but maybe watch out for Screen2Seed
!
Well I hope you enjoyed today story.
This was a long one so I will recap it
In alpha beta, the world was solely determined
using the 48 lower bits and almost everything
use Java Random 48 bits LCG, then the biomes
were introduced and they were the only ones
to use the full 64 bit, but they influenced
a lot of element like terrain and structure.
The first generation of people that cracked
seed used gpu to go through the full 48 bits
period of the java random lcg using structure
or Slime chunks, then l64 came and split that
48bit range in a 16 bit one and a 32 bit one
dividing by a factor of 65k the time to search.
Then dungeon cracking helped a lot by not
needing the end and then matthew Bolan came
and just broke everything by making it go
in order of seconds.
Now we are waiting for new tool to be even
more versatile and less dependant of specific
in game data but more only on displayed one.
Here the actual “tree” of seed finder
Gen 0 well is unknown but I will put that
guy in 2012 then we have Gen 1 that use structures
and slime,
Gen 2 with L64 and me a bit later, Gen 3 with
kap and matthew bolan and now we are waiting
for Gen 4, maybe it could be you ! Join Monkeys
if you feel so!
