Javascript CRC32C实现与Intel的SSE4.2硬件实现兼容

时间:2014-01-28 18:29:02

标签: javascript node.js polynomial-math crc32

在我开始之前,免责声明:虽然我可以使用C / C ++代码,但我不是巫师,也没有做过足够的编程来称呼自己是一个有能力的程序员。

我正在尝试使用CRC32C验证从浏览器进入我们服务器的数据。目前这两个实现都使用相同的代码(服务器上的nodeJS),但我们希望切换到硬件实现(blog postgithub repo)(如果可用),为此我需要一个正确运行的版本浏览器。

我尝试使用this implementation(和另一个,内部开发,但也没有工作),但使用正确的多项式(0x82F63B78代替0xEDB88320,以及{{1} }& 0x1EDC6F41)但我没有使用多项生成正确的输出。

继续我的研究,我发现了Mark Adler的帖子,其中包含一个软件实现,并决定尝试将其转换为Javascript(据我所知C)。

结果:

0x8F6E37A0

仍然没有运气。无论我使用什么函数,什么表或什么多项式,结果都不匹配:

function crc32c_table_intel() {
var POLY = 0x82f63b78;
var n, crc, k;
var crc32c_table = gen2darr(8, 256, 0);

for (n = 0; n < 256; n++) {
    crc = n;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    crc32c_table[0][n] = crc;
}
for (n = 0; n < 256; n++) {
    crc = crc32c_table[0][n];
    for (k = 1; k < 8; k++) {
        crc = crc32c_table[0][crc & 0xff] ^ (crc >> 8);
        crc32c_table[k][n] = crc;
      _crc_tmptable.push(crc32c_table[k][n]);
    }
}
return crc32c_table;
}


function crc32c_sw(crci, str) {
var len = str.length;
var crc;
var crc32c_table = crc32c_table_intel();

crc = crci ^ 0xffffffff;
for(var next = 0; next < 7; next++) { // was: while (len && ((uintptr_t)next & 7) != 0) {
    crc = crc32c_table[0][(crc ^ str.charCodeAt(next++)) & 0xff] ^ (crc >> 8);
    len--;
}
while (len >= 8) {
    // was: crc ^= *(uint64_t *)next;
    crc ^= str.charCodeAt(next);
    crc = crc32c_table[7][crc & 0xff] ^
          crc32c_table[6][(crc >> 8) & 0xff] ^
          crc32c_table[5][(crc >> 16) & 0xff] ^
          crc32c_table[4][(crc >> 24) & 0xff] ^
          crc32c_table[3][(crc >> 32) & 0xff] ^
          crc32c_table[2][(crc >> 40) & 0xff] ^
          crc32c_table[1][(crc >> 48) & 0xff] ^
          crc32c_table[0][crc >> 56];
    next += 1;
    len -= 1;
}
while (len) {
    // was: crc = crc32c_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
    crc = crc32c_table[0][(crc ^ str.charCodeAt(next++)) & 0xff] ^ (crc >> 8);
    len--;
}
return crc ^ 0xffffffff;
}


// a helper function
function gen2darr( rows, cols, defaultValue){
    var arr = [];
    for(var i=0; i < rows; i++){
            arr.push([]);
            arr[i].push( new Array(cols));
            for(var j=0; j < cols; j++){
                    arr[i][j] = defaultValue;
                    }
            }
    return arr;
}

然后我认为它必须是从Javascript字符串转换为C / C ++数据的东西,我看到nodeJS实现使用UTF8(https://github.com/Voxer/sse4_crc32/blob/master/src/sse4_crc32.cpp#L56),而Javascript使用UCS-2编码。

现在,我的问题是:

  1. 这些功能中的任何一个都有效吗?第一个似乎是这样,对于我发布的那个,我不确定我是否正确地翻译了所有的按位操作
  2. 如何解决编码问题?这是否是我怀疑的编码问题?有没有人有任何其他想法如何确保nodeJS HW实现和客户端实现返回相同的输出?
  3. 感谢您的任何想法!

1 个答案:

答案 0 :(得分:2)

有关兼容的软件实现和使用硬件指令的快速实现,请参阅this answer

你有一些问题。一个是在Javascript中你需要使用逻辑右移>>>而不是算术右移>>。其次是您正在使用charCodeAt,它返回一个字符的Unicode值,该值可能超过一个字节。 CRC算法对字节序列进行操作,而不是Unicode字符序列。第三,你每次都在计算相同的表 - 表只应计算一次。最后,你正在直接进入一个复杂的实现。

作为一个简单的例子,这将在Javascript中计算一个值为0..255的整数值的数组中的CRC-32C,即字节:

function crc32c(crc, bytes) {
  var POLY = 0x82f63b78;
  var n;

  crc ^= 0xffffffff;
  for (n = 0; n < bytes.length; n++) {
    crc ^= bytes[n];
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
    crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
  }
  return crc ^ 0xffffffff;
}