signature.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #
  2. # Copyright (C) 2014-2015 UAVCAN Development Team <uavcan.org>
  3. #
  4. # This software is distributed under the terms of the MIT License.
  5. #
  6. # Author: Pavel Kirienko <pavel.kirienko@zubax.com>
  7. # Ben Dyer <ben_dyer@mac.com>
  8. #
  9. from __future__ import division, absolute_import, print_function, unicode_literals
  10. #
  11. # CRC-64-WE
  12. # Description: http://reveng.sourceforge.net/crc-catalogue/17plus.htm#crc.cat-bits.64
  13. # Initial value: 0xFFFFFFFFFFFFFFFF
  14. # Poly: 0x42F0E1EBA9EA3693
  15. # Reverse: no
  16. # Output xor: 0xFFFFFFFFFFFFFFFF
  17. # Check: 0x62EC59E3F1A4F00A
  18. #
  19. class Signature:
  20. '''
  21. This class implements the UAVCAN DSDL signature hash function. Please refer to the specification for details.
  22. '''
  23. MASK64 = 0xFFFFFFFFFFFFFFFF
  24. POLY = 0x42F0E1EBA9EA3693
  25. def __init__(self, extend_from=None):
  26. '''
  27. extend_from Initial value (optional)
  28. '''
  29. if extend_from is not None:
  30. self._crc = (int(extend_from) & Signature.MASK64) ^ Signature.MASK64
  31. else:
  32. self._crc = Signature.MASK64
  33. def add(self, data_bytes):
  34. '''Feed ASCII string or bytes to the signature function'''
  35. try:
  36. if isinstance(data_bytes, basestring): # Python 2.7 compatibility
  37. data_bytes = map(ord, data_bytes)
  38. except NameError:
  39. if isinstance(data_bytes, str): # This branch will be taken on Python 3
  40. data_bytes = map(ord, data_bytes)
  41. for b in data_bytes:
  42. self._crc ^= (b << 56) & Signature.MASK64
  43. for _ in range(8):
  44. if self._crc & (1 << 63):
  45. self._crc = ((self._crc << 1) & Signature.MASK64) ^ Signature.POLY
  46. else:
  47. self._crc <<= 1
  48. def get_value(self):
  49. '''Returns integer signature value'''
  50. return (self._crc & Signature.MASK64) ^ Signature.MASK64
  51. def compute_signature(data):
  52. '''
  53. One-shot signature computation for ASCII string or bytes.
  54. Returns integer signture value.
  55. '''
  56. s = Signature()
  57. s.add(data)
  58. return s.get_value()
  59. # if __name__ == '__main__':
  60. if 1:
  61. s = Signature()
  62. s.add(b'123')
  63. s.add('456789')
  64. assert s.get_value() == 0x62EC59E3F1A4F00A