我在 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 使用运算符的整个宽度?
我不得不求助于使用 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);
}