1
1
"""Module for calculating CRC-sums.
2
2
3
- Contains all crc implementations know on the interwebz. For most implementations it
4
- contains only the core crc algorithm and not e.g. padding schemes.
3
+ Contains all crc implementations know on the interwebz. For most implementations
4
+ it contains only the core crc algorithm and not e.g. padding schemes.
5
5
6
6
It is horribly slow, as implements a naive algorithm working direclty on
7
- bit polynomials.
7
+ bit polynomials. This class is exposed as `BitPolynom`.
8
8
9
9
The current algorithm is super-linear and takes about 4 seconds to calculate
10
10
the crc32-sum of ``'A'*40000``.
18
18
from . import known
19
19
from .. import fiddling
20
20
from .. import packing
21
+ from .. import safeeval
21
22
22
23
23
24
class BitPolynom (object ):
25
+ """Class for representing GF(2)[X], i.e. the field of polynomials over
26
+ GF(2).
27
+
28
+ In practice the polynomials are represented as numbers such that `x**n`
29
+ corresponds to `1 << n`. In this representation calculations are easy: Just
30
+ do everything as normal, but forget about everything the carries.
31
+
32
+ Addition becomes xor and multiplication becomes carry-less multiplication.
33
+
34
+ Examples:
35
+
36
+ >>> p1 = BitPolynom("x**3 + x + 1")
37
+ >>> p1
38
+ BitPolynom('x**3 + x + 1')
39
+ >>> int(p1)
40
+ 11
41
+ >>> p1 == BitPolynom(11)
42
+ True
43
+ >>> p2 = BitPolynom("x**2 + x + 1")
44
+ >>> p1 + p2
45
+ BitPolynom('x**3 + x**2')
46
+ >>> p1 * p2
47
+ BitPolynom('x**5 + x**4 + 1')
48
+ >>> p1 / p2
49
+ BitPolynom('x + 1')
50
+ >>> p1 % p2
51
+ BitPolynom('x')
52
+ >>> d, r = divmod(p1, p2)
53
+ >>> d * p2 + r == p1
54
+ True
55
+ >>> BitPolynom(-1)
56
+ Traceback (most recent call last):
57
+ ...
58
+ ValueError: Polynomials cannot be negative: -1
59
+ >>> BitPolynom('y')
60
+ Traceback (most recent call last):
61
+ ...
62
+ ValueError: Not a valid polynomial: y
63
+ """
64
+
65
+
24
66
def __init__ (self , n ):
25
- if not isinstance (n , (int , long )):
26
- raise TypeError ("Polynomial must be called with an integer or a list" )
27
- if n < 0 :
28
- raise ValueError ("Polynomials cannot be negative: %d" % n )
29
- self .n = n
67
+ if isinstance (n , (str , unicode )):
68
+ self .n = 0
69
+ x = BitPolynom (2 )
70
+ try :
71
+ for p in n .split ('+' ):
72
+ k = safeeval .values (p .strip (), {'x' : x , 'X' : x })
73
+ assert isinstance (k , (BitPolynom , int , long ))
74
+ assert k >= 0
75
+ self .n ^= int (k )
76
+ except (ValueError , NameError , AssertionError ):
77
+ raise ValueError ("Not a valid polynomial: %s" % n )
78
+ elif isinstance (n , (int , long )):
79
+ if n >= 0 :
80
+ self .n = n
81
+ else :
82
+ raise ValueError ("Polynomials cannot be negative: %d" % n )
83
+ else :
84
+ raise TypeError ("Polynomial must be called with a string or integer" )
30
85
31
86
def __int__ (self ):
32
87
return self .n
@@ -126,25 +181,51 @@ def __rshift__(self, other):
126
181
def __rrshift__ (self , other ):
127
182
return BitPolynom (int (other ) >> int (self ))
128
183
184
+ def __pow__ (self , other ):
185
+ r = BitPolynom (1 )
186
+ for _ in range (other ):
187
+ r *= self
188
+ return r
189
+
129
190
def degree (self ):
191
+ """Returns the degree of the polynomial.
192
+
193
+ Examples:
194
+
195
+ >>> BitPolynom(0).degree()
196
+ 0
197
+ >>> BitPolynom(1).degree()
198
+ 0
199
+ >>> BitPolynom(2).degree()
200
+ 1
201
+ >>> BitPolynom(7).degree()
202
+ 2
203
+ >>> BitPolynom((1 << 10) - 1).degree()
204
+ 9
205
+ >>> BitPolynom(1 << 10).degree()
206
+ 10
207
+ """
130
208
return max (0 , int (self ).bit_length ()- 1 )
131
209
132
210
def __repr__ (self ):
133
211
if int (self ) == 0 :
134
212
return '0'
135
213
136
214
out = []
137
- for n in range (self .degree (), 0 , - 1 ):
215
+ for n in range (self .degree (), 1 , - 1 ):
138
216
if int (self ) & (1 << n ):
139
217
out .append ("x**%d" % n )
218
+ if int (self ) & 2 :
219
+ out .append ("x" )
140
220
if int (self ) & 1 :
141
221
out .append ("1" )
142
- return ' + ' .join (out )
222
+ return 'BitPolynom(%r)' % ' + ' .join (out )
143
223
144
224
class Module (types .ModuleType ):
145
225
def __init__ (self ):
146
226
super (Module , self ).__init__ (__name__ )
147
227
self ._cached_crcs = None
228
+ self .BitPolynom = BitPolynom
148
229
self .__dict__ .update ({
149
230
'__file__' : __file__ ,
150
231
'__package__' : __package__ ,
@@ -154,7 +235,7 @@ def __getattr__(self, attr):
154
235
crcs = known .all_crcs
155
236
156
237
if attr == '__all__' :
157
- return ['generic_crc' , 'cksum' , 'find_crc_function' ] + sorted (crcs .keys ())
238
+ return ['BitPolynom' , ' generic_crc' , 'cksum' , 'find_crc_function' ] + sorted (crcs .keys ())
158
239
159
240
info = crcs .get (attr , None )
160
241
if not info :
0 commit comments