You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
4.8KB

  1. import sys
  2. # -----------------------------------------------------------------------------
  3. # Some code below reference to crcmod which base on python2 version
  4. # Replace some functions to compat python3+ version
  5. #
  6. is_py3 = (sys.version_info[0] == 3)
  7. if is_py3:
  8. xrange = range
  9. long = int
  10. sys.maxint = sys.maxsize
  11. # -----------------------------------------------------------------------------
  12. # Export mkCombineFun to user to support crc64 combine feature.
  13. #
  14. # Example:
  15. #
  16. # import crcmod
  17. #
  18. # _POLY = 0x142F0E1EBA9EA3693
  19. # _XOROUT = 0XFFFFFFFFFFFFFFFF
  20. #
  21. # string_a = '12345'
  22. # string_b = '67890'
  23. #
  24. # combine_fun = mkCombineFun(_POLY, 0, True, _XOROUT)
  25. #
  26. # crc64_a = crcmod.Crc(_POLY, initCrc=0, xorOut=_XOROUT)
  27. # crc64_a.update(string_a)
  28. #
  29. # crc64_b = crcmod.Crc(_POLY, initCrc=0, xorOut=_XOROUT)
  30. # crc64_b.update(string_b)
  31. #
  32. # combine_fun(crc64_a.crcValue, crc64_b.crcValue, len(string_b))
  33. #
  34. def mkCombineFun(poly, initCrc=~long(0), rev=True, xorOut=0):
  35. # mask = (1L<<n) - 1
  36. (sizeBits, initCrc, xorOut) = _verifyParams(poly, initCrc, xorOut)
  37. mask = (long(1) << sizeBits) - 1
  38. if rev:
  39. poly = _bitrev(long(poly) & mask, sizeBits)
  40. else:
  41. poly = long(poly) & mask
  42. if sizeBits == 64:
  43. fun = _combine64
  44. else:
  45. raise NotImplemented
  46. def combine_fun(crc1, crc2, len2):
  47. return fun(poly, initCrc ^ xorOut, rev, xorOut, crc1, crc2, len2)
  48. return combine_fun
  49. # -----------------------------------------------------------------------------
  50. # The below code implemented crc64 combine logic, the algorithm reference to aliyun-oss-ruby-sdk
  51. # See more details please visist:
  52. # - https://github.com/aliyun/aliyun-oss-ruby-sdk/tree/master/ext/crcx
  53. GF2_DIM = 64
  54. def gf2_matrix_square(square, mat):
  55. for n in xrange(GF2_DIM):
  56. square[n] = gf2_matrix_times(mat, mat[n])
  57. def gf2_matrix_times(mat, vec):
  58. summary = 0
  59. mat_index = 0
  60. while vec:
  61. if vec & 1:
  62. summary ^= mat[mat_index]
  63. vec >>= 1
  64. mat_index += 1
  65. return summary
  66. def _combine64(poly, initCrc, rev, xorOut, crc1, crc2, len2):
  67. if len2 == 0:
  68. return crc1
  69. even = [0] * GF2_DIM
  70. odd = [0] * GF2_DIM
  71. crc1 ^= initCrc ^ xorOut
  72. if (rev):
  73. # put operator for one zero bit in odd
  74. odd[0] = poly # CRC-64 polynomial
  75. row = 1
  76. for n in xrange(1, GF2_DIM):
  77. odd[n] = row
  78. row <<= 1
  79. else:
  80. row = 2
  81. for n in xrange(0, GF2_DIM - 1):
  82. odd[n] = row
  83. row <<= 1
  84. odd[GF2_DIM - 1] = poly
  85. gf2_matrix_square(even, odd)
  86. gf2_matrix_square(odd, even)
  87. while True:
  88. gf2_matrix_square(even, odd)
  89. if len2 & long(1):
  90. crc1 = gf2_matrix_times(even, crc1)
  91. len2 >>= 1
  92. if len2 == 0:
  93. break
  94. gf2_matrix_square(odd, even)
  95. if len2 & long(1):
  96. crc1 = gf2_matrix_times(odd, crc1)
  97. len2 >>= 1
  98. if len2 == 0:
  99. break
  100. crc1 ^= crc2
  101. return crc1
  102. # -----------------------------------------------------------------------------
  103. # The below code copy from crcmod, see more detail please visist:
  104. # https://bitbucket.org/cmcqueen1975/crcmod/src/8fb658289c35eff1d37cc47799569f90c5b39e1e/python2/crcmod/crcmod.py?at=default&fileviewer=file-view-default
  105. # -----------------------------------------------------------------------------
  106. # Check the polynomial to make sure that it is acceptable and return the number
  107. # of bits in the CRC.
  108. def _verifyPoly(poly):
  109. msg = 'The degree of the polynomial must be 8, 16, 24, 32 or 64'
  110. poly = long(poly) # Use a common representation for all operations
  111. for n in (8, 16, 24, 32, 64):
  112. low = long(1) << n
  113. high = low * 2
  114. if low <= poly < high:
  115. return n
  116. raise ValueError(msg)
  117. # -----------------------------------------------------------------------------
  118. # Bit reverse the input value.
  119. def _bitrev(x, n):
  120. x = long(x)
  121. y = long(0)
  122. for i in xrange(n):
  123. y = (y << 1) | (x & long(1))
  124. x = x >> 1
  125. if ((long(1) << n) - 1) <= sys.maxint:
  126. return int(y)
  127. return y
  128. # -----------------------------------------------------------------------------
  129. # The following function validates the parameters of the CRC, namely,
  130. # poly, and initial/final XOR values.
  131. # It returns the size of the CRC (in bits), and "sanitized" initial/final XOR values.
  132. def _verifyParams(poly, initCrc, xorOut):
  133. sizeBits = _verifyPoly(poly)
  134. mask = (long(1) << sizeBits) - 1
  135. # Adjust the initial CRC to the correct data type (unsigned value).
  136. initCrc = long(initCrc) & mask
  137. if mask <= sys.maxint:
  138. initCrc = int(initCrc)
  139. # Similar for XOR-out value.
  140. xorOut = long(xorOut) & mask
  141. if mask <= sys.maxint:
  142. xorOut = int(xorOut)
  143. return (sizeBits, initCrc, xorOut)