blob: 3ebcebd5378cc3a377d78b343eacea03583ee075 [file] [log] [blame]
Brian Silverman84b22232019-01-25 20:29:29 -08001# pycrc -- parameterisable CRC calculation utility and C source code generator
2#
3# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to
7# deal in the Software without restriction, including without limitation the
8# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9# sell copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21# IN THE SOFTWARE.
22
23
24"""
25CRC algorithms implemented in Python.
26If you want to study the Python implementation of the CRC routines, then this
27is a good place to start from.
28
29The algorithms Bit by Bit, Bit by Bit Fast and Table-Driven are implemented.
30
31This module can also be used as a library from within Python.
32
33Examples
34========
35
36This is an example use of the different algorithms:
37
38 from pycrc.algorithms import Crc
39
40 crc = Crc(width = 16, poly = 0x8005,
41 reflect_in = True, xor_in = 0x0000,
42 reflect_out = True, xor_out = 0x0000)
43 print("{0:#x}".format(crc.bit_by_bit("123456789")))
44 print("{0:#x}".format(crc.bit_by_bit_fast("123456789")))
45 print("{0:#x}".format(crc.table_driven("123456789")))
46"""
47
48class Crc(object):
49 """
50 A base class for CRC routines.
51 """
52 # pylint: disable=too-many-instance-attributes
53
54 def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_idx_width=None, slice_by=1):
55 """The Crc constructor.
56
57 The parameters are as follows:
58 width
59 poly
60 reflect_in
61 xor_in
62 reflect_out
63 xor_out
64 """
65 # pylint: disable=too-many-arguments
66
67 self.width = width
68 self.poly = poly
69 self.reflect_in = reflect_in
70 self.xor_in = xor_in
71 self.reflect_out = reflect_out
72 self.xor_out = xor_out
73 self.tbl_idx_width = table_idx_width
74 self.slice_by = slice_by
75
76 self.msb_mask = 0x1 << (self.width - 1)
77 self.mask = ((self.msb_mask - 1) << 1) | 1
78 if self.tbl_idx_width != None:
79 self.tbl_width = 1 << self.tbl_idx_width
80 else:
81 self.tbl_idx_width = 8
82 self.tbl_width = 1 << self.tbl_idx_width
83
84 self.direct_init = self.xor_in
85 self.nondirect_init = self.__get_nondirect_init(self.xor_in)
86 if self.width < 8:
87 self.crc_shift = 8 - self.width
88 else:
89 self.crc_shift = 0
90
91
92 def __get_nondirect_init(self, init):
93 """
94 return the non-direct init if the direct algorithm has been selected.
95 """
96 crc = init
97 for dummy_i in range(self.width):
98 bit = crc & 0x01
99 if bit:
100 crc ^= self.poly
101 crc >>= 1
102 if bit:
103 crc |= self.msb_mask
104 return crc & self.mask
105
106
107 def reflect(self, data, width):
108 """
109 reflect a data word, i.e. reverts the bit order.
110 """
111 # pylint: disable=no-self-use
112
113 res = data & 0x01
114 for dummy_i in range(width - 1):
115 data >>= 1
116 res = (res << 1) | (data & 0x01)
117 return res
118
119
120 def bit_by_bit(self, in_data):
121 """
122 Classic simple and slow CRC implementation. This function iterates bit
123 by bit over the augmented input message and returns the calculated CRC
124 value at the end.
125 """
126 # If the input data is a string, convert to bytes.
127 if isinstance(in_data, str):
128 in_data = bytearray(in_data, 'utf-8')
129
130 reg = self.nondirect_init
131 for octet in in_data:
132 if self.reflect_in:
133 octet = self.reflect(octet, 8)
134 for i in range(8):
135 topbit = reg & self.msb_mask
136 reg = ((reg << 1) & self.mask) | ((octet >> (7 - i)) & 0x01)
137 if topbit:
138 reg ^= self.poly
139
140 for i in range(self.width):
141 topbit = reg & self.msb_mask
142 reg = ((reg << 1) & self.mask)
143 if topbit:
144 reg ^= self.poly
145
146 if self.reflect_out:
147 reg = self.reflect(reg, self.width)
148 return (reg ^ self.xor_out) & self.mask
149
150
151 def bit_by_bit_fast(self, in_data):
152 """
153 This is a slightly modified version of the bit-by-bit algorithm: it
154 does not need to loop over the augmented bits, i.e. the Width 0-bits
155 wich are appended to the input message in the bit-by-bit algorithm.
156 """
157 # If the input data is a string, convert to bytes.
158 if isinstance(in_data, str):
159 in_data = bytearray(in_data, 'utf-8')
160
161 reg = self.direct_init
162 for octet in in_data:
163 if self.reflect_in:
164 octet = self.reflect(octet, 8)
165 for i in range(8):
166 topbit = reg & self.msb_mask
167 if octet & (0x80 >> i):
168 topbit ^= self.msb_mask
169 reg <<= 1
170 if topbit:
171 reg ^= self.poly
172 reg &= self.mask
173 if self.reflect_out:
174 reg = self.reflect(reg, self.width)
175 return reg ^ self.xor_out
176
177
178 def gen_table(self):
179 """
180 This function generates the CRC table used for the table_driven CRC
181 algorithm. The Python version cannot handle tables of an index width
182 other than 8. See the generated C code for tables with different sizes
183 instead.
184 """
185 table_length = 1 << self.tbl_idx_width
186 tbl = [[0 for i in range(table_length)] for j in range(self.slice_by)]
187 for i in range(table_length):
188 reg = i
189 if self.reflect_in:
190 reg = self.reflect(reg, self.tbl_idx_width)
191 reg = reg << (self.width - self.tbl_idx_width + self.crc_shift)
192 for dummy_j in range(self.tbl_idx_width):
193 if reg & (self.msb_mask << self.crc_shift) != 0:
194 reg = (reg << 1) ^ (self.poly << self.crc_shift)
195 else:
196 reg = (reg << 1)
197 if self.reflect_in:
198 reg = self.reflect(reg >> self.crc_shift, self.width) << self.crc_shift
199 tbl[0][i] = (reg >> self.crc_shift) & self.mask
200
201 for j in range(1, self.slice_by):
202 for i in range(table_length):
203 tbl[j][i] = (tbl[j - 1][i] >> 8) ^ tbl[0][tbl[j - 1][i] & 0xff]
204 return tbl
205
206
207 def table_driven(self, in_data):
208 """
209 The Standard table_driven CRC algorithm.
210 """
211 # pylint: disable = line-too-long
212
213 # If the input data is a string, convert to bytes.
214 if isinstance(in_data, str):
215 in_data = bytearray(in_data, 'utf-8')
216
217 tbl = self.gen_table()
218
219 if not self.reflect_in:
220 reg = self.direct_init << self.crc_shift
221 for octet in in_data:
222 tblidx = ((reg >> (self.width - self.tbl_idx_width + self.crc_shift)) ^ octet) & 0xff
223 reg = ((reg << (self.tbl_idx_width - self.crc_shift)) ^ (tbl[0][tblidx] << self.crc_shift)) & (self.mask << self.crc_shift)
224 reg = reg >> self.crc_shift
225 else:
226 reg = self.reflect(self.direct_init, self.width)
227 for octet in in_data:
228 tblidx = (reg ^ octet) & 0xff
229 reg = ((reg >> self.tbl_idx_width) ^ tbl[0][tblidx]) & self.mask
230 reg = self.reflect(reg, self.width) & self.mask
231
232 if self.reflect_out:
233 reg = self.reflect(reg, self.width)
234 return reg ^ self.xor_out
235