Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/libs/ntl/ntl_GF2X.pyx
4097 views
1
#*****************************************************************************
2
# Copyright (C) 2005 William Stein <[email protected]>
3
# Copyright (C) 2007 Martin Albrecht <[email protected]>
4
#
5
# Distributed under the terms of the GNU General Public License (GPL)
6
#
7
# This code is distributed in the hope that it will be useful,
8
# but WITHOUT ANY WARRANTY; without even the implied warranty of
9
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
# General Public License for more details.
11
#
12
# The full text of the GPL is available at:
13
#
14
# http://www.gnu.org/licenses/
15
#*****************************************************************************
16
17
include "../../ext/interrupt.pxi"
18
include "../../ext/stdsage.pxi"
19
include 'misc.pxi'
20
include 'decl.pxi'
21
22
from sage.rings.integer cimport Integer
23
24
from ntl_ZZ import unpickle_class_value
25
from ntl_GF2 cimport ntl_GF2
26
27
28
##############################################################################
29
#
30
# ntl_GF2X: Polynomials over GF(2) via NTL
31
#
32
# AUTHORS:
33
# - Martin Albrecht <[email protected]>
34
# 2006-01: initial version (based on code by William Stein)
35
# - Martin Albrecht <[email protected]>
36
# 2007-10: adapted to new conventions
37
#
38
##############################################################################
39
40
def GF2XHexOutput(have_hex=None):
41
"""
42
Represent GF2X and GF2E elements in the more compact
43
hexadecimal form to the user.
44
45
If no parameter is provided the currently set value will be
46
returned.
47
48
INPUT:
49
have_hex if True hex representation will be used
50
51
EXAMPLES:
52
sage: m = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1]))
53
sage: x = ntl.GF2E([1,0,1,0,1], m) ; x
54
[1 0 1 0 1]
55
56
sage: ntl.GF2XHexOutput() ## indirect doctest
57
False
58
sage: ntl.GF2XHexOutput(True)
59
sage: ntl.GF2XHexOutput()
60
True
61
62
sage: x
63
0x51
64
65
sage: ntl.GF2XHexOutput(False)
66
sage: x
67
[1 0 1 0 1]
68
"""
69
if have_hex is None:
70
return bool(GF2XHexOutput_c[0])
71
72
if have_hex:
73
GF2XHexOutput_c[0] = 1
74
else:
75
GF2XHexOutput_c[0] = 0
76
77
cdef class ntl_GF2X:
78
"""
79
Univariate Polynomials over GF(2) via NTL.
80
"""
81
def __init__(self, x=[]):
82
"""
83
Constructs a new polynomial over GF(2).
84
85
A value may be passed to this constructor. If you pass a string
86
to the constructor please note that byte sequences and the hexadecimal
87
notation are little endian. So e.g. '[0 1]' == '0x2' == x.
88
89
Input types are ntl.ZZ_px, strings, lists of digits, FiniteFieldElements
90
from extension fields over GF(2), Polynomials over GF(2), Integers, and finite
91
extension fields over GF(2) (uses modulus).
92
93
INPUT:
94
x -- value to be assigned to this element. See examples.
95
96
OUTPUT:
97
a new ntl.GF2X element
98
99
EXAMPLES:
100
sage: ntl.GF2X(ntl.ZZ_pX([1,1,3],2))
101
[1 1 1]
102
sage: ntl.GF2X('0x1c')
103
[1 0 0 0 0 0 1 1]
104
sage: ntl.GF2X('[1 0 1 0]')
105
[1 0 1]
106
sage: ntl.GF2X([1,0,1,0])
107
[1 0 1]
108
sage: ntl.GF2X(GF(2**8,'a').gen()**20)
109
[0 0 1 0 1 1 0 1]
110
sage: ntl.GF2X(GF(2**8,'a'))
111
[1 0 1 1 1 0 0 0 1]
112
sage: ntl.GF2X(2)
113
[0 1]
114
sage: ntl.GF2X(ntl.GF2(1))
115
[1]
116
117
sage: R.<x> = GF(2)[]
118
sage: f = x^5+x^2+1
119
sage: ntl.GF2X(f)
120
[1 0 1 0 0 1]
121
"""
122
123
from sage.rings.finite_rings.element_ext_pari import FiniteField_ext_pariElement
124
from sage.rings.finite_rings.element_givaro import FiniteField_givaroElement
125
from sage.rings.finite_rings.element_ntl_gf2e import FiniteField_ntl_gf2eElement
126
from sage.rings.finite_rings.finite_field_base import FiniteField
127
from sage.rings.polynomial.polynomial_gf2x import Polynomial_GF2X
128
129
cdef long _x
130
131
if PY_TYPE_CHECK(x,ntl_GF2):
132
GF2X_conv_GF2(self.x,(<ntl_GF2>x).x)
133
return
134
elif PY_TYPE_CHECK(x,ntl_GF2X):
135
self.x = (<ntl_GF2X>x).x
136
return
137
elif PY_TYPE_CHECK(x,int):
138
_x = x
139
GF2XFromBytes(self.x, <unsigned char *>(&_x),sizeof(long))
140
return
141
142
if PY_TYPE_CHECK(x, Integer):
143
#binary repr, reversed, and "["..."]" added
144
x="["+x.binary()[::-1].replace(""," ")+"]"
145
elif PY_TYPE_CHECK(x, Polynomial_GF2X):
146
x = x.list() # this is slow but cimport leads to circular imports
147
elif PY_TYPE_CHECK(x, FiniteField):
148
if x.characteristic() == 2:
149
x= list(x.modulus())
150
elif PY_TYPE_CHECK(x, FiniteField_ext_pariElement):
151
if x.parent().characteristic() == 2:
152
x=x._pari_().centerlift().centerlift().subst('a',2).int_unsafe()
153
x="0x"+hex(x)[2:][::-1]
154
elif PY_TYPE_CHECK(x, FiniteField_givaroElement):
155
x = "0x"+hex(x.integer_representation())[2:][::-1]
156
elif PY_TYPE_CHECK(x, FiniteField_ntl_gf2eElement):
157
x = x.polynomial().list()
158
s = str(x).replace(","," ")
159
sig_on()
160
# TODO: this is very slow, but we wait until somebody complains
161
GF2X_from_str(&self.x, s)
162
sig_off()
163
164
def __cinit__(self):
165
GF2X_construct(&self.x)
166
167
def __dealloc__(self):
168
GF2X_destruct(&self.x)
169
170
def __reduce__(self):
171
"""
172
EXAMPLES:
173
sage: f = ntl.GF2X(ntl.ZZ_pX([1,1,3],2))
174
sage: loads(dumps(f)) == f
175
True
176
sage: f = ntl.GF2X('0x1c')
177
sage: loads(dumps(f)) == f
178
True
179
"""
180
return unpickle_class_value, (ntl_GF2X, hex(self))
181
182
def __repr__(self):
183
"""
184
Return the string representation of self.
185
186
EXAMPLES:
187
sage: ntl.GF2X(ntl.ZZ_pX([1,1,3],2)).__repr__()
188
'[1 1 1]'
189
"""
190
return GF2X_to_PyString(&self.x)
191
192
def __mul__(ntl_GF2X self, other):
193
"""
194
EXAMPLES:
195
sage: f = ntl.GF2X([1,0,1,1]) ; g = ntl.GF2X([0,1])
196
sage: f*g ## indirect doctest
197
[0 1 0 1 1]
198
"""
199
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
200
if not PY_TYPE_CHECK(other, ntl_GF2X):
201
other = ntl_GF2X(other)
202
GF2X_mul(r.x, self.x, (<ntl_GF2X>other).x)
203
return r
204
205
def __div__(ntl_GF2X self, b):
206
"""
207
EXAMPLES:
208
sage: a = ntl.GF2X(4)
209
sage: a / ntl.GF2X(2)
210
[0 1]
211
sage: a / ntl.GF2X(3)
212
Traceback (most recent call last):
213
...
214
ArithmeticError: self (=[0 0 1]) is not divisible by b (=[1 1])
215
"""
216
cdef ntl_GF2X q = PY_NEW(ntl_GF2X)
217
cdef int divisible
218
219
if not PY_TYPE_CHECK(b, ntl_GF2X):
220
b = ntl_GF2X(b)
221
222
divisible = GF2X_divide(q.x, self.x, (<ntl_GF2X>b).x)
223
if not divisible:
224
raise ArithmeticError, "self (=%s) is not divisible by b (=%s)"%(self, b)
225
return q
226
227
def DivRem(ntl_GF2X self, b):
228
"""
229
EXAMPLES:
230
sage: a = ntl.GF2X(4)
231
sage: a.DivRem( ntl.GF2X(2) )
232
([0 1], [])
233
sage: a.DivRem( ntl.GF2X(3) )
234
([1 1], [1])
235
"""
236
cdef ntl_GF2X q = PY_NEW(ntl_GF2X)
237
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
238
239
if not PY_TYPE_CHECK(b, ntl_GF2X):
240
b = ntl_GF2X(b)
241
242
GF2X_DivRem(q.x, r.x, self.x, (<ntl_GF2X>b).x)
243
return q,r
244
245
def __floordiv__(ntl_GF2X self, b):
246
"""
247
EXAMPLES:
248
sage: a = ntl.GF2X(4)
249
sage: a // ntl.GF2X(2)
250
[0 1]
251
sage: a // ntl.GF2X(3)
252
[1 1]
253
"""
254
cdef ntl_GF2X q = PY_NEW(ntl_GF2X)
255
256
if not PY_TYPE_CHECK(b, ntl_GF2X):
257
b = ntl_GF2X(b)
258
259
GF2X_div(q.x, self.x, (<ntl_GF2X>b).x)
260
return q
261
262
def __mod__(ntl_GF2X self, b):
263
"""
264
EXAMPLES:
265
sage: a = ntl.GF2X(4)
266
sage: a % ntl.GF2X(2)
267
[]
268
sage: a % ntl.GF2X(3)
269
[1]
270
"""
271
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
272
273
if not PY_TYPE_CHECK(b, ntl_GF2X):
274
b = ntl_GF2X(b)
275
276
GF2X_rem(r.x, self.x, (<ntl_GF2X>b).x)
277
return r
278
279
def __sub__(ntl_GF2X self, other):
280
"""
281
EXAMPLES:
282
sage: f = ntl.GF2X([1,0,1,1]) ; g = ntl.GF2X([0,1])
283
sage: f - g ## indirect doctest
284
[1 1 1 1]
285
sage: g - f
286
[1 1 1 1]
287
"""
288
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
289
if not PY_TYPE_CHECK(other, ntl_GF2X):
290
other = ntl_GF2X(other)
291
GF2X_sub(r.x, self.x, (<ntl_GF2X>other).x)
292
return r
293
294
def __add__(ntl_GF2X self, other):
295
"""
296
EXAMPLES:
297
sage: f = ntl.GF2X([1,0,1,1]) ; g = ntl.GF2X([0,1,0])
298
sage: f + g ## indirect doctest
299
[1 1 1 1]
300
"""
301
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
302
if not PY_TYPE_CHECK(other, ntl_GF2X):
303
other = ntl_GF2X(other)
304
GF2X_add(r.x, self.x, (<ntl_GF2X>other).x)
305
return r
306
307
def __neg__(ntl_GF2X self):
308
"""
309
EXAMPLES:
310
sage: f = ntl.GF2X([1,0,1,1])
311
sage: -f ## indirect doctest
312
[1 0 1 1]
313
sage: f == -f
314
True
315
"""
316
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
317
GF2X_negate(r.x, self.x)
318
return r
319
320
def __pow__(ntl_GF2X self, long e, ignored):
321
"""
322
EXAMPLES:
323
sage: f = ntl.GF2X([1,0,1,1]) ; g = ntl.GF2X([0,1,0])
324
sage: f**3 ## indirect doctest
325
[1 0 1 1 1 0 0 1 1 1]
326
"""
327
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
328
GF2X_power(r.x, self.x, e)
329
return r
330
331
332
def __richcmp__(self, other, op):
333
"""
334
EXAMPLES:
335
sage: f = ntl.GF2X([1,0,1,1]) ; g = ntl.GF2X([0,1,0])
336
sage: f == g ## indirect doctest
337
False
338
sage: f == f
339
True
340
"""
341
if op != 2 and op != 3:
342
raise TypeError, "elements in GF(2)[X] are not ordered."
343
344
if not PY_TYPE_CHECK(other, ntl_GF2X):
345
other = ntl_GF2X(other)
346
347
if not PY_TYPE_CHECK(self, ntl_GF2X):
348
self = ntl_GF2X(self)
349
350
cdef int t
351
t = GF2X_equal((<ntl_GF2X>self).x, (<ntl_GF2X>other).x)
352
if op == 2:
353
return t == 1
354
elif op == 3:
355
return t == 0
356
357
def __lshift__(ntl_GF2X self, int i):
358
"""
359
Return left shift of self by i bits ( == multiplication by
360
$X^i$).
361
362
INPUT:
363
i -- offset/power of X
364
365
EXAMPLES:
366
sage: a = ntl.GF2X(4); a
367
[0 0 1]
368
sage: a << 2
369
[0 0 0 0 1]
370
"""
371
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
372
GF2X_LeftShift(r.x, self.x, <long>i)
373
return r
374
375
def __rshift__(ntl_GF2X self, int offset):
376
"""
377
Return right shift of self by i bits ( == floor division by
378
$X^i$).
379
380
INPUT:
381
i -- offset/power of X
382
383
EXAMPLES:
384
sage: a = ntl.GF2X(4); a
385
[0 0 1]
386
sage: a >> 1
387
[0 1]
388
"""
389
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
390
GF2X_RightShift(r.x, self.x, <long>offset)
391
return r
392
393
def GCD(ntl_GF2X self, other):
394
"""
395
Return GCD of self and other.
396
397
INPUT:
398
other -- ntl.GF2X
399
400
EXAMPLE:
401
sage: a = ntl.GF2X(10)
402
sage: b = ntl.GF2X(4)
403
sage: a.GCD(b)
404
[0 1]
405
"""
406
cdef ntl_GF2X gcd = PY_NEW(ntl_GF2X)
407
408
if not PY_TYPE_CHECK(other, ntl_GF2X):
409
other = ntl_GF2X(other)
410
411
gcd.x = GF2X_GCD(self.x, (<ntl_GF2X>other).x)
412
return gcd
413
414
def XGCD(ntl_GF2X self, other):
415
"""
416
Return the extended gcd of self and other, i.e., elements r, s, t such that
417
418
r = s * self + t * other.
419
420
INPUT:
421
other -- ntl.GF2X
422
423
EXAMPLE:
424
sage: a = ntl.GF2X(10)
425
sage: b = ntl.GF2X(4)
426
sage: r,s,t = a.XGCD(b)
427
sage: r == a*s + t*b
428
True
429
430
"""
431
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
432
cdef ntl_GF2X s = PY_NEW(ntl_GF2X)
433
cdef ntl_GF2X t = PY_NEW(ntl_GF2X)
434
435
if not PY_TYPE_CHECK(other, ntl_GF2X):
436
other = ntl_GF2X(other)
437
438
GF2X_XGCD(r.x, s.x, t.x, self.x, (<ntl_GF2X>other).x)
439
return r,s,t
440
441
def deg(ntl_GF2X self):
442
"""
443
Returns the degree of this polynomial
444
445
EXAMPLES:
446
sage: ntl.GF2X([1,0,1,1]).deg()
447
3
448
"""
449
return GF2X_deg(self.x)
450
451
def list(ntl_GF2X self):
452
"""
453
Represents this element as a list of binary digits.
454
455
EXAMPLES:
456
sage: e=ntl.GF2X([0,1,1])
457
sage: e.list()
458
[0, 1, 1]
459
sage: e=ntl.GF2X('0xff')
460
sage: e.list()
461
[1, 1, 1, 1, 1, 1, 1, 1]
462
463
OUTPUT:
464
a list of digits representing the coefficients in this element's
465
polynomial representation
466
"""
467
return [self[i] for i in range(GF2X_deg(self.x)+1)]
468
469
def bin(ntl_GF2X self):
470
"""
471
Returns binary representation of this element. It is
472
the same as setting \code{ntl.GF2XHexOutput(False)} and
473
representing this element afterwards. However it should be
474
faster and preserves the HexOutput state as opposed to
475
the above code.
476
477
EXAMPLES:
478
sage: e=ntl.GF2X([1,1,0,1,1,1,0,0,1])
479
sage: e.bin()
480
'[1 1 0 1 1 1 0 0 1]'
481
482
OUTPUT:
483
string representing this element in binary digits
484
"""
485
cdef long _hex = GF2XHexOutput_c[0]
486
GF2XHexOutput_c[0] = 0
487
s = GF2X_to_PyString(&self.x)
488
GF2XHexOutput_c[0] = _hex
489
return s
490
491
def __hex__(ntl_GF2X self):
492
"""
493
Returns hexadecimal representation of this element. It is
494
the same as setting \code{ntl.GF2XHexOutput(True)} and
495
representing this element afterwards. However it should be
496
faster and preserves the HexOutput state as opposed to
497
the above code.
498
499
EXAMPLES:
500
sage: e=ntl.GF2X([1,1,0,1,1,1,0,0,1])
501
sage: hex(e)
502
'0xb31'
503
504
OUTPUT:
505
string representing this element in hexadecimal
506
507
"""
508
cdef long _hex = GF2XHexOutput_c[0]
509
GF2XHexOutput_c[0] = 1
510
s = GF2X_to_PyString(&self.x)
511
GF2XHexOutput_c[0] = _hex
512
return s
513
514
def __hash__(self):
515
return hash(hex(self))
516
517
def _sage_(ntl_GF2X self, R=None):
518
"""
519
Returns a Sage polynomial over GF(2) equivalent to
520
this element. If a ring R is provided it is used
521
to construct the polynomial in, otherwise
522
an appropriate ring is generated.
523
524
INPUT:
525
self -- GF2X element
526
R -- PolynomialRing over GF(2)
527
528
OUTPUT:
529
polynomial in R
530
531
EXAMPLES:
532
sage: f = ntl.GF2X([1,0,1,1,0,1])
533
sage: f._sage_()
534
x^5 + x^3 + x^2 + 1
535
sage: f._sage_(PolynomialRing(Integers(2),'y'))
536
y^5 + y^3 + y^2 + 1
537
"""
538
if R==None:
539
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
540
from sage.rings.finite_rings.constructor import FiniteField
541
R = PolynomialRing(FiniteField(2), 'x')
542
543
return R(map(int,self.list()))
544
545
def coeff(self, int i):
546
"""
547
Return the coefficient of the monomial $X^i$ in self.
548
549
INPUT:
550
i -- degree of X
551
552
EXAMPLE:
553
sage: e = ntl.GF2X([0,1,0,1])
554
sage: e.coeff(0)
555
0
556
sage: e.coeff(1)
557
1
558
"""
559
cdef ntl_GF2 c = PY_NEW(ntl_GF2)
560
c.x = GF2X_coeff(self.x, i)
561
return c
562
563
def __getitem__(self, int i):
564
"""
565
sage: e = ntl.GF2X([0,1,0,1])
566
sage: e[0] # indirect doctest
567
0
568
sage: e[1]
569
1
570
"""
571
cdef ntl_GF2 c = PY_NEW(ntl_GF2)
572
c.x = GF2X_coeff(self.x, i)
573
return c
574
575
def LeadCoeff(self):
576
"""
577
Return the leading coefficient of self. This is always 1
578
except when self == 0.
579
580
EXAMPLE:
581
sage: e = ntl.GF2X([0,1])
582
sage: e.LeadCoeff()
583
1
584
sage: e = ntl.GF2X(0)
585
sage: e.LeadCoeff()
586
0
587
"""
588
cdef ntl_GF2 c = PY_NEW(ntl_GF2)
589
c.x = GF2X_LeadCoeff(self.x)
590
return c
591
592
def ConstTerm(self):
593
"""
594
Return the constant term of self.
595
596
EXAMPLE:
597
sage: e = ntl.GF2X([1,0,1])
598
sage: e.ConstTerm()
599
1
600
sage: e = ntl.GF2X(0)
601
sage: e.ConstTerm()
602
0
603
"""
604
cdef ntl_GF2 c = PY_NEW(ntl_GF2)
605
c.x = GF2X_ConstTerm (self.x)
606
return c
607
608
def SetCoeff(self, int i, a):
609
"""
610
Return the constant term of self.
611
612
EXAMPLE:
613
sage: e = ntl.GF2X([1,0,1]); e
614
[1 0 1]
615
sage: e.SetCoeff(1,1)
616
sage: e
617
[1 1 1]
618
"""
619
cdef ntl_GF2 _a = ntl_GF2(a)
620
621
GF2X_SetCoeff(self.x, i, _a.x)
622
623
def __setitem__(self, int i, a):
624
"""
625
sage: e = ntl.GF2X([1,0,1]); e
626
[1 0 1]
627
sage: e[1] = 1 # indirect doctest
628
sage: e
629
[1 1 1]
630
"""
631
cdef ntl_GF2 _a = ntl_GF2(a)
632
GF2X_SetCoeff(self.x, i, _a.x)
633
634
def diff(self):
635
"""
636
Differentiate self.
637
sage: e = ntl.GF2X([1,0,1,1,0])
638
sage: e.diff()
639
[0 0 1]
640
"""
641
cdef ntl_GF2X d = PY_NEW(ntl_GF2X)
642
d.x = GF2X_diff(self.x)
643
return d
644
645
def reverse(self, int hi = -2):
646
"""
647
Return reverse of a[0]..a[hi] (hi >= -1)
648
hi defaults to deg(a)
649
650
INPUT:
651
hi -- bit position until which reverse is requested
652
653
EXAMPLE:
654
sage: e = ntl.GF2X([1,0,1,1,0])
655
sage: e.reverse()
656
[1 1 0 1]
657
"""
658
cdef ntl_GF2X r = PY_NEW(ntl_GF2X)
659
if hi < -1:
660
hi = GF2X_deg(self.x)
661
r.x = GF2X_reverse(self.x, hi)
662
return r
663
664
def weight(self):
665
"""
666
Return the number of nonzero coefficients in self.
667
668
EXAMPLE:
669
sage: e = ntl.GF2X([1,0,1,1,0])
670
sage: e.weight()
671
3
672
"""
673
return int(GF2X_weight(self.x))
674
675
def __int__(self):
676
"""
677
sage: e = ntl.GF2X([1,0,1,1,0])
678
sage: int(e)
679
Traceback (most recent call last):
680
...
681
ValueError: cannot convert non-constant polynomial to integer
682
sage: e = ntl.GF2X([1])
683
sage: int(e)
684
1
685
"""
686
cdef long l = 0
687
if GF2X_deg(self.x) != 0:
688
raise ValueError, "cannot convert non-constant polynomial to integer"
689
else:
690
return GF2_conv_to_long(GF2X_coeff(self.x,0))
691
692
def NumBits(self):
693
"""
694
returns number of bits of self, i.e., deg(self) + 1.
695
696
EXAMPLE:
697
sage: e = ntl.GF2X([1,0,1,1,0])
698
sage: e.NumBits()
699
4
700
"""
701
return int(GF2X_NumBits(self.x))
702
703
def __len__(self):
704
"""
705
sage: e = ntl.GF2X([1,0,1,1,0])
706
sage: len(e)
707
4
708
"""
709
return int(GF2X_NumBits(self.x))
710
711
def NumBytes(self):
712
"""
713
Returns number of bytes of self, i.e., floor((NumBits(self)+7)/8)
714
715
EXAMPLE:
716
sage: e = ntl.GF2X([1,0,1,1,0,0,0,0,1,1,1,0,0,1,1,0,1,1])
717
sage: e.NumBytes()
718
3
719
"""
720
return int(GF2X_NumBytes(self.x))
721
722