You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2022/04/05 12:27:02 UTC
[commons-rng] 02/03: RNG-175: Fix MSWS createSeed(UniformRandomProvider) to handle a bad RNG
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git
commit d01b5051799cd60f7b675e4ee1680bc35079b436
Author: aherbert <ah...@apache.org>
AuthorDate: Tue Apr 5 13:26:04 2022 +0100
RNG-175: Fix MSWS createSeed(UniformRandomProvider) to handle a bad RNG
The createSeed(UniformRandomProvider) method should generate a seed even
if the input RNG is non-functional. This fixes an infinite loop when the
RNG output is not suitably random to create a seed.
---
.../rng/simple/internal/ProviderBuilder.java | 29 +++++++++++++++++++++-
.../commons/rng/simple/RandomSourceTest.java | 19 ++++++++++++++
src/changes/changes.xml | 4 +++
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java
index 11399b9a..78e76548 100644
--- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java
@@ -30,6 +30,7 @@ import org.apache.commons.rng.core.source32.Well19937c;
import org.apache.commons.rng.core.source32.Well44497a;
import org.apache.commons.rng.core.source32.Well44497b;
import org.apache.commons.rng.core.source32.ISAACRandom;
+import org.apache.commons.rng.core.source32.IntProvider;
import org.apache.commons.rng.core.source32.MersenneTwister;
import org.apache.commons.rng.core.source32.MiddleSquareWeylSequence;
import org.apache.commons.rng.core.source32.MultiplyWithCarry256;
@@ -281,7 +282,33 @@ public final class ProviderBuilder {
@Override
protected byte[] createByteArraySeed(UniformRandomProvider source) {
- return NativeSeedType.convertSeedToBytes(createMswsSeed(source));
+ // The seed requires approximately 4-6 calls to nextInt().
+ // Wrap the input and switch to a default if the input is faulty.
+ final UniformRandomProvider wrapped = new IntProvider() {
+ /** The number of remaining calls to the source generator. */
+ private int calls = 100;
+ /** Default generator, initialised when required. */
+ private UniformRandomProvider defaultGen;
+ @Override
+ public int next() {
+ if (calls == 0) {
+ // The input source is broken.
+ // Seed a default
+ if (defaultGen == null) {
+ defaultGen = new SplitMix64(source.nextLong());
+ }
+ return defaultGen.nextInt();
+ }
+ calls--;
+ return source.nextInt();
+ }
+ @Override
+ public long nextLong() {
+ // No specific requirements so always use the source
+ return source.nextLong();
+ }
+ };
+ return NativeSeedType.convertSeedToBytes(createMswsSeed(wrapped));
}
/**
diff --git a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java
index e5e7ea71..5bb0c8ef 100644
--- a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java
+++ b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.commons.rng.simple;
+import java.time.Duration;
+import org.apache.commons.rng.core.source64.LongProvider;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -80,4 +82,21 @@ class RandomSourceTest {
Assertions.assertFalse(RandomSource.XOR_SHIFT_1024_S_PHI.isLongJumpable(), "XOR_SHIFT_1024_S_PHI is not LongJumpable");
Assertions.assertTrue(RandomSource.XO_SHI_RO_256_SS.isLongJumpable(), "XO_SHI_RO_256_SS is LongJumpable");
}
+
+ /**
+ * MSWS should not infinite loop if the input RNG fails to provide randomness to create a seed.
+ * See RNG-175.
+ */
+ @Test
+ void testMSWSCreateSeed() {
+ final LongProvider broken = new LongProvider() {
+ @Override
+ public long next() {
+ return 0;
+ }
+ };
+ Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
+ RandomSource.MSWS.createSeed(broken);
+ });
+ }
}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 0b0a08cf..f986aae4 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -86,6 +86,10 @@ behavioural compatibility between releases; derived types
may break behavioural compatibility. Any functional changes
will be recorded in the release notes.
">
+ <action dev="aherbert" type="fix" issue="175">
+ "RandomSource.MSWS": createSeed(UniformRandomProvider) to handle a bad RNG.
+ This fixes an infinite loop when the RNG output is not suitably random to create a seed.
+ </action>
<action dev="aherbert" type="add" issue="173">
"BaseProvider": Add a static method to extend input int[] and long[] seeds to a
minimum length.