Some Relevant Repositories
mjtb49 opened this issue · comments
As I did not see it mentioned in the blog post, the Minecraft community has already produced some fairly general seed cracking tools for Java Random. One which handles nextInt(n) for any n is
https://github.com/mjtb49/LattiCG
which works via lattice reduction. It can be slow for smaller values of n (I think n = 3 and n = 6 are troublesome, though for any even n you should probably not use this tool), as if n is not a power of 2 we need to devote two dimensions of the lattice to that constraint to make the method work.
Skips are rarely a worry for us, as the seeds which skip in a given range of calls are easily calculated, so you can often just assume no skips will occur and later iterate over the tiny number of seeds which will skip. If we are dealing with code that does so many calls between our measured targets that this is unfeasible, I have a lazy example at
https://github.com/mjtb49/BoundNextIntSkips which can place exact upper bounds on the number of skips which can occur in that time.
This is awesome, I knew there had to be a lattice approach :) It seems like both of our approaches break down (complexity wise) for a few annoying bounds that give very little information but that's probably not too big of an issue for either of our applications. A nice benefit of the lattice approach is that it seems like it should work better given more outputs, and the lattice dimensions remain quite small so the LLL step doesn't take too long, though it does seem like the step after lattice reduction can take longer than the elementary approach in some cases when there are a lot of conditions. Either way it's nice to see two different approaches to the problem, thanks for bringing this up!
Yeah, the step after the lattice reduction is what historically took us the longest to figure out, currently it's some sort of branch and bound thing with a linear programming step to bound widths of cross sections. We also often solve different instances of the same problem, so we can compute the reduced lattice once and then reuse it.
Blog post has been updated to mention latticg too :)