1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.hash; 16 17 import static java.nio.charset.StandardCharsets.UTF_8; 18 19 import java.util.Arrays; 20 import java.util.Random; 21 import junit.framework.TestCase; 22 23 /** 24 * Unit tests for {@link Crc32c}. Known test values are from RFC 3720, Section B.4. 25 * 26 * @author Patrick Costello 27 * @author Kurt Alfred Kluever 28 */ 29 public class Crc32cHashFunctionTest extends TestCase { testEmpty()30 public void testEmpty() { 31 assertCrc(0, new byte[0]); 32 } 33 testZeros()34 public void testZeros() { 35 // Test 32 byte array of 0x00. 36 byte[] zeros = new byte[32]; 37 assertCrc(0x8a9136aa, zeros); 38 } 39 testZeros100()40 public void testZeros100() { 41 // Test 100 byte array of 0x00. 42 byte[] zeros = new byte[100]; 43 assertCrc(0x07cb9ff6, zeros); 44 } 45 testFull()46 public void testFull() { 47 // Test 32 byte array of 0xFF. 48 byte[] fulls = new byte[32]; 49 Arrays.fill(fulls, (byte) 0xFF); 50 assertCrc(0x62a8ab43, fulls); 51 } 52 testFull100()53 public void testFull100() { 54 // Test 100 byte array of 0xFF. 55 byte[] fulls = new byte[100]; 56 Arrays.fill(fulls, (byte) 0xFF); 57 assertCrc(0xbc753add, fulls); 58 } 59 testAscending()60 public void testAscending() { 61 // Test 32 byte arrays of ascending. 62 byte[] ascending = new byte[32]; 63 for (int i = 0; i < 32; i++) { 64 ascending[i] = (byte) i; 65 } 66 assertCrc(0x46dd794e, ascending); 67 } 68 testDescending()69 public void testDescending() { 70 // Test 32 byte arrays of descending. 71 byte[] descending = new byte[32]; 72 for (int i = 0; i < 32; i++) { 73 descending[i] = (byte) (31 - i); 74 } 75 assertCrc(0x113fdb5c, descending); 76 } 77 testDescending100()78 public void testDescending100() { 79 // Test 100 byte arrays of descending. 80 byte[] descending = new byte[100]; 81 for (int i = 0; i < 100; i++) { 82 descending[i] = (byte) (99 - i); 83 } 84 assertCrc(0xd022db97, descending); 85 } 86 testScsiReadCommand()87 public void testScsiReadCommand() { 88 // Test SCSI read command. 89 byte[] scsiReadCommand = 90 new byte[] { 91 0x01, (byte) 0xc0, 0x00, 0x00, 92 0x00, 0x00, 0x00, 0x00, 93 0x00, 0x00, 0x00, 0x00, 94 0x00, 0x00, 0x00, 0x00, 95 0x14, 0x00, 0x00, 0x00, 96 0x00, 0x00, 0x04, 0x00, 97 0x00, 0x00, 0x00, 0x14, 98 0x00, 0x00, 0x00, 0x18, 99 0x28, 0x00, 0x00, 0x00, 100 0x00, 0x00, 0x00, 0x00, 101 0x02, 0x00, 0x00, 0x00, 102 0x00, 0x00, 0x00, 0x00 103 }; 104 assertCrc(0xd9963a56, scsiReadCommand); 105 } 106 107 // Known values from http://www.evanjones.ca/crc32c.html testSomeOtherKnownValues()108 public void testSomeOtherKnownValues() { 109 assertCrc(0x22620404, "The quick brown fox jumps over the lazy dog".getBytes(UTF_8)); 110 assertCrc(0xE3069283, "123456789".getBytes(UTF_8)); 111 assertCrc(0xf3dbd4fe, "1234567890".getBytes(UTF_8)); 112 assertCrc(0xBFE92A83, "23456789".getBytes(UTF_8)); 113 } 114 testAgainstSimplerImplementation()115 public void testAgainstSimplerImplementation() { 116 Random r = new Random(1234567); 117 for (int length = 0; length < 1000; length++) { 118 byte[] bytes = new byte[length]; 119 r.nextBytes(bytes); 120 assertCrc(referenceCrc(bytes), bytes); 121 } 122 } 123 referenceCrc(byte[] bytes)124 private static int referenceCrc(byte[] bytes) { 125 int crc = ~0; 126 for (byte b : bytes) { 127 crc = (crc >>> 8) ^ Crc32cHashFunction.Crc32cHasher.BYTE_TABLE[(crc ^ b) & 0xFF]; 128 } 129 return ~crc; 130 } 131 132 /** 133 * Verifies that the crc of an array of byte data matches the expected value. 134 * 135 * @param expectedCrc the expected crc value. 136 * @param data the data to run the checksum on. 137 */ assertCrc(int expectedCrc, byte[] data)138 private static void assertCrc(int expectedCrc, byte[] data) { 139 int actualCrc = Hashing.crc32c().hashBytes(data).asInt(); 140 assertEquals( 141 String.format("expected: %08x, actual: %08x", expectedCrc, actualCrc), 142 expectedCrc, 143 actualCrc); 144 int actualCrcHasher = Hashing.crc32c().newHasher().putBytes(data).hash().asInt(); 145 assertEquals( 146 String.format("expected: %08x, actual: %08x", expectedCrc, actualCrc), 147 expectedCrc, 148 actualCrcHasher); 149 } 150 151 // From RFC 3720, Section 12.1, the polynomial generator is 0x11EDC6F41. 152 // We calculate the constant below by: 153 // 1. Omitting the most significant bit (because it's always 1). => 0x1EDC6F41 154 // 2. Flipping the bits of the constant so we can process a byte at a time. => 0x82F63B78 155 private static final int CRC32C_GENERATOR = 0x1EDC6F41; // 0x11EDC6F41 156 private static final int CRC32C_GENERATOR_FLIPPED = Integer.reverse(CRC32C_GENERATOR); 157 testCrc32cByteTable()158 public void testCrc32cByteTable() { 159 // See Hacker's Delight 2nd Edition, Figure 14-7. 160 int[] expected = new int[256]; 161 for (int i = 0; i < expected.length; i++) { 162 int crc = i; 163 for (int j = 7; j >= 0; j--) { 164 int mask = -(crc & 1); 165 crc = ((crc >>> 1) ^ (CRC32C_GENERATOR_FLIPPED & mask)); 166 } 167 expected[i] = crc; 168 } 169 170 int[] actual = Crc32cHashFunction.Crc32cHasher.BYTE_TABLE; 171 assertTrue( 172 "Expected: \n" + Arrays.toString(expected) + "\nActual:\n" + Arrays.toString(actual), 173 Arrays.equals(expected, actual)); 174 } 175 advanceOneBit(int next)176 static int advanceOneBit(int next) { 177 if ((next & 1) != 0) { 178 return (next >>> 1) ^ CRC32C_GENERATOR_FLIPPED; 179 } else { 180 return next >>> 1; 181 } 182 } 183 testCrc32cStrideTable()184 public void testCrc32cStrideTable() { 185 int next = CRC32C_GENERATOR_FLIPPED; 186 for (int i = 0; i < 12; i++) { // for 3 ints = 12 bytes in between each stride window 187 next = (next >>> 8) ^ Crc32cHashFunction.Crc32cHasher.BYTE_TABLE[next & 0xFF]; 188 } 189 int[][] expected = new int[4][256]; 190 for (int b = 0; b < 4; ++b) { 191 for (int bit = 128; bit != 0; bit >>= 1) { 192 expected[b][bit] = next; 193 next = advanceOneBit(next); 194 } 195 } 196 for (int b = 0; b < 4; ++b) { 197 expected[b][0] = 0; 198 for (int bit = 2; bit < 256; bit <<= 1) { 199 for (int i = bit + 1; i < (bit << 1); i++) { 200 expected[b][i] = expected[b][bit] ^ expected[b][i ^ bit]; 201 } 202 } 203 } 204 205 int[][] actual = Crc32cHashFunction.Crc32cHasher.STRIDE_TABLE; 206 assertTrue( 207 "Expected: \n" 208 + Arrays.deepToString(expected) 209 + "\nActual:\n" 210 + Arrays.deepToString(actual), 211 Arrays.deepEquals(expected, actual)); 212 } 213 } 214