2013-11-24 3 views
3

Мне очень интересно, как работает Java RNG. Я читал, что довольно легко использовать метод getLong() и с getInt() и двумя значениями. Я заинтересован в получении семени getInt(int n), зная значение n.Получить семя Java RNG с методом getInt (int n)

Поскольку getInt(n) обычно использует val = bits % n; и повторять это до тех пор, bits - val + (n-1) >= 0), будучи биты next(31) так VAL == бит (по модулю п)

Я испытал брутфорс тестирования всех Возможную пару чисел, сравнимые с начальным один, но это очень долго и сложно для компьютера.

Любые другие идеи о том, как получить семя эффективным способом?

+0

Считаете ли вы, что это легко с 'getLong'? Кроме того, вы имеете в виду при первом вызове 'getInt' или произвольном вызове? –

+0

http://stackoverflow.com/questions/15236151/inverse-function-of-javas-random-function И вызов getInt() без параметров 2 раза – mcat

ответ

2

Вы должны быть в состоянии использовать отражение для этого:

Random r = new Random(1); 

Field f; 
try { 
    f = r.getClass().getDeclaredField("seed"); 
    f.setAccessible(true); 
    AtomicLong seed = (AtomicLong) f.get(r); 
    System.out.println("seed: " + seed); 

    f = r.getClass().getDeclaredField("mask"); 
    f.setAccessible(true); 
    Long mask = (Long) f.get(r); 
    System.out.println("mask: " + mask); 

    f = r.getClass().getDeclaredField("multiplier"); 
    f.setAccessible(true); 
    Long multiplier = (Long) f.get(r); 
    System.out.println("multiplier: " + multiplier); 


    long initialSeed = (seed.longValue()^multiplier); 
    System.out.println("restored initial seed: " + initialSeed); 
} catch (NoSuchFieldException e1) { 
} catch (SecurityException e2) { 
} catch (IllegalAccessException e3) { 
} catch (IllegalArgumentException e4) { 
} 

Выход на моей машине:

seed: 25214903916 
mask: 281474976710655 
multiplier: 25214903917 
restored initial seed: 1 

Когда seed установлен, то значение скремблировавшего:

public Random(long seed) { 
    if (getClass() == Random.class) 
     this.seed = new AtomicLong(initialScramble(seed)); 
    else { 
     // subclass might have overriden setSeed 
     this.seed = new AtomicLong(); 
     setSeed(seed); 
    } 
} 

private static long initialScramble(long seed) { 
    return (seed^multiplier) & mask; // (seed XOR multiplier) AND mask 
} 

Однако mask и multiplier определяются как:

private static final long mask = (1L << 48) - 1; 
private static final long multiplier = 0x5DEECE66DL; 

Как mask это все 1 s для младших 48 бит и XOR является обратимым, вы можете получить обратно начальное семя, если (и только если!) Он был меньше, чем (1L < < 48) , то есть 2^48:

выход для:

Random r = new Random((1L << 48)-1); 

seed: 281449761806738 
mask: 281474976710655 
multiplier: 25214903917 
restored initial seed: 281474976710655 

и:

Random r = new Random((1L << 48)); 

seed: 25214903917 
mask: 281474976710655 
multiplier: 25214903917 
restored initial seed: 0 

См. Также this answer on StackOverflow

+0

Нельзя ли вычесть исходное семя, когда у вас есть полученное семя и выполняемые операции? –

+0

Позвольте мне проверить, я думаю, что возможно, если начальное семя меньше 2^48 – jmiserez

+2

См. Мой обновленный ответ о том, как вернуть начальное значение семени. – jmiserez

Смежные вопросы