【问题标题】:Implement CRC8 checksum with JS用 JS 实现 CRC8 校验和
【发布时间】:2020-05-23 20:40:10
【问题描述】:

已经尝试过 CRC8,但我无法获得正确的校验和。

有人知道如何使用 JS 生成此校验和吗?

【问题讨论】:

  • This 可能是一个不错的起点。通过谷歌搜索“js crc8”找到它。那里似乎还有许多其他 NPM 包和 github 存储库。
  • 在您的问题中包含这样的信息会非常体贴。否则没有人会知道你尝试了什么。也许您可以阅读thisthis,然后相应地编辑您的问题?就个人而言,如果我看到您尝试过的代码,我更有可能花时间解决您的问题,并解释说“这是我期望的答案,但这是我得到的答案。”
  • 我注意到关于您的示例代码的几件事:您有十六进制字符串,所以我怀疑您希望以 [0x02, 0xfd, 0x10, ...] 结尾。这不是你使用charCodeAt 得到的。 CRC8 的计算方式也有几个变量:多项式、初始化、反射(输入/输出)、异或输出等。一些资源:en.wikipedia.org/wiki/Cyclic_redundancy_checkcrc.drque.net 即使有了这一切,我也找不到方法匹配您的校验和...如果您可以找到任何语言(java、c、python)的代码并给出正确的结果,那可能会有所帮助...
  • 我快速浏览了 Java 代码,看起来移植到 JavaScript 不会太难......除了你的 CRC 表有我找不到的常量。我建立了一个 java 项目并添加了对 org.bouncycastlecom.google.guava 的依赖项......但是标准 google guava 中没有定义十个常量。所有Ascii.fXXXX。如果我没有该 CRC 表的所有值,我无能为力。如果你能给我正确的 maven 依赖,或者你能给我一个这十个常量及其值的列表,也许我可以再看看。
  • 这能回答你的问题吗? Generate a Hash from string in Javascript

标签: javascript bluetooth-lowenergy checksum


【解决方案1】:

这被证明是一个非常棘手的问题,但我想我有一个解决方案。它是 Java 的一个 JavaScript 端口(主要是)。我对代码做了一些简化,以消除似乎不影响答案的事情。

首先,我必须在您的 Java 程序中导出与 CRC8_DATA 等效的十六进制。我只使用了一个简单的bytesToHex 例程就实现了这一点,我发现了here(这部分是用Java 编写的):

System.out.print(bytesToHex(CRC8_DATA));
...
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

一旦我有了这张表,我就将 Java 代码转换为 JavaScript,得到这个:

var CRC8_DATA = '005EBCE2613FDD83C29C7E20A3FD1F419DC3217FFCA2401E5F01E3BD3E6082DC237D9FC1421CFEA0E1BF5D0380DE3C62BEE0025CDF81633D7C22C09E1D43A1FF4618FAA427799BC584DA3866E5BB5907DB856739BAE406581947A5FB7826C49A653BD987045AB8E6A7F91B45C6987A24F8A6441A99C7257B3A6486D85B05E7B98CD2306EEDB3510F4E10F2AC2F7193CD114FADF3702ECC92D38D6F31B2EC0E50AFF1134DCE90722C6D33D18F0C52B0EE326C8ED0530DEFB1F0AE4C1291CF2D73CA947628ABF517490856B4EA6937D58B5709EBB536688AD495CB2977F4AA4816E9B7550B88D6346A2B7597C94A14F6A8742AC896154BA9F7B6E80A54D7896B35';

function strToArr(str) {
  var arr = str.match(/[0-9a-f]{2}/ig); // convert into array of hex pairs
  arr = arr.map(x=> parseInt(x, 16)); // convert hex pairs into ints (bytes)
  return arr;
}

CRC8_DATA = strToArr(CRC8_DATA);

function calculateCRC8(bArr) {
  var i = 1;
  var i2 = bArr.length - 1;
  var b = 0;
  while (i <= i2) {
    b = CRC8_DATA[(b ^ bArr[i]) & 255];
    i++;
  }
  return b;
}

