1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.codec.digest;
18
19 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertThrows;
22
23 import java.nio.charset.StandardCharsets;
24 import java.util.Arrays;
25
26 import org.junit.jupiter.api.Test;
27 import org.junit.jupiter.params.ParameterizedTest;
28 import org.junit.jupiter.params.provider.ValueSource;
29
30 class Blake3Test {
31 private static void assertThrowsProperExceptionWithKeySize(final int keySize) {
32 assertThrows(IllegalArgumentException.class, () -> Blake3.initKeyedHash(new byte[keySize]), "Blake3 keys must be 32 bytes");
33 }
34
35 private static byte[] input(final int length) {
36 final byte[] input = new byte[length];
37 for (int i = 0; i < length; i++) {
38 input[i] = (byte) (i % 251);
39 }
40 return input;
41 }
42
43 private static Blake3[] newHashers() {
44 return new Blake3[] {
45 Blake3.initHash(),
46 Blake3.initKeyedHash("whats the Elvish word for friend".getBytes(StandardCharsets.UTF_8)),
47 Blake3.initKeyDerivationFunction("org.apache.commons.codec.digest.Blake3Test".getBytes(StandardCharsets.UTF_8))
48 };
49 }
50
51 @ParameterizedTest
52 @ValueSource(ints = {0, 1, 63, 64, 65, 1023, 1024, 1025, 2048, 3073})
53 void testFinalizeIsIdempotent(final int inputLength) {
54 for (final Blake3 hasher : newHashers()) {
55 hasher.update(input(inputLength));
56 final byte[] expected = hasher.doFinalize(131);
57 assertArrayEquals(expected, hasher.doFinalize(131));
58 assertArrayEquals(Arrays.copyOf(expected, 32), hasher.doFinalize(32));
59 assertArrayEquals(new byte[0], hasher.doFinalize(0));
60 final byte[] actual = new byte[131];
61 hasher.doFinalize(actual);
62 assertArrayEquals(expected, actual);
63 final byte[] destination = new byte[137];
64 Arrays.fill(destination, (byte) 0x5a);
65 final byte[] expectedDestination = destination.clone();
66 System.arraycopy(expected, 0, expectedDestination, 3, expected.length);
67 hasher.doFinalize(destination, 3, expected.length);
68 assertArrayEquals(expectedDestination, destination);
69 assertArrayEquals(expected, hasher.doFinalize(131));
70 }
71 }
72
73 @Test
74 void testKdfExampleDerivesDistinctKeys() {
75 final Blake3 kdf = Blake3.initKeyDerivationFunction("org.apache.commons.codec.digest.Blake3Example".getBytes(StandardCharsets.UTF_8));
76 kdf.update("shared secret".getBytes(StandardCharsets.UTF_8));
77 kdf.update("sender".getBytes(StandardCharsets.UTF_8));
78 kdf.update("recipient".getBytes(StandardCharsets.UTF_8));
79 final byte[] keys = kdf.doFinalize(64);
80 final byte[] txKey = Arrays.copyOfRange(keys, 0, 32);
81 final byte[] rxKey = Arrays.copyOfRange(keys, 32, 64);
82 assertFalse(Arrays.equals(txKey, rxKey));
83 assertArrayEquals(txKey, kdf.doFinalize(32));
84 assertArrayEquals(txKey, kdf.doFinalize(32));
85 }
86
87 @ParameterizedTest
88 @ValueSource(ints = {0, 1, 63, 64, 65, 1023, 1024, 1025, 2048, 3073})
89 void testResetAfterFinalize(final int inputLength) {
90 final Blake3[] hashers = newHashers();
91 final Blake3[] freshHashers = newHashers();
92 final byte[] message = input(inputLength);
93 for (int i = 0; i < hashers.length; i++) {
94 final Blake3 hasher = hashers[i];
95 final byte[] expected = hasher.update(message).doFinalize(131);
96 assertArrayEquals(freshHashers[i].doFinalize(131), hasher.reset().doFinalize(131));
97 assertArrayEquals(expected, hasher.update(message).doFinalize(131));
98 }
99 }
100
101 @Test
102 void testShouldThrowIllegalArgumentExceptionWhenIncorrectKeySize() {
103 for (int i = 0; i < 32; i++) {
104 assertThrowsProperExceptionWithKeySize(i);
105 }
106 assertThrowsProperExceptionWithKeySize(33);
107 }
108
109 @ParameterizedTest
110 @ValueSource(ints = {0, 1, 63, 64, 65, 1023, 1024, 1025, 2048, 3073})
111 void testUpdateAfterFinalize(final int inputLength) {
112 final byte[] message = input(inputLength + 1025);
113 final Blake3[] hashers = newHashers();
114 final Blake3[] freshHashers = newHashers();
115 for (int i = 0; i < hashers.length; i++) {
116 final Blake3 hasher = hashers[i];
117 hasher.update(message, 0, inputLength).doFinalize(131);
118 hasher.update(message, inputLength, message.length - inputLength);
119 final byte[] expected = freshHashers[i].update(message).doFinalize(131);
120 assertArrayEquals(expected, hasher.doFinalize(131));
121 assertArrayEquals(expected, hasher.doFinalize(131));
122 }
123 }
124 }