Skip to content

Instantly share code, notes, and snippets.

@bryc
Last active July 18, 2022 13:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bryc/5916452ad0d1ef5c39f1a3f19566d315 to your computer and use it in GitHub Desktop.
Save bryc/5916452ad0d1ef5c39f1a3f19566d315 to your computer and use it in GitHub Desktop.
CRC
/*
Cyclic redundancy check (CRC-4, CRC-8, CRC-16, CRC-32)
Common CRC implementation supporting wide range of configurations:
http://reveng.sourceforge.net/crc-catalogue/all.htm
NOTE: These common polynomials are likely suboptimal.
In the future I should make a page of Koopman's best general purpose polynomials.
http://github.com/bryc
*/
// :::::::::::::::: CRC-4/ITU ::::::::::::::::
var crc4 = function(data) {
var POLY = 0xC, INIT = 0, XOROUT = 0;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ data[i];
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
}
return (crc ^ XOROUT) & 0xF;
};
// :::::::::::::::: CRC-4/ITU (lookup table) ::::::::::::::::
var crc4 = function(data) {
var POLY = 0xC, INIT = 0, XOROUT = 0;
for(var crc = 0, i = 0, table = []; i < 256; i++) {
crc = i;
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
table[i] = crc & 0xF;
}
return function(data) {
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = table[data[i] ^ crc & 0xFF] ^ crc >>> 8;
}
return (crc ^ XOROUT) & 0xF;
}
}();
// :::::::::::::::: CRC-8/ITU ::::::::::::::::
var crc8 = function(data) {
var POLY = 0x07, INIT = 0, XOROUT = 0x55;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ data[i];
for(var j = 0; j < 8; j++) {
crc = crc & 0x80 ? crc << 1 ^ POLY : crc << 1;
}
}
return (crc ^ XOROUT) & 0xFF;
};
// :::::::::::::::: CRC-8/ITU (lookup table) ::::::::::::::::
var crc8 = function(data) {
var POLY = 0x07, INIT = 0, XOROUT = 0x55;
for(var crc = INIT, i = 0, table = []; i < 256; i++) {
crc = i;
for(var j = 0; j < 8; j++) {
crc = crc & 0x80 ? crc << 1 ^ POLY : crc << 1;
}
table[i] = crc & 0xFF;
}
return function(data) {
for(var crc = 0, i = 0; i < data.length; i++) {
crc = table[data[i] ^ crc & 0xFF] ^ crc << 8;
}
return (crc ^ XOROUT) & 0xFF;
}
}();
// :::::::::::::::: CRC-16/CCITT ::::::::::::::::
var crc16 = function(data) {
var POLY = 0x8408, INIT = 0, XOROUT = 0;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ data[i];
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
}
return (crc ^ XOROUT) & 0xFFFF;
};
// :::::::::::::::: CRC-16/CCITT (lookup table) ::::::::::::::::
var crc16 = function(data) {
var POLY = 0x8408, INIT = 0, XOROUT = 0;
for(var crc = INIT, i = 0, table = []; i < 256; i++) {
crc = i;
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
table[i] = crc & 0xFFFF;
}
return function(data) {
for(var crc = 0, i = 0; i < data.length; i++) {
crc = table[data[i] ^ crc & 0xFF] ^ crc >>> 8;
}
return (crc ^ XOROUT) & 0xFFFF;
}
}();
//:::::::::::::::: CRC-16/CCITT-FALSE ::::::::::::::::
var crc16b = function(data) {
var POLY = 0x1021, INIT = 0xFFFF, XOROUT = 0;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ (data[i] << 8);
for(var j = 0; j < 8; j++) {
crc = crc & 0x8000 ? crc << 1 ^ POLY : crc << 1;
}
}
return (crc ^ XOROUT) & 0xFFFF;
};
//:::::::::::::::: CRC-16/CCITT-FALSE (lookup table) ::::::::::::::::
var crc16b = function(data) {
var POLY = 0x1021, INIT = 0xFFFF, XOROUT = 0;
for(var crc = 0, i = 0, table = []; i < 256; i++) {
crc = i << 8;
for(var j = 0; j < 8; j++) {
crc = crc & 0x8000 ? crc << 1 ^ POLY : crc << 1;
}
table[i] = crc & 0xFFFF;
}
return function(data) {
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = table[data[i] ^ (crc >>> 8) & 0xFF] ^ crc << 8;
}
return (crc ^ XOROUT) & 0xFFFF;
}
}();
//:::::::::::::::: CRC-32 ::::::::::::::::
var crc32 = function(data) {
var POLY = 0xEDB88320, INIT = -1, XOROUT = -1;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ (data[i]);
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
}
return (crc ^ XOROUT) >>> 0;
};
//:::::::::::::::: CRC-32 (lookup table) ::::::::::::::::
var crc32 = function(data) {
var POLY = 0xEDB88320, INIT = -1, XOROUT = -1;
for(var crc = 0, i = 0, table = []; i < 256; i++) {
crc = i;
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
table[i] = crc >>> 0;
}
return function(data) {
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = table[data[i] ^ crc & 0xFF] ^ crc >>> 8;
}
return (crc ^ XOROUT) >>> 0;
}
}();
//:::::::::::::::: CRC-32/BZIP2 ::::::::::::::::
var crc32b = function(data) {
var POLY = 0x04C11DB7, INIT = -1, XOROUT = -1;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ (data[i] << 24);
for(var j = 0; j < 8; j++) {
crc = crc & 0x80000000 ? crc << 1 ^ POLY : crc << 1;
}
}
return (crc ^ XOROUT) >>> 0;
};
//:::::::::::::::: CRC-32/BZIP2 (lookup table) ::::::::::::::::
var crc32b = function(data) {
var POLY = 0x04C11DB7, INIT = -1, XOROUT = -1;
for(var crc = 0, i = 0, table = []; i < 256; i++) {
crc = i << 16;
for(var j = 0; j < 16; j++) {
crc = crc & 0x80000000 ? crc << 1 ^ POLY : crc << 1;
}
table[i] = crc >>> 0;
}
return function(data) {
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = table[data[i] ^ (crc >>> 24) & 0xFF] ^ crc << 8;
}
return (crc ^ XOROUT) >>> 0;
}
}();
// ---- Important Links -------------------------------------------------------------------------------------
// http://reveng.sourceforge.net/crc-catalogue/all.htm
// https://archive.is/Yjh32#selection-375.0-375.9
// https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Polynomial_representations_of_cyclic_redundancy_checks
// http://crppit.epfl.ch/documentation/Hash_Function/WiKi/Cyclic_redundancy_check.htm
// http://www.zorc.breitbandkatze.de/crc.html
// https://users.ece.cmu.edu/~koopman/crc/crc4.html
// http://www.ross.net/crc/download/crc_v3.txt
// http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html
// just some old crc32 code for posterity
var crc32 = function(data)
{
for(var i=256, tbl=[], crc, j; i--; tbl[i]=crc>>>0){
j=8;for(crc=i;j--;)crc=crc&1?crc>>>1^0xEDB88320:crc>>>1;
}
return function(str) {
for(var i=0, crc=-1; i<data.length; ++i)
crc=tbl[crc&255^data[i]]^crc>>>8;
return crc^-1;
}
}();
// Older implementation
var crc32 = (function(data) {
var table = [];
for (var i = 256, crc; i--;) {
crc = i;
for (var j = 8; j--;) {
if(crc & 1) {
crc = crc >>> 1 ^ 3988292384;
}
else {crc = crc >>> 1;}
}
table[i] = crc;
}
return function (data) {
crc = -1;
for (var i = 0; i < data.length; i++) {
var ptr = crc & 255 ^ data[i];
crc = crc >>> 8 ^ table[ptr];
}
crc = ((crc ^ -1) >>> 0).toString(16).toUpperCase();
return ("00000000" + crc).slice(-8);
}
}());
@zhuhaishen
Copy link

I got a invalid value with this function(data = 'abc', valid result:20810, but got 52380):
var crc16b = function(data) {
var POLY = 0x1021, INIT = 0xFFFF, XOROUT = 0;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ (data[i] << 8);
for(var j = 0; j < 8; j++) {
crc = crc & 0x8000 ? crc << 1 ^ POLY : crc << 1;
}
}
return (crc ^ XOROUT) & 0xFFFF;
};
Then I checked it, and changed data[i] to data.charCodeAt(i) , then got the valid result.

@bryc
Copy link
Author

bryc commented Sep 27, 2019

I got a invalid value with this function(data = 'abc', valid result:20810, but got 52380):
Then I checked it, and changed data[i] to data.charCodeAt(i) , then got the valid result.

Yes these functions take array as input, but you can swap with strings.
These are purely academic. For highly optimized implementations have a look here:
https://gist.github.com/bryc/79d1a62304773285317191f1ae5aa5b8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment