Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/rings/finite_rings/finite_field_givaro.py
4145 views
1
2
from sage.rings.finite_rings.finite_field_base import FiniteField, is_FiniteField
3
from sage.rings.integer import Integer
4
from sage.rings.finite_rings.element_givaro import Cache_givaro
5
from sage.rings.integer_ring import ZZ
6
from sage.databases.conway import ConwayPolynomials
7
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic
8
from sage.libs.pari.all import pari
9
10
class FiniteField_givaro(FiniteField):
11
def __init__(self, q, name="a", modulus=None, repr="poly", cache=False):
12
"""
13
Finite Field. These are implemented using Zech logs and the
14
cardinality must be < 2^16. By default conway polynomials are
15
used as minimal polynomial.
16
17
INPUT:
18
q -- p^n (must be prime power)
19
name -- variable used for poly_repr (default: 'a')
20
modulus -- you may provide a minimal polynomial to use for
21
reduction or 'random' to force a random
22
irreducible polynomial. (default: None, a conway
23
polynomial is used if found. Otherwise a random
24
polynomial is used)
25
repr -- controls the way elements are printed to the user:
26
(default: 'poly')
27
'log': repr is element.log_repr()
28
'int': repr is element.int_repr()
29
'poly': repr is element.poly_repr()
30
cache -- if True a cache of all elements of this field is
31
created. Thus, arithmetic does not create new
32
elements which speeds calculations up. Also, if
33
many elements are needed during a calculation
34
this cache reduces the memory requirement as at
35
most self.order() elements are created. (default: False)
36
37
OUTPUT:
38
Givaro finite field with characteristic p and cardinality p^n.
39
40
EXAMPLES:
41
42
By default conway polynomials are used:
43
44
sage: k.<a> = GF(2**8)
45
sage: -a ^ k.degree()
46
a^4 + a^3 + a^2 + 1
47
sage: f = k.modulus(); f
48
x^8 + x^4 + x^3 + x^2 + 1
49
50
You may enforce a modulus:
51
52
sage: P.<x> = PolynomialRing(GF(2))
53
sage: f = x^8 + x^4 + x^3 + x + 1 # Rijndael Polynomial
54
sage: k.<a> = GF(2^8, modulus=f)
55
sage: k.modulus()
56
x^8 + x^4 + x^3 + x + 1
57
sage: a^(2^8)
58
a
59
60
You may enforce a random modulus:
61
62
sage: k = GF(3**5, 'a', modulus='random')
63
sage: k.modulus() # random polynomial
64
x^5 + 2*x^4 + 2*x^3 + x^2 + 2
65
66
Three different representations are possible:
67
68
sage: sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro(9,repr='poly').gen()
69
a
70
sage: sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro(9,repr='int').gen()
71
3
72
sage: sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro(9,repr='log').gen()
73
5
74
75
sage: k.<a> = GF(2^3)
76
sage: j.<b> = GF(3^4)
77
sage: k == j
78
False
79
80
sage: GF(2^3,'a') == copy(GF(2^3,'a'))
81
True
82
sage: TestSuite(j).run()
83
"""
84
self._kwargs = {}
85
86
if repr not in ['int', 'log', 'poly']:
87
raise ValueError, "Unknown representation %s"%repr
88
89
q = Integer(q)
90
if q < 2:
91
raise ValueError, "q must be a prime power"
92
F = q.factor()
93
if len(F) > 1:
94
raise ValueError, "q must be a prime power"
95
p = F[0][0]
96
k = F[0][1]
97
98
if q >= 1<<16:
99
raise ValueError, "q must be < 2^16"
100
101
import constructor
102
FiniteField.__init__(self, constructor.FiniteField(p), name, normalize=False)
103
104
self._kwargs['repr'] = repr
105
self._kwargs['cache'] = cache
106
107
self._is_conway = False
108
if modulus is None or modulus == 'conway':
109
if k == 1:
110
modulus = 'random' # this will use the gfq_factory_pk function.
111
elif ConwayPolynomials().has_polynomial(p, k):
112
from sage.rings.finite_rings.constructor import conway_polynomial
113
modulus = conway_polynomial(p, k)
114
self._is_conway = True
115
elif modulus is None:
116
modulus = 'random'
117
else:
118
raise ValueError, "Conway polynomial not found"
119
120
from sage.rings.polynomial.all import is_Polynomial
121
if is_Polynomial(modulus):
122
modulus = modulus.list()
123
124
self._cache = Cache_givaro(self, p, k, modulus, repr, cache)
125
126
def characteristic(self):
127
"""
128
Return the characteristic of this field.
129
130
EXAMPLES:
131
sage: p = GF(19^5,'a').characteristic(); p
132
19
133
sage: type(p)
134
<type 'sage.rings.integer.Integer'>
135
"""
136
return Integer(self._cache.characteristic())
137
138
def order(self):
139
"""
140
Return the cardinality of this field.
141
142
OUTPUT:
143
Integer -- the number of elements in self.
144
145
EXAMPLES:
146
sage: n = GF(19^5,'a').order(); n
147
2476099
148
sage: type(n)
149
<type 'sage.rings.integer.Integer'>
150
"""
151
return self._cache.order()
152
153
def degree(self):
154
r"""
155
If \code{self.cardinality() == p^n} this method returns $n$.
156
157
OUTPUT:
158
Integer -- the degree
159
160
EXAMPLES:
161
sage: GF(3^4,'a').degree()
162
4
163
"""
164
return Integer(self._cache.exponent())
165
166
def is_atomic_repr(self):
167
"""
168
Return whether elements of self are printed using an atomic
169
representation.
170
171
EXAMPLES:
172
sage: GF(3^4,'a').is_atomic_repr()
173
False
174
"""
175
if self._cache.repr==0: #modulus
176
return False
177
else:
178
return True
179
180
def random_element(self, *args, **kwds):
181
"""
182
Return a random element of self.
183
184
INPUT:
185
*args -- ignored
186
**kwds -- ignored
187
188
EXAMPLES:
189
sage: k = GF(23**3, 'a')
190
sage: e = k.random_element(); e
191
9*a^2 + 10*a + 3
192
sage: type(e)
193
<type 'sage.rings.finite_rings.element_givaro.FiniteField_givaroElement'>
194
195
sage: P.<x> = PowerSeriesRing(GF(3^3, 'a'))
196
sage: P.random_element(5)
197
a^2 + 2*a + 1 + (a + 1)*x + (a^2 + a + 1)*x^2 + (a^2 + 1)*x^3 + (2*a^2 + a)*x^4 + O(x^5)
198
"""
199
return self._cache.random_element()
200
201
def _element_constructor_(self, e):
202
"""
203
Coerces several data types to self.
204
205
INPUT:
206
207
e -- data to coerce
208
209
EXAMPLES:
210
211
FiniteField_givaroElement are accepted where the parent
212
is either self, equals self or is the prime subfield::
213
214
sage: k = GF(2**8, 'a')
215
sage: k.gen() == k(k.gen())
216
True
217
218
Floats, ints, longs, Integer are interpreted modulo characteristic::
219
220
sage: k(2) # indirect doctest
221
0
222
223
Floats coerce in:
224
sage: k(float(2.0))
225
0
226
227
Rational are interpreted as self(numerator)/self(denominator).
228
Both may not be >= self.characteristic().
229
::
230
231
sage: k = GF(3**8, 'a')
232
sage: k(1/2) == k(1)/k(2)
233
True
234
235
Free module elements over self.prime_subfield() are interpreted 'little endian'::
236
237
sage: k = GF(2**8, 'a')
238
sage: e = k.vector_space().gen(1); e
239
(0, 1, 0, 0, 0, 0, 0, 0)
240
sage: k(e)
241
a
242
243
'None' yields zero::
244
245
sage: k(None)
246
0
247
248
Strings are evaluated as polynomial representation of elements in self::
249
250
sage: k('a^2+1')
251
a^2 + 1
252
253
Univariate polynomials coerce into finite fields by evaluating
254
the polynomial at the field's generator::
255
256
sage: from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro
257
sage: R.<x> = QQ[]
258
sage: k, a = FiniteField_givaro(5^2, 'a').objgen()
259
sage: k(R(2/3))
260
4
261
sage: k(x^2)
262
a + 3
263
sage: R.<x> = GF(5)[]
264
sage: k(x^3-2*x+1)
265
2*a + 4
266
267
sage: x = polygen(QQ)
268
sage: k(x^25)
269
a
270
271
sage: Q, q = FiniteField_givaro(5^3,'q').objgen()
272
sage: L = GF(5)
273
sage: LL.<xx> = L[]
274
sage: Q(xx^2 + 2*xx + 4)
275
q^2 + 2*q + 4
276
277
278
Multivariate polynomials only coerce if constant::
279
280
sage: R = k['x,y,z']; R
281
Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 5^2
282
sage: k(R(2))
283
2
284
sage: R = QQ['x,y,z']
285
sage: k(R(1/5))
286
Traceback (most recent call last):
287
...
288
ZeroDivisionError: division by zero in finite field.
289
290
291
PARI elements are interpreted as finite field elements; this PARI flexibility
292
is (absurdly!) liberal::
293
294
sage: k = GF(2**8, 'a')
295
sage: k(pari('Mod(1,2)'))
296
1
297
sage: k(pari('Mod(2,3)'))
298
0
299
sage: k(pari('Mod(1,3)*a^20'))
300
a^7 + a^5 + a^4 + a^2
301
302
GAP elements need to be finite field elements::
303
304
sage: from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro
305
sage: x = gap('Z(13)')
306
sage: F = FiniteField_givaro(13)
307
sage: F(x)
308
2
309
sage: F(gap('0*Z(13)'))
310
0
311
sage: F = FiniteField_givaro(13^2)
312
sage: x = gap('Z(13)')
313
sage: F(x)
314
2
315
sage: x = gap('Z(13^2)^3')
316
sage: F(x)
317
12*a + 11
318
sage: F.multiplicative_generator()^3
319
12*a + 11
320
321
sage: k.<a> = GF(29^3)
322
sage: k(48771/1225)
323
28
324
325
sage: from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro
326
sage: F9 = FiniteField_givaro(9)
327
sage: F81 = FiniteField_givaro(81)
328
sage: F81(F9.gen())
329
Traceback (most recent call last):
330
...
331
TypeError: unable to coerce from a finite field other than the prime subfield
332
"""
333
return self._cache.element_from_data(e)
334
335
def _coerce_map_from_(self, R):
336
"""
337
Returns True if this finite field has a coercion map from R.
338
339
EXAMPLES::
340
341
sage: k.<a> = GF(3^8)
342
sage: a + 1 # indirect doctest
343
a + 1
344
sage: a + int(1)
345
a + 1
346
sage: a + GF(3)(1)
347
a + 1
348
"""
349
from sage.rings.integer_ring import ZZ
350
from sage.rings.finite_rings.finite_field_base import is_FiniteField
351
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic
352
if R is int or R is long or R is ZZ:
353
return True
354
if is_FiniteField(R):
355
if R is self:
356
return True
357
from sage.rings.residue_field import ResidueField_generic
358
if isinstance(R, ResidueField_generic):
359
return False
360
if R.characteristic() == self.characteristic():
361
if isinstance(R, IntegerModRing_generic):
362
return True
363
if R.degree() == 1:
364
return True
365
elif self.degree() % R.degree() == 0:
366
# This is where we *would* do coercion from one nontrivial finite field to another...
367
# We use this error message for backward compatibility until #8335 is finished
368
raise TypeError, "unable to coerce from a finite field other than the prime subfield"
369
370
def gen(self, n=0):
371
r"""
372
Return a generator of self. All elements x of self are
373
expressed as $\log_{self.gen()}(p)$ internally.
374
375
This generator might differ between different runs or
376
different architectures.
377
378
WARNING: The generator is not guaranteed to be a generator for
379
the multiplicative group. To obtain the latter, use
380
multiplicative_generator().
381
382
EXAMPLES:
383
sage: k = GF(3^4, 'b'); k.gen()
384
b
385
sage: k.gen(1)
386
Traceback (most recent call last):
387
...
388
IndexError: only one generator
389
sage: F = sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro(31)
390
sage: F.gen()
391
1
392
"""
393
if n > 0:
394
raise IndexError, "only one generator"
395
return self._cache.gen()
396
397
def prime_subfield(self):
398
r"""
399
Return the prime subfield $\FF_p$ of self if self is $\FF_{p^n}$.
400
401
EXAMPLES:
402
sage: GF(3^4, 'b').prime_subfield()
403
Finite Field of size 3
404
405
sage: S.<b> = GF(5^2); S
406
Finite Field in b of size 5^2
407
sage: S.prime_subfield()
408
Finite Field of size 5
409
sage: type(S.prime_subfield())
410
<class 'sage.rings.finite_rings.finite_field_prime_modn.FiniteField_prime_modn_with_category'>
411
"""
412
try:
413
return self._prime_subfield
414
except AttributeError:
415
import constructor
416
self._prime_subfield = constructor.FiniteField(self.characteristic())
417
return self._prime_subfield
418
419
def log_to_int(self, n):
420
r"""
421
Given an integer $n$ this method returns $i$ where $i$
422
satisfies \code{self.gen()^n == i}, if the result is
423
interpreted as an integer.
424
425
INPUT:
426
n -- log representation of a finite field element
427
428
OUTPUT:
429
integer representation of a finite field element.
430
431
EXAMPLE:
432
sage: k = GF(2**8, 'a')
433
sage: k.log_to_int(4)
434
16
435
sage: k.log_to_int(20)
436
180
437
"""
438
return self._cache.log_to_int(n)
439
440
def int_to_log(self, n):
441
r"""
442
Given an integer $n$ this method returns $i$ where $i$ satisfies
443
\code{self.gen()^i==(n\%self.characteristic())}.
444
445
INPUT:
446
n -- integer representation of an finite field element
447
448
OUTPUT:
449
log representation of n
450
451
EXAMPLE:
452
sage: k = GF(7**3, 'a')
453
sage: k.int_to_log(4)
454
228
455
sage: k.int_to_log(3)
456
57
457
sage: k.gen()^57
458
3
459
"""
460
return self._cache.int_to_log(n)
461
462
def fetch_int(self, n):
463
r"""
464
Given an integer $n$ return a finite field element in self
465
which equals $n$ under the condition that self.gen() is set to
466
self.characteristic().
467
468
EXAMPLE:
469
sage: k.<a> = GF(2^8)
470
sage: k.fetch_int(8)
471
a^3
472
sage: e = k.fetch_int(151); e
473
a^7 + a^4 + a^2 + a + 1
474
sage: 2^7 + 2^4 + 2^2 + 2 + 1
475
151
476
"""
477
return self._cache.fetch_int(n)
478
479
def polynomial(self, name=None):
480
"""
481
Return the defining polynomial of this field as an element of
482
self.polynomial_ring().
483
484
This is the same as the characteristic polynomial of the
485
generator of self.
486
487
INPUT:
488
name -- optional name of the generator
489
490
EXAMPLES:
491
sage: k = GF(3^4, 'a')
492
sage: k.polynomial()
493
a^4 + 2*a^3 + 2
494
"""
495
if name is not None:
496
try:
497
return self._polynomial
498
except AttributeError:
499
pass
500
quo = (-(self.gen()**(self.degree()))).integer_representation()
501
b = int(self.characteristic())
502
503
ret = []
504
for i in range(self.degree()):
505
ret.append(quo%b)
506
quo = quo/b
507
ret = ret + [1]
508
R = self.polynomial_ring(name)
509
if name is None:
510
self._polynomial = R(ret)
511
return self._polynomial
512
else:
513
return R(ret)
514
515
def __hash__(self):
516
"""
517
The hash of a Givaro finite field is a hash over it's
518
characteristic polynomial and the string 'givaro'.
519
520
EXAMPLES:
521
sage: {GF(3^4, 'a'):1} #indirect doctest
522
{Finite Field in a of size 3^4: 1}
523
"""
524
try:
525
return self._hash
526
except AttributeError:
527
if self.degree() > 1:
528
self._hash = hash((self.characteristic(), self.polynomial(), self.variable_name(), "givaro"))
529
else:
530
self._hash = hash((self.characteristic(), self.variable_name(), "givaro"))
531
return self._hash
532
533
def _pari_modulus(self):
534
"""
535
EXAMPLES:
536
sage: GF(3^4,'a')._pari_modulus()
537
Mod(1, 3)*a^4 + Mod(2, 3)*a^3 + Mod(2, 3)
538
"""
539
f = pari(str(self.modulus()))
540
return f.subst('x', 'a') * pari("Mod(1,%s)"%self.characteristic())
541
542
def _finite_field_ext_pari_(self): # todo -- cache
543
"""
544
Return a FiniteField_ext_pari isomorphic to self with the same
545
defining polynomial.
546
547
EXAMPLES:
548
sage: GF(3^4,'z')._finite_field_ext_pari_()
549
Finite Field in z of size 3^4
550
"""
551
f = self.polynomial()
552
import finite_field_ext_pari
553
return finite_field_ext_pari.FiniteField_ext_pari(self.order(),
554
self.variable_name(), f)
555
556
def __iter__(self):
557
"""
558
Finite fields may be iterated over:
559
560
EXAMPLE:
561
sage: list(GF(2**2, 'a'))
562
[0, a, a + 1, 1]
563
"""
564
from element_givaro import FiniteField_givaro_iterator
565
return FiniteField_givaro_iterator(self._cache)
566
567
def a_times_b_plus_c(self, a, b, c):
568
"""
569
Return r = a*b + c. This is faster than multiplying a and b
570
first and adding c to the result.
571
572
INPUT:
573
a -- FiniteField_givaroElement
574
b -- FiniteField_givaroElement
575
c -- FiniteField_givaroElement
576
577
EXAMPLE:
578
sage: k.<a> = GF(2**8)
579
sage: k.a_times_b_plus_c(a,a,k(1))
580
a^2 + 1
581
"""
582
return self._cache.a_times_b_plus_c(a, b, c)
583
584
def a_times_b_minus_c(self, a, b, c):
585
"""
586
Return r = a*b - c.
587
588
INPUT:
589
a -- FiniteField_givaroElement
590
b -- FiniteField_givaroElement
591
c -- FiniteField_givaroElement
592
593
EXAMPLE:
594
sage: k.<a> = GF(3**3)
595
sage: k.a_times_b_minus_c(a,a,k(1))
596
a^2 + 2
597
"""
598
return self._cache.a_times_b_minus_c(a, b, c)
599
600
def c_minus_a_times_b(self, a, b, c):
601
"""
602
Return r = c - a*b.
603
604
INPUT:
605
a -- FiniteField_givaroElement
606
b -- FiniteField_givaroElement
607
c -- FiniteField_givaroElement
608
609
EXAMPLE:
610
sage: k.<a> = GF(3**3)
611
sage: k.c_minus_a_times_b(a,a,k(1))
612
2*a^2 + 1
613
"""
614
return self._cache.c_minus_a_times_b(a, b, c)
615
616
617