11"""Module for calculating CRC-sums.
22
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.
55
66It is horribly slow, as implements a naive algorithm working direclty on
7- bit polynomials.
7+ bit polynomials. This class is exposed as `BitPolynom`.
88
99The current algorithm is super-linear and takes about 4 seconds to calculate
1010the crc32-sum of ``'A'*40000``.
1818from . import known
1919from .. import fiddling
2020from .. import packing
21+ from .. import safeeval
2122
2223
2324class 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+
2466 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" )
3085
3186 def __int__ (self ):
3287 return self .n
@@ -126,25 +181,51 @@ def __rshift__(self, other):
126181 def __rrshift__ (self , other ):
127182 return BitPolynom (int (other ) >> int (self ))
128183
184+ def __pow__ (self , other ):
185+ r = BitPolynom (1 )
186+ for _ in range (other ):
187+ r *= self
188+ return r
189+
129190 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+ """
130208 return max (0 , int (self ).bit_length ()- 1 )
131209
132210 def __repr__ (self ):
133211 if int (self ) == 0 :
134212 return '0'
135213
136214 out = []
137- for n in range (self .degree (), 0 , - 1 ):
215+ for n in range (self .degree (), 1 , - 1 ):
138216 if int (self ) & (1 << n ):
139217 out .append ("x**%d" % n )
218+ if int (self ) & 2 :
219+ out .append ("x" )
140220 if int (self ) & 1 :
141221 out .append ("1" )
142- return ' + ' .join (out )
222+ return 'BitPolynom(%r)' % ' + ' .join (out )
143223
144224class Module (types .ModuleType ):
145225 def __init__ (self ):
146226 super (Module , self ).__init__ (__name__ )
147227 self ._cached_crcs = None
228+ self .BitPolynom = BitPolynom
148229 self .__dict__ .update ({
149230 '__file__' : __file__ ,
150231 '__package__' : __package__ ,
@@ -154,7 +235,7 @@ def __getattr__(self, attr):
154235 crcs = known .all_crcs
155236
156237 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 ())
158239
159240 info = crcs .get (attr , None )
160241 if not info :
0 commit comments