BLAKE2s implementation

Implementation is based on the BLAKE2b implementation from BouncyCastle, and is
therefore licensed under the BouncyCastle license (which will make future
upstreaming of the code easier).
This commit is contained in:
str4d
2015-12-26 05:14:12 +00:00
committed by akwizgran
parent 2dee821f3c
commit d5b347e6c9
2 changed files with 719 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
package org.briarproject.crypto;
import org.briarproject.BriarTestCase;
import org.briarproject.util.StringUtils;
import org.junit.Test;
import java.util.Random;
import static org.junit.Assert.assertArrayEquals;
public class Blake2sDigestTest extends BriarTestCase {
// Vectors from BLAKE2 web site: https://blake2.net/blake2s-test.txt
private static final String[][] keyedTestVectors = {
// input/message, key, hash
{
"",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49",
},
{
"00",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1",
},
{
"0001",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803",
},
{
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"172ffc67153d12e0ca76a8b6cd5d4731885b39ce0cac93a8972a18006c8b8baf",
},
{
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"4f8ce1e51d2fe7f24043a904d898ebfc91975418753413aa099b795ecb35cedb",
},
{
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd",
},
};
@Test
public void testDigestWithKeyedTestVectors() {
Blake2sDigest digest = new Blake2sDigest(StringUtils.fromHexString(
keyedTestVectors[0][1]));
for (String[] keyedTestVector : keyedTestVectors) {
byte[] input = StringUtils.fromHexString(keyedTestVector[0]);
digest.reset();
digest.update(input, 0, input.length);
byte[] hash = new byte[32];
digest.doFinal(hash, 0);
assertArrayEquals(StringUtils.fromHexString(keyedTestVector[2]),
hash);
}
}
@Test
public void testDigestWithKeyedTestVectorsAndRandomUpdate() {
Blake2sDigest digest = new Blake2sDigest(StringUtils.fromHexString(
keyedTestVectors[0][1]));
Random random = new Random();
for (int i = 0; i < 100; i++) {
for (String[] keyedTestVector : keyedTestVectors) {
byte[] input = StringUtils.fromHexString(keyedTestVector[0]);
if (input.length < 3) continue;
digest.reset();
int pos = random.nextInt(input.length);
if (pos > 0)
digest.update(input, 0, pos);
digest.update(input[pos]);
if (pos < (input.length - 1))
digest.update(input, pos + 1, input.length - (pos + 1));
byte[] hash = new byte[32];
digest.doFinal(hash, 0);
assertArrayEquals(StringUtils.fromHexString(keyedTestVector[2]),
hash);
}
}
}
@Test
public void testReset() {
// Generate a non-zero key
byte[] key = new byte[32];
for (byte i = 0; i < key.length; i++) key[i] = i;
// Generate some non-zero input longer than the key
byte[] input = new byte[key.length + 1];
for (byte i = 0; i < input.length; i++) input[i] = i;
// Hash the input
Blake2sDigest digest = new Blake2sDigest(key);
digest.update(input, 0, input.length);
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
// Create a second instance, hash the input without calling doFinal()
Blake2sDigest digest1 = new Blake2sDigest(key);
digest1.update(input, 0, input.length);
// Reset the second instance and hash the input again
digest1.reset();
digest1.update(input, 0, input.length);
byte[] hash1 = new byte[digest.getDigestSize()];
digest1.doFinal(hash1, 0);
// The hashes should be identical
assertArrayEquals(hash, hash1);
}
// Self-test routine from https://tools.ietf.org/html/rfc7693#appendix-E
private static final String SELF_TEST_RESULT =
"6A411F08CE25ADCDFB02ABA641451CEC53C598B24F4FC787FBDC88797F4C1DFE";
private static final int[] SELF_TEST_DIGEST_LEN = {16, 20, 28, 32};
private static final int[] SELF_TEST_INPUT_LEN = {0, 3, 64, 65, 255, 1024};
private static byte[] selfTestSequence(int len, int seed) {
int a = 0xDEAD4BAD * seed;
int b = 1;
int t;
byte[] out = new byte[len];
for (int i = 0; i < len; i++) {
t = a + b;
a = b;
b = t;
out[i] = (byte) ((t >> 24) & 0xFF);
}
return out;
}
@Test
public void runSelfTest() {
Blake2sDigest testDigest = new Blake2sDigest();
byte[] md = new byte[32];
for (int i = 0; i < 4; i++) {
int outlen = SELF_TEST_DIGEST_LEN[i];
for (int j = 0; j < 6; j++) {
int inlen = SELF_TEST_INPUT_LEN[j];
// unkeyed hash
byte[] in = selfTestSequence(inlen, inlen);
Blake2sDigest unkeyedDigest = new Blake2sDigest(outlen * 8);
unkeyedDigest.update(in, 0, inlen);
unkeyedDigest.doFinal(md, 0);
// hash the hash
testDigest.update(md, 0, outlen);
// keyed hash
byte[] key = selfTestSequence(outlen, outlen);
Blake2sDigest keyedDigest = new Blake2sDigest(key, outlen, null,
null);
keyedDigest.update(in, 0, inlen);
keyedDigest.doFinal(md, 0);
// hash the hash
testDigest.update(md, 0, outlen);
}
}
byte[] hash = new byte[32];
testDigest.doFinal(hash, 0);
assertArrayEquals(StringUtils.fromHexString(SELF_TEST_RESULT), hash);
}
}