CRC16.h 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /*
  2. * Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Endian.h>
  8. #include <AK/Format.h>
  9. #include <AK/Types.h>
  10. #include <LibCrypto/Checksum/ChecksumFunction.h>
  11. namespace Crypto::Checksum {
  12. // A generic 16-bit Cyclic Redundancy Check.
  13. // Just like CRC32, this class receives its polynomial little-endian.
  14. // For example, the polynomial x¹⁶ + x¹² + x⁵ + 1 is represented as 0x8408.
  15. template<u16 polynomial>
  16. class CRC16 : public ChecksumFunction<u16> {
  17. public:
  18. static constexpr u16 be_polynomial = bitswap(polynomial);
  19. // This is a big endian table, while CRC-32 uses a little endian table.
  20. static constexpr auto generate_table()
  21. {
  22. Array<u16, 256> data {};
  23. data[0] = 0;
  24. u16 value = 0x8000;
  25. auto i = 1u;
  26. do {
  27. if ((value & 0x8000) != 0) {
  28. value = be_polynomial ^ (value << 1);
  29. } else {
  30. value = value << 1;
  31. }
  32. for (auto j = 0u; j < i; ++j) {
  33. data[i + j] = value ^ data[j];
  34. }
  35. i <<= 1;
  36. } while (i < 256);
  37. return data;
  38. }
  39. static constexpr auto table = generate_table();
  40. virtual ~CRC16() = default;
  41. CRC16() = default;
  42. CRC16(ReadonlyBytes data)
  43. {
  44. update(data);
  45. }
  46. CRC16(u16 initial_state, ReadonlyBytes data)
  47. : m_state(initial_state)
  48. {
  49. update(data);
  50. }
  51. // FIXME: This implementation is naive and slow.
  52. // Figure out how to adopt the slicing-by-8 algorithm (see CRC32) for 16-bit polynomials.
  53. virtual void update(ReadonlyBytes data) override
  54. {
  55. for (size_t i = 0; i < data.size(); i++) {
  56. size_t table_index = ((m_state >> 8) ^ data.at(i)) & 0xFF;
  57. m_state = (table[table_index] ^ (static_cast<u32>(m_state) << 8)) & 0xFFFF;
  58. }
  59. }
  60. virtual u16 digest() override
  61. {
  62. return m_state;
  63. }
  64. private:
  65. u16 m_state { 0 };
  66. };
  67. }