• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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