// $Id: Speed.java 54 2007-01-24 16:22:09Z tp $
package fr.cryptohash.test;
import fr.cryptohash.Digest;
import fr.cryptohash.MD2;
import fr.cryptohash.MD4;
import fr.cryptohash.MD5;
import fr.cryptohash.SHA0;
import fr.cryptohash.SHA1;
import fr.cryptohash.SHA224;
import fr.cryptohash.SHA256;
import fr.cryptohash.SHA384;
import fr.cryptohash.SHA512;
import fr.cryptohash.RIPEMD;
import fr.cryptohash.RIPEMD128;
import fr.cryptohash.RIPEMD160;
import fr.cryptohash.Tiger;
import fr.cryptohash.Tiger2;
import fr.cryptohash.PANAMA;
import fr.cryptohash.HAVAL256_3;
import fr.cryptohash.HAVAL256_4;
import fr.cryptohash.HAVAL256_5;
import fr.cryptohash.WHIRLPOOL;
/**
* <p>This class implements some speed tests for hash functions.</p>
*
* <pre>
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2007 Projet RNRT SAPHIR
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* ===========================(LICENSE END)=============================
* </pre>
*
* @version $Revision: 54 $
* @author Thomas Pornin <thomas.pornin@cryptolog.com>
*/
public class Speed {
public static void main(String[] args)
{
int todo = 0;
for (int i = 0; i < args.length; i ++) {
String s = normalize(args[i]);
if (s.equals("md2"))
todo |= DO_MD2;
else if (s.equals("md4"))
todo |= DO_MD4;
else if (s.equals("md5"))
todo |= DO_MD5;
else if (s.equals("sha0"))
todo |= DO_SHA0;
else if (s.equals("sha1"))
todo |= DO_SHA1;
else if (s.equals("sha2"))
todo |= DO_SHA224 | DO_SHA256;
else if (s.equals("sha224"))
todo |= DO_SHA224;
else if (s.equals("sha256"))
todo |= DO_SHA256;
else if (s.equals("sha3"))
todo |= DO_SHA384 | DO_SHA512;
else if (s.equals("sha384"))
todo |= DO_SHA384;
else if (s.equals("sha512"))
todo |= DO_SHA512;
else if (s.equals("rmd") || s.equals("ripemd"))
todo |= DO_RIPEMD;
else if (s.equals("rmd128") || s.equals("ripemd128"))
todo |= DO_RIPEMD128;
else if (s.equals("rmd160") || s.equals("ripemd160"))
todo |= DO_RIPEMD160;
else if (s.equals("tiger"))
todo |= DO_TIGER;
else if (s.equals("tiger2"))
todo |= DO_TIGER2;
else if (s.equals("panama"))
todo |= DO_PANAMA;
else if (s.equals("haval3"))
todo |= DO_HAVAL3;
else if (s.equals("haval4"))
todo |= DO_HAVAL4;
else if (s.equals("haval5"))
todo |= DO_HAVAL5;
else if (s.equals("whirlpool"))
todo |= DO_WHIRLPOOL;
else
usage(args[i]);
}
if (todo == 0)
todo = -1;
if ((todo & DO_MD2) != 0)
speed("MD2", new MD2());
if ((todo & DO_MD4) != 0)
speed("MD4", new MD4());
if ((todo & DO_MD5) != 0)
speed("MD5", new MD5());
if ((todo & DO_SHA0) != 0)
speed("SHA-0", new SHA0());
if ((todo & DO_SHA1) != 0)
speed("SHA-1", new SHA1());
if ((todo & DO_SHA224) != 0)
speed("SHA-224", new SHA224());
if ((todo & DO_SHA256) != 0)
speed("SHA-256", new SHA256());
if ((todo & DO_SHA384) != 0)
speed("SHA-384", new SHA384());
if ((todo & DO_SHA512) != 0)
speed("SHA-512", new SHA512());
if ((todo & DO_RIPEMD) != 0)
speed("RIPEMD", new RIPEMD());
if ((todo & DO_RIPEMD128) != 0)
speed("RIPEMD-128", new RIPEMD128());
if ((todo & DO_RIPEMD160) != 0)
speed("RIPEMD-160", new RIPEMD160());
if ((todo & DO_TIGER) != 0)
speed("Tiger", new Tiger());
if ((todo & DO_TIGER2) != 0)
speed("Tiger2", new Tiger2());
if ((todo & DO_PANAMA) != 0)
speed("PANAMA", new PANAMA());
if ((todo & DO_HAVAL3) != 0)
speed("HAVAL[3 passes]", new HAVAL256_3());
if ((todo & DO_HAVAL4) != 0)
speed("HAVAL[4 passes]", new HAVAL256_4());
if ((todo & DO_HAVAL5) != 0)
speed("HAVAL[5 passes]", new HAVAL256_5());
if ((todo & DO_WHIRLPOOL) != 0)
speed("WHIRLPOOL", new WHIRLPOOL());
}
private static final int DO_MD2 = 0x00000001;
private static final int DO_MD4 = 0x00000002;
private static final int DO_MD5 = 0x00000004;
private static final int DO_SHA0 = 0x00000008;
private static final int DO_SHA1 = 0x00000010;
private static final int DO_SHA224 = 0x00000020;
private static final int DO_SHA256 = 0x00000040;
private static final int DO_SHA384 = 0x00000080;
private static final int DO_SHA512 = 0x00000100;
private static final int DO_RIPEMD = 0x00000200;
private static final int DO_RIPEMD128 = 0x00000400;
private static final int DO_RIPEMD160 = 0x00000800;
private static final int DO_TIGER = 0x00001000;
private static final int DO_TIGER2 = 0x00002000;
private static final int DO_PANAMA = 0x00004000;
private static final int DO_HAVAL3 = 0x00008000;
private static final int DO_HAVAL4 = 0x00010000;
private static final int DO_HAVAL5 = 0x00020000;
private static final int DO_WHIRLPOOL = 0x00040000;
private static String normalize(String name)
{
name = name.toLowerCase();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < name.length(); i ++) {
char c = name.charAt(i);
if (c != '-' && c != '/')
sb.append(c);
}
return sb.toString();
}
private static void usage(String name)
{
System.err.println("unknown hash function name: '"
+ name + "'");
System.exit(1);
}
private static void speed(String name, Digest dig)
{
System.out.println("Speed test: " + name);
byte[] buf = new byte[8192];
for (int i = 0; i < buf.length; i ++)
buf[i] = 'a';
long num = 2L;
for (int clen = 16;; clen <<= 2) {
if (clen == 4096) {
clen = 8192;
if (num > 1L)
num >>= 1;
}
long tt;
for (;;) {
tt = speedUnit(dig, buf, clen, num);
if (tt > 6000L) {
if (num <= 1L)
break;
num >>= 1L;
} else if (tt < 2000L) {
num += num;
} else {
break;
}
}
long tlen = (long)clen * num;
long div = 10L * tt;
long rate = (tlen + (div - 1) / 2) / div;
System.out.println("message length = "
+ formatLong((long)clen, 5)
+ " -> "
+ prependSpaces(Long.toString(rate / 100L), 4)
+ "."
+ prependZeroes(Long.toString(rate % 100L), 2)
+ " MBytes/s");
if (clen == 8192) {
tt = speedLong(dig, buf, clen, num);
tlen = (long)clen * num;
div = 10L * tt;
rate = (tlen + (div - 1) / 2) / div;
System.out.println("long messages -> "
+ prependSpaces(
Long.toString(rate / 100L), 4)
+ "."
+ prependZeroes(
Long.toString(rate % 100L), 2)
+ " MBytes/s");
break;
}
if (num > 4L)
num >>= 2;
}
}
private static long speedUnit(Digest dig, byte[] buf, int len, long num)
{
byte[] out = new byte[dig.getDigestLength()];
long orig = System.currentTimeMillis();
while (num -- > 0) {
dig.update(buf, 0, len);
dig.digest(out, 0, out.length);
}
long end = System.currentTimeMillis();
return end - orig;
}
private static long speedLong(Digest dig, byte[] buf, int len, long num)
{
byte[] out = new byte[dig.getDigestLength()];
long orig = System.currentTimeMillis();
while (num -- > 0) {
dig.update(buf, 0, len);
}
long end = System.currentTimeMillis();
dig.digest(out, 0, out.length);
return end - orig;
}
private static String formatLong(long num, int len)
{
return prependSpaces(Long.toString(num), len);
}
private static String prependSpaces(String s, int len)
{
return prependChar(s, ' ', len);
}
private static String prependZeroes(String s, int len)
{
return prependChar(s, '0', len);
}
private static String prependChar(String s, char c, int len)
{
int slen = s.length();
if (slen >= len)
return s;
StringBuffer sb = new StringBuffer();
while (len -- > slen)
sb.append(c);
sb.append(s);
return sb.toString();
}
}