package io.eguan.hash;
/*
* #%L
* Project eguan
* %%
* Copyright (C) 2012 - 2017 Oodrive
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import io.eguan.hash.TigerDigest;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
/**
* Unit tests for the Tiger digest.
*
* @author oodrive
* @author llambert
* @author ebredzinski
*
*/
public class TestTigerDigest {
private final String[][] TEST_VALUES = {
// data, md
// ......................
{ "", "3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3" },
{ "abc", "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93" },
{ "Tiger", "DD00230799F5009FEC6DEBC838BB6A27DF2B9D6F110C7937" },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
"F71C8583902AFB879EDFE610F82C0D4786A3A534504486B5" },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
"48CEEB6308B87D46E95D656112CDF18D97915F9765658957" },
{ "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham",
"8A866829040A410C729AD23F5ADA711603B3CDD357E4C15E" },
{
"Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, "
+ "proceedings of Fast Software Encryption 3, Cambridge.",
"CE55A6AFD591F5EBAC547FF84F89227F9331DAB0B611C889" },
{
"Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, "
+ "proceedings of Fast Software Encryption 3, Cambridge, 1996.",
"631ABDD103EB9A3D245B6DFD4D77B257FC7439501D1568DD" },
{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
"C54034E5B43EB8005848A7E0AE6AAC76E4FF590AE715FD25" } };
@Test
public void testTiger() {
for (int i = 0; i < TEST_VALUES.length; i++) {
final String[] testVal = TEST_VALUES[i];
final byte[] src = testVal[0].getBytes();
final byte[] digBouncy = digestBouncy(src, 0, src.length);
final byte[] digLocal = digestLocal(src, 0, src.length);
final StringBuilder hexString = new StringBuilder(digBouncy.length * 2);
for (int j = 0; j < digBouncy.length; j++) {
hexString.append(String.format("%02X", Byte.valueOf(digBouncy[j])));
}
Assert.assertEquals(testVal[1], hexString.toString());
Assert.assertTrue(Arrays.equals(digBouncy, digLocal));
}
}
@Test
public void testTiger4k() {
final byte[] src = new byte[4096];
new SecureRandom().nextBytes(src);
for (int i = 0; i <= 4096; i++) {
for (int j = 0; j < i; j += 30) {
final byte[] digBouncy = digestBouncy(src, j, i);
final byte[] digLocal = digestLocal(src, j, i);
Assert.assertTrue(Arrays.equals(digBouncy, digLocal));
}
}
}
private byte[] digestBouncy(final byte[] src, final int offsetStart, final int offsetEnd) {
final org.bouncycastle.crypto.digests.TigerDigest digest = new org.bouncycastle.crypto.digests.TigerDigest();
digest.update(src, offsetStart, offsetEnd - offsetStart);
final byte[] result = new byte[24];
digest.doFinal(result, 0);
return result;
}
private byte[] digestLocal(final byte[] src, final int offsetStart, final int offsetEnd) {
// Do not call ByteBuffer.wrap(src, offset, len) to check that digest will start from position and not cross the
// limit
final ByteBuffer buffer = ByteBuffer.wrap(src);
buffer.position(offsetStart).limit(offsetEnd);
final TigerDigest digest = new TigerDigest(buffer);
final byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
return result;
}
@Test
public void testTigerPerf() {
testTigerPerf(true);
}
/**
* Real world usage of local hash function. Base code for a performance comparison campaign.
*
* @param callAssert
*/
private void testTigerPerf(final boolean callAssert) {
// Prepare buffer
final int len = 4096;
final int loopCount = 40960;
final byte[] src = new byte[len];
new SecureRandom().nextBytes(src);
final ByteBuffer bufBouncy = ByteBuffer.allocateDirect(len);
bufBouncy.put(src).rewind();
final ByteBuffer bufLocal = ByteBuffer.allocateDirect(len);
bufLocal.put(src).rewind();
// Count bouncy castle implementation time
final byte[] digBouncy = new byte[24];
{
final long startBouncy = System.nanoTime();
for (int i = 0; i < loopCount; i++) {
final org.bouncycastle.crypto.digests.TigerDigest digest = new org.bouncycastle.crypto.digests.TigerDigest();
// Get data from ByteBuffer
final byte[] blockCopy = new byte[len];
bufBouncy.position(0);
bufBouncy.limit(len);
bufBouncy.get(blockCopy);
digest.update(blockCopy, 0, len);
digest.doFinal(digBouncy, 0);
// Avoid loop suppression: use value
bufBouncy.rewind();
bufBouncy.put(digBouncy[12]);
// System.out.print(" " + digBouncy[12]);
}
final long endBouncy = System.nanoTime();
System.out.println("Bouncy Castle impl "
+ ((float) loopCount / ((float) (endBouncy - startBouncy)) * 1000000000) + " hash/seconds");
}
// Count local implementation time
final byte[] digLocal = new byte[24];
final long startLocal = System.nanoTime();
for (int i = 0; i < loopCount; i++) {
final TigerDigest digest = new TigerDigest(bufLocal);
digest.doFinal(digLocal, 0);
// Avoid loop suppression: use value
bufLocal.rewind();
bufLocal.put(digLocal[12]).rewind();
// System.out.print(" " + digLocal[12]);
}
final long endLocal = System.nanoTime();
System.out.println("Local impl " + ((float) loopCount / ((float) (endLocal - startLocal)) * 1000000000)
+ " hash/seconds");
if (callAssert) {
Assert.assertTrue(Arrays.equals(digBouncy, digLocal));
}
}
/**
* Call perf test.
*
* @param ignored
*/
public static void main(final String[] ignored) {
final TestTigerDigest t = new TestTigerDigest();
t.testTiger();
t.testTigerPerf(false);
}
}