Используйте Boost для вычисления ECMA-128 64bit CRC - PullRequest
0 голосов
/ 08 июня 2018

С помощью следующей программы я пытаюсь вычислить CRC 64bit в соответствии со стандартом ECMA-128 .

Тестовые данные - "123456789", и я пытаюсь сопоставить те же самые данные, предоставленные здесь , что предполагает, что результат для CRC-64 / ECMA-182 должен быть 62ec59e3f1a4f00a.К сожалению, я получаю 9d13a61c0e5b0ff5, который является результатом CRC-64 / WE.

Я начал с примера кода, предоставленного здесь .Я создал 64-битные хэши с нормальным полиномиальным представлением 0x42F0E1EBA9EA3693 для 64-битной CRC ECMA-128.


Я получаю следующее предупреждение VS: C4293: '<<':Сдвиг счета отрицательное или слишком большое, неопределенное поведение.Именно для этого макроса: </p>

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

Насколько я могу судить, 0 сдвигается в битах на весь диапазон из 64 битов, что является неопределенным поведением.Я удивлен, что не вижу это предупреждение для 32-битной CRC.


Как эту программу можно исправить, чтобы правильно вычислить 64-битную CRC ECMA-128 без неопределенного поведения?

// 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;
}

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

Внимательно посмотрите на 62ec59e3f1a4f00a и 9d13a61c0e5b0ff5, цифра за цифрой.Видите ли вы связь между этими двумя?

Обновление:

Хорошо!Ты видел это.(Я не хочу лишать других радости открытия.) Что касается того, почему, вы можете найти в каталоге CRC Грега Кука определение CRC ECMA-182, называемого просто CRC-64:

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

Определяет CRC с начальным значением, равным нулю, и конечным исключающим или нулевым, то есть без изменений.Это не является обычным для CRC, поскольку приводит к тому, что строка нулей любой длины имеет тот же CRC, равный нулю.

CRC-64 / WE также определен там, что дает:

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

Это более распространено, с инициализацией и эксклюзивом или обоими со всеми, так как CRC строки нулей будет зависеть от длины строки, а CRC сообщения нулевой длины равен нулю.

Однако это не соответствует расчету по предоставленной вами ссылке.Ссылка, которую вы предоставили, рассчитала ее с начальным значением ноль, тогда как определение в каталоге Грега инициализирует CRC со всеми.Только один из них правильный.

Обновление 2:

Каталог Грега правильный.Связанный он-лайн калькулятор хешей неверен.Я проверил определение CRC, посмотрев исходный код Вольфганга Эрхардта ("МЫ" в CRC-64 / WE) (zip-файл) .Связанный калькулятор ошибочен вдвойне, поскольку он дает контрольное значение CRC-64 / WE 62ec... в качестве результата CRC-64 / ECMA-182 и дает результат для CRC-64 / WE, который не соответствует ни CRC-64,Остерегайтесь того, что вы найдете в паутинах.

0 голосов
/ 08 июня 2018

Корректные параметры для CRC

Boost имеет следующий typedef для CRC-32 / B / BZIP2 / AAL5 / DECT-B:

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

Аналогично, для ECMA-128 64bit CRC требуетсяокончательное значение xor (3-й параметр):

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

Причина предупреждения:

Следующий шаблон

template < std::size_t Bits >
class crc_basic

использует

template < std::size_t Bits >
struct mask_uint_t

и этот 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) )) );

Но неспециализированная версия отличается и выдает предупреждение о неопределенном поведении:

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

В MSVC все равно выдает правильное значение, но оновероятно, не следует полагаться.

...