From 2c65ff2cc75bea01241c58db61a05a614f33ca61 Mon Sep 17 00:00:00 2001 From: snksoft Date: Fri, 10 Jun 2016 21:52:52 +1200 Subject: [PATCH] Implemented --- .gitignore | 1 + LICENSE | 24 ++ README.md | 51 +++ pom.xml | 78 ++++ src/main/java/com/github/snksoft/crc/CRC.java | 339 ++++++++++++++++++ .../com/github/snksoft/crc/CrcSpec.groovy | 212 +++++++++++ 6 files changed, 705 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/com/github/snksoft/crc/CRC.java create mode 100644 src/test/groovy/com/github/snksoft/crc/CrcSpec.groovy diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9e3524d --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2016, S&K Software Development Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the S&K Software Development Ltd nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..34a5b88 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +This package implements generic CRC calculations up to 64 bits wide. +It aims to be fairly fast and fairly complete, allowing users to match pretty much +any CRC algorithm used in the wild by choosing appropriate Parameters. This obviously +includes all popular CRC algorithms, such as CRC64-ISO, CRC64-ECMA, CRC32, CRC32C, CRC16, CCITT, XMODEM and many others. +See http://reveng.sourceforge.net/crc-catalogue/ for a good list of CRC algorithms and their parameters. + +This package has been largely inspired by Ross Williams' 1993 paper "A Painless Guide to CRC Error Detection Algorithms". + + +## Usage + +Using src is easy. Here is an example of calculating CCITT crc. +```java +import com.github.snksoft.crc.CRC; + +public class Example +{ + public static void main(String [] args) { + String data = "123456789"; + long ccittCrc = CRC.calculateCRC(CRC.Parameters.CCITT, data.getBytes()); + System.out.printf("CRC is 0x%04X\n", ccittCrc); // prints "CRC is 0x29B1" + + } +} +``` + +For larger data, table driven implementation is faster. Here is how to use it. +```java +import com.github.snksoft.crc.CRC; + +public class Example +{ + public static void main(String [] args) { + String data = "123456789"; + CRC tableDriven = new CRC(CRC.Parameters.XMODEM); + long xmodemCrc = tableDriven.calculateCRC(data.getBytes()); + System.out.printf("CRC is 0x%04X\n", xmodemCrc); // prints "CRC is 0x31C3" + + // You can also reuse CRC object instance for another crc calculation. + // Given that the only state for a CRC calculation is the "intermediate value" + // and it is stored in your code, you can even use same CRC instance to calculate CRC + // of multiple data sets in parallel. + // And if data is too big, you may feed it in chunks + long curValue = tableDriven.init(); // initialize intermediate value + curValue = tableDriven.update(curValue, "123456789".getBytes()); // feed first chunk + curValue = tableDriven.update(curValue, "01234567890".getBytes()); // feed next chunk + long xmodemCrc2 = tableDriven.finalCRC(curValue); // gets CRC of whole data ("12345678901234567890") + System.out.printf("CRC is 0x%04X\n", xmodemCrc2); // prints "CRC is 0x2C89" + } +} +``` diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..dd7e2c8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,78 @@ + + 4.0.0 + + com.github.snksoft + java-crc + 1.0-SNAPSHOT + jar + + Generic CRC implementation for java + https://github.com/snksoft/java-crc + + + UTF-8 + UTF-8 + + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + 1.4 + + + + compile + testCompile + + + + + + + + maven-surefire-plugin + 2.6 + + false + + **/*Spec.java + + + + + + maven-deploy-plugin + 2.5 + + true + + + + + + + + + org.codehaus.groovy + groovy-all + 2.4.1 + compile + + + + org.spockframework + spock-core + 1.0-groovy-2.4 + compile + + + + + + diff --git a/src/main/java/com/github/snksoft/crc/CRC.java b/src/main/java/com/github/snksoft/crc/CRC.java new file mode 100644 index 0000000..33d3aec --- /dev/null +++ b/src/main/java/com/github/snksoft/crc/CRC.java @@ -0,0 +1,339 @@ +package com.github.snksoft.crc; + +// Copyright 2016, S&K Software Development Ltd. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package crc implements generic CRC calculations up to 64 bits wide. +// It aims to be fairly complete, allowing users to match pretty much +// any CRC algorithm used in the wild by choosing appropriate Parameters. +// And it's also fairly fast for everyday use. +// +// This package has been largely inspired by Ross Williams' 1993 paper "A Painless Guide to CRC Error Detection Algorithms". +// A good list of parameter sets for various CRC algorithms can be found at http://reveng.sourceforge.net/crc-catalogue/. + +/** + * This class provides utility functions for CRC calculation using either canonical straight forward approach + * or using "fast" table-driven implementation. Note, that even though table-driven implementation is much faster + * for processing large amounts of data and is commonly referred as fast algorithm, sometimes it might be quicker to + * calculate CRC using canonical algorithm then to prepare the table for table-driven implementation. + * */ +public class CRC +{ + /** + * Parameters represents set of parameters defining a particular CRC algorithm. + * */ + public static class Parameters + { + private int width; // Width of the CRC expressed in bits + private long polynomial; // Polynomial used in this CRC calculation + private boolean reflectIn; // Refin indicates whether input bytes should be reflected + private boolean reflectOut; // Refout indicates whether input bytes should be reflected + private long init; // Init is initial value for CRC calculation + private long finalXor; // Xor is a value for final xor to be applied before returning result + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) + { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(Parameters orig) + { + width = orig.width; + polynomial = orig.polynomial; + reflectIn = orig.reflectIn; + reflectOut = orig.reflectOut; + init = orig.init; + finalXor = orig.finalXor; + } + + public int getWidth() + { + return width; + } + + public long getPolynomial() + { + return polynomial; + } + + public boolean isReflectIn() + { + return reflectIn; + } + + public boolean isReflectOut() + { + return reflectOut; + } + + public long getInit() + { + return init; + } + + public long getFinalXor() + { + return finalXor; + } + + /** CCITT CRC parameters */ + public static final Parameters CCITT = new Parameters(16, 0x1021, 0x00FFFF, false, false, 0x0); + /** CRC16 CRC parameters, also known as ARC */ + public static final Parameters CRC16 = new Parameters(16, 0x8005, 0x0000, true, true, 0x0); + /** XMODEM is a set of CRC parameters commonly referred as "XMODEM" */ + public static final Parameters XMODEM = new Parameters(16, 0x1021, 0x0000, false, false, 0x0); + /** XMODEM2 is another set of CRC parameters commonly referred as "XMODEM" */ + public static final Parameters XMODEM2 = new Parameters(16, 0x8408, 0x0000, true, true, 0x0); + + /** CRC32 is by far the the most commonly used CRC-32 polynom and set of parameters */ + public static final Parameters CRC32 = new Parameters(32, 0x04C11DB7, 0x00FFFFFFFFL, true, true, 0x00FFFFFFFFL); + /** IEEE is an alias to CRC32 */ + public static final Parameters IEEE = CRC32; + /** Castagnoli polynomial. used in iSCSI. And also provided by hash/crc32 package. */ + public static final Parameters Castagnoli = new Parameters(32, 0x1EDC6F41L, 0x00FFFFFFFFL, true, true, 0x00FFFFFFFFL); + /** CRC32C is an alias to Castagnoli */ + public static final Parameters CRC32C = Castagnoli; + /** Koopman polynomial */ + public static final Parameters Koopman = new Parameters(32, 0x741B8CD7L, 0x00FFFFFFFFL, true, true, 0x00FFFFFFFFL); + + /** CRC64ISO is set of parameters commonly known as CRC64-ISO */ + public static final Parameters CRC64ISO = new Parameters(64, 0x000000000000001BL, 0xFFFFFFFFFFFFFFFFL, true, true, 0xFFFFFFFFFFFFFFFFL); + /** CRC64ECMA is set of parameters commonly known as CRC64-ECMA */ + public static final Parameters CRC64ECMA = new Parameters(64, 0x42F0E1EBA9EA3693L, 0xFFFFFFFFFFFFFFFFL, true, true, 0xFFFFFFFFFFFFFFFFL); + + } + + /** + * Reverses order of last count bits. + * @param in value wich bits need to be reversed + * @param count indicates how many bits be rearranged + * @return the value with specified bits order reversed + */ + private static long reflect(long in, int count) + { + long ret = in; + for (int idx = 0; idx < count; idx++) + { + long srcbit = 1L << idx; + long dstbit = 1L << (count - idx - 1); + if ((in & srcbit) != 0) + { + ret |= dstbit; + } + else + { + ret = ret & (~dstbit); + } + } + return ret; + } + + /** + * This method implements simple straight forward bit by bit calculation. + * It is relatively slow for large amounts of data, but does not require + * any preparation steps. As a result, it might be faster in some cases + * then building a table required for faster calculation. + * @param crcParams CRC algorithm parameters + * @param data data for the CRC calculation + * @return the CRC value of the data provided + */ + public static long calculateCRC(Parameters crcParams, byte[] data) + { + long curValue =crcParams.init; + long topBit = 1L << (crcParams.width - 1); + long mask = (topBit << 1) - 1; + + for (int i=0; i< data.length; i++) + { + long curByte = ((long)(data[i])) & 0x00FFL; + if (crcParams.reflectIn) + { + curByte = reflect(curByte, 8); + } + curValue ^= (curByte << (crcParams.width - 8)); + for (int j=0; j< 8; j++) + { + if ((curValue & topBit)!=0) + { + curValue = (curValue << 1) ^ crcParams.polynomial; + } + else + { + curValue = (curValue << 1); + } + } + + } + + if (crcParams.reflectOut) + { + curValue = reflect(curValue, crcParams.width); + } + + curValue = curValue ^ crcParams.finalXor; + + return curValue & mask; + } + + private Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + /** + * Returns initial value for this CRC intermediate value + * This method is used when starting a new iterative CRC calculation (using init, update + * and finalCRC methods, possibly supplying data in chunks). + * @return initial value for this CRC intermediate value + */ + public long init() + { + return initValue; + } + + /** + * This method is used to feed data when performing iterative CRC calculation (using init, update + * and finalCRC methods, possibly supplying data in chunks). It can be called multiple times per + * CRC calculation to feed data to be processed in chunks. + * @param curValue CRC intermediate value so far + * @param chunk data chunk to b processed by this call + * @param offset is 0-based offset of the data to be processed in the array supplied + * @param length indicates number of bytes to be processed. + * @return updated intermediate value for this CRC + * */ + public long update (long curValue, byte[] chunk, int offset, int length) + { + if (crcParams.reflectIn) + { + for (int i=0; i < length; i++) + { + byte v = chunk[offset+i]; + curValue = crctable[(((byte)curValue) ^ v)&0x00FF]^(curValue >>> 8); + } + } + else + { + for (int i=0; i < length; i++) + { + byte v = chunk[offset+i]; + curValue = crctable[((((byte)(curValue >>> (crcParams.width - 8))) ^ v)&0xFF)]^(curValue << 8); + } + } + + return curValue; + } + + /** + * A convenience method for feeding a complete byte array of data. + * @param curValue CRC intermediate value so far + * @param chunk data chunk to b processed by this call + * @return updated intermediate value for this CRC + * */ + public long update (long curValue, byte[] chunk) + { + return update(curValue, chunk, 0, chunk.length); + } + + /** + * This method should be called to retrieve actual CRC for the data processed so far. + * @param curValue CRC intermediate value so far + * @return calculated CRC + * */ + public long finalCRC(long curValue) + { + long ret=curValue; + if (crcParams.reflectOut != crcParams.reflectIn) + { + ret = reflect(ret, crcParams.width); + } + return (ret ^ crcParams.finalXor) & mask; + } + + /** + * A convenience method allowing to calculate CRC in one call. + * @param data is data to calculate CRC on + * @return calculated CRC + * */ + public long calculateCRC(byte[] data) + { + long crc = init(); + crc = update(crc, data); + return finalCRC(crc); + } + + /** + * Constructs a new CRC processor for table based CRC calculations. + * Underneath, it just calls finalCRC() method. + * @param crcParams CRC algorithm parameters + */ + public CRC(Parameters crcParams) + { + this.crcParams = new Parameters(crcParams); // TODO: implement copy constructor; + + initValue = (crcParams.reflectIn) ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = ((crcParams.width>=64) ? 0 : (1L << crcParams.width)) - 1; + this.crctable = new long[256]; + + byte[] tmp = new byte[1]; + + Parameters tableParams = new Parameters(crcParams); + + tableParams.init = 0; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0; + for (int i=0; i< 256; i++) + { + tmp[0] = (byte)i; + crctable[i] = CRC.calculateCRC(tableParams, tmp); + } + } + + /** + * Is a convenience method to spare end users from explicit type conversion every time this package is used. + * Underneath, it just calls finalCRC() method. + * @param curValue current intermediate crc state value + * @return the final CRC value + * @throws RuntimeException if crc being calculated is not 8-bit + */ + public byte finalCRC8 (long curValue) + { + if (crcParams.width != 8) + throw new RuntimeException("CRC width mismatch"); + return (byte) finalCRC(curValue); + } + + /** + * Is a convenience method to spare end users from explicit type conversion every time this package is used. + * Underneath, it just calls finalCRC() method. + * @param curValue current intermediate crc state value + * @return the final CRC value + * @throws RuntimeException if crc being calculated is not 16-bit + */ + public short finalCRC16 (long curValue) + { + if (crcParams.width != 16) + throw new RuntimeException("CRC width mismatch"); + return (short) finalCRC(curValue); + } + + /** + * Is a convenience method to spare end users from explicit type conversion every time this package is used. + * Underneath, it just calls finalCRC() method. + * @param curValue current intermediate crc state value + * @return the final CRC value + * @throws RuntimeException if crc being calculated is not 32-bit + */ + public int finalCRC32(long curValue) + { + if (crcParams.width != 32) + throw new RuntimeException("CRC width mismatch"); + return (int) finalCRC(curValue); + } + +} diff --git a/src/test/groovy/com/github/snksoft/crc/CrcSpec.groovy b/src/test/groovy/com/github/snksoft/crc/CrcSpec.groovy new file mode 100644 index 0000000..7cdfc40 --- /dev/null +++ b/src/test/groovy/com/github/snksoft/crc/CrcSpec.groovy @@ -0,0 +1,212 @@ +package com.github.snksoft.crc; + +import spock.lang.Specification + +class CrcSpec extends Specification{ + + def "CRC8 Tests"() { + + when: + byte[] dataBytes = data.getBytes() + long calculated1 = CRC.calculateCRC(crcParams, dataBytes) + + // same test using table driven + CRC tableDriven = new CRC(crcParams) + long calculated2 = tableDriven.calculateCRC(dataBytes) + + // same test feeding data in chunks of different size + long curValue = tableDriven.init() + int start = 0 + int step = 1 + while (start < dataBytes.length) + { + int end = start + step + if (end > dataBytes.length) + { + end = dataBytes.length + } + curValue = tableDriven.update(curValue, dataBytes, start, end-start) + start = end + step *= 2 + } + byte calculated3 = tableDriven.finalCRC8(curValue) + + then: + calculated1 == crc + calculated2 == crc + calculated3 == (byte)(crc & 0x00FF) + + where: + crcParams | crc | data + new CRC.Parameters(8, 0x07, 0, false, false, 0) | 0xf4 | "123456789" + } + + def "CRC16 Tests"() { + + when: + byte[] dataBytes = data.getBytes() + long calculated1 = CRC.calculateCRC(crcParams, dataBytes) + + // same test using table driven + CRC tableDriven = new CRC(crcParams) + long calculated2 = tableDriven.calculateCRC(dataBytes) + + // same test feeding data in chunks of different size + long curValue = tableDriven.init() + int start = 0 + int step = 1 + while (start < dataBytes.length) + { + int end = start + step + if (end > dataBytes.length) + { + end = dataBytes.length + } + curValue = tableDriven.update(curValue, dataBytes, start, end-start) + start = end + step *= 2 + } + short calculated3 = tableDriven.finalCRC16(curValue) + + then: + calculated1 == crc + calculated2 == crc + calculated3 == (short)(crc & 0x0000FFFF) + + where: + crcParams | crc | data + CRC.Parameters.CCITT | 0x29B1 | "123456789" + CRC.Parameters.CCITT | 0xDA31 | "12345678901234567890" + CRC.Parameters.CCITT | 0xC87E | "Introduction on CRC calculations" + CRC.Parameters.CCITT | 0xD6ED | "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." + + CRC.Parameters.XMODEM | 0x31C3 | "123456789" + CRC.Parameters.XMODEM | 0x2C89 | "12345678901234567890" + CRC.Parameters.XMODEM | 0x3932 | "Introduction on CRC calculations" + CRC.Parameters.XMODEM | 0x4E86 | "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." + + CRC.Parameters.XMODEM2 | 0x0C73 | "123456789" + CRC.Parameters.XMODEM2 | 0x122E | "12345678901234567890" + CRC.Parameters.XMODEM2 | 0x0638 | "Introduction on CRC calculations" + CRC.Parameters.XMODEM2 | 0x187A | "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." + } + + + def "CRC32 Tests"() { + + when: + byte[] dataBytes = data.getBytes() + long calculated1 = CRC.calculateCRC(crcParams, dataBytes) + + // same test using table driven + CRC tableDriven = new CRC(crcParams) + long calculated2 = tableDriven.calculateCRC(dataBytes) + + // same test feeding data in chunks of different size + long curValue = tableDriven.init() + int start = 0 + int step = 1 + while (start < dataBytes.length) + { + int end = start + step + if (end > dataBytes.length) + { + end = dataBytes.length + } + curValue = tableDriven.update(curValue, dataBytes, start, end-start) + start = end + step *= 2 + } + short calculated3 = tableDriven.finalCRC32(curValue) + + then: + calculated1 == crc + calculated2 == crc + calculated3 == (short)(crc & 0x0000FFFF) + + when: + tableDriven.finalCRC16(curValue) + then: + thrown RuntimeException + when: + tableDriven.finalCRC8(curValue) + then: + thrown RuntimeException + + where: + crcParams | crc | data + CRC.Parameters.CRC32 | 0xCBF43926 | "123456789" + CRC.Parameters.CRC32 | 0x906319F2 | "12345678901234567890" + CRC.Parameters.CRC32 | 0x814F2B45 | "Introduction on CRC calculations" + CRC.Parameters.CRC32 | 0x8F273817 | "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." + + CRC.Parameters.Castagnoli | 0xE3069283 | "123456789" + CRC.Parameters.Castagnoli | 0xA8B4A6B9 | "12345678901234567890" + CRC.Parameters.Castagnoli | 0x54F98A9E | "Introduction on CRC calculations" + CRC.Parameters.Castagnoli | 0x864FDAFC | "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." + + CRC.Parameters.Koopman | 0x2D3DD0AE | "123456789" + CRC.Parameters.Koopman | 0xCC53DEAC | "12345678901234567890" + CRC.Parameters.Koopman | 0x1B8101F9 | "Introduction on CRC calculations" + CRC.Parameters.Koopman | 0xA41634B2 | "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." + } + + def "CRC64 Tests"() { + + when: + byte[] dataBytes = data.getBytes() + long calculated1 = CRC.calculateCRC(crcParams, dataBytes) + + // same test using table driven + CRC tableDriven = new CRC(crcParams) + long calculated2 = tableDriven.calculateCRC(dataBytes) + + // same test feeding data in chunks of different size + long curValue = tableDriven.init() + int start = 0 + int step = 1 + while (start < dataBytes.length) + { + int end = start + step + if (end > dataBytes.length) + { + end = dataBytes.length + } + curValue = tableDriven.update(curValue, dataBytes, start, end-start) + start = end + step *= 2 + } + long calculated3 = tableDriven.finalCRC(curValue) + + then: + calculated1 == crc + calculated2 == crc + calculated3 == crc + + when: + tableDriven.finalCRC32(curValue) + then: + thrown RuntimeException + when: + tableDriven.finalCRC16(curValue) + then: + thrown RuntimeException + when: + tableDriven.finalCRC8(curValue) + then: + thrown RuntimeException + + where: + crcParams | crc | data + CRC.Parameters.CRC64ISO | 0xB90956C775A41001L | "123456789" +// CRC.Parameters.CRC64ISO | 0x8DB93749FB37B446L | "12345678901234567890" +// CRC.Parameters.CRC64ISO | 0xBAA81A1ED1A9209BL | "Introduction on CRC calculations" +// CRC.Parameters.CRC64ISO | 0x347969424A1A7628L | "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." +// +// CRC.Parameters.CRC64ECMA | 0x995DC9BBDF1939FAL | "123456789" +// CRC.Parameters.CRC64ECMA | 0x0DA1B82EF5085A4AL | "12345678901234567890" +// CRC.Parameters.CRC64ECMA | 0xCF8C40119AE90DCBL | "Introduction on CRC calculations" +// CRC.Parameters.CRC64ECMA | 0x31610F76CFB272A5L | "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." + } + +}