Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sim: Use a CSPRNG #10806

Merged
merged 22 commits into from
Jan 11, 2025
Merged

Sim: Use a CSPRNG #10806

merged 22 commits into from
Jan 11, 2025

Conversation

mia-pi-git
Copy link
Member

Yes, it's a new dependency. No, I do not think we should roll our own crypto, nor should we maintain our own crypto.

@mia-pi-git mia-pi-git changed the title PRNG: Use a CSPRNG Sim: Use a CSPRNG Jan 8, 2025
@mia-pi-git mia-pi-git force-pushed the csprng branch 2 times, most recently from d82a9cc to 5a070aa Compare January 8, 2025 18:57
@mia-pi-git mia-pi-git marked this pull request as draft January 8, 2025 19:04
@mia-pi-git mia-pi-git marked this pull request as ready for review January 8, 2025 19:10
@DaWoblefet DaWoblefet self-requested a review January 8, 2025 19:28
@mia-pi-git mia-pi-git force-pushed the csprng branch 2 times, most recently from b9a93e8 to d5a34be Compare January 8, 2025 19:45
sim/prng.ts Outdated Show resolved Hide resolved
sim/prng.ts Outdated Show resolved Hide resolved
@Slayer95
Copy link
Contributor

Slayer95 commented Jan 8, 2025

Doesn't this break RNG accuracy in old gens?

sim/prng.ts Show resolved Hide resolved
sim/prng.ts Outdated Show resolved Hide resolved
@DaWoblefet
Copy link
Member

DaWoblefet commented Jan 10, 2025

I am currently unable to /exportinputlog and start a battle produced by that output with /importinputlog. Here's sample output from /exportinputlog on this branch:

>start {"formatid":"gen9ou","seed":{"type":"Buffer","data":[11,69,137,245,223,243,216,165,17,20,1,110,46,168,60,11,55,93,224,7,215,192,82,15,48,248,8,164,34,225,214,225]}}
>player p1 {"name":"DaWoblefet","avatar":"steven-masters2","team":"Chandelure|||FlashFire|Inferno||252,,,,,|F|,0,,,,|||,,,,,Ghost","rating":0}
>player p2 {"name":"jlfjsadf","avatar":"101","team":"Blissey|||NaturalCure|SoftBoiled||252,,,,,|F|,0,,,,|||,,,,,Normal","rating":0}
>p1 team 1
>p2 team 1
>p1 move inferno
>p2 move softboiled
>forcelose p1

Here's sample output on main:

>start {"formatid":"gen9ou","seed":[63433,64785,32115,55087]}
>player p1 {"name":"fklsdjfas","avatar":"170","team":"Blissey|||NaturalCure|SoftBoiled||252,,,,,|F|,0,,,,|||,,,,,Normal","rating":0}
>player p2 {"name":"DaWoblefet","avatar":"#dawoblefet","team":"Chandelure|||FlashFire|Inferno||252,,,,,|F|,0,,,,|||,,,,,Ghost","rating":0}
>p1 team 1
>p2 team 1
>p1 move softboiled
>p2 move inferno
>forcelose p2

In addition, although I can import an old inputlog, it does not give the same RNG results (on master, this Inferno will miss; on this branch it hits). So we should either have it use the old RNG when using an older seed, or prevent old inputlogs from being imported, because a good chunk of the time you will get a crash or the battle will otherwise be very screwed up from trying to perform actions only possible because of previous RNG.

sim/prng.ts Outdated Show resolved Hide resolved
test/sim/misc/state.js Outdated Show resolved Hide resolved
This is a pretty major refactor which is mostly unrelated to the
feature, but it does make the code a lot simpler.
@@ -32,8 +32,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
// However, just in case, use 1 if it is undefined.
const counter = this.effectState.counter || 1;
if (counter >= 256) {
// 2^32 - special-cased because Battle.random(n) can't handle n > 2^16 - 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holy shit, I traced this back to

9bbb0b8#diff-1876d2faa56ede4eb79712f3c52e03d209fbd5e4b99ad47f5d1b31d3197fbfafR8460

Back then we were using the Gen 3 RNG, which only generated 16-bit numbers. Very different times.

@@ -1248,7 +1248,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
target.clearBoosts();
this.add('-clearboost', target);
target.addVolatile('protect');
const set = Math.floor(Math.random() * 4);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof, this is a real bug and pretty bad.

@@ -32,8 +32,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
// However, just in case, use 1 if it is undefined.
const counter = this.effectState.counter || 1;
if (counter >= 256) {
// 2^32 - special-cased because Battle.random(n) can't handle n > 2^16 - 1
return (this.random() * 4294967296 < 1);
return this.random(0x100000000) === 0; // 2^32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait why is this 2^32 when counter >= 256? Before that point, the chance is 1 in counter and counter doubles on each success, so the chance of each successive success would be 1/1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/4294967296…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously it was already like this before this PR I’m just noticing this now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is how it actually works in gen 5? Need a mechanics expert, though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mia-pi-git mia-pi-git merged commit d3e60b3 into smogon:master Jan 11, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants