forked from I2P_Developers/i2p.i2p
* FortunaRandomSource:
- Fix bug that wasted entropy in nextInt() - Improved synchronization
This commit is contained in:
@@ -14,7 +14,7 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
* Note that this class is not fully Thread safe!
|
* Note that this class is not fully Thread safe!
|
||||||
* The following methods must be synchronized externally, they are not
|
* The following methods must be synchronized externally, they are not
|
||||||
* sycned here or in super():
|
* synced here or in super():
|
||||||
* addRandomByte(), addRandomBytes(), nextByte(), nextBytes(), seed()
|
* addRandomByte(), addRandomBytes(), nextByte(), nextBytes(), seed()
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@@ -55,7 +55,7 @@ public abstract class BasePRNGStandalone implements IRandomStandalone {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
/** The canonical name prefix of the PRNG algorithm. */
|
/** The canonical name prefix of the PRNG algorithm. */
|
||||||
protected String name;
|
protected final String name;
|
||||||
|
|
||||||
/** Indicate if this instance has already been initialised or not. */
|
/** Indicate if this instance has already been initialised or not. */
|
||||||
protected boolean initialised;
|
protected boolean initialised;
|
||||||
@@ -75,10 +75,7 @@ public abstract class BasePRNGStandalone implements IRandomStandalone {
|
|||||||
* @param name the canonical name of this instance.
|
* @param name the canonical name of this instance.
|
||||||
*/
|
*/
|
||||||
protected BasePRNGStandalone(String name) {
|
protected BasePRNGStandalone(String name) {
|
||||||
super();
|
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
initialised = false;
|
|
||||||
buffer = new byte[0];
|
buffer = new byte[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,13 +49,17 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
|||||||
* @since 0.8.8
|
* @since 0.8.8
|
||||||
*/
|
*/
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
synchronized(_fortuna) {
|
||||||
_fortuna.shutdown();
|
_fortuna.shutdown();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setSeed(byte buf[]) {
|
public void setSeed(byte buf[]) {
|
||||||
|
synchronized(_fortuna) {
|
||||||
_fortuna.addRandomBytes(buf);
|
_fortuna.addRandomBytes(buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* According to the java docs (http://java.sun.com/j2se/1.4.1/docs/api/java/util/Random.html#nextInt(int))
|
* According to the java docs (http://java.sun.com/j2se/1.4.1/docs/api/java/util/Random.html#nextInt(int))
|
||||||
@@ -93,16 +97,21 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
|||||||
// return (int)((n * (long)nextBits(31)) >> 31);
|
// return (int)((n * (long)nextBits(31)) >> 31);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
int numBits = 0;
|
// get at least 4 extra bits if possible for better
|
||||||
int remaining = n;
|
// distribution after the %
|
||||||
int rv = 0;
|
int numBits;
|
||||||
while (remaining > 0) {
|
if (n > 0xfffff)
|
||||||
remaining >>= 1;
|
numBits = 31;
|
||||||
rv += nextBits(8) << numBits*8;
|
else if (n > 0xfff)
|
||||||
numBits++;
|
numBits = 24;
|
||||||
|
else if (n > 0xf)
|
||||||
|
numBits = 16;
|
||||||
|
else
|
||||||
|
numBits = 8;
|
||||||
|
int rv;
|
||||||
|
synchronized(_fortuna) {
|
||||||
|
rv = nextBits(numBits);
|
||||||
}
|
}
|
||||||
if (rv < 0)
|
|
||||||
rv += n;
|
|
||||||
return rv % n;
|
return rv % n;
|
||||||
|
|
||||||
//int bits, val;
|
//int bits, val;
|
||||||
@@ -121,7 +130,7 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
|||||||
@Override
|
@Override
|
||||||
public long nextLong(long n) {
|
public long nextLong(long n) {
|
||||||
if (n == 0) return 0;
|
if (n == 0) return 0;
|
||||||
long rv = signedNextLong(n);
|
long rv = signedNextLong();
|
||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
rv = 0 - rv;
|
rv = 0 - rv;
|
||||||
rv %= n;
|
rv %= n;
|
||||||
@@ -129,26 +138,32 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long nextLong() { return signedNextLong(Long.MAX_VALUE); }
|
public long nextLong() { return signedNextLong(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation from Sun's java.util.Random javadocs
|
* Implementation from Sun's java.util.Random javadocs
|
||||||
*/
|
*/
|
||||||
private long signedNextLong(long n) {
|
private long signedNextLong() {
|
||||||
|
synchronized(_fortuna) {
|
||||||
return ((long)nextBits(32) << 32) + nextBits(32);
|
return ((long)nextBits(32) << 32) + nextBits(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean nextBoolean() {
|
|
||||||
// wasteful, might be worth caching the boolean byte later
|
|
||||||
byte val = _fortuna.nextByte();
|
|
||||||
return ((val & 0x01) == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void nextBytes(byte buf[]) {
|
public boolean nextBoolean() {
|
||||||
|
byte val;
|
||||||
|
synchronized(_fortuna) {
|
||||||
|
val = _fortuna.nextByte();
|
||||||
|
}
|
||||||
|
return ((val & 0x01) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nextBytes(byte buf[]) {
|
||||||
|
synchronized(_fortuna) {
|
||||||
_fortuna.nextBytes(buf);
|
_fortuna.nextBytes(buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not part of java.util.SecureRandom, but added for efficiency, since Fortuna supports it.
|
* Not part of java.util.SecureRandom, but added for efficiency, since Fortuna supports it.
|
||||||
@@ -156,33 +171,46 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
|||||||
* @since 0.8.12
|
* @since 0.8.12
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void nextBytes(byte buf[], int offset, int length) {
|
public void nextBytes(byte buf[], int offset, int length) {
|
||||||
|
synchronized(_fortuna) {
|
||||||
_fortuna.nextBytes(buf, offset, length);
|
_fortuna.nextBytes(buf, offset, length);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation from sun's java.util.Random javadocs
|
* Implementation from sun's java.util.Random javadocs
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public double nextDouble() {
|
public double nextDouble() {
|
||||||
return (((long)nextBits(26) << 27) + nextBits(27)) / (double)(1L << 53);
|
long d;
|
||||||
|
synchronized(_fortuna) {
|
||||||
|
d = ((long)nextBits(26) << 27) + nextBits(27);
|
||||||
}
|
}
|
||||||
|
return d / (double)(1L << 53);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation from sun's java.util.Random javadocs
|
* Implementation from sun's java.util.Random javadocs
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float nextFloat() {
|
public float nextFloat() {
|
||||||
return nextBits(24) / ((float)(1 << 24));
|
int d;
|
||||||
|
synchronized(_fortuna) {
|
||||||
|
d = nextBits(24);
|
||||||
}
|
}
|
||||||
|
return d / ((float)(1 << 24));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation from sun's java.util.Random javadocs
|
* Implementation from sun's java.util.Random javadocs
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized double nextGaussian() {
|
public double nextGaussian() {
|
||||||
|
synchronized (this) {
|
||||||
if (_haveNextGaussian) {
|
if (_haveNextGaussian) {
|
||||||
_haveNextGaussian = false;
|
_haveNextGaussian = false;
|
||||||
return _nextGaussian;
|
return _nextGaussian;
|
||||||
} else {
|
}
|
||||||
double v1, v2, s;
|
double v1, v2, s;
|
||||||
do {
|
do {
|
||||||
v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
|
v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
|
||||||
@@ -197,10 +225,12 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pull the next numBits of random data off the fortuna instance (returning -2^numBits-1
|
* Pull the next numBits of random data off the fortuna instance (returning 0
|
||||||
* through 2^numBits-1
|
* through 2^numBits-1
|
||||||
|
*
|
||||||
|
* Caller must synchronize!
|
||||||
*/
|
*/
|
||||||
protected synchronized int nextBits(int numBits) {
|
protected int nextBits(int numBits) {
|
||||||
long rv = 0;
|
long rv = 0;
|
||||||
int bytes = (numBits + 7) / 8;
|
int bytes = (numBits + 7) / 8;
|
||||||
for (int i = 0; i < bytes; i++)
|
for (int i = 0; i < bytes; i++)
|
||||||
@@ -218,15 +248,19 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
|||||||
|
|
||||||
/** reseed the fortuna */
|
/** reseed the fortuna */
|
||||||
@Override
|
@Override
|
||||||
public synchronized void feedEntropy(String source, long data, int bitoffset, int bits) {
|
public void feedEntropy(String source, long data, int bitoffset, int bits) {
|
||||||
|
synchronized(_fortuna) {
|
||||||
_fortuna.addRandomByte((byte)(data & 0xFF));
|
_fortuna.addRandomByte((byte)(data & 0xFF));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** reseed the fortuna */
|
/** reseed the fortuna */
|
||||||
@Override
|
@Override
|
||||||
public synchronized void feedEntropy(String source, byte[] data, int offset, int len) {
|
public void feedEntropy(String source, byte[] data, int offset, int len) {
|
||||||
|
synchronized(_fortuna) {
|
||||||
_fortuna.addRandomBytes(data, offset, len);
|
_fortuna.addRandomBytes(data, offset, len);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*****
|
/*****
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
|
Reference in New Issue
Block a user