Skip to content

Instantly share code, notes, and snippets.

@nilsreichardt
Created March 25, 2026 20:06
Show Gist options
  • Select an option

  • Save nilsreichardt/a3ac142263c19387bccb48a35c8cb51a to your computer and use it in GitHub Desktop.

Select an option

Save nilsreichardt/a3ac142263c19387bccb48a35c8cb51a to your computer and use it in GitHub Desktop.
Proof of concept to predict next values if you use Random() instead of Random.secure() in Dart.
// Generated with Gemini 3 Flash
//
// Usage: dart run predict_random.dart
import 'dart:math';
void main() {
final random = Random();
final A = 0xFFFFDA61;
final MASK_32 = 0xFFFFFFFF;
print('--- Dart Random Predictor PoC ---');
// 1. Observe two consecutive values
// We use nextInt(1 << 32) to get the full 32-bit output of the generator
// Note: 1 << 32 is 4294967296. nextInt allows up to this value.
final maxVal = 1 << 32;
final v1 = random.nextInt(maxVal);
final v2 = random.nextInt(maxVal);
print('Observed value 1: $v1');
print('Observed value 2: $v2');
// 2. Recover the state
// v2 = (A * v1 + state1_upper) % 2^32
// so state1_upper = (v2 - A * v1) % 2^32
// In Dart, we need to be careful with large integers.
// Dart's int is 64-bit signed.
BigInt bigA = BigInt.from(A);
BigInt bigV1 = BigInt.from(v1);
BigInt bigV2 = BigInt.from(v2);
BigInt bigMask32 = BigInt.from(MASK_32);
BigInt big2pow32 = BigInt.from(1) << 32;
// state1_upper = (v2 - (A * v1)) % 2^32
BigInt term = bigA * bigV1;
BigInt state1Upper = (bigV2 - term) % big2pow32;
// Since state1_upper must be < A, and bigV2 = (A*v1 + state1_upper) % 2^32,
// we can confirm if we got it right.
// The result of % in Dart/BigInt can be negative if the input is negative.
if (state1Upper < BigInt.zero) {
state1Upper += big2pow32;
}
print('Recovered state1_upper: $state1Upper');
// The state AFTER producing v1 was state1 = (state1Upper << 32) | v1
// To get state2 (the state after producing v2):
// state2 = A * (state1 & MASK_32) + (state1 >> 32)
// state2 = A * v1 + state1Upper
BigInt state2 = bigA * bigV1 + state1Upper;
// Verify state2 produces v2
if ((state2 & bigMask32) != bigV2) {
print('Error: Recovered state does not match v2!');
return;
}
// 3. Predict next values
print('\nPredicting next 5 values:');
BigInt currentState = state2;
List<int> predictions = [];
for (int i = 0; i < 5; i++) {
// next_state = A * (current_state & MASK_32) + (current_state >> 32)
BigInt lower = currentState & bigMask32;
BigInt upper = currentState >> 32;
currentState = bigA * lower + upper;
predictions.add((currentState & bigMask32).toInt());
print('Prediction ${i + 1}: ${predictions.last}');
}
// 4. Verify against actual values
print('\nActual next 5 values:');
for (int i = 0; i < 5; i++) {
final actual = random.nextInt(maxVal);
print('Actual ${i + 1}: $actual');
if (actual == predictions[i]) {
print(' -> MATCH! ✅');
} else {
print(' -> MISMATCH! ❌');
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment