implement PSOV2Encryption::single

This commit is contained in:
Martin Michelsen
2025-12-22 00:14:22 -08:00
parent ea23f18aa2
commit 87b048dc15
4 changed files with 75 additions and 4 deletions
+26
View File
@@ -103,6 +103,32 @@ PSOEncryption::Type PSOV2Encryption::type() const {
return Type::V2;
}
uint32_t PSOV2Encryption::single(uint32_t seed) {
// This function is an optimized implementation of `PSOV2Encryption(seed).next()`; that is, it allows the caller to
// get a single value from a PSOV2Encryption instance without actually constructing it. This method is 22x-100x
// faster (depending on build configuration) than constructing a PSOV2Encryption and calling .next() on it once.
// If fib(n) is the n'th Fibonacci number (starting with 1, 1, 2, 3, 5, etc.), then a closed form for the integer
// sequence generated by the first loop in PSOV2Encryption::PSOV2Encryption is:
// a(n) = (-1)^n * (fib(n) - fib(n-1) * seed)
// The recurrence used in that loop is a(n) = a(n-2) - a(n-1), which we can use to prove the closed form correct:
// a(n) = a(n-2) - a(n-1)
// a(n) = (-1)^(n-2) * (fib(n-2) - fib(n-3) * seed) - ((-1)^(n-1) * (fib(n-1) - fib(n-2) * seed))
// a(n) = (-1)^(n-2) * (fib(n-2) - fib(n-3) * seed) + ((-1)^(n-2) * (fib(n-1) - fib(n-2) * seed))
// a(n) = (-1)^(n-2) * (fib(n-2) - fib(n-3) * seed + fib(n-1) - fib(n-2) * seed)
// a(n) = (-1)^(n-2) * (fib(n-2) + fib(n-1) - (fib(n-3) + fib(n-2)) * seed)
// a(n) = (-1)^(n-2) * (fib(n) - fib(n-1) * seed)
// a(n) = (-1)^(n) * (fib(n) - fib(n-1) * seed)
// The sequence begins with a(-1) = seed (which is not generated by the loop but is used as an initial input, hence
// the negative index) and a(0) = 1. Using the closed form and the values of a(-1) and a(0), we can eliminate all
// arithmetic done in the normal constructor that isn't necessary to produce the first result value. To do so, we
// trace backward from the result value, through the 5 update_stream calls and the initialization loop, to see which
// indexes within the stream are actually needed, and the expression to generate each one. We can then simplify the
// overall expression and truncate constants to 32 bits (since it's a linear equation, overflow bits cannot affect
// the final 32-bit result). The full expression simplifies to:
return 0xC6DCAB76 * seed - 0x9E1977BA;
}
PSOV3Encryption::PSOV3Encryption(uint32_t seed) : PSOLFGEncryption(seed, STREAM_LENGTH, STREAM_LENGTH) {
uint32_t x, y, basekey, source1, source2, source3;
basekey = 0;