From db42d9ec373e432ff975688aa179950f6bb6f592 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Tue, 11 Sep 2012 19:40:20 +0000
Subject: [PATCH]   * FortunaRandomSource:     - Fix bug that wasted entropy in
 nextInt()     - Improved synchronization

---
 .../crypto/prng/AsyncFortunaStandalone.java   |   2 +-
 .../gnu/crypto/prng/BasePRNGStandalone.java   |   5 +-
 .../src/net/i2p/util/FortunaRandomSource.java | 108 ++++++++++++------
 3 files changed, 73 insertions(+), 42 deletions(-)

diff --git a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java
index 71c9ed60c5..46e994695d 100644
--- a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java
+++ b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java
@@ -14,7 +14,7 @@ import net.i2p.util.Log;
  *
  * Note that this class is not fully Thread safe!
  * 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()
  *
  */
diff --git a/core/java/src/gnu/crypto/prng/BasePRNGStandalone.java b/core/java/src/gnu/crypto/prng/BasePRNGStandalone.java
index 6b71330d86..4b88e0f0b5 100644
--- a/core/java/src/gnu/crypto/prng/BasePRNGStandalone.java
+++ b/core/java/src/gnu/crypto/prng/BasePRNGStandalone.java
@@ -55,7 +55,7 @@ public abstract class BasePRNGStandalone implements IRandomStandalone {
    // -------------------------------------------------------------------------
 
    /** 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. */
    protected boolean initialised;
@@ -75,10 +75,7 @@ public abstract class BasePRNGStandalone implements IRandomStandalone {
     * @param name the canonical name of this instance.
     */
    protected BasePRNGStandalone(String name) {
-      super();
-
       this.name = name;
-      initialised = false;
       buffer = new byte[0];
    }
 
diff --git a/core/java/src/net/i2p/util/FortunaRandomSource.java b/core/java/src/net/i2p/util/FortunaRandomSource.java
index 6d57f1c6cc..2209785cf6 100644
--- a/core/java/src/net/i2p/util/FortunaRandomSource.java
+++ b/core/java/src/net/i2p/util/FortunaRandomSource.java
@@ -49,12 +49,16 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
      *  @since 0.8.8
      */
     public void shutdown() {
-        _fortuna.shutdown();
+        synchronized(_fortuna) {
+            _fortuna.shutdown();
+        }
     }
 
     @Override
-    public synchronized void setSeed(byte buf[]) {
-      _fortuna.addRandomBytes(buf);
+    public void setSeed(byte buf[]) {
+        synchronized(_fortuna) {
+            _fortuna.addRandomBytes(buf);
+        }
     }
 
     /**
@@ -93,16 +97,21 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
         //    return (int)((n * (long)nextBits(31)) >> 31);
         //}
 
-        int numBits = 0;
-        int remaining = n;
-        int rv = 0;
-        while (remaining > 0) {
-            remaining >>= 1;
-            rv += nextBits(8) << numBits*8;
-            numBits++;
+        // get at least 4 extra bits if possible for better
+        // distribution after the %
+        int numBits;
+        if (n > 0xfffff)
+            numBits = 31;
+        else if (n > 0xfff)
+            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;
         
         //int bits, val;
@@ -121,7 +130,7 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
     @Override
     public long nextLong(long n) {
         if (n == 0) return 0;
-        long rv = signedNextLong(n);
+        long rv = signedNextLong();
         if (rv < 0) 
             rv = 0 - rv;
         rv %= n;
@@ -129,25 +138,31 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
     }
     
     @Override
-    public long nextLong() { return signedNextLong(Long.MAX_VALUE); }
+    public long nextLong() { return signedNextLong(); }
 
     /**
      * Implementation from Sun's java.util.Random javadocs
      */
-    private long signedNextLong(long n) {
-        return ((long)nextBits(32) << 32) + nextBits(32);
+    private long signedNextLong() {
+        synchronized(_fortuna) {
+            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);
+    public boolean nextBoolean() { 
+        byte val;
+        synchronized(_fortuna) {
+            val = _fortuna.nextByte();
+        }
+        return ((val & 0x01) != 0);
     }
 
     @Override
-    public synchronized void nextBytes(byte buf[]) { 
-        _fortuna.nextBytes(buf);
+    public void nextBytes(byte buf[]) { 
+        synchronized(_fortuna) {
+            _fortuna.nextBytes(buf);
+        }
     }
 
     /**
@@ -156,8 +171,10 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
      * @since 0.8.12
      */
     @Override
-    public synchronized void nextBytes(byte buf[], int offset, int length) {
-        _fortuna.nextBytes(buf, offset, length);
+    public void nextBytes(byte buf[], int offset, int length) {
+        synchronized(_fortuna) {
+            _fortuna.nextBytes(buf, offset, length);
+        }
     }
 
     /**
@@ -165,24 +182,35 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
      */
     @Override
     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 
      */
     @Override
     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 
      */
     @Override
-    public synchronized double nextGaussian() { 
-        if (_haveNextGaussian) {
-            _haveNextGaussian = false;
-            return _nextGaussian;
-        } else {
+    public double nextGaussian() { 
+        synchronized (this) {
+            if (_haveNextGaussian) {
+                _haveNextGaussian = false;
+                return _nextGaussian;
+            }
             double v1, v2, s;
             do { 
                 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
+     *
+     * Caller must synchronize!
      */
-    protected synchronized int nextBits(int numBits) {
+    protected int nextBits(int numBits) {
         long rv = 0;
         int bytes = (numBits + 7) / 8;
         for (int i = 0; i < bytes; i++)
@@ -218,14 +248,18 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
  
     /** reseed the fortuna */
     @Override
-    public synchronized void feedEntropy(String source, long data, int bitoffset, int bits) {
-        _fortuna.addRandomByte((byte)(data & 0xFF));
+    public void feedEntropy(String source, long data, int bitoffset, int bits) {
+        synchronized(_fortuna) {
+            _fortuna.addRandomByte((byte)(data & 0xFF));
+        }
     }
  
     /** reseed the fortuna */
     @Override
-    public synchronized void feedEntropy(String source, byte[] data, int offset, int len) {
-        _fortuna.addRandomBytes(data, offset, len);
+    public void feedEntropy(String source, byte[] data, int offset, int len) {
+        synchronized(_fortuna) {
+            _fortuna.addRandomBytes(data, offset, len);
+        }
     }
     
 /*****
-- 
GitLab