Reputation: 9857
I have this function in Go:
package main
import (
"fmt"
"github.com/snksoft/crc"
)
var crcTable *crc.Table
func init() {
params := crc.CRC32
params.FinalXor = 0
params.ReflectOut = false
crcTable = crc.NewTable(params)
}
func crcCalculateBlock(data []byte) uint32 {
if len(data)%4 > 0 {
panic("block size needs to be a multiple of 4")
}
h := crc.NewHashWithTable(crcTable)
var buf [4]byte
for i := 0; i < len(data); i += 4 {
buf[0] = data[i+3]
buf[1] = data[i+2]
buf[2] = data[i+1]
buf[3] = data[i+0]
h.Update(buf[:])
}
return h.CRC32()
}
func main() {
data := []byte{1, 2, 3, 4, 5, 6, 7, 8}
crc := crcCalculateBlock([]byte(data))
fmt.Printf("CRC is 0x%04X\n", crc)
}
The result is: 0x948B389D
I am trying to translate it to JavaScript but I am missing something:
var makeCRCTable = function(){
var c;
var crcTable = [];
for(var n =0; n < 256; n++){
c = n;
for(var k =0; k < 8; k++){
c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
crcTable[n] = c;
}
return crcTable;
}
var crc32 = function(u8array) {
var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
var crc = 0 ^ (-1);
for (var i = 0; i < u8array.length; i+=4 ) {
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i+3]) & 0xFF];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i+2]) & 0xFF];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i+1]) & 0xFF];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i]) & 0xFF];
}
return (crc ^ (-1)) >>> 0;
};
console.log(crc32(Uint8Array.from([1,2,3,4,5,6,7,8])).toString(16))
but the result is different. ( 46e32ed6 )
even without the final xor I get b91cd129
Can anyone explain to me how to correct that and why is that wrong?
Upvotes: 0
Views: 153
Reputation: 7485
There are two differences:
the Go implementation has called reflect
(see https://github.com/snksoft/crc/blob/03404db21ad4e7182edf4843b51f6252799f7140/crc.go#L168-L170):
if t.crcParams.ReflectOut != t.crcParams.ReflectIn {
ret = reflect(ret, t.crcParams.Width)
}
the FinalXor
in Go is 0
(params.FinalXor = 0
) while in js it's -1
(return (crc ^ (-1)) >>> 0;
)
Here is the updated js implementation that generates the same hash value.
var makeCRCTable = function () {
var c;
var crcTable = [];
for (var n = 0; n < 256; n++) {
c = n;
for (var k = 0; k < 8; k++) {
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
}
crcTable[n] = c;
}
return crcTable;
};
var crc32 = function (u8array) {
var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
var crc = 0 ^ -1;
for (var i = 0; i < u8array.length; i += 4) {
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i + 3]) & 0xff];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i + 2]) & 0xff];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i + 1]) & 0xff];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i]) & 0xff];
}
crc = reverseBits(crc, 32);
return (crc ^ 0) >>> 0;
};
function reverseBits(integer, bitLength) {
if (bitLength > 32) {
throw Error(
'Bit manipulation is limited to <= 32 bit numbers in JavaScript.'
);
}
let result = 0;
for (let i = 0; i < bitLength; i++) {
result |= ((integer >> i) & 1) << (bitLength - 1 - i);
}
return result >>> 0; // >>> 0 makes it unsigned even if bit 32 (the sign bit) was set
}
console.log(crc32(Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8])).toString(16));
Note: the reverseBits
function is copied from this answer: https://stackoverflow.com/a/67064710/1369400
Upvotes: 3
Reputation: 9857
Thanks to Zeke Lu, I prefer this code.
function rev(x) {
x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);
x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);
x = ((x >> 4) & 0x0F0F0F0F) | ((x & 0x0F0F0F0F) << 4);
x = ((x >> 8) & 0x00FF00FF) | ((x & 0x00FF00FF) << 8);
x = (x >>> 16) | (x << 16);
return x >>> 0;
}
var makeCRCTable = function(){
var c;
var crcTable = [];
for(var n =0; n < 256; n++){
c = n;
for(var k =0; k < 8; k++){
c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
crcTable[n] = c;
}
return crcTable;
}
var crc32 = function(u8array) {
var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
var crc = 0 ^ (-1);
for (var i = 0; i < u8array.length; i+=4 ) {
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i+3]) & 0xFF];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i+2]) & 0xFF];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i+1]) & 0xFF];
crc = (crc >>> 8) ^ crcTable[(crc ^ u8array[i]) & 0xFF];
}
return rev(crc);
};
console.log(crc32(Uint8Array.from([1,2,3,4,5,6,7,8])).toString(16))
Upvotes: 0