In the process of cross-language development, we often encounter situations where we need to translate an algorithm or function from one language to another. In this process, block CRC32 translation is a common requirement. However, translating this block CRC32 from Go to JavaScript is not an easy task. In this article, PHP editor Xigua will introduce how to correctly translate this block CRC32 from Go to JavaScript to help developers solve this problem.
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'm trying to translate this to javascript, but I'm 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 results are different. (46e32ed6)
Even without the final XOR I get b91cd129
Can anyone explain to me how to correct this and why this is wrong?
There are two differences:
go implementation has called reflect
(see https://www.php.cn/link/f23775b54b9e62e2d15498c3b9418630):
if t.crcparams.reflectout != t.crcparams.reflectin { ret = reflect(ret, t.crcparams.width) }
in go is
0
(params.finalxor = 0
) and in js it is -1
(return (crc ^ (-1)) phpcngt phpcn>> 0;phpcnendc phpcn)
This is an 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));
The above is the detailed content of How to correctly translate this block CRC32 from Go to JavaScript?. For more information, please follow other related articles on the PHP Chinese website!