Skip to content

Commit a71076b

Browse files
author
Sergiy Sevastyanov
committed
Fixed table based algorithm for polynoms width less then 8
1 parent 9dce0cd commit a71076b

File tree

2 files changed

+65
-26
lines changed

2 files changed

+65
-26
lines changed

src/main/java/com/github/snksoft/crc/CRC.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ private static long reflect(long in, int count)
179179
* It is relatively slow for large amounts of data, but does not require
180180
* any preparation steps. As a result, it might be faster in some cases
181181
* then building a table required for faster calculation.
182+
*
183+
* Note: this implementation follows section 8 ("A Straightforward CRC Implementation")
184+
* of Ross N. Williams paper as even though final/sample implementation of this algorithm
185+
* provided near the end of that paper (and followed by most other implementations)
186+
* is a bit faster, it does not work for polynomials shorter then 8 bits.
187+
*
182188
* @param crcParams CRC algorithm parameters
183189
* @param data data for the CRC calculation
184190
* @return the CRC value of the data provided
@@ -261,6 +267,14 @@ public long update (long curValue, byte[] chunk, int offset, int length)
261267
curValue = crctable[(((byte)curValue) ^ v)&0x00FF]^(curValue >>> 8);
262268
}
263269
}
270+
else if (crcParams.width<8)
271+
{
272+
for (int i=0; i < length; i++)
273+
{
274+
byte v = chunk[offset+i];
275+
curValue = crctable[((((byte)(curValue << (8-crcParams.width))) ^ v)&0xFF)]^(curValue << 8);
276+
}
277+
}
264278
else
265279
{
266280
for (int i=0; i < length; i++)
@@ -319,11 +333,6 @@ public long calculateCRC(byte[] data)
319333
*/
320334
public CRC(Parameters crcParams)
321335
{
322-
if (crcParams.width % 8 != 0)
323-
{
324-
throw new RuntimeException("Table based CRC calculation not supported for CRC sum width of " + crcParams.width);
325-
}
326-
327336
this.crcParams = new Parameters(crcParams);
328337

329338
initValue = (crcParams.reflectIn) ? reflect(crcParams.init, crcParams.width) : crcParams.init;

src/test/groovy/com/github/snksoft/crc/CrcSpec.groovy

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,64 @@ import spock.lang.Specification
44

55
class CrcSpec extends Specification{
66

7-
def "CRC3 to CRC7 Tests (only non-table-driven calculation is supported)"() {
7+
private static final longText = "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits."
88

9-
when:
10-
byte[] dataBytes = data.getBytes()
11-
long calculated1 = CRC.calculateCRC(crcParams, dataBytes)
9+
private static byte[] testArray = null
1210

13-
then:
14-
calculated1 == crc
11+
static {
12+
testArray = new byte[256];
13+
for (int i=0; i<testArray.length; i++)
14+
{
15+
testArray[i] = (byte)(i&0x0FF)
16+
}
17+
}
1518

19+
def "Test CRC polynomials of various widths"() {
1620
when:
17-
new CRC(crcParams)
18-
21+
byte[] dataBytes = data instanceof byte[] ? data : data.getBytes()
22+
long calculated1 = CRC.calculateCRC(crcParams, dataBytes)
23+
then:
24+
calculated1 == crc
25+
when:
26+
CRC table = new CRC(crcParams)
27+
long tableBasedCrc = table.calculateCRC(dataBytes)
1928
then:
20-
RuntimeException e = thrown(RuntimeException)
21-
e.message == "Table based CRC calculation not supported for CRC sum width of ${crcParams.width}"
29+
tableBasedCrc == crc
2230

2331
where:
24-
crcParams | crc | data
25-
new CRC.Parameters(3, 0x03, 0x00, false, false, 0x7) | 0x04 | "123456789" // CRC-3/GSM
26-
new CRC.Parameters(3, 0x03, 0x07, true, true, 0x0) | 0x06 | "123456789" // CRC-3/ROHC
27-
new CRC.Parameters(4, 0x03, 0x00, true, true, 0x0) | 0x07 | "123456789" // CRC-4/ITU
28-
new CRC.Parameters(4, 0x03, 0x0f, false, false, 0xf) | 0x0b | "123456789" // CRC-4/INTERLAKEN
29-
new CRC.Parameters(5, 0x09, 0x09, false, false, 0x0) | 0x00 | "123456789" // CRC-5/EPC
30-
new CRC.Parameters(5, 0x15, 0x00, true, true, 0x0) | 0x07 | "123456789" // CRC-5/ITU
31-
new CRC.Parameters(6, 0x27, 0x3f, false, false, 0x0) | 0x0d | "123456789" // CRC-6/CDMA2000-A
32-
new CRC.Parameters(6, 0x07, 0x3f, false, false, 0x0) | 0x3b | "123456789" // CRC-6/CDMA2000-B
33-
new CRC.Parameters(7, 0x09, 0x00, false, false, 0x0) | 0x75 | "123456789" // CRC-7
34-
new CRC.Parameters(7, 0x4f, 0x7f, true, true, 0x0) | 0x53 | "123456789" // CRC-7/ROHC
32+
crcParams | crc | data
33+
new CRC.Parameters(3, 0x03, 0x00, false, false, 0x7) | 0x04 | "123456789" // CRC-3/GSM
34+
new CRC.Parameters(3, 0x03, 0x00, false, false, 0x7) | 0x06 | longText
35+
new CRC.Parameters(3, 0x03, 0x00, false, false, 0x7) | 0x02 | testArray
36+
new CRC.Parameters(3, 0x03, 0x07, true, true, 0x0) | 0x06 | "123456789" // CRC-3/ROHC
37+
new CRC.Parameters(3, 0x03, 0x07, true, true, 0x0) | 0x03 |longText
38+
new CRC.Parameters(4, 0x03, 0x00, true, true, 0x0) | 0x07 | "123456789" // CRC-4/ITU
39+
new CRC.Parameters(4, 0x03, 0x0f, false, false, 0xf) | 0x0b | "123456789" // CRC-4/INTERLAKEN
40+
new CRC.Parameters(4, 0x03, 0x0f, false, false, 0xf) | 0x01 | longText // CRC-4/INTERLAKEN
41+
new CRC.Parameters(4, 0x03, 0x0f, false, false, 0xf) | 0x07 | testArray // CRC-4/INTERLAKEN
42+
new CRC.Parameters(5, 0x09, 0x09, false, false, 0x0) | 0x00 | "123456789" // CRC-5/EPC
43+
new CRC.Parameters(5, 0x15, 0x00, true, true, 0x0) | 0x07 | "123456789" // CRC-5/ITU
44+
new CRC.Parameters(6, 0x27, 0x3f, false, false, 0x0) | 0x0d | "123456789" // CRC-6/CDMA2000-A
45+
new CRC.Parameters(6, 0x07, 0x3f, false, false, 0x0) | 0x3b | "123456789" // CRC-6/CDMA2000-B
46+
new CRC.Parameters(6, 0x07, 0x3f, false, false, 0x0) | 0x24 | testArray // CRC-6/CDMA2000-B
47+
new CRC.Parameters(7, 0x09, 0x00, false, false, 0x0) | 0x75 | "123456789" // CRC-7
48+
new CRC.Parameters(7, 0x09, 0x00, false, false, 0x0) | 0x78 | testArray // CRC-7
49+
new CRC.Parameters(7, 0x4f, 0x7f, true, true, 0x0) | 0x53 | "123456789" // CRC-7/ROHC
50+
51+
new CRC.Parameters(12, 0xd31, 0x00, false, false, 0xfff) | 0x0b34 | "123456789" // CRC-12/GSM
52+
new CRC.Parameters(12, 0x80f, 0x00, false, true, 0x00) | 0x0daf | "123456789" // CRC-12/UMTS
53+
new CRC.Parameters(13, 0x1cf5, 0x00, false, false, 0x00) | 0x04fa | "123456789" // CRC-13/BBC
54+
new CRC.Parameters(14, 0x0805, 0x00, true, true, 0x00) | 0x082d | "123456789" // CRC-14/DARC
55+
new CRC.Parameters(14, 0x202d, 0x00, false, false, 0x3fff) | 0x30ae | "123456789" // CRC-14/GSM
56+
57+
new CRC.Parameters(15, 0x4599, 0x00, false, false, 0x00) | 0x059e | "123456789" // CRC-15
58+
new CRC.Parameters(15, 0x4599, 0x00, false, false, 0x00) | 0x2857 | longText
59+
new CRC.Parameters(15, 0x6815, 0x00, false, false, 0x0001) | 0x2566 | "123456789" // CRC-15/MPT1327
60+
61+
new CRC.Parameters(21, 0x102899, 0x000000, false, false, 0x000000) | 0x0ed841 | "123456789" // CRC-21/CAN-FD
62+
new CRC.Parameters(24, 0x864cfb, 0xb704ce, false, false, 0x000000) | 0x21cf02 | "123456789" // CRC-24
63+
new CRC.Parameters(24, 0x5d6dcb, 0xfedcba, false, false, 0x000000) | 0x7979bd | "123456789" // CRC-24/FLEXRAY-A
64+
new CRC.Parameters(31, 0x04c11db7, 0x7fffffff, false, false, 0x7fffffff) | 0x0ce9e46c | "123456789" // CRC-31/PHILIPS
3565
}
3666

3767
def "CRC8 Tests"() {

0 commit comments

Comments
 (0)