ECCHacks |
A gentle introduction to elliptic-curve cryptography |
|
Finite fieldsReduction modulo 7 is the operation that reads an integer, divides the integer by 7 to produce a quotient and remainder, and outputs the remainder. Math people write "x mod 7" for the reduction of x modulo 7. Python people write "x % 7": for n in range(0,20): print n,n%7 # output: 0 0 # output: 1 1 # output: 2 2 # output: 3 3 # output: 4 4 # output: 5 5 # output: 6 6 # output: 7 0 # output: 8 1 # output: 9 2 # output: 10 3 # output: 11 4 # output: 12 5 # output: 13 6 # output: 14 0 # output: 15 1 # output: 16 2 # output: 17 3 # output: 18 4 # output: 19 5 The output is always in the set {0,1,2,3,4,5,6}. Warning: C also has an "x % 7", but most compilers produce a negative remainder if x is negative, and we don't want negative remainders; the same operation in C is "((x % 7) + 7) % 7". A finite fieldF7 means the set {0,1,2,3,4,5,6} with the following overloaded arithmetic operations:
These operations, together with 0 and 1, satisfy all the equations that you expect: for example, x*(y-z) = x*y-x*z. Here's how to define an "F7" type in Python with its own +,-,*, separate from the integer +,-,*. First let's define an initializer F7(x) converting an integer x into x mod 7, and some output functions: class F7: def __init__(self,x): self.int = x % 7 def __str__(self): return str(self.int) __repr__ = __str__ # examples: print F7(2) # output: 2 print F7(6) # output: 6 print F7(7) # output: 0 print F7(10) # output: 3 Now we can define +,-,* operations for this type: F7.__add__ = lambda a,b: F7(a.int + b.int) F7.__sub__ = lambda a,b: F7(a.int - b.int) F7.__mul__ = lambda a,b: F7(a.int * b.int) # examples: print F7(2) + F7(5) # output: 0 print F7(2) - F7(5) # output: 4 print F7(2) * F7(5) # output: 3 Let's also allow equality tests and inequality tests: F7.__eq__ = lambda a,b: a.int==b.int F7.__ne__ = lambda a,b: a.int!=b.int # examples: print F7(7) == F7(0) # output: True print F7(10) == F7(3) # output: True print F7(-3) == F7(4) # output: True print F7(0) != F7(1) # output: True print F7(0) != F7(2) # output: True print F7(1) != F7(2) # output: True print F7(7) != F7(0) # output: False print F7(10) != F7(3) # output: False print F7(-3) != F7(4) # output: False print F7(0) == F7(1) # output: False print F7(0) == F7(2) # output: False print F7(1) == F7(2) # output: False Division, and the field conceptThe equations 1*1=1, 2*4=1, 3*5=1, 6*6=1 in F7 show that 1, 2, 3, 4, 5, 6 have reciprocals in F7: 1/1 = 1, 1/2 = 4, 1/3 = 5, 1/4 = 2, 1/5 = 3, 1/6 = 6. 0 doesn't have a reciprocal: there's nothing you can multiply 0 by to obtain 1. We don't say field, and don't use the F notation, unless the nonzero elements are exactly the elements with reciprocals. For example, the integers modulo 10 aren't a field (and there isn't an F10), since the set {1,2,3,4,5,6,7,8,9} of nonzero integers modulo 10 isn't the same as the set {1,3,7,9} of integers modulo 10 with reciprocals. As another (nitpicky) example, the integers modulo 1 aren't a field, since the set {} of nonzero integers modulo 1 isn't the same as the set {0} of integers modulo 1 with reciprocals. More finite fieldsFor every prime number p (2 or 3 or 5 or 7 or 11 or ...), Fp is the finite field of integers modulo p: def F(p): # caveat: caller must ensure that p is prime class F: def __init__(self,x): self.int = x % p def __str__(self): return str(self.int) __repr__ = __str__ def __eq__(a,b): return a.int == b.int def __ne__(a,b): return a.int != b.int def __add__(a,b): return F(a.int + b.int) def __sub__(a,b): return F(a.int - b.int) def __mul__(a,b): return F(a.int * b.int) def __div__(a,b): # caveat: caller must ensure that b is nonzero return a*F(pow(b.int,p-2,p)) return F # examples: F1009 = F(1009) print F1009(-1) == F1009(1008) # output: True print F1009(6) != F1009(5) # output: True print F1009(101) + F1009(1000) == F1009(92) # output: True print F1009(101) - F1009(1000) == F1009(110) # output: True print F1009(101) * F1009(1000) == F1009(100) # output: True print F1009(101) / F1009(1000) == F1009(213) # output: True There are also "non-prime" finite fields (of sizes 4, 8, 9, 16, 25, 27, 32, ...), but we won't need those for ECCHacks. The __div__ function above uses "Fermat's little theorem", which says that you can compute the reciprocal of any nonzero x in Fp by computing xp-2. There are other division methods, but the Fermat method is very simple to implement, and its performance is tolerable even when p is very large. Version: This is version 2014.12.27 of the finitefield.html web page. |