Skip to content

Instantly share code, notes, and snippets.

@zaksabeast
Last active November 9, 2019 22:03
Show Gist options
  • Save zaksabeast/49e11ff55c63fe528792eaca6a40afd7 to your computer and use it in GitHub Desktop.
Save zaksabeast/49e11ff55c63fe528792eaca6a40afd7 to your computer and use it in GitHub Desktop.
Gen 7 Initial Seed RNG

Gen 7 initial seed research

Initial seed process

The papertrail (in chronological order)

sub_3FCAD0 -> sub_367D90 (at 0x3FCBDC)
sub_367D90 -> sub_367F54 (at 0x367DA8)
sub_367F54 -> sub_280F04 (at 0x367FAC)
sub_280F04 -> sub_281E4C (at 0x280F10)
sub_281E4C -> sub_280F00 (at 0x281EA8)
sub_280F00 -> sub_281ED4 (at 0x280F00)
sub_281ED4 -> sub_10E66C (at 0x281F3C)

sub_10E66C (sha256) creates the initial seed

Important events (in chronological order)

0x3FCBB0 (sub_3FCAD0) - system time/day are obtained for the init seed
0x3FCBB4 (sub_3FCAD0) - system ticks are obtained for the init seed
0x10E770 (sub_10E66C) - r2 is now the init seed backwards
0x280F18 (sub_280F00) - reverses the init seed to its final value
0x280F20 (sub_280F00) - stores the init seed to 0x32663BF0 (where we read the init seed in memory)
0x3FCC18 (sub_3FCAD0) - memcpy’s the init seed for the main prng

Creating the initial seed

The initial seed takes four parts:

  • System ticks
  • Unknown (button presses?)
  • System time & 0xFFFFFFFF (last half)
  • System time >> 32 (first half)

The unknown hasn't been tested much - I believe it may be button presses from testing on my n3ds vs citra. My n3ds always had a value above zero (presumably from closing luma's rosalina) while citra always had zero (I never had to press buttons when starting citra).

This may be incorrect though.

To create an initial seed:

  1. Put the four pieces of data as a byte array into a sha256
  2. Take the first four bytes of the hash
  3. Reverse their order (i.e. 0xDDCCBBAA becomes 0xAABBCCDD)

Citra notes

Citra appears to be consistent when hitting the system ticks - I've only had three different system tick values. Of the three different system tick values, one was more common by far. This makes it much easier to hit specific seeds, as system ticks move really fast.

The amount of time added between citra starting and the game getting the current time has been very consistent for me - it varies slightly, but has a value more common.

Based on others having tested seed consistency with a set date/time, both of these appear to be true in general.

When disabling CPU JIT, my seed is different - I haven't looked into this, but it makes sense as the emulator will be running at a different speed.

While citra doesn't currently allow setting seconds in its settings (which limits possible seeds) we should still be able to get plenty of good spreads from the many, many possible seeds.

As previously mentioned, the unknown value given to the sha256 is always zero (keep in mind, I don't hold buttons down when starting citra and haven't looked into it).

Citra appears to have a constant tick value for anyone using it, and most people have the same time offset. This means given a specific time, most people should be able to hit the same seed.

Citra takes daylight savings into account for some people - for this reason, some people will need to modify their fixed time by an hour from the fixed time they enter into citra to get the same seeds as other people.

What's next

  • A more formal tool needs to be written for finding seeds that have specific spreads
  • More research on the unknown value used to create the init seed
  • More testing needs to be done in general

Other notes

There's nothing console specific - every console should be able to hit any seed.

While it may be technically possible to do initial seed RNG on a console, it is not plausible (and may never be).

The game's 'get now' function (sub_3680C8) puts the 3ds epoch in milliseconds to r1 and r2.

For example, r1 was 98568D07 and r2 was 00000089, which makes the 3ds now 0x8998568D07 or 590966328583.

3DS epoch to standard epoch

Notes:

  • 3ds base epoch is 2000
  • Standard epoch is 1970

Math:

  • 2000 - 1970 = 30

Conclusion:

  • 946684800000 - 30 years in milliseconds
  • now - 946684800000 = 3ds now
  • 3ds now + 946684800000 = now

Credits

  • Citra and all contributors for such a stellar emulator and 3ds time code
  • Admiral_Fish for pointing out sub_10E66C may be sha256
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment