Не думаю, что в целом можно полагаться на то, что экземпляр SecureRandom
может быть клонирован, или на клон, обеспечивающий ту же последовательность, что и оригинал.
Проблема заключается в том, что типичная платформа Java предоставляет несколько реализаций безопасного случайного выбора, и когда вы вызываете new SecureRandom()
, вы получаете реализацию по умолчанию. Это может быть PRNG или RNG, который использует источник «реальной» случайности. В последнем случае, даже если clone()
поддерживается классом, объект-клон не будет выдавать ту же случайную последовательность, что и оригинал.
Я могу придумать пару решений (в общем).
Первое решение - создать собственный класс Random
, который обёртывает экземпляр SecureRandom
. Особый соус заключается в том, что вашему классу-обертке нужно записать поток случайных чисел, которые он раздает. Затем вам нужен метод reset()
, который заставляет PRNG переключаться на использование записанных чисел.
Недостатком является то, что вам нужно достаточно памяти для хранения всех чисел. (В зависимости от представления, это может быть много памяти. Например, если вы записываете N целых чисел в ArrayList<Integer>
, наихудший случай - N x 24 байта для объектов Integer
и пик 3 x N x 8 байтов для ArrayList
. int[]
гораздо более плотный, но более сложный в управлении.)
Я вижу, что вы сказали, что последовательности будут слишком длинными, чтобы держать их в памяти при вашем использовании. дело. Вы могли бы записать их в файл, но даже это не масштабируется бесконечно.
Второе решение - использовать возможность классов SecureRandom
для выбора алгоритма и повторного заполнения себя.
SecureRandom seeder = new SecureRandom();
byte[] seed = seeder.generateSeed(NOS_BYTES);
SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");
prng.setSeed(seed);
SecureRandom prng2 = SecureRandom.getInstance("SHA1PRNG");
prng2.setSeed(seed);
// prng1 and prng2 created as above should generate the same sequences
Установите NOS_BYTES
на количество байтов начального числа, которое вы хотите использовать. Или вы можете сгенерировать начальное число «вручную» или прочитать его из файла.
Обратите внимание, что вы не можете надежно установить начальное значение для экземпляра, полученного с помощью new SecureRandom()
, и вы не можете надежно восстановить заполнить существующий экземпляр 1 .
Могут быть и другие алгоритмы PRNG, которые вы можете использовать, в зависимости от ваших Java платформ, настроенных провайдерами безопасности.
Пожалуйста, обратитесь к SecureRandom
javado c для получения дополнительной информации.
Я протестировал описанный выше подход и на моей машине с Java 11 объекты prng
и prng2
генерировали одинаковую последовательность значений int
... до тех пор, пока я не нажму ^ C.
1 - Суть проблемы в том, что javado c для setSeed
говорит так: "Данное семя дополняет, а не заменяет существующее семена. ". В другом месте говорится, что конструкторы возвращают объект, который был засеян. К счастью, в нем также говорится, что методы getInstance
возвращают объекты, которые не были заполнены.
Наконец, из вашего обновленного вопроса я вижу, что вы рассматриваете возможность использования "roll-your- собственный "PRNG" реализован с использованием BigInteger
.
Осторожно!
Очень легко реализовать PRNG, который не так хорош, как вы думаете. Я бы не стал этого делать. Но если вы решите go пойти по этому пути, вам следует ознакомиться с теорией PRNG и их свойствами и выполнить серию (соответствующих) статистических тестов вашей реализации.
(И если вы намерены опубликовать sh свои результаты, в вашей статье должно быть упомянуто, что вы внедрили собственный PRNG, и вы должны предоставить исходный код PRNG и результаты статистического теста для читателей, чтобы проверить. Ради открытости и научной * воспроизводимости c. На мой взгляд.)