Updated for Python3

This commit is contained in:
Ethan L. Miller 2020-09-02 12:20:36 -07:00
parent 54cbe3c594
commit 0d92601702

View File

@ -23,13 +23,19 @@ class GaloisNumber:
The class supports "normal" syntax for the addition, subtraction, multiplication, The class supports "normal" syntax for the addition, subtraction, multiplication,
division, additive inverse (-), and multiplicative inverse (~) operations. division, additive inverse (-), and multiplicative inverse (~) operations.
''' '''
def __init__ (self, x, value=0): def __init__ (self, x, field=None):
if isinstance(x, GaloisNumber): if isinstance(x, GaloisNumber):
self.field = x.field self.field = x.field
self.value = x.value self.value = x.value
elif type(field) not in (GaloisFieldLog, GaloisFieldDirect):
raise ValueError ("Must specify field")
else: else:
self.field = x self.field = field
self.assign (value) if type(x) == bytes:
x = int.from_bytes (x, 'big')
elif type(x) != int:
raise ValueError ("Must be an integer or bytes")
self.assign (x)
def assign (self, v): def assign (self, v):
''' '''
@ -37,13 +43,13 @@ class GaloisNumber:
the field with which the GaloisNumber instance was defined. the field with which the GaloisNumber instance was defined.
''' '''
if v > self.field.size: if v > self.field.size:
raise GaloisException ("Value {0} is outside field".format (v)) raise ValueError ("Value {0} is outside field".format (v))
self.value = v self.value = v
def __add__ (self, other): def __add__ (self, other):
if self.field != other.field: if self.field != other.field:
raise GaloisException ("Field elements from different fields") raise GaloisException ("Field elements from different fields")
return GaloisNumber (self.field, self.value ^ other.value) return GaloisNumber (self.value ^ other.value, self.field)
def __iadd__ (self, other): def __iadd__ (self, other):
if self.field != other.field: if self.field != other.field:
@ -72,11 +78,14 @@ class GaloisNumber:
raise GaloisException ("Field elements from different fields") raise GaloisException ("Field elements from different fields")
self.value = self.field.direct_multiply (self.value, other.value) self.value = self.field.direct_multiply (self.value, other.value)
def __div__ (self, other): def __floordiv__ (self, other):
if self.field != other.field: if self.field != other.field:
raise GaloisException ("Field elements from different fields") raise GaloisException ("Field elements from different fields")
return self.field.divide (self, other) return self.field.divide (self, other)
def __truediv__ (self, other):
return self // other
def __eq__ (self, other): def __eq__ (self, other):
if self.field != other.field: if self.field != other.field:
raise GaloisException ("Field elements from different fields") raise GaloisException ("Field elements from different fields")
@ -128,33 +137,32 @@ class GaloisFieldLog:
a = v1.value a = v1.value
b = v2.value b = v2.value
if a == 0 or b == 0: if a == 0 or b == 0:
return GaloisNumber (self, 0) return GaloisNumber (0, self)
return GaloisNumber (self, self.antilog_tbl[(self.log_tbl[a] + self.log_tbl[b]) % return GaloisNumber (self.antilog_tbl[(self.log_tbl[a] + self.log_tbl[b]) % (self.size - 1)], self)
(self.size - 1)])
def invert (self, v): def invert (self, v):
if v.value == 0: if v.value == 0:
return GaloisNumber(self, 0) return GaloisNumber(0, self)
elif v.value == 1: elif v.value == 1:
return GaloisNumber (self, 1) return GaloisNumber (1, self)
else: else:
return GaloisNumber (self, self.antilog_tbl[self.size - 1 - self.log_tbl[v.value]]) return GaloisNumber (self.antilog_tbl[self.size - 1 - self.log_tbl[v.value]], self)
def divide (self, v1, v2): def divide (self, v1, v2):
return self.multiply (v1, self.invert(v2)) return self.multiply (v1, self.invert(v2))
def self_test (self): def self_test (self):
mul_identity = GaloisNumber (self, 1) mul_identity = GaloisNumber (1, self)
v = GaloisNumber (self) v = GaloisNumber (0, self)
g_0 = GaloisNumber (self, 0) g_0 = GaloisNumber (0, self)
g_1 = GaloisNumber (self, 1) g_1 = GaloisNumber (1, self)
for i in range (self.size): for i in range (self.size):
v.assign (i) v.assign (i)
if i == 0: continue if i == 0: continue
assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i) assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i)
assert g_0 - v == -v, "Additive inverse failed at {}".format (i) assert g_0 - v == -v, "Additive inverse failed at {}".format (i)
assert v * g_1 == v, "Multiplicative identity failed at {}".format (i) assert v * g_1 == v, "Multiplicative identity failed at {}".format (i)
vb = GaloisNumber (self) vb = GaloisNumber (0, self)
for a in range (1, self.multiply_test_size): for a in range (1, self.multiply_test_size):
v.assign (random.randint (1, self.size - 1)) v.assign (random.randint (1, self.size - 1))
vb.assign (random.randint (1, self.size - 1)) vb.assign (random.randint (1, self.size - 1))
@ -184,7 +192,7 @@ class GaloisFieldDirect:
self.bits = bits self.bits = bits
self.size = (1 << bits) self.size = (1 << bits)
self.prim = self.poly_defaults[bits] if not primitive_polynomial else primitive_polynomial self.prim = self.poly_defaults[bits] if not primitive_polynomial else primitive_polynomial
self.value_format = repr_prefix + '{:0>' + str(bits / 4) + 'x}' self.value_format = repr_prefix + '{:0>' + str(bits // 4) + 'x}'
self.alpha = alpha self.alpha = alpha
def __eq__ (self, other): def __eq__ (self, other):
@ -194,7 +202,7 @@ class GaloisFieldDirect:
return self.value_format.format (v) return self.value_format.format (v)
def multiply (self, v1, v2): def multiply (self, v1, v2):
return GaloisNumber (self, self.direct_multiply (v1.value, v2.value)) return GaloisNumber (self.direct_multiply (v1.value, v2.value), self)
def direct_multiply (self, a, b): def direct_multiply (self, a, b):
# Multiplication is commutative, and it's faster if we use the smaller value as the # Multiplication is commutative, and it's faster if we use the smaller value as the
@ -223,24 +231,24 @@ class GaloisFieldDirect:
to field width in bits. to field width in bits.
''' '''
if v.value == 0: if v.value == 0:
return GaloisNumber(self, 0) return GaloisNumber(0, self)
elif v.value == 1: elif v.value == 1:
return GaloisNumber (self, 1) return GaloisNumber (1, self)
inv = 1 inv = 1
sq = v.value sq = v.value
for i in range (1, self.bits): for i in range (1, self.bits):
sq = self.direct_multiply (sq, sq) sq = self.direct_multiply (sq, sq)
inv = self.direct_multiply (inv, sq) inv = self.direct_multiply (inv, sq)
return GaloisNumber (self, inv) return GaloisNumber (inv, self)
def divide (self, v1, v2): def divide (self, v1, v2):
return self.multiply (v1, self.invert(v2)) return self.multiply (v1, self.invert(v2))
def self_test (self): def self_test (self):
mul_identity = GaloisNumber (self, 1) mul_identity = GaloisNumber (1, self)
v = GaloisNumber (self) v = GaloisNumber (0, self)
g_0 = GaloisNumber (self, 0) g_0 = GaloisNumber (0, self)
g_1 = GaloisNumber (self, 1) g_1 = GaloisNumber (1, self)
small_field = self.size < self.max_test_size small_field = self.size < self.max_test_size
n_tests = (self.size - 1) if small_field else self.max_test_size n_tests = (self.size - 1) if small_field else self.max_test_size
for i in range (0, n_tests): for i in range (0, n_tests):
@ -248,7 +256,7 @@ class GaloisFieldDirect:
assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i) assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i)
assert g_0 - v == -v, "Additive inverse failed at {}".format (i) assert g_0 - v == -v, "Additive inverse failed at {}".format (i)
assert v * g_1 == v, "Multiplicative identity failed at {}".format (i) assert v * g_1 == v, "Multiplicative identity failed at {}".format (i)
vb = GaloisNumber (self) vb = GaloisNumber (0, self)
for a in range (1, self.max_test_size): for a in range (1, self.max_test_size):
v.assign (random.randint (1, self.size - 1)) v.assign (random.randint (1, self.size - 1))
vb.assign (random.randint (1, self.size - 1)) vb.assign (random.randint (1, self.size - 1))
@ -261,16 +269,16 @@ if __name__ == '__main__':
print ('\nTesting direct fields...........') print ('\nTesting direct fields...........')
for width in GaloisFieldDirect.field_widths: for width in GaloisFieldDirect.field_widths:
field = GaloisFieldDirect (width) field = GaloisFieldDirect (width)
g0 = GaloisNumber (field, 2) g0 = GaloisNumber (2, field)
g1 = GaloisNumber (field, 7) g1 = GaloisNumber (7, field)
print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1)) print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1))
if field.self_test (): if field.self_test ():
print ("{0} bit field (direct) passed!".format (width)) print ("{0} bit field (direct) passed!".format (width))
print ('\nTesting log fields...........') print ('\nTesting log fields...........')
for width in GaloisFieldLog.field_widths: for width in GaloisFieldLog.field_widths:
field = GaloisFieldLog (width) field = GaloisFieldLog (width)
g0 = GaloisNumber (field, 2) g0 = GaloisNumber (2, field)
g1 = GaloisNumber (field, 7) g1 = GaloisNumber (7, field)
print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1)) print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1))
if field.self_test (): if field.self_test ():
print ("{0} bit field (log) passed!".format (width)) print ("{0} bit field (log) passed!".format (width))