简体   繁体   English

使用Boost计算ECMA-128 64位CRC

[英]Use Boost to compute ECMA-128 64bit CRC

With the following program I'm trying to compute a 64bit CRC as per the ECMA-128 standard . 通过以下程序,我尝试根据ECMA-128标准计算64位CRC

The test data is "123456789" and I'm trying to match the same data provided here which suggests that the result for CRC-64/ECMA-182 should be 62ec59e3f1a4f00a. 测试数据为“ 123456789”,我尝试匹配此处提供的相同数据,这表明CRC-64 / ECMA-182的结果应为62ec59e3f1a4f00a。 Unfortunately I get 9d13a61c0e5b0ff5 which is the CRC-64/WE result. 不幸的是我得到9d13a61c0e5b0ff5这是CRC-64 / WE结果。

I started with the sample code provided here . 我从这里提供的示例代码开始。 I created the 64 bit hashes with the normal polynomial representation of 0x42F0E1EBA9EA3693 for the ECMA-128 64bit crc. 我为ECMA-128 64位crc创建了具有0x42F0E1EBA9EA3693的普通多项式表示形式的64位哈希。


I get the following VS warning: C4293: '<<': shift count negative or too big, undefined behavior. 我收到以下VS警告:C4293:'<<':移位计数为负数或太大,不确定的行为。 It is for this macro: 它用于此宏:

BOOST_STATIC_CONSTANT( least, sig_bits = (~( ~(least( 0u )) << Bits )) );

As far as I can tell the 0 is being bit shifted by the full range of 64 bits which is undefined behavior. 据我所知, 0正在移位64位的全部范围,这是未定义的行为。 I'm surprised I don't see this warning for the 32bit crc. 我很惊讶我没有看到针对32位crc的警告。


How can this program be corrected to calculate an ECMA-128 64bit crc correctly without undefined behavior? 如何纠正此程序以正确计算ECMA-128 64bit crc而没有未定义的行为?

// from https://www.boost.org/doc/libs/1_67_0/libs/crc/crc.html#usage
#include <boost/crc.hpp>      // for boost::crc_basic, boost::crc_optimal
#include <boost/cstdint.hpp>  // for boost::uint16_t
#include <algorithm>  // for std::for_each
#include <cassert>    // for assert
#include <cstddef>    // for std::size_t
#include <iostream>   // for std::cout
#include <ostream>    // for std::endl

//#define SHOW_ERROR

#if defined( SHOW_ERROR )
#define CRC ecma_crc // expected
#else 
#define CRC other_crc // actually received
#endif