function calcFromString(str) {
  // convert from string to "byte" array
  var byte_array = strToArr(str);
  var checksum = calculateCRC8(byte_array)
  console.log(str, checksum.toString(16));
}

calcFromString('02FD 1000 2322 4978 0140 00AF 6000 0000 0000');
calcFromString('02FD 1000 D82E 4F76 0189 00AF FA14 0000 0000');

原来的Java是以i=1开头的,所以它实际上不包括校验和计算的第一个字节。这可能是许多 JavaScript 库没有给出相同答案的原因之一。

我回去并与此在线CRC calculator 进行了比较。消除第一个字节 (0x02) 时,我能够使用 CRC-8/MAXIM;DOW-CRC 获得等效结果。

即使在删除第一个字节并更改多项式以匹配该网站的多项式之后,我也无法让原始小提琴工作。其他一些选项也必须不同。

【讨论】:

    【解决方案2】:

    JavaScript 中的校验和计算 在默认情况下数字是双浮点数的语言中进行整数按位数学可能非常困难。您的代码必须确保数字保持整数,甚至可能保持无符号并在特定位范围内(16 位、32 位)。这些额外的步骤可能会使事情复杂化。

    技巧 确保数字是 x 位整数的一些技巧是使用 AND 运算符和允许该范围内所有位的位掩码。例如确保 16 位数字可以通过数字 &= 0xffff; 来完成。此外,我使用诸如 num | 之类的操作。 0 或 num >>> 0 以确保它是 32 位整数,有符号或无符号。这是防止产生负面结果所必需的,当您以十六进制显示校验和时,这看起来特别奇怪。

    速度 显然我没有尝试这个来制作一个快速校验和引擎,我只是想在我的 SmallPRNG 和 ISAAC CPRNG 笔之后测试更多的按位计算的可能性(待定;))。这些算法在所有浏览器和浏览器版本中的执行方式都不同,在某些浏览器中甚至可能非常慢。我相信 Chrome 会非常快速地处理数据,并且可以以合理的速度计算校验和!

    基类 我将实现多个校验和算法,因此我将创建一个基类,它将为所选算法构造一个状态 (ctx)。此状态将跟踪校验和和算法类的实例。这个类也会正确处理字符串,考虑到它们的编码。

    该类还包含对 Uint8Array 支持的测试。我不确定这是否是测试支持的最佳方法,但它确实成功了。

    var hasTyped = (function() {
        if(!('Uint8Array' in window)) {
            return false;
        }
    
        try {
            var a = new window.Uint8Array(10);
            a[0] = 100;
            if(a[0] === 100) {
                return true;
            }
            return false;
        } catch (e) {
            return false;
        }
    }());
    

    算法类 现在我们可以使用 Checksum.registerChecksum 添加算法。每个 Algorithm 类都应该实现一个用于处理数据的单个和一个数组方法,以及一个可选的 setup 方法,该方法将在构造 Checksum 对象时调用。

    BSD16 这是一个非常简单的,这个算法只需要一点代码。 BSD校验和算法!

    (function() {
        'use strict';
    
        if(typeof(window.Checksum) === "undefined") {
            throw "The Checksum class is required for this code.";
        }
    
        /**
         * Initialize anything you want in the constructor, such as setting up a lookup
         * table of bytes. Make sure to cache your calculations, so they only have to be
         * done once.
         */
        var BSD16 = function BSD16() {
            this.init = 0;
        };
    
        /**
         * bsd16 for arrays, each value must be numeric and will be bound to 8-bits (Int8Array or Uint8Array works best!)
         * @param   {Array}  a input (8-bit array)
         * @param   {Number} p previous checksum state
         * @returns {Number} new checksum state
         */
        BSD16.prototype.array = function(a, p) {
            var c = p || 0, i = 0, l = a.length;
            for(; i < l; i++) c = (((((c >>> 1) + ((c & 1) << 15)) | 0) + (a[i] & 0xff)) & 0xffff) | 0;
            return c;
        };
    
        /**
         * bsd16 for a single value, update a checksum with a new byte
         * @param   {Number} b byte (0-255)
         * @param   {Number} p previous checksum state
         * @returns {Number} new checksum state
         */
        BSD16.prototype.single = function(b, p) {
            var c = p || 0;
            return (((((c >>> 1) + ((c & 1) << 15)) | 0) + (b & 0xff)) & 0xffff) | 0;
        };
    
        Checksum.registerChecksum("bsd16", BSD16);
    }());
    

    FNV32(FNV-0 和 FNV-1)

    另一个简单的算法,FNV 哈希算法 - 生成 32 位校验和!

    (function() {
        'use strict';
    
        if(typeof(window.Checksum) === "undefined") {
            throw "The Checksum class is required for this code.";
        }
    
        var prime = 0x01000193;
    
        /**
         * Initialize anything you want in the constructor, such as setting up a lookup
         * table of bytes. Make sure to cache your calculations, so they only have to be
         * done once.
         */
        var FNV32 = function FNV32() {
            this.init = 2166136261; // fnv-1!
        };
    
        /**
         * The setup method which will be called when new Checksum("fletcher", ...) is called.
         * This method is supposed to initialize the checksum cipher and to recieve parameters
         * from the constructor.
         *
         * @param {Number} mode the FNV32 mode (FNV-1 (defualt) or FNV-0)
         */
        FNV32.prototype.setup = function(mode) {
            if(mode === 0) {
                this.init = 0; // fnv-0.
            }
        };
    
        FNV32.prototype.array = function(a, p) {
            var len = a.length,
                fnv = p || this.init;
    
            for(var i = 0; i < len; i++) {
                fnv = (fnv + (((fnv << 1) + (fnv << 4) + (fnv << 7) + (fnv << 8) + (fnv << 24)) >>> 0)) ^ (a[i] & 0xff);
            }
    
            return fnv >>> 0;
        };
    
        FNV32.prototype.single = function(b, p) {
            var fnv = p || this.init;
            return ((fnv + (((fnv << 1) + (fnv << 4) + (fnv << 7) + (fnv << 8) + (fnv << 24)) >>> 0)) ^ (b & 0xff)) >>> 0;
        };
    
        Checksum.registerChecksum("fnv32", FNV32);
    }());
    

    您可以使用此网址阅读全文

    https://codepen.io/ImagineProgramming/post/checksum-algorithms-in-javascript-checksum-js-engine?cf_chl_jschl_tk=39bd0de9934c580b6ce33374feddb9c37ee59c20-1590266531-0-AcdpYddIKyEBHAf0tuLzYDLpqpVAYrXmTKfWqF_3OLQVepxEcJq9z0gjYtxrVssDX487qBCful5gnyyFlqtl1fUzzH-lQXJhSZkUquU7GWLTAWAMbH2st22M1Ef6NxBfdHZKL5K0oLWb7gU88-MWOVWW3Ioponmmm7GVfHqSL7bdGcrSZIWjw_U2hKl57DXPw8YO3eWcykQnewEQPVOV7mQV5MlHPf17K-_Doo9NOoOtFJUQGHZyLJL2ANJAiWP98nK6vBZcIyLh69YUbuYFFgYB7uRmzfnb-NKCFLDbRUTBaq0I6Xr_blRfzAsyen4Jc-7bWN0cvNlKPQzViAxIR68edJx4gYcFIOrJiu-kQmmMQJMcHuwZFuvWCqAYLQEPX63ttncdhJUEXU8ThjhPhiHNPwX4FjzI1PxLRMH8Hoj1GlIur1DyZDxwz-4t64Pwqg

    【讨论】:

    • 感谢 Fouad,但看起来它们都不符合预期的结果
    猜你喜欢
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-14
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2016-04-13
    相关资源
    最近更新 更多