Skip to content

Commit f932b6b

Browse files
author
Release Manager
committed
Trac #33941: Implement from_integer and to_integer for all finite fields, extending and replacing fetch_int and integer_representation
Finite fields have `.fetch_int()` to decode integers into finite-field elements by reinterpreting the base-`p` representation as a polynomial: {{{#!sage sage: F.<t> = GF(7^10) sage: el = F.fetch_int(2424); el t^4 + 3*t + 2 }}} However, the inverse operation is a bit cumbersome: {{{#!sage sage: el.polynomial().change_ring(ZZ)(el.parent().characteristic()) 2424 }}} In this patch, we add an inverse to `.fetch_int()`, named `.to_integer()` in resemblance with the Python method `int.to_bytes()`. For symmetry, we then rename `.fetch_int()` to `.from_integer()`: I, for one, could never remember if `.fetch_int()` refers to "fetching an element from an int" or "fetching this element into an int", so I think the new name makes a lot more sense. Also, some code cleanup and optimization while we're at it. URL: https://trac.sagemath.org/33941 Reported by: lorenz Ticket author(s): Lorenz Panny Reviewer(s): Kwankyu Lee
2 parents 0c12be1 + 0eabc46 commit f932b6b

File tree

12 files changed

+157
-72
lines changed

12 files changed

+157
-72
lines changed

src/sage/crypto/mq/rijndael_gf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ def _GF_to_hex(self, GF):
785785
not GF.parent().order() == 2**8:
786786
msg = "keyword 'GF' must be in"
787787
raise TypeError(msg.format(self._F))
788-
return hex(GF.integer_representation())[2:].zfill(2)
788+
return hex(GF.to_integer())[2:].zfill(2)
789789

790790
def _bin_to_GF(self, B, matrix=True):
791791
r"""
@@ -911,7 +911,7 @@ def _GF_to_bin(self, GF):
911911
not GF.parent().order() == 2**8:
912912
msg = "keyword 'GF' must be in"
913913
raise TypeError(msg.format(self._F))
914-
return bin(GF.integer_representation())[2:].zfill(8)
914+
return bin(GF.to_integer())[2:].zfill(8)
915915

916916
def encrypt(self, plain, key, format='hex'):
917917
r"""

src/sage/crypto/mq/sr.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -762,9 +762,9 @@ def sub_byte(self, b):
762762

763763
# constant addition
764764
if e == 4:
765-
b = b + k.fetch_int(6)
765+
b = b + k.from_integer(6)
766766
elif e == 8:
767-
b = b + k.fetch_int(99)
767+
b = b + k.from_integer(99)
768768

769769
return b
770770

@@ -782,9 +782,9 @@ def sbox_constant(self):
782782
"""
783783
k = self.k
784784
if self.e == 4:
785-
return k.fetch_int(6)
785+
return k.from_integer(6)
786786
elif self.e == 8:
787-
return k.fetch_int(99)
787+
return k.from_integer(99)
788788
else:
789789
raise TypeError("sbox constant only defined for e in (4, 8)")
790790

@@ -1006,7 +1006,7 @@ def state_array(self, d=None):
10061006
10071007
sage: sr = mq.SR(2, 2, 2, 4)
10081008
sage: k = sr.base_ring()
1009-
sage: e1 = [k.fetch_int(e) for e in range(2*2)]; e1
1009+
sage: e1 = [k.from_integer(e) for e in range(2*2)]; e1
10101010
[0, 1, a, a + 1]
10111011
sage: e2 = sr.phi( Matrix(k, 2*2, 1, e1) )
10121012
sage: sr.state_array(e1) # note the column major ordering
@@ -1229,8 +1229,8 @@ def __call__(self, P, K):
12291229
12301230
sage: sr = mq.SR(10, 4, 4, 8, star=True, allow_zero_inversions=True)
12311231
sage: k = sr.base_ring()
1232-
sage: plaintext = sr.state_array([k.fetch_int(e) for e in range(16)])
1233-
sage: key = sr.state_array([k.fetch_int(e) for e in range(16)])
1232+
sage: plaintext = sr.state_array([k.from_integer(e) for e in range(16)])
1233+
sage: key = sr.state_array([k.from_integer(e) for e in range(16)])
12341234
sage: print(sr.hex_str_matrix( sr(plaintext, key) ))
12351235
0A 41 F1 C6
12361236
94 6E C3 53
@@ -1301,9 +1301,9 @@ def __call__(self, P, K):
13011301
F = self.base_ring()
13021302

13031303
if isinstance(P, str):
1304-
P = self.state_array([F.fetch_int(ZZ(P[i:i+2], 16)) for i in range(0, len(P), 2)])
1304+
P = self.state_array([F.from_integer(ZZ(P[i: i + 2], 16)) for i in range(0, len(P), 2)])
13051305
if isinstance(K, str):
1306-
K = self.state_array([F.fetch_int(ZZ(K[i:i+2], 16)) for i in range(0, len(K), 2)])
1306+
K = self.state_array([F.from_integer(ZZ(K[i: i + 2], 16)) for i in range(0, len(K), 2)])
13071307

13081308
if self.is_state_array(P) and self.is_state_array(K):
13091309
_type = self.state_array
@@ -1433,9 +1433,9 @@ def hex_str_matrix(self, M):
14331433
for x in range(M.nrows()):
14341434
for y in range(M.ncols()):
14351435
if e == 8:
1436-
st.append("%02X" % M[x, y].integer_representation())
1436+
st.append("%02X" % M[x, y].to_integer())
14371437
else:
1438-
st.append("%X" % M[x, y].integer_representation())
1438+
st.append("%X" % M[x, y].to_integer())
14391439
st.append("\n")
14401440
return " ".join(st)
14411441

@@ -1464,9 +1464,9 @@ def hex_str_vector(self, M):
14641464
for y in range(M.ncols()):
14651465
for x in range(M.nrows()):
14661466
if e == 8:
1467-
st.append("%02X" % M[x, y].integer_representation())
1467+
st.append("%02X" % M[x, y].to_integer())
14681468
else:
1469-
st.append("%X" % M[x, y].integer_representation())
1469+
st.append("%X" % M[x, y].to_integer())
14701470
#st.append("\n")
14711471
return "".join(st)
14721472

@@ -2321,13 +2321,13 @@ def lin_matrix(self, length = None):
23212321

23222322
lin = Matrix(self.base_ring(), length*e, length*e)
23232323
if e == 4:
2324-
l = [ k.fetch_int(x) for x in (5, 1, 12, 5) ]
2324+
l = [k.from_integer(x) for x in (5, 1, 12, 5)]
23252325
for k in range( 0, length ):
23262326
for i in range(0, 4):
23272327
for j in range(0, 4):
23282328
lin[k*4+j, k*4+i] = l[(i-j)%4] ** (2**j)
23292329
elif e == 8:
2330-
l = [ k.fetch_int(x) for x in (5, 9, 249, 37, 244, 1, 181, 143) ]
2330+
l = [k.from_integer(x) for x in (5, 9, 249, 37, 244, 1, 181, 143)]
23312331
for k in range( 0, length ):
23322332
for i in range(0, 8):
23332333
for j in range(0, 8):

src/sage/libs/ntl/ntl_GF2X.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ cdef class ntl_GF2X():
160160
if x.characteristic() == 2:
161161
x = list(x.modulus())
162162
elif isinstance(x, FiniteField_givaroElement):
163-
x = "0x"+hex(x.integer_representation())[2:][::-1]
163+
x = "0x" + hex(x.to_integer())[2:][::-1]
164164
elif isinstance(x, FiniteField_ntl_gf2eElement):
165165
x = x.polynomial().list()
166166
s = str(x).replace(","," ")

src/sage/libs/ntl/ntl_mat_GF2E.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ cdef class ntl_mat_GF2E():
7878
[0x0 0x0 0x0 0x0 0x0]
7979
[0x0 0x0 0x0 0x0 0x0]
8080
]
81-
sage: A= matrix(k,5,5,[k.fetch_int(_%(2^4)) for _ in range(25)])
81+
sage: A = matrix(k, 5, 5, [k.from_integer(i % 2^4) for i in range(25)])
8282
sage: ntl.mat_GF2E(ctx, A)
8383
[[0x0 0x1 0x2 0x3 0x4]
8484
[0x5 0x6 0x7 0x8 0x9]

src/sage/matrix/matrix_gf2e_dense.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ cdef class M4RIE_finite_field:
129129
gf2e_free(self.ff)
130130

131131
cdef m4ri_word poly_to_word(f):
132-
return f.integer_representation()
132+
return f.to_integer()
133133

134134

135135
cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense):

src/sage/matrix/matrix_gfpn_dense.pyx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ cdef class FieldConverter_class:
105105
sage: C = M._converter
106106
sage: C.fel_to_field(15)
107107
3*y
108-
sage: F.fetch_int(15)
108+
sage: F.from_integer(15)
109109
3*y
110110
sage: C.field_to_fel(y)
111111
5
112-
sage: y.integer_representation()
112+
sage: y.to_integer()
113113
5
114114
"""
115115
def __init__(self, field):
@@ -139,7 +139,7 @@ cdef class FieldConverter_class:
139139
sage: C = FieldConverter_class(F)
140140
sage: C.fel_to_field(15)
141141
3*y
142-
sage: F.fetch_int(15)
142+
sage: F.from_integer(15)
143143
3*y
144144
"""
145145
return self.field(FfToInt(x))
@@ -155,7 +155,7 @@ cdef class FieldConverter_class:
155155
sage: C = FieldConverter_class(F)
156156
sage: C.field_to_fel(y)
157157
5
158-
sage: y.integer_representation()
158+
sage: y.to_integer()
159159
5
160160
161161
TESTS:
@@ -165,9 +165,9 @@ cdef class FieldConverter_class:
165165
sage: C.field_to_fel('foo')
166166
Traceback (most recent call last):
167167
...
168-
AttributeError: 'str' object has no attribute 'integer_representation'
168+
AttributeError: 'str' object has no attribute 'to_integer'
169169
"""
170-
return FfFromInt(x.integer_representation())
170+
return FfFromInt(x.to_integer())
171171

172172

173173
cdef class PrimeFieldConverter_class(FieldConverter_class):

src/sage/rings/finite_rings/element_base.pyx

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ AUTHORS:
1919

2020
from sage.structure.element cimport Element
2121
from sage.structure.parent cimport Parent
22+
from sage.rings.integer_ring import ZZ
2223
from sage.rings.integer import Integer
24+
from sage.misc.superseded import deprecated_function_alias
2325

2426
def is_FiniteFieldElement(x):
2527
"""
@@ -213,7 +215,7 @@ cdef class FinitePolyExtElement(FiniteRingElement):
213215

214216
def __getitem__(self, n):
215217
r"""
216-
Return the `n`\th coefficient of this finite-field element when
218+
Return the `n`\th coefficient of this finite field element when
217219
written as a polynomial in the generator.
218220
219221
EXAMPLES::
@@ -250,7 +252,7 @@ cdef class FinitePolyExtElement(FiniteRingElement):
250252
def list(self):
251253
r"""
252254
Return the list of coefficients (in little-endian) of this
253-
finite-field element when written as a polynomial in the
255+
finite field element when written as a polynomial in the
254256
generator.
255257
256258
Equivalent to calling ``list()`` on this element.
@@ -266,7 +268,7 @@ cdef class FinitePolyExtElement(FiniteRingElement):
266268
True
267269
268270
The coefficients returned are those of a fully reduced
269-
representative of the finite-field element::
271+
representative of the finite field element::
270272
271273
sage: b = u^777
272274
sage: b.list()
@@ -288,7 +290,7 @@ cdef class FinitePolyExtElement(FiniteRingElement):
288290

289291
def __iter__(self):
290292
r"""
291-
Return an iterator over the coefficients of this finite-field
293+
Return an iterator over the coefficients of this finite field
292294
element, in the same order as :meth:`list`.
293295
294296
EXAMPLES::
@@ -670,7 +672,6 @@ cdef class FinitePolyExtElement(FiniteRingElement):
670672
1
671673
"""
672674
if self.is_zero():
673-
from sage.rings.integer import Integer
674675
return Integer(1)
675676
return self.parent().characteristic()
676677

@@ -878,7 +879,6 @@ cdef class FinitePolyExtElement(FiniteRingElement):
878879
else: raise ValueError
879880
if extend:
880881
raise NotImplementedError
881-
from sage.rings.integer import Integer
882882
n = Integer(n)
883883
return self._nth_root_common(n, all, algorithm, cunningham)
884884

@@ -983,6 +983,67 @@ cdef class FinitePolyExtElement(FiniteRingElement):
983983

984984
return self.pth_power(k=k)
985985

986+
def to_integer(self, reverse=False):
987+
r"""
988+
Return an integer representation of this finite field element
989+
obtained by lifting its representative polynomial to `\ZZ` and
990+
evaluating it at the characteristic `p`.
991+
992+
If ``reverse`` is set to ``True`` (default: ``False``),
993+
the list of coefficients is reversed prior to evaluation.
994+
995+
Inverse of :meth:`sage.rings.finite_rings.finite_field_base.FiniteField.from_integer`.
996+
997+
EXAMPLES::
998+
999+
sage: F.<t> = GF(7^5)
1000+
sage: F(5).to_integer()
1001+
5
1002+
sage: t.to_integer()
1003+
7
1004+
sage: (t^2).to_integer()
1005+
49
1006+
sage: (t^2+1).to_integer()
1007+
50
1008+
sage: (t^2+t+1).to_integer()
1009+
57
1010+
1011+
::
1012+
1013+
sage: F.<t> = GF(2^8)
1014+
sage: u = F.from_integer(0xd1)
1015+
sage: bin(u.to_integer(False))
1016+
'0b11010001'
1017+
sage: bin(u.to_integer(True))
1018+
'0b10001011'
1019+
1020+
TESTS::
1021+
1022+
sage: p = random_prime(2^99)
1023+
sage: k = randrange(2,10)
1024+
sage: F.<t> = GF((p, k))
1025+
sage: rev = bool(randrange(2))
1026+
sage: u = F.random_element()
1027+
sage: 0 <= u.to_integer(rev) < F.cardinality()
1028+
True
1029+
sage: F.from_integer(u.to_integer(rev), rev) == u
1030+
True
1031+
sage: n = randrange(F.cardinality())
1032+
sage: F.from_integer(n, rev).to_integer(rev) == n
1033+
True
1034+
"""
1035+
if not reverse:
1036+
try:
1037+
return self._integer_representation()
1038+
except AttributeError:
1039+
pass
1040+
p = self.parent().characteristic()
1041+
f = self.polynomial().change_ring(ZZ)
1042+
if reverse:
1043+
f = f.reverse(self.parent().degree() - 1)
1044+
return f(p)
1045+
1046+
integer_representation = deprecated_function_alias(33941, to_integer)
9861047

9871048
cdef class Cache_base(SageObject):
9881049
cpdef FinitePolyExtElement fetch_int(self, number):

src/sage/rings/finite_rings/element_givaro.pyx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ cdef class Cache_givaro(Cache_base):
643643
sage: k._cache._element_int_repr(a^20)
644644
'74'
645645
"""
646-
return str(e.integer_representation())
646+
return str(e._integer_representation())
647647

648648
def _element_poly_repr(self, FiniteField_givaroElement e, varname=None):
649649
"""
@@ -1350,7 +1350,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
13501350
raise TypeError("Cannot coerce element to an integer.")
13511351
return self_int
13521352

1353-
def integer_representation(FiniteField_givaroElement self):
1353+
def _integer_representation(FiniteField_givaroElement self):
13541354
r"""
13551355
Return the integer representation of ``self``. When ``self`` is in the
13561356
prime subfield, the integer returned is equal to ``self``.
@@ -1362,15 +1362,19 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
13621362
13631363
OUTPUT: A Python ``int``.
13641364
1365+
.. SEEALSO::
1366+
1367+
:meth:`sage.rings.finite_rings.element_base.FinitePolyExtElement.to_integer`
1368+
13651369
EXAMPLES::
13661370
13671371
sage: k.<b> = GF(5^2); k
13681372
Finite Field in b of size 5^2
1369-
sage: k(4).integer_representation()
1373+
sage: k(4)._integer_representation()
13701374
4
1371-
sage: b.integer_representation()
1375+
sage: b._integer_representation()
13721376
5
1373-
sage: type(b.integer_representation())
1377+
sage: type(b._integer_representation())
13741378
<... 'int'>
13751379
"""
13761380
return self._cache.log_to_int(self.element)
@@ -1669,7 +1673,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
16691673
sage: hash(a)
16701674
5
16711675
"""
1672-
return hash(self.integer_representation())
1676+
return hash(self._integer_representation())
16731677

16741678
def _vector_(FiniteField_givaroElement self, reverse=False):
16751679
"""

0 commit comments

Comments
 (0)