diff --git a/fastcrc/__init__.py b/fastcrc/__init__.py index 6182aca..16d4113 100644 --- a/fastcrc/__init__.py +++ b/fastcrc/__init__.py @@ -1,4 +1,4 @@ -from . import crc16, crc32, crc64 +from . import crc8, crc16, crc32, crc64 from .__info__ import ( __author__, __author_email__, diff --git a/fastcrc/crc8.py b/fastcrc/crc8.py new file mode 100644 index 0000000..3008899 --- /dev/null +++ b/fastcrc/crc8.py @@ -0,0 +1,428 @@ +""" +Compute a CRC-16 checksum of data. +""" +from typing import Optional + +from .fastcrc import crc_8_autosar as _crc_8_autosar +from .fastcrc import crc_8_bluetooth as _crc_8_bluetooth +from .fastcrc import crc_8_cdma2000 as _crc_8_cdma2000 +from .fastcrc import crc_8_darc as _crc_8_darc +from .fastcrc import crc_8_dvb_s2 as _crc_8_dvb_s2 +from .fastcrc import crc_8_gsm_a as _crc_8_gsm_a +from .fastcrc import crc_8_gsm_b as _crc_8_gsm_b +from .fastcrc import crc_8_i_432_1 as _crc_8_i_432_1 +from .fastcrc import crc_8_i_code as _crc_8_i_code +from .fastcrc import crc_8_lte as _crc_8_lte +from .fastcrc import crc_8_maxim_dow as _crc_8_maxim_dow +from .fastcrc import crc_8_mifare_mad as _crc_8_mifare_mad +from .fastcrc import crc_8_nrsc_5 as _crc_8_nrsc_5 +from .fastcrc import crc_8_opensafety as _crc_8_opensafety +from .fastcrc import crc_8_rohc as _crc_8_rohc +from .fastcrc import crc_8_sae_j1850 as _crc_8_sae_j1850 +from .fastcrc import crc_8_smbus as _crc_8_smbus +from .fastcrc import crc_8_tech_3250 as _crc_8_tech_3250 +from .fastcrc import crc_8_wcdma as _crc_8_wcdma + +__always_supported = ( + "autosar", + "bluetooth", + "cdma2000", + "darc", + "dvb_s2", + "gsm_a", + "gsm_b", + "i_432_1", + "i_code", + "lte", + "maxim_dow", + "mifare_mad", + "nrsc_5", + "opensafety", + "rohc", + "sae_j1850", + "smbus", + "tech_3250", + "wcdma", +) + +algorithms_guaranteed = set(__always_supported) +algorithms_available = set(__always_supported) + +def autosar(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `autosar` algorithm. + + Algorithm parameters: + - poly: 0x2f + - init: 0xff + - xorout: 0xff + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_autosar(data, initial) + + +def bluetooth(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `bluetooth` algorithm. + + Algorithm parameters: + - poly: 0xa7 + - init: 0x00 + - xorout: 0x00 + - refin: True + - refout: True + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_bluetooth(data, initial) + + +def cdma2000(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `cdma2000` algorithm. + + Algorithm parameters: + - poly: 0x9b + - init: 0xff + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_cdma2000(data, initial) + + +def darc(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `darc` algorithm. + + Algorithm parameters: + - poly: 0x39 + - init: 0x00 + - xorout: 0x00 + - refin: True + - refout: True + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_darc(data, initial) + + +def dvb_s2(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `dvb_s2` algorithm. + + Algorithm parameters: + - poly: 0xd5 + - init: 0x00 + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_dvb_s2(data, initial) + + +def gsm_a(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `gsm_a` algorithm. + + Algorithm parameters: + - poly: 0x1d + - init: 0x00 + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_gsm_a(data, initial) + + +def gsm_b(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `gsm_b` algorithm. + + Algorithm parameters: + - poly: 0x49 + - init: 0x00 + - xorout: 0xff + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_gsm_b(data, initial) + + +def i_432_1(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `i_432_1` algorithm. + + Algorithm parameters: + - poly: 0x07 + - init: 0x00 + - xorout: 0x55 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_i_432_1(data, initial) + + +def i_code(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `i_code` algorithm. + + Algorithm parameters: + - poly: 0x1d + - init: 0xfd + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_i_code(data, initial) + + +def lte(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `lte` algorithm. + + Algorithm parameters: + - poly: 0x9b + - init: 0x00 + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_lte(data, initial) + + +def maxim_dow(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `maxim_dow` algorithm. + + Algorithm parameters: + - poly: 0x31 + - init: 0x00 + - xorout: 0x00 + - refin: True + - refout: True + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_maxim_dow(data, initial) + + +def mifare_mad(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `mifare_mad` algorithm. + + Algorithm parameters: + - poly: 0x1d + - init: 0xc7 + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_mifare_mad(data, initial) + + +def nrsc_5(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `nrsc_5` algorithm. + + Algorithm parameters: + - poly: 0x31 + - init: 0xff + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_nrsc_5(data, initial) + + +def opensafety(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `opensafety` algorithm. + + Algorithm parameters: + - poly: 0x2f + - init: 0x00 + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_opensafety(data, initial) + + +def rohc(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `rohc` algorithm. + + Algorithm parameters: + - poly: 0x07 + - init: 0xff + - xorout: 0x00 + - refin: True + - refout: True + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_rohc(data, initial) + + +def sae_j1850(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `sae_j1850` algorithm. + + Algorithm parameters: + - poly: 0x1d + - init: 0xff + - xorout: 0xff + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_sae_j1850(data, initial) + + +def smbus(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `smbus` algorithm. + + Algorithm parameters: + - poly: 0x07 + - init: 0x00 + - xorout: 0x00 + - refin: False + - refout: False + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_smbus(data, initial) + + +def tech_3250(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `tech_3250` algorithm. + + Algorithm parameters: + - poly: 0x1d + - init: 0xff + - xorout: 0x00 + - refin: True + - refout: True + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_tech_3250(data, initial) + + +def wcdma(data: bytes, initial: Optional[int] = None) -> int: + """ + Compute a CRC-8 checksum of data with the `wcdma` algorithm. + + Algorithm parameters: + - poly: 0x9b + - init: 0x00 + - xorout: 0x00 + - refin: True + - refout: True + + :param bytes data: The data to be computed + :param Optional[int] initial: The optional starting value of the checksum + :return: The checksum + :rtype: int + :raises TypeError: if the data is not a bytes-like object + """ + return _crc_8_wcdma(data, initial) \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b1aadc7..5f1011d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,15 @@ use crc::{ - Crc, CRC_16_ARC, CRC_16_CDMA2000, CRC_16_CMS, CRC_16_DDS_110, CRC_16_DECT_R, CRC_16_DECT_X, + Crc, CRC_8_AUTOSAR, CRC_8_BLUETOOTH, CRC_8_CDMA2000, CRC_8_DARC, CRC_8_DVB_S2, CRC_8_GSM_A, + CRC_8_GSM_B, CRC_8_I_432_1, CRC_8_I_CODE, CRC_8_LTE, CRC_8_MAXIM_DOW, CRC_8_MIFARE_MAD, + CRC_8_NRSC_5, CRC_8_OPENSAFETY, CRC_8_ROHC, CRC_8_SAE_J1850, CRC_8_SMBUS, CRC_8_TECH_3250, + CRC_8_WCDMA, CRC_16_ARC, CRC_16_CDMA2000, CRC_16_CMS, CRC_16_DDS_110, CRC_16_DECT_R, CRC_16_DECT_X, CRC_16_DNP, CRC_16_EN_13757, CRC_16_GENIBUS, CRC_16_GSM, CRC_16_IBM_3740, CRC_16_IBM_SDLC, CRC_16_ISO_IEC_14443_3_A, CRC_16_KERMIT, CRC_16_LJ1200, CRC_16_MAXIM_DOW, CRC_16_MCRF4XX, CRC_16_MODBUS, CRC_16_NRSC_5, CRC_16_OPENSAFETY_A, CRC_16_OPENSAFETY_B, CRC_16_PROFIBUS, CRC_16_RIELLO, CRC_16_SPI_FUJITSU, CRC_16_T10_DIF, CRC_16_TELEDISK, CRC_16_TMS37157, CRC_16_UMTS, CRC_16_USB, CRC_16_XMODEM, CRC_32_AIXM, CRC_32_AUTOSAR, CRC_32_BASE91_D, CRC_32_BZIP2, CRC_32_CD_ROM_EDC, CRC_32_CKSUM, CRC_32_ISCSI, CRC_32_ISO_HDLC, CRC_32_JAMCRC, - CRC_32_MPEG_2, CRC_32_XFER, CRC_64_ECMA_182, CRC_64_GO_ISO, CRC_64_WE, CRC_64_XZ, Algorithm + CRC_32_MPEG_2, CRC_32_XFER, CRC_64_ECMA_182, CRC_64_GO_ISO, CRC_64_WE, CRC_64_XZ, Algorithm, }; use pyo3::prelude::*; use pyo3::wrap_pyfunction; @@ -60,6 +63,25 @@ const CRC_32_K_REVERSED_RECIPROCAL_REFIN: Algorithm = Algorithm { residue: 0x00000000 }; +define_crc_fn!(crc_8_autosar, u8, CRC_8_AUTOSAR); +define_crc_fn!(crc_8_bluetooth, u8, CRC_8_BLUETOOTH); +define_crc_fn!(crc_8_cdma2000, u8, CRC_8_CDMA2000); +define_crc_fn!(crc_8_darc, u8, CRC_8_DARC); +define_crc_fn!(crc_8_dvb_s2, u8, CRC_8_DVB_S2); +define_crc_fn!(crc_8_gsm_a, u8, CRC_8_GSM_A); +define_crc_fn!(crc_8_gsm_b, u8, CRC_8_GSM_B); +define_crc_fn!(crc_8_i_432_1, u8, CRC_8_I_432_1); +define_crc_fn!(crc_8_i_code, u8, CRC_8_I_CODE); +define_crc_fn!(crc_8_lte, u8, CRC_8_LTE); +define_crc_fn!(crc_8_maxim_dow, u8, CRC_8_MAXIM_DOW); +define_crc_fn!(crc_8_mifare_mad, u8, CRC_8_MIFARE_MAD); +define_crc_fn!(crc_8_nrsc_5, u8, CRC_8_NRSC_5); +define_crc_fn!(crc_8_opensafety, u8, CRC_8_OPENSAFETY); +define_crc_fn!(crc_8_rohc, u8, CRC_8_ROHC); +define_crc_fn!(crc_8_sae_j1850, u8, CRC_8_SAE_J1850); +define_crc_fn!(crc_8_smbus, u8, CRC_8_SMBUS); +define_crc_fn!(crc_8_tech_3250, u8, CRC_8_TECH_3250); +define_crc_fn!(crc_8_wcdma, u8, CRC_8_WCDMA); define_crc_fn!(crc_16_arc, u16, CRC_16_ARC); define_crc_fn!(crc_16_cdma2000, u16, CRC_16_CDMA2000); define_crc_fn!(crc_16_cms, u16, CRC_16_CMS); @@ -114,6 +136,25 @@ define_crc_fn!(crc_64_xz, u64, CRC_64_XZ); #[pymodule] fn fastcrc(_: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(crc_8_autosar,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_bluetooth,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_cdma2000,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_darc,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_dvb_s2,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_gsm_a,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_gsm_b,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_i_432_1,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_i_code,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_lte,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_maxim_dow,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_mifare_mad,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_nrsc_5,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_opensafety,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_rohc,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_sae_j1850,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_smbus,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_tech_3250,m)?)?; + m.add_function(wrap_pyfunction!(crc_8_wcdma,m)?)?; m.add_function(wrap_pyfunction!(crc_16_arc, m)?)?; m.add_function(wrap_pyfunction!(crc_16_cdma2000, m)?)?; m.add_function(wrap_pyfunction!(crc_16_cms, m)?)?; diff --git a/tests/test_fastcrc.py b/tests/test_fastcrc.py index 897c6ca..ad2eb4e 100644 --- a/tests/test_fastcrc.py +++ b/tests/test_fastcrc.py @@ -1,11 +1,102 @@ import unittest -from fastcrc import crc16, crc32, crc64 +from fastcrc import crc8, crc16, crc32, crc64 data = b"123456789" data_part1 = b"1234" data_part2 = b"56789" +class TestCrc8(unittest.TestCase): + def test_bluetooth(self): + self.assertEqual(38, crc8.bluetooth(data)) + def test_bluetooth_init(self): + self.assertEqual(38, crc8.bluetooth(data_part2, crc8.bluetooth(data_part1))) + + def test_cdma2000(self): + self.assertEqual(218, crc8.cdma2000(data)) + def test_cdma2000_init(self): + self.assertEqual(218, crc8.cdma2000(data_part2, crc8.cdma2000(data_part1))) + + def test_darc(self): + self.assertEqual(21, crc8.darc(data)) + def test_darc_init(self): + self.assertEqual(21, crc8.darc(data_part2, crc8.darc(data_part1))) + + def test_dvb_s2(self): + self.assertEqual(188, crc8.dvb_s2(data)) + def test_dvb_s2_init(self): + self.assertEqual(188, crc8.dvb_s2(data_part2, crc8.dvb_s2(data_part1))) + + def test_gsm_a(self): + self.assertEqual(55, crc8.gsm_a(data)) + def test_gsm_a_init(self): + self.assertEqual(55, crc8.gsm_a(data_part2, crc8.gsm_a(data_part1))) + + def test_gsm_b(self): + self.assertEqual(148, crc8.gsm_b(data)) + def test_gsm_b_init(self): + self.assertEqual(148, crc8.gsm_b(data_part2, crc8.gsm_b(data_part1))) + + def test_i_432_1(self): + self.assertEqual(161, crc8.i_432_1(data)) + def test_i_432_1_init(self): + self.assertEqual(161, crc8.i_432_1(data_part2, crc8.i_432_1(data_part1))) + + def test_i_code(self): + self.assertEqual(126, crc8.i_code(data)) + def test_i_code_init(self): + self.assertEqual(126, crc8.i_code(data_part2, crc8.i_code(data_part1))) + + def test_lte(self): + self.assertEqual(234, crc8.lte(data)) + def test_lte_init(self): + self.assertEqual(234, crc8.lte(data_part2, crc8.lte(data_part1))) + + def test_maxim_dow(self): + self.assertEqual(161, crc8.maxim_dow(data)) + def test_maxim_dow_init(self): + self.assertEqual(161, crc8.maxim_dow(data_part2, crc8.maxim_dow(data_part1))) + + def test_mifare_mad(self): + self.assertEqual(153, crc8.mifare_mad(data)) + def test_mifare_mad_init(self): + self.assertEqual(153, crc8.mifare_mad(data_part2, crc8.mifare_mad(data_part1))) + + def test_nrsc_5(self): + self.assertEqual(247, crc8.nrsc_5(data)) + def test_nrsc_5_init(self): + self.assertEqual(247, crc8.nrsc_5(data_part2, crc8.nrsc_5(data_part1))) + + def test_opensafety(self): + self.assertEqual(62, crc8.opensafety(data)) + def test_opensafety_init(self): + self.assertEqual(62, crc8.opensafety(data_part2, crc8.opensafety(data_part1))) + + def test_rohc(self): + self.assertEqual(208, crc8.rohc(data)) + def test_rohc_init(self): + self.assertEqual(208, crc8.rohc(data_part2, crc8.rohc(data_part1))) + + def test_sae_j1850(self): + self.assertEqual(75, crc8.sae_j1850(data)) + def test_sae_j1850_init(self): + self.assertEqual(75, crc8.sae_j1850(data_part2, crc8.sae_j1850(data_part1))) + + def test_smbus(self): + self.assertEqual(244, crc8.smbus(data)) + def test_smbus_init(self): + self.assertEqual(244, crc8.smbus(data_part2, crc8.smbus(data_part1))) + + def test_tech_3250(self): + self.assertEqual(151, crc8.tech_3250(data)) + def test_tech_3250_init(self): + self.assertEqual(151, crc8.tech_3250(data_part2, crc8.tech_3250(data_part1))) + + def test_wcdma(self): + self.assertEqual(37, crc8.wcdma(data)) + def test_wcdma_init(self): + self.assertEqual(37, crc8.wcdma(data_part2, crc8.wcdma(data_part1))) + class TestCrc16(unittest.TestCase): def test_arc(self):