Dart 中的按位运算的 CRC

问题描述 投票:0回答:1

我在 Dart 中执行 CRC-64 ECMA 计算时遇到问题。虽然我得到 a 结果,但它不正确,执行相同 CRC 计算的 Python 脚本证明了这一点。

这是Python代码:

def crc64ecma(data):
    """Calculate the CRC64-ECMA value for given data."""
    crc = 0xFFFFFFFFFFFFFFFF
    poly = 0x42EA3693F0E1EBA9

    print(f"[crc64ecma] Received data is {data.hex()}")  # Log the received data in hex format
    for byte in data:
        print(f"[crc64ecma] Byte is {byte}")
        crc ^= byte
        print(f"[crc64ecma] CRC is {crc:#018x}")
        for _ in range(8):
            if crc & 1:
                crc = (crc >> 1) ^ poly
                print(f"[crc64ecma] CRC is XOR with POLY as {crc:#018x}")
            else:
                crc >>= 1
                print(f"[crc64ecma] CRC is shifted as {crc:#018x}")
    crc = ~crc & 0xFFFFFFFFFFFFFFFF
    print(f"[crc64ecma] Final CRC is: {crc:#018x}")

    return crc


if __name__ == "__main__":
    while True:
        # Getting user input for 4 bytes
        user_input = input("Enter 4 bytes (in hexadecimal format, e.g., 1A2B3C4D): ")

        try:
            # Convert the input to bytes
            data = bytes.fromhex(user_input)

            # Ensure the input is exactly 4 bytes
            if len(data) != 4:
                raise ValueError("Input must be exactly 4 bytes")

            # Calculating CRC value
            crc_value = crc64ecma(data)

            # Printing the CRC result
            print(f"CRC: {crc_value:#018x}\n")  # Print CRC in hex format

        except ValueError as e:
            print(f"Error: {e}")

        # Option to continue or break the loop
        if input("Continue? (y/n): ").lower() != 'y':
            break

对于诸如 0x65a58220 这样的输入,它会产生预期结果:0xc179f267d045a14e

这是我的此类脚本的 Dart 版本:

import 'dart:developer';
import 'dart:typed_data';

const int POLY = 0x42EA3693F0E1EBA9;

Uint8List crc64ecma(Uint8List d) {
  var d2 = [101, 165, 130, 32];
  var data = Uint8List.fromList(d2);
  int crc = 0xFFFFFFFFFFFFFFFF;
  log('[crc64ecma] Received data is ${bytesToHex(data)}');
  for (var byte in data) {
    log('[crc64ecma] Byte is ${byte.toRadixString(16)}');
    crc ^= byte;
    log('[crc64ecma] CRC is ${crc.toRadixString(16)}');
    for (int i = 0; i < 8; i++) {
      if (crc & 1 != 0) {
        crc = (crc >> 1) ^ POLY;
        log('[crc64ecma] CRC is XOR with POLY as ${crc.toRadixString(16)}');
      } else {
        crc >>= 1;
        log('[crc64ecma] CRC is shifted as ${crc.toRadixString(16)}');
      }
    }
  }
  crc = ~crc & 0xFFFFFFFFFFFFFFFF;

  ByteData byteData = ByteData(8); 
  byteData.setUint64(0, crc, Endian.big);
  log('[crc64ecma] Final CRC is: ${bytesToHex(byteData.buffer.asUint8List())}');
  return byteData.buffer.asUint8List();
}

String bytesToHex(Uint8List bytes) {
  return bytes.map((byte) => byte.toRadixString(16)).join();
}

Dart 脚本生成的 CRC 为 0x3e86d98d045a14e。

那么问题出在哪里呢?按位运算的处理。

我有算法每个步骤的日志。 Python 记录了这个:

[crc64ecma] CRC is 0xffffffffffffff9a

当 Dart 记录以下内容时:

[crc64ecma] CRC is -66 // 0xFF9A

看来Dart的按位运算对不同大小的字节的处理方式不同,截断了CRC值。我该怎么做才能强制 Dart 使用运算符的整个宽度?

python flutter dart crc
1个回答
0
投票

我不得不求助于使用 Dart 的 Big Int 实现,这样值就不会被截断:

Uint8List crc64ecma(Uint8List data) {
  BigInt crc = BigInt.parse('FFFFFFFFFFFFFFFF', radix: 16);
  log('[crc64ecma] Received data is ${bytesToHex(data)}');

  for (var byte in data) {
    log('[crc64ecma] Byte is ${byte.toRadixString(16)}');
    crc ^= BigInt.from(byte);
    log('[crc64ecma] CRC is ${crc.toRadixString(16)}');

    for (int i = 0; i < 8; i++) {
      if ((crc & BigInt.from(1)) != BigInt.zero) {
        crc = (crc >> 1) ^ BigInt.from(POLY);
      } else {
        crc >>= 1;
      }
      log('[crc64ecma] CRC after operation is ${crc.toRadixString(16)}');
    }
  }
  crc = ~crc & BigInt.parse('FFFFFFFFFFFFFFFF', radix: 16);

  
  var res = bigIntToUint8List(crc);

  log('[crc64ecma] Final CRC is: ${  crc.toRadixString(16)}');
  return res;
}

Uint8List bigIntToUint8List(BigInt bigInt) {
  var byteList = bigInt.toRadixString(16).padLeft(16, '0');

  // Convert hex string to byte array
  List<int> byteArray = [];
  for (int i = 0; i < byteList.length; i += 2) {
    String hexByte = byteList.substring(i, i + 2);
    byteArray.add(int.parse(hexByte, radix: 16));
  }

  // Convert byte array to Uint8List
  return Uint8List.fromList(byteArray);
}
© www.soinside.com 2019 - 2024. All rights reserved.