int main()
{
    // This is "123456789" in ASCII
    unsigned char const  data[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
    std::size_t const    data_len = sizeof(data) / sizeof(data[0]);

    // The expected CRC for the given data
    boost::uint16_t const  expected = 0x29B1;
    // Expected CRCs for "123456789" as per https://www.nitrxgen.net/hashgen/
    long long const  other_crc = 0x9D13A61C0E5B0FF5; // Wolfgang Ehrhardt http://www.wolfgang-ehrhardt.de/crchash_en.html
    long long const  ecma_crc = 0x62EC59E3F1A4F00A; // CRC-64-ECMA-128 https://en.wikipedia.org/wiki/Cyclic_redundancy_check

    // Simulate CRC-CCITT
    boost::crc_basic<16>  crc_ccitt1(0x1021, 0xFFFF, 0, false, false);
    crc_ccitt1.process_bytes(data, data_len);
    assert(crc_ccitt1.checksum() == expected);

    // Repeat with the optimal version (assuming a 16-bit type exists)
    boost::crc_optimal<16, 0x1021, 0xFFFF, 0, false, false>  crc_ccitt2;
    crc_ccitt2 = std::for_each(data, data + data_len, crc_ccitt2);
    assert(crc_ccitt2() == expected);

    // Attempt 64 bit CRC
    boost::crc_basic<64>  crc_64_ecma1(0x42F0E1EBA9EA3693, 0xFFFFFFFFFFFFFFFF, 0, false, false);
    crc_64_ecma1.process_bytes(data, data_len);
    assert(crc_64_ecma1.checksum() == CRC);

    boost::crc_optimal<64, 0x42F0E1EBA9EA3693, 0xFFFFFFFFFFFFFFFF, 0, false, false>  crc_64_ecma2;
    crc_64_ecma2 = std::for_each(data, data + data_len, crc_64_ecma2);
    assert(crc_64_ecma2() == CRC);

    std::cout << "All tests passed." << std::endl;
    return 0;
}

Look carefully at 62ec59e3f1a4f00a and 9d13a61c0e5b0ff5, digit by digit. 仔细逐位查看62ec59e3f1a4f00a和9d13a61c0e5b0ff5。 Do you see a relation between those two? 您看到这两者之间的关系吗?

Update: 更新:

Good! 好! You saw it. 看到了 (I hate to deprive others the joy of discovery.) As to why, you can look to Greg Cook's CRC catalog for the definition of the ECMA-182 CRC, referred to as simply CRC-64 there: (我不想剥夺其他人获得发现的乐趣。)至于为什么,您可以查看Greg Cook的CRC目录 ,以获取ECMA-182 CRC的定义,在这里简称为CRC-64:

width=64 poly=0x42f0e1eba9ea3693 init=0x0000000000000000 refin=false refout=false xorout=0x0000000000000000 check=0x6c40df5f0b497347 residue=0x0000000000000000 name="CRC-64"

This defines the CRC with an initial value of zero, and a final exclusive-or of zero, ie no change. 这将CRC定义为初始值为零,最终的异或值为零,即不变。 This is not common for CRCs, since it results in a string of zeros of any length having the same CRC, equal to zero. 这对于CRC并不常见,因为它会导致具有相同CRC(等于零)的任意长度的零字符串。

CRC-64/WE is also defined there, which gives: 在那里也定义了CRC-64 / WE,它给出:

width=64 poly=0x42f0e1eba9ea3693 init=0xffffffffffffffff refin=false refout=false xorout=0xffffffffffffffff check=0x62ec59e3f1a4f00a residue=0xfcacbebd5931a992 name="CRC-64/WE"

This is more common, with an initialization and exclusive-or both with all ones, since the CRC of a string of zeros will depend on the length of the string, and the CRC of a zero length message is zero. 这对于初始化和/或异或比较全的情况更常见,因为零字符串的CRC取决于字符串的长度,零长度消息的CRC为零。

However that disagrees with the calculation at the link you provided. 但是,这与您提供的链接中的计算不一致。 The link you provided calculated it with an initial value of zero, whereas the definition in Greg's catalog initializes the CRC with all ones. 您提供的链接计算出的初始值为零,而Greg目录中的定义将CRC初始化为全1。 Only one of them is correct. 其中只有一个是正确的。

Update 2: 更新2:

Greg's catalog is correct. 格雷格的目录是正确的。 The linked on-line hash calculator is wrong. 链接的在线哈希计算器是错误的。 I verified the CRC definition by looking at Wolfgang Ehrhardt's (the "WE" in CRC-64/WE) source code (a zip file) . 我通过查看Wolfgang Ehrhardt (CRC-64 / WE中的“ WE”) 源代码(一个zip文件)来验证CRC定义。 The linked calculator is doubly wrong, in that it gives the CRC-64/WE check value 62ec... as the CRC-64/ECMA-182 result, and it gives a result for CRC-64/WE that matches neither CRC-64. 链接的计算器是双重错误的,因为它给出了CRC-64 / WE检查值62ec...作为CRC-64 / ECMA-182结果,并且给出了与CRC-64 / WE都不匹配的结果。 64。 Beware of what you find on the interwebs. 当心您在互连网上发现的东西。

Correct parameters for CRC CRC的正确参数

Boost has the following typedef for CRC-32/B/BZIP2/AAL5/DECT-B: Boost对于CRC-32 / B / BZIP2 / AAL5 / DECT-B具有以下typedef:

typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true>
  crc_32_type;

Similarly the ECMA-128 64bit CRC requires a final xor value (3rd parameter): 同样,ECMA-128 64位CRC要求最终的异或值(第3个参数):

boost::crc_basic<64>  crc_64_ecma1(0x42F0E1EBA9EA3693, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, false, false);
                                                                           ^^^^^^^^^^^^^^^^^^

Reason for warning message 警告消息的原因

The following template 以下模板

template < std::size_t Bits >
class crc_basic

uses 用途

template < std::size_t Bits >
struct mask_uint_t

and this mask_uint_t has been specialized for various numbers of bits: 并且该mask_uint_t已专门用于各种位数:

  • unsigned char -> BOOST_STATIC_CONSTANT( least, sig_bits = (~( least(0u) )) );
  • unsigned short -> BOOST_STATIC_CONSTANT( least, sig_bits = (~( least(0u) )) );
  • unsigned int -> BOOST_STATIC_CONSTANT( least, sig_bits = (~( least(0u) )) );

But the unspecialized version is different and triggers the undefined behavior warning: 但是非专业版本有所不同,并会触发未定义行为警告:

  • BOOST_STATIC_CONSTANT( least, sig_bits = (~( ~(least( 0u )) << Bits )) ); BOOST_STATIC_CONSTANT( least, sig_bits = (~( ~(least( 0u )) << Bits )) );

On MSVC it still yields the correct value, but it should probably not be relied upon. 在MSVC上,它仍然可以产生正确的值,但是可能不应该依赖它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM