* Crypto:

- Use java.security.MessageDigest instead of bundled GNU SHA-256 code
        if available, which it should always be.
        5 to 20% faster on Oracle JVM; 40 to 60% on Harmony;
        5 to 15% on JamVM; 20x (!) on GIJ.
      - Use java.security.MessageDigest instead of bundled Bitzi SHA-1 code
        if available on non-Oracle JVMs, which it should always be.
        Not faster on Oracle JVM; 30 to 60% faster on Harmony;
        15 to 20% on JamVM; 10-15x (!) on GIJ.
This commit is contained in:
zzz
2011-06-01 11:44:10 +00:00
parent 5990dd5879
commit 43332bb6d0
7 changed files with 243 additions and 33 deletions

View File

@ -24,7 +24,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -401,7 +400,7 @@ public class MetaInfo
****/
private boolean fast_checkPiece(int piece, byte[] bs, int off, int length) {
SHA1 sha1 = new SHA1();
MessageDigest sha1 = SHA1.getInstance();
sha1.update(bs, off, length);
byte[] hash = sha1.digest();
@ -519,18 +518,11 @@ public class MetaInfo
}
byte[] infoBytes = BEncoder.bencode(info);
//_log.debug("info bencoded: [" + Base64.encode(infoBytes, true) + "]");
try
{
MessageDigest digest = MessageDigest.getInstance("SHA");
MessageDigest digest = SHA1.getInstance();
byte hash[] = digest.digest(infoBytes);
if (_log.shouldLog(Log.DEBUG))
_log.debug("info hash: " + I2PSnarkUtil.toHex(hash));
return hash;
}
catch(NoSuchAlgorithmException nsa)
{
throw new InternalError(nsa.toString());
}
}
/** @since 0.8.5 */

View File

@ -23,6 +23,7 @@ package org.klomp.snark;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@ -165,7 +166,7 @@ public class Storage
*/
private byte[] fast_digestCreate() throws IOException {
// Calculate piece_hashes
SHA1 digest = new SHA1();
MessageDigest digest = SHA1.getInstance();
byte[] piece_hashes = new byte[20 * pieces];

View File

@ -32,6 +32,7 @@ package net.i2p.crypto;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
@ -228,25 +229,25 @@ public class DSAEngine {
/** @return hash SHA-1 hash, NOT a SHA-256 hash */
public SHA1Hash calculateHash(InputStream in) {
SHA1 digest = new SHA1();
MessageDigest digest = SHA1.getInstance();
byte buf[] = new byte[64];
int read = 0;
try {
while ( (read = in.read(buf)) != -1) {
digest.engineUpdate(buf, 0, read);
digest.update(buf, 0, read);
}
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to hash the stream", ioe);
return null;
}
return new SHA1Hash(digest.engineDigest());
return new SHA1Hash(digest.digest());
}
/** @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);
MessageDigest h = SHA1.getInstance();
h.update(source, offset, len);
byte digested[] = h.digest();
return new SHA1Hash(digested);
}

View File

@ -15,10 +15,17 @@ package net.i2p.crypto;
* put("MessageDigest.SHA-1", "com.bitzi.util.SHA1");
*/
//package com.bitzi.util;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import net.i2p.data.Base64;
/**
* NOTE: As of 0.8.7, use getInstance() instead of new SHA1(), which will
* return the JVM's MessageDigest if it is faster.
*
* <p>The FIPS PUB 180-2 standard specifies four secure hash algorithms (SHA-1,
* SHA-256, SHA-384 and SHA-512) for computing a condensed representation of
* electronic data (message). When a message of any length < 2^^64 bits (for
@ -85,8 +92,27 @@ public final class SHA1 extends MessageDigest implements Cloneable {
*/
private int hA, hB, hC, hD, hE;
private static final boolean _useBitzi;
static {
// oddly, Bitzi is faster than Oracle - see test results below
boolean useBitzi = true;
String vendor = System.getProperty("java.vendor");
if (vendor.startsWith("Apache") || // Harmony
vendor.startsWith("GNU Classpath") || // JamVM
vendor.startsWith("Free Software Foundation")) { // gij
try {
MessageDigest.getInstance("SHA-1");
useBitzi = false;
} catch (NoSuchAlgorithmException e) {}
}
//if (useBitzi)
// System.out.println("INFO: Using Bitzi SHA-1");
_useBitzi = useBitzi;
}
/**
* Creates a SHA1 object with default initial state.
* NOTE: Use getInstance() to get the fastest implementation.
*/
public SHA1() {
super("SHA-1");
@ -94,6 +120,19 @@ public final class SHA1 extends MessageDigest implements Cloneable {
init();
}
/**
* @return the fastest digest, either new SHA1() or MessageDigest.getInstance("SHA-1")
* @since 0.8.7
*/
public static MessageDigest getInstance() {
if (!_useBitzi) {
try {
return MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {}
}
return new SHA1();
}
/**
* Clones this object.
*/
@ -699,4 +738,63 @@ public final class SHA1 extends MessageDigest implements Cloneable {
hD += d;
hC += /* c= */ (c << 30) | (c >>> 2);
}
private static final int RUNS = 100000;
/**
* Test the GNU and the JVM's implementations for speed
*
* Results: 2011-05 eeepc Atom
* <pre>
* JVM strlen GNU ms JVM ms
* Oracle 387 1406 2357
* Oracle 40 522 475
* Harmony 387 5504 3474
* Harmony 40 4396 1593
* JamVM 387 25578 21966
* JamVM 40 5380 4195
* gij 387 47225 3501
* gij 40 9861 919
* </pre>
*
* @since 0.8.7
*/
public static void main(String args[]) {
if (args.length <= 0) {
System.err.println("Usage: SHA1 string");
return;
}
byte[] data = args[0].getBytes();
SHA1 gnu = new SHA1();
long start = System.currentTimeMillis();
for (int i = 0; i < RUNS; i++) {
gnu.update(data, 0, data.length);
byte[] sha = gnu.digest();
if (i == 0)
System.out.println("SHA1 [" + args[0] + "] = [" + Base64.encode(sha) + "]");
gnu.reset();
}
long time = System.currentTimeMillis() - start;
System.out.println("Time for " + RUNS + " SHA-256 computations:");
System.out.println("GNU time (ms): " + time);
start = System.currentTimeMillis();
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
System.err.println("Fatal: " + e);
return;
}
for (int i = 0; i < RUNS; i++) {
md.reset();
byte[] sha = md.digest(data);
if (i == 0)
System.out.println("SHA1 [" + args[0] + "] = [" + Base64.encode(sha) + "]");
}
time = System.currentTimeMillis() - start;
System.out.println("JVM time (ms): " + time);
}
}

View File

@ -2,6 +2,8 @@ package net.i2p.crypto;
import gnu.crypto.hash.Sha256Standalone;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
@ -9,14 +11,29 @@ import net.i2p.data.Base64;
import net.i2p.data.Hash;
/**
* Defines a wrapper for SHA-256 operation. All the good stuff occurs
* in the GNU-Crypto {@link gnu.crypto.hash.Sha256Standalone}
* Defines a wrapper for SHA-256 operation.
*
* As of release 0.8.7, uses java.security.MessageDigest by default.
* If that is unavailable, it uses
* GNU-Crypto {@link gnu.crypto.hash.Sha256Standalone}
*/
public final class SHA256Generator {
private final LinkedBlockingQueue<Sha256Standalone> _digestsGnu;
private final LinkedBlockingQueue<MessageDigest> _digests;
private static final boolean _useGnu;
static {
boolean useGnu = false;
try {
MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
useGnu = true;
System.out.println("INFO: Using GNU SHA-256");
}
_useGnu = useGnu;
}
public SHA256Generator(I2PAppContext context) {
_digestsGnu = new LinkedBlockingQueue(32);
_digests = new LinkedBlockingQueue(32);
}
public static final SHA256Generator getInstance() {
@ -36,10 +53,10 @@ public final class SHA256Generator {
* Calculate the hash and cache the result.
*/
public final Hash calculateHash(byte[] source, int start, int len) {
Sha256Standalone digest = acquireGnu();
MessageDigest digest = acquire();
digest.update(source, start, len);
byte rv[] = digest.digest();
releaseGnu(digest);
release(digest);
//return new Hash(rv);
return Hash.create(rv);
}
@ -47,31 +64,121 @@ public final class SHA256Generator {
/**
* Use this if you only need the data, not a Hash object.
* Does not cache.
* @param out needs 32 bytes starting at outOffset
*/
public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) {
Sha256Standalone digest = acquireGnu();
MessageDigest digest = acquire();
digest.update(source, start, len);
byte rv[] = digest.digest();
releaseGnu(digest);
release(digest);
System.arraycopy(rv, 0, out, outOffset, rv.length);
}
private Sha256Standalone acquireGnu() {
Sha256Standalone rv = _digestsGnu.poll();
private MessageDigest acquire() {
MessageDigest rv = _digests.poll();
if (rv != null)
rv.reset();
else
rv = new Sha256Standalone();
rv = getDigestInstance();
return rv;
}
private void releaseGnu(Sha256Standalone digest) {
_digestsGnu.offer(digest);
private void release(MessageDigest digest) {
_digests.offer(digest);
}
private static MessageDigest getDigestInstance() {
if (!_useGnu) {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {}
}
return new GnuMessageDigest();
}
/**
* Wrapper to make Sha256Standalone a MessageDigest
* @since 0.8.7
*/
private static class GnuMessageDigest extends MessageDigest {
private final Sha256Standalone _gnu;
protected GnuMessageDigest() {
super("SHA-256");
_gnu = new Sha256Standalone();
}
protected byte[] engineDigest() {
return _gnu.digest();
}
protected void engineReset() {
_gnu.reset();
}
protected void engineUpdate(byte input) {
_gnu.update(input);
}
protected void engineUpdate(byte[] input, int offset, int len) {
_gnu.update(input, offset, len);
}
}
private static final int RUNS = 100000;
/**
* Test the GNU and the JVM's implementations for speed
*
* Results: 2011-05 eeepc Atom
* <pre>
* JVM strlen GNU ms JVM ms
* Oracle 387 3861 3565
* Oracle 40 825 635
* Harmony 387 8082 5158
* Harmony 40 4137 1753
* JamVM 387 36301 34100
* JamVM 40 7022 6016
* gij 387 125833 4342
* gij 40 22417 988
* </pre>
*/
public static void main(String args[]) {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
for (int i = 0; i < args.length; i++)
System.out.println("SHA256 [" + args[i] + "] = [" + Base64.encode(ctx.sha().calculateHash(args[i].getBytes()).getData()) + "]");
if (args.length <= 0) {
System.err.println("Usage: SHA256Generator string");
return;
}
byte[] data = args[0].getBytes();
Sha256Standalone gnu = new Sha256Standalone();
long start = System.currentTimeMillis();
for (int i = 0; i < RUNS; i++) {
gnu.update(data, 0, data.length);
byte[] sha = gnu.digest();
if (i == 0)
System.out.println("SHA256 [" + args[0] + "] = [" + Base64.encode(sha) + "]");
gnu.reset();
}
long time = System.currentTimeMillis() - start;
System.out.println("Time for " + RUNS + " SHA-256 computations:");
System.out.println("GNU time (ms): " + time);
start = System.currentTimeMillis();
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
System.err.println("Fatal: " + e);
return;
}
for (int i = 0; i < RUNS; i++) {
md.reset();
byte[] sha = md.digest(data);
if (i == 0)
System.out.println("SHA256 [" + args[0] + "] = [" + Base64.encode(sha) + "]");
}
time = System.currentTimeMillis() - start;
System.out.println("JVM time (ms): " + time);
}
}

View File

@ -1,3 +1,14 @@
2011-06-01 zzz
* Crypto:
- Use java.security.MessageDigest instead of bundled GNU SHA-256 code
if available, which it should always be.
5 to 20% faster on Oracle JVM; 40 to 60% on Harmony;
5 to 15% on JamVM; 20x (!) on GIJ.
- Use java.security.MessageDigest instead of bundled Bitzi SHA-1 code
if available on non-Oracle JVMs, which it should always be.
Not faster on Oracle JVM; 30 to 60% faster on Harmony;
15 to 20% on JamVM; 10-15x (!) on GIJ.
2011-06-01 sponge
* ConfigClients stopClient stubbed out.

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 14;
public final static long BUILD = 15;
/** for example "-test" */
public final static String EXTRA = "";