* Crypto:
- Convert all ArrayList caching to LBQs in YKGenerator, HMACGenerator, and AESKeyCache. - Change DSAEngine params from Hash to new SHA1Hash, since these were really 20 byte hashes, not 32 byte Hashes. - Add stats to track YKGenerator caching success - Fix YKGenerator precalculation to be much more useful by increasing the cache size and dramatically shortening the delay - Option cleanups - YKGenerator cleanups - Mark HMAC256Generator unused
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
package net.i2p.crypto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Cache the objects used in CryptixRijndael_Algorithm.makeKey to reduce
|
||||
@ -11,7 +10,7 @@ import java.util.List;
|
||||
*
|
||||
*/
|
||||
public final class CryptixAESKeyCache {
|
||||
private final List _availableKeys;
|
||||
private final LinkedBlockingQueue<KeyCacheEntry> _availableKeys;
|
||||
|
||||
private static final int KEYSIZE = 32; // 256bit AES
|
||||
private static final int BLOCKSIZE = 16;
|
||||
@ -22,7 +21,7 @@ public final class CryptixAESKeyCache {
|
||||
private static final int MAX_KEYS = 64;
|
||||
|
||||
public CryptixAESKeyCache() {
|
||||
_availableKeys = new ArrayList(MAX_KEYS);
|
||||
_availableKeys = new LinkedBlockingQueue(MAX_KEYS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,10 +29,9 @@ public final class CryptixAESKeyCache {
|
||||
*
|
||||
*/
|
||||
public final KeyCacheEntry acquireKey() {
|
||||
synchronized (_availableKeys) {
|
||||
if (!_availableKeys.isEmpty())
|
||||
return (KeyCacheEntry)_availableKeys.remove(0);
|
||||
}
|
||||
KeyCacheEntry rv = _availableKeys.poll();
|
||||
if (rv != null)
|
||||
return rv;
|
||||
return createNew();
|
||||
}
|
||||
|
||||
@ -42,10 +40,7 @@ public final class CryptixAESKeyCache {
|
||||
*
|
||||
*/
|
||||
public final void releaseKey(KeyCacheEntry key) {
|
||||
synchronized (_availableKeys) {
|
||||
if (_availableKeys.size() < MAX_KEYS)
|
||||
_availableKeys.add(key);
|
||||
}
|
||||
_availableKeys.offer(key);
|
||||
}
|
||||
|
||||
public static final KeyCacheEntry createNew() {
|
||||
|
@ -65,35 +65,17 @@ public class DHSessionKeyBuilder {
|
||||
public final static String PROP_DH_PRECALC_MIN = "crypto.dh.precalc.min";
|
||||
public final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
|
||||
public final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
|
||||
public final static String DEFAULT_DH_PRECALC_MIN = "5";
|
||||
public final static String DEFAULT_DH_PRECALC_MAX = "50";
|
||||
public final static String DEFAULT_DH_PRECALC_DELAY = "10000";
|
||||
public final static int DEFAULT_DH_PRECALC_MIN = 5;
|
||||
public final static int DEFAULT_DH_PRECALC_MAX = 50;
|
||||
public final static int DEFAULT_DH_PRECALC_DELAY = 10000;
|
||||
|
||||
static {
|
||||
I2PAppContext ctx = _context;
|
||||
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
||||
try {
|
||||
int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN));
|
||||
MIN_NUM_BUILDERS = val;
|
||||
} catch (Throwable t) {
|
||||
int val = Integer.parseInt(DEFAULT_DH_PRECALC_MIN);
|
||||
MIN_NUM_BUILDERS = val;
|
||||
}
|
||||
try {
|
||||
int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX));
|
||||
MAX_NUM_BUILDERS = val;
|
||||
} catch (Throwable t) {
|
||||
int val = Integer.parseInt(DEFAULT_DH_PRECALC_MAX);
|
||||
MAX_NUM_BUILDERS = val;
|
||||
}
|
||||
try {
|
||||
int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY));
|
||||
CALC_DELAY = val;
|
||||
} catch (Throwable t) {
|
||||
int val = Integer.parseInt(DEFAULT_DH_PRECALC_DELAY);
|
||||
CALC_DELAY = val;
|
||||
}
|
||||
MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN);
|
||||
MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX);
|
||||
CALC_DELAY = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
|
||||
|
@ -41,6 +41,10 @@ import net.i2p.data.SigningPublicKey;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.NativeBigInteger;
|
||||
|
||||
/**
|
||||
* Params and rv's changed from Hash to SHA1Hash for version 0.8.1
|
||||
* There shouldn't be any external users of those variants.
|
||||
*/
|
||||
public class DSAEngine {
|
||||
private Log _log;
|
||||
private I2PAppContext _context;
|
||||
@ -61,7 +65,9 @@ public class DSAEngine {
|
||||
public boolean verifySignature(Signature signature, InputStream in, SigningPublicKey verifyingKey) {
|
||||
return verifySignature(signature, calculateHash(in), verifyingKey);
|
||||
}
|
||||
public boolean verifySignature(Signature signature, Hash hash, SigningPublicKey verifyingKey) {
|
||||
|
||||
/** @param hash SHA-1 hash, NOT a SHA-256 hash */
|
||||
public boolean verifySignature(Signature signature, SHA1Hash hash, SigningPublicKey verifyingKey) {
|
||||
long start = _context.clock().now();
|
||||
|
||||
try {
|
||||
@ -111,17 +117,18 @@ public class DSAEngine {
|
||||
}
|
||||
public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
|
||||
if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
|
||||
Hash h = calculateHash(data, offset, length);
|
||||
SHA1Hash h = calculateHash(data, offset, length);
|
||||
return sign(h, signingKey);
|
||||
}
|
||||
|
||||
public Signature sign(InputStream in, SigningPrivateKey signingKey) {
|
||||
if ((signingKey == null) || (in == null) ) return null;
|
||||
Hash h = calculateHash(in);
|
||||
SHA1Hash h = calculateHash(in);
|
||||
return sign(h, signingKey);
|
||||
}
|
||||
|
||||
public Signature sign(Hash hash, SigningPrivateKey signingKey) {
|
||||
/** @param hash SHA-1 hash, NOT a SHA-256 hash */
|
||||
public Signature sign(SHA1Hash hash, SigningPrivateKey signingKey) {
|
||||
if ((signingKey == null) || (hash == null)) return null;
|
||||
long start = _context.clock().now();
|
||||
|
||||
@ -186,7 +193,8 @@ public class DSAEngine {
|
||||
return sig;
|
||||
}
|
||||
|
||||
public Hash calculateHash(InputStream in) {
|
||||
/** @return hash SHA-1 hash, NOT a SHA-256 hash */
|
||||
public SHA1Hash calculateHash(InputStream in) {
|
||||
SHA1 digest = new SHA1();
|
||||
byte buf[] = new byte[64];
|
||||
int read = 0;
|
||||
@ -199,14 +207,15 @@ public class DSAEngine {
|
||||
_log.warn("Unable to hash the stream", ioe);
|
||||
return null;
|
||||
}
|
||||
return new Hash(digest.engineDigest());
|
||||
return new SHA1Hash(digest.engineDigest());
|
||||
}
|
||||
|
||||
public static Hash calculateHash(byte[] source, int offset, int len) {
|
||||
/** @return hash SHA-1 hash, NOT a SHA-256 hash */
|
||||
public static SHA1Hash calculateHash(byte[] source, int offset, int len) {
|
||||
SHA1 h = new SHA1();
|
||||
h.engineUpdate(source, offset, len);
|
||||
byte digested[] = h.digest();
|
||||
return new Hash(digested);
|
||||
return new SHA1Hash(digested);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
|
@ -15,16 +15,16 @@ import org.bouncycastle.crypto.macs.I2PHMac;
|
||||
* in {@link org.bouncycastle.crypto.macs.I2PHMac} and
|
||||
* {@link org.bouncycastle.crypto.digests.MD5Digest}.
|
||||
*
|
||||
* deprecated unused
|
||||
*/
|
||||
public class HMAC256Generator extends HMACGenerator {
|
||||
public HMAC256Generator(I2PAppContext context) { super(context); }
|
||||
|
||||
@Override
|
||||
protected I2PHMac acquire() {
|
||||
synchronized (_available) {
|
||||
if (!_available.isEmpty())
|
||||
return (I2PHMac)_available.remove(0);
|
||||
}
|
||||
I2PHMac rv = _available.poll();
|
||||
if (rv != null)
|
||||
return rv;
|
||||
// the HMAC is hardcoded to use SHA256 digest size
|
||||
// for backwards compatability. next time we have a backwards
|
||||
// incompatible change, we should update this by removing ", 32"
|
||||
@ -43,6 +43,7 @@ public class HMAC256Generator extends HMACGenerator {
|
||||
|
||||
}
|
||||
|
||||
/******
|
||||
public static void main(String args[]) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
byte data[] = new byte[64];
|
||||
@ -51,4 +52,5 @@ public class HMAC256Generator extends HMACGenerator {
|
||||
Hash mac = ctx.hmac256().calculate(key, data);
|
||||
System.out.println(Base64.encode(mac.getData()));
|
||||
}
|
||||
******/
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
package net.i2p.crypto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
@ -22,14 +21,14 @@ import org.bouncycastle.crypto.macs.I2PHMac;
|
||||
public class HMACGenerator {
|
||||
private I2PAppContext _context;
|
||||
/** set of available HMAC instances for calculate */
|
||||
protected final List _available;
|
||||
protected final LinkedBlockingQueue<I2PHMac> _available;
|
||||
/** set of available byte[] buffers for verify */
|
||||
private final List _availableTmp;
|
||||
private final LinkedBlockingQueue<byte[]> _availableTmp;
|
||||
|
||||
public HMACGenerator(I2PAppContext context) {
|
||||
_context = context;
|
||||
_available = new ArrayList(32);
|
||||
_availableTmp = new ArrayList(32);
|
||||
_available = new LinkedBlockingQueue(32);
|
||||
_availableTmp = new LinkedBlockingQueue(32);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,39 +87,30 @@ public class HMACGenerator {
|
||||
}
|
||||
|
||||
protected I2PHMac acquire() {
|
||||
synchronized (_available) {
|
||||
if (!_available.isEmpty())
|
||||
return (I2PHMac)_available.remove(0);
|
||||
}
|
||||
I2PHMac rv = _available.poll();
|
||||
if (rv != null)
|
||||
return rv;
|
||||
// the HMAC is hardcoded to use SHA256 digest size
|
||||
// for backwards compatability. next time we have a backwards
|
||||
// incompatible change, we should update this by removing ", 32"
|
||||
return new I2PHMac(new MD5Digest(), 32);
|
||||
}
|
||||
private void release(Mac mac) {
|
||||
synchronized (_available) {
|
||||
if (_available.size() < 64)
|
||||
_available.add(mac);
|
||||
}
|
||||
|
||||
private void release(I2PHMac mac) {
|
||||
_available.offer(mac);
|
||||
}
|
||||
|
||||
// temp buffers for verify(..)
|
||||
private byte[] acquireTmp() {
|
||||
byte rv[] = null;
|
||||
synchronized (_availableTmp) {
|
||||
if (!_availableTmp.isEmpty())
|
||||
rv = (byte[])_availableTmp.remove(0);
|
||||
}
|
||||
byte rv[] = _availableTmp.poll();
|
||||
if (rv != null)
|
||||
Arrays.fill(rv, (byte)0x0);
|
||||
else
|
||||
rv = new byte[Hash.HASH_LENGTH];
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void releaseTmp(byte tmp[]) {
|
||||
synchronized (_availableTmp) {
|
||||
if (_availableTmp.size() < 64)
|
||||
_availableTmp.add((Object)tmp);
|
||||
}
|
||||
_availableTmp.offer(tmp);
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ public final class SHA1 extends MessageDigest implements Cloneable {
|
||||
/**
|
||||
* This implementation returns a fixed-size digest.
|
||||
*/
|
||||
private static final int HASH_LENGTH = 20; // bytes == 160 bits
|
||||
static final int HASH_LENGTH = 20; // bytes == 160 bits
|
||||
|
||||
/**
|
||||
* Private context for incomplete blocks and padding bytes.
|
||||
|
81
core/java/src/net/i2p/crypto/SHA1Hash.java
Normal file
81
core/java/src/net/i2p/crypto/SHA1Hash.java
Normal file
@ -0,0 +1,81 @@
|
||||
package net.i2p.crypto;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.DataStructureImpl;
|
||||
|
||||
/**
|
||||
* Because DSAEngine was abusing Hash for 20-byte hashes
|
||||
*
|
||||
* @since 0.8.1
|
||||
* @author zzz
|
||||
*/
|
||||
public class SHA1Hash extends DataStructureImpl {
|
||||
private byte[] _data;
|
||||
private int _cachedHashCode;
|
||||
|
||||
public final static int HASH_LENGTH = SHA1.HASH_LENGTH;
|
||||
|
||||
/** @throws IllegalArgumentException if data is not 20 bytes (null is ok) */
|
||||
public SHA1Hash(byte data[]) {
|
||||
setData(data);
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return _data;
|
||||
}
|
||||
|
||||
/** @throws IllegalArgumentException if data is not 20 bytes (null is ok) */
|
||||
public void setData(byte[] data) {
|
||||
// FIXME DSAEngine uses a SHA-1 "Hash" as parameters and return values!
|
||||
if (data != null && data.length != HASH_LENGTH)
|
||||
throw new IllegalArgumentException("Hash must be 20 bytes");
|
||||
_data = data;
|
||||
_cachedHashCode = calcHashCode();
|
||||
}
|
||||
|
||||
/** @throws IOException always */
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
throw new IOException("unimplemented");
|
||||
}
|
||||
|
||||
/** @throws IOException always */
|
||||
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||
throw new IOException("unimplemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ((obj == null) || !(obj instanceof SHA1Hash)) return false;
|
||||
return DataHelper.eq(_data, ((SHA1Hash) obj)._data);
|
||||
}
|
||||
|
||||
/** a Hash is a hash, so just use the first 4 bytes for speed */
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _cachedHashCode;
|
||||
}
|
||||
|
||||
/** a Hash is a hash, so just use the first 4 bytes for speed */
|
||||
private int calcHashCode() {
|
||||
int rv = 0;
|
||||
if (_data != null) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
rv ^= (_data[i] << (i*8));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
@ -10,24 +10,22 @@ package net.i2p.crypto;
|
||||
*/
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.NativeBigInteger;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
/**
|
||||
* Precalculate the Y and K for ElGamal encryption operations.
|
||||
*
|
||||
* This class precalcs a set of values on its own thread, using those transparently
|
||||
* when a new instance is created. By default, the minimum threshold for creating
|
||||
* new values for the pool is 5, and the max pool size is 10. Whenever the pool has
|
||||
* new values for the pool is 20, and the max pool size is 50. Whenever the pool has
|
||||
* less than the minimum, it fills it up again to the max. There is a delay after
|
||||
* each precalculation so that the CPU isn't hosed during startup (defaulting to 10 seconds).
|
||||
* each precalculation so that the CPU isn't hosed during startup.
|
||||
* These three parameters are controlled by java environmental variables and
|
||||
* can be adjusted via:
|
||||
* -Dcrypto.yk.precalc.min=40 -Dcrypto.yk.precalc.max=100 -Dcrypto.yk.precalc.delay=60000
|
||||
@ -39,51 +37,36 @@ import net.i2p.util.RandomSource;
|
||||
* @author jrandom
|
||||
*/
|
||||
class YKGenerator {
|
||||
private final static Log _log = new Log(YKGenerator.class);
|
||||
private static int MIN_NUM_BUILDERS = -1;
|
||||
private static int MAX_NUM_BUILDERS = -1;
|
||||
private static int CALC_DELAY = -1;
|
||||
/* FIXME final type if you are to syncronize FIXME */
|
||||
private static volatile List _values = new ArrayList(50); // list of BigInteger[] values (y and k)
|
||||
private static Thread _precalcThread = null;
|
||||
//private final static Log _log = new Log(YKGenerator.class);
|
||||
private static final int MIN_NUM_BUILDERS;
|
||||
private static final int MAX_NUM_BUILDERS;
|
||||
private static final int CALC_DELAY;
|
||||
private static final LinkedBlockingQueue<BigInteger[]> _values = new LinkedBlockingQueue(50); // list of BigInteger[] values (y and k)
|
||||
private static final Thread _precalcThread;
|
||||
private static final I2PAppContext ctx;
|
||||
|
||||
public final static String PROP_YK_PRECALC_MIN = "crypto.yk.precalc.min";
|
||||
public final static String PROP_YK_PRECALC_MAX = "crypto.yk.precalc.max";
|
||||
public final static String PROP_YK_PRECALC_DELAY = "crypto.yk.precalc.delay";
|
||||
public final static String DEFAULT_YK_PRECALC_MIN = "10";
|
||||
public final static String DEFAULT_YK_PRECALC_MAX = "30";
|
||||
public final static String DEFAULT_YK_PRECALC_DELAY = "10000";
|
||||
public final static int DEFAULT_YK_PRECALC_MIN = 20;
|
||||
public final static int DEFAULT_YK_PRECALC_MAX = 50;
|
||||
public final static int DEFAULT_YK_PRECALC_DELAY = 200;
|
||||
|
||||
/** check every 30 seconds whether we have less than the minimum */
|
||||
private final static long CHECK_DELAY = 30 * 1000;
|
||||
private static long CHECK_DELAY = 30 * 1000;
|
||||
|
||||
static {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
try {
|
||||
int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_MIN, DEFAULT_YK_PRECALC_MIN));
|
||||
MIN_NUM_BUILDERS = val;
|
||||
} catch (Throwable t) {
|
||||
int val = Integer.parseInt(DEFAULT_YK_PRECALC_MIN);
|
||||
MIN_NUM_BUILDERS = val;
|
||||
}
|
||||
try {
|
||||
int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_MAX, DEFAULT_YK_PRECALC_MAX));
|
||||
MAX_NUM_BUILDERS = val;
|
||||
} catch (Throwable t) {
|
||||
int val = Integer.parseInt(DEFAULT_YK_PRECALC_MAX);
|
||||
MAX_NUM_BUILDERS = val;
|
||||
}
|
||||
try {
|
||||
int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_DELAY, DEFAULT_YK_PRECALC_DELAY));
|
||||
CALC_DELAY = val;
|
||||
} catch (Throwable t) {
|
||||
int val = Integer.parseInt(DEFAULT_YK_PRECALC_DELAY);
|
||||
CALC_DELAY = val;
|
||||
}
|
||||
ctx = I2PAppContext.getGlobalContext();
|
||||
MIN_NUM_BUILDERS = ctx.getProperty(PROP_YK_PRECALC_MIN, DEFAULT_YK_PRECALC_MIN);
|
||||
MAX_NUM_BUILDERS = ctx.getProperty(PROP_YK_PRECALC_MAX, DEFAULT_YK_PRECALC_MAX);
|
||||
CALC_DELAY = ctx.getProperty(PROP_YK_PRECALC_DELAY, DEFAULT_YK_PRECALC_DELAY);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("ElGamal YK Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
|
||||
+ CALC_DELAY + ")");
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("ElGamal YK Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
|
||||
// + CALC_DELAY + ")");
|
||||
|
||||
ctx.statManager().createRateStat("crypto.YKUsed", "Need a YK from the queue", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.YKEmpty", "YK queue empty", "Encryption", new long[] { 60*60*1000 });
|
||||
|
||||
_precalcThread = new I2PThread(new YKPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS));
|
||||
_precalcThread.setName("YK Precalc");
|
||||
@ -93,45 +76,36 @@ class YKGenerator {
|
||||
}
|
||||
|
||||
private static final int getSize() {
|
||||
synchronized (_values) {
|
||||
return _values.size();
|
||||
}
|
||||
return _values.size();
|
||||
}
|
||||
|
||||
private static final int addValues(BigInteger yk[]) {
|
||||
int sz = 0;
|
||||
synchronized (_values) {
|
||||
_values.add(yk);
|
||||
sz = _values.size();
|
||||
}
|
||||
return sz;
|
||||
/** @return true if successful, false if full */
|
||||
private static final boolean addValues(BigInteger yk[]) {
|
||||
return _values.offer(yk);
|
||||
}
|
||||
|
||||
/** @return rv[0] = Y; rv[1] = K */
|
||||
public static BigInteger[] getNextYK() {
|
||||
if (true) {
|
||||
synchronized (_values) {
|
||||
if (!_values.isEmpty()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sufficient precalculated YK values - fetch the existing");
|
||||
return (BigInteger[]) _values.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("Insufficient precalculated YK values - create a new one");
|
||||
ctx.statManager().addRateData("crypto.YKUsed", 1, 0);
|
||||
BigInteger[] rv = _values.poll();
|
||||
if (rv != null)
|
||||
return rv;
|
||||
ctx.statManager().addRateData("crypto.YKEmpty", 1, 0);
|
||||
return generateYK();
|
||||
}
|
||||
|
||||
private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02});
|
||||
|
||||
/** @return rv[0] = Y; rv[1] = K */
|
||||
private static final BigInteger[] generateYK() {
|
||||
NativeBigInteger k = null;
|
||||
BigInteger y = null;
|
||||
long t0 = 0;
|
||||
long t1 = 0;
|
||||
//long t0 = 0;
|
||||
//long t1 = 0;
|
||||
while (k == null) {
|
||||
t0 = Clock.getInstance().now();
|
||||
k = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, RandomSource.getInstance());
|
||||
t1 = Clock.getInstance().now();
|
||||
//t0 = Clock.getInstance().now();
|
||||
k = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, ctx.random());
|
||||
//t1 = Clock.getInstance().now();
|
||||
if (BigInteger.ZERO.compareTo(k) == 0) {
|
||||
k = null;
|
||||
continue;
|
||||
@ -139,39 +113,31 @@ class YKGenerator {
|
||||
BigInteger kPlus2 = k.add(_two);
|
||||
if (kPlus2.compareTo(CryptoConstants.elgp) > 0) k = null;
|
||||
}
|
||||
long t2 = Clock.getInstance().now();
|
||||
//long t2 = Clock.getInstance().now();
|
||||
y = CryptoConstants.elgg.modPow(k, CryptoConstants.elgp);
|
||||
|
||||
BigInteger yk[] = new BigInteger[2];
|
||||
yk[0] = y;
|
||||
yk[1] = k;
|
||||
|
||||
long diff = t2 - t0;
|
||||
if (diff > 1000) {
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to generate YK value for ElGamal (" + diff + "ms)");
|
||||
}
|
||||
//long diff = t2 - t0;
|
||||
//if (diff > 1000) {
|
||||
// if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to generate YK value for ElGamal (" + diff + "ms)");
|
||||
//}
|
||||
|
||||
return yk;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
RandomSource.getInstance().nextBoolean(); // warm it up
|
||||
try {
|
||||
Thread.sleep(20 * 1000);
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
_log.debug("\n\n\n\nBegin test\n");
|
||||
System.out.println("\n\n\n\nBegin test\n");
|
||||
long negTime = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
long startNeg = Clock.getInstance().now();
|
||||
getNextYK();
|
||||
long endNeg = Clock.getInstance().now();
|
||||
negTime += endNeg - startNeg;
|
||||
}
|
||||
_log.debug("YK fetch time for 5 runs: " + negTime + " @ " + negTime / 5l + "ms each");
|
||||
try {
|
||||
Thread.sleep(30 * 1000);
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
System.out.println("YK fetch time for 5 runs: " + negTime + " @ " + negTime / 5l + "ms each");
|
||||
}
|
||||
|
||||
private static class YKPrecalcRunner implements Runnable {
|
||||
@ -186,15 +152,21 @@ class YKGenerator {
|
||||
public void run() {
|
||||
while (true) {
|
||||
int curSize = 0;
|
||||
long start = Clock.getInstance().now();
|
||||
//long start = Clock.getInstance().now();
|
||||
int startSize = getSize();
|
||||
// Adjust delay
|
||||
if (startSize <= (_minSize / 2) && CHECK_DELAY > 1000)
|
||||
CHECK_DELAY -= 1000;
|
||||
else if (startSize > (_minSize * 2) && CHECK_DELAY < 60000)
|
||||
CHECK_DELAY += 1000;
|
||||
curSize = startSize;
|
||||
while (curSize < _minSize) {
|
||||
while (curSize < _maxSize) {
|
||||
long begin = Clock.getInstance().now();
|
||||
curSize = addValues(generateYK());
|
||||
long end = Clock.getInstance().now();
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Precalculated YK value in " + (end - begin) + "ms");
|
||||
if (curSize < _minSize) {
|
||||
for (int i = curSize; i < _maxSize; i++) {
|
||||
//long begin = Clock.getInstance().now();
|
||||
if (!addValues(generateYK()))
|
||||
break;
|
||||
//long end = Clock.getInstance().now();
|
||||
//if (_log.shouldLog(Log.DEBUG)) _log.debug("Precalculated YK value in " + (end - begin) + "ms");
|
||||
// for some relief...
|
||||
try {
|
||||
Thread.sleep(CALC_DELAY);
|
||||
@ -202,14 +174,14 @@ class YKGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
long end = Clock.getInstance().now();
|
||||
int numCalc = curSize - startSize;
|
||||
if (numCalc > 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Precalced " + numCalc + " to " + curSize + " in "
|
||||
+ (end - start - CALC_DELAY * numCalc) + "ms (not counting "
|
||||
+ (CALC_DELAY * numCalc) + "ms relief). now sleeping");
|
||||
}
|
||||
//long end = Clock.getInstance().now();
|
||||
//int numCalc = curSize - startSize;
|
||||
//if (numCalc > 0) {
|
||||
// if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Precalced " + numCalc + " to " + curSize + " in "
|
||||
// + (end - start - CALC_DELAY * numCalc) + "ms (not counting "
|
||||
// + (CALC_DELAY * numCalc) + "ms relief). now sleeping");
|
||||
//}
|
||||
try {
|
||||
Thread.sleep(CHECK_DELAY);
|
||||
} catch (InterruptedException ie) { // nop
|
||||
@ -217,4 +189,4 @@ class YKGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user