Research SFMT RNG in Sun&Moon

#1
Discuss SFMT random number generator in Sun&Moon.

In Sun&Moon, when decide a wild pokemon's IVs, PID, Encryption Constant, etc, it is SFMT (SIMD-oriented Fast Mersenne Twister; MEXP=19937) that be used.

And the initial seed is a 32-bit value, used by sfmt_init_gen_rand().

Moreover, in the QR scanner, when the message "Searching for a QR code..." is showed, "sfmt_genrand_uint64(&sfmt) % 17" is used to decide the hands of clock.

So, you can identify the seed by brute force of 2^32 seeds. I tried it in practice, and succeeded.

Here is a picture of the hands of clock.

 
Last edited by a moderator:
#2
I will provide an additional explanation.

I say, when the game calls genrand_uint64(), one frame advances.

There are 416 417 frame advances when the game starts.

And while the player is on the field, frame advances about 30 times per second to decide player's blinking. If NPCs exist, more advances will occur.

Of course, in the QR scanner, there is no frame advance for blinking.
 
Last edited:
#4
This sounds cool. I haven't really done any RNG manipulation except for gen III since it was so easy to set up on VBA for getting good things to play with.
 
#11
That's really cool.

(If only there were such a fast way to get the RNG for Eggs...)
The rng for eggs only have a 127 bit internal state while this one is assumed to have the full 19937. If they actually went by the same method, this one would have required much more inputs than just 127 eggs. However, with eggs each input is from a %2 or just 1 bit which also carries far less information than a %17 would.
 
#12
The rng for eggs only have a 127 bit internal state while this one is assumed to have the full 19937. If they actually went by the same method, this one would have required much more inputs than just 127 eggs. However, with eggs each input is from a %2 or just 1 bit which also carries far less information than a %17 would.
Sounds like the "TinyMT" algorithm, which was based on the Mersenne Twister.

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html
 

Princess Emily

Fear the nice-smelling Princess!
#14
This reminds me of Dream Radar RNG where we use the clock/spinner positions to find a seed, only this time there are 17 instead of 8 (0 & 16 looks a bit similar tho)
Does this work on WCs & gift mons too?
 
#15
The seed is decided by the following algorithm.

Code:
uint64_t msg[2];
uint32_t digest[16];
msg[0] = GetSystemTick();
msg[1] = getTimeInMilliseconds();
SHA256Digest((unsigned char *)digest, (unsigned char *)msg, 16);
seed = digest[0];
where:
`GetSystemTick()` means the total CPU ticks elapsed since the CPU was powered-on (see: https://www.3dbrew.org/wiki/SVC).
`getTimeInMilliseconds()` means the milliseconds elapsed since 00:00:00, 1 Jan 2000.
`SHA256Digest(digest, msg, len)` calculates SHA-256 digest from `msg` and store into `digest`.

For example, if GetSystemTick() returns 0x12345678, getTimeInMilliseconds() returns 0x7d349cc000 (that means 00:00:00, 15 Jan 2016), then seed is 0xddcdcba7.
 
Last edited:

Princess Emily

Fear the nice-smelling Princess!
#17
There are some NPCs in pokemon center.
So, perhaps RNG abuse for gift pokemons may be more difficult than that for legendary pokemons.
But most NPCs in Pokemon centers don't move that much & are always standing still, unlike their previous gen counterparts.
Will they still advance frames even if not moving?
 
#21
Characters' blinking is decided by the following algorithm.

When the function is called first, `state`, `dblflag`, and `count` are 0. `chr->eyes == 1` or `chr->eyes == 2` mean the character's eyes are open. `chr->eyes == 3` means the character's eyes are closed. `rand(n)` means `sfmt_genrand_uint64(&sfmt) % n`.

This function is called 30 times per second for each character.

Code:
void character_blink(Character *chr) {
   switch (chr->state) {
   case 0:
     chr->eyes = 1;
     if (chr->dblflag) {
       chr->state = 1;
       return;
     }
     if (chr->count != 0) {
       chr->count--;
       if (chr->count != 0) return;
     }
     if (rand(128) == 0) {
       chr->state = 1;
     }
     return;
   case 1:
     chr->eyes = 2;
     chr->state = 2;
     return;
   case 2:
     chr->eyes = 3;
     chr->state = 3;
     return;
   case 3:
     chr->eyes = 2;
     chr->state = 4;
     return;
   case 4:
     chr->eyes = 2;
     chr->state = 5;
     return;
   case 5:
     chr->eyes = 1;
     if (chr->dblflag == 0) {
       if (rand(3) == 0) {
         chr->dblflag = 1;
         chr->count = 60;
         chr->state = 0;
         return;
       }
     }
     chr->dblflag = 0;
     chr->count = 30;
     chr->state = 0;
     return;
   }
}