Skip to content

Commit 5e106eb

Browse files
committed
add simple methods to convert Integers to and from bytes
1 parent 30b3d78 commit 5e106eb

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

src/sage/rings/integer.pyx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7162,7 +7162,44 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
71627162
return the_integer_ring(self.__pari__().binomial(mm))
71637163
else:
71647164
raise ValueError("algorithm must be one of: 'pari' or 'gmp' (alias: 'mpir')")
7165+
7166+
def to_bytes(self, length=1, byteorder="big", is_signed=False):
7167+
"""
7168+
Return an array of bytes representing an integer. Internally relies
7169+
on the python ``int.to_bytes()`` method.
7170+
7171+
INPUT:
7172+
7173+
- ``length`` -- positive integer (default: ``1``); integer is represented in
7174+
``length`` bytes. ``OverflowError`` is raised if the integer is not representable
7175+
with the given length.
71657176
7177+
- ``byteorder`` -- str (default: ``"big"``); determines the byte order of
7178+
``input_bytes``; can only be ``"big"`` or ``"little"``
7179+
7180+
- ``is_signed`` -- boolean (default: ``False``); determines whether to use two's
7181+
compliment to represent the integer
7182+
7183+
OUTPUT:
7184+
7185+
- Bytes representing ``self``
7186+
7187+
TODO: should we convert straight from the gmp type in cython? This is definitely
7188+
possible but I'm not sure the cleanest way to do this
7189+
7190+
EXAMPLES::
7191+
7192+
sage: (1024).to_bytes(2, byteorder='big')
7193+
b'\x04\x00'
7194+
sage: (1024).to_bytes(10, byteorder='big')
7195+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00'
7196+
sage: (-1024).to_bytes(10, byteorder='big', is_signed=True)
7197+
b'\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00'
7198+
sage: x = 1000
7199+
sage: x.to_bytes((x.bit_length() + 7) // 8, byteorder='little')
7200+
b'\xe8\x03'
7201+
"""
7202+
return int(self).to_bytes(length=length, byteorder=byteorder, signed=is_signed)
71667203

71677204
cdef int mpz_set_str_python(mpz_ptr z, char* s, int base) except -1:
71687205
"""

src/sage/rings/integer_ring.pyx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,43 @@ cdef class IntegerRing_class(PrincipalIdealDomain):
15741574
from sage.rings.padics.padic_valuation import pAdicValuation
15751575
return pAdicValuation(self, p)
15761576

1577+
def from_bytes(self, input_bytes, byteorder="big", is_signed=False):
1578+
"""
1579+
Return the integer represented by the given array of bytes. Internally relies
1580+
on the python ``int.from_bytes()`` method.
1581+
1582+
INPUT:
1583+
1584+
- ``input_bytes`` -- a bytes-like object or iterable producing bytes
1585+
1586+
- ``byteorder`` -- str (default: ``"big"``); determines the byte order of
1587+
``input_bytes``; can only be ``"big"`` or ``"little"``
1588+
1589+
- ``is_signed`` -- boolean (default: ``False``); determines whether to use two's
1590+
compliment to represent the integer
1591+
1592+
OUTPUT:
1593+
1594+
- An integer represented by the ``input_bytes``
1595+
1596+
EXAMPLES::
1597+
1598+
sage: ZZ.from_bytes(b'\x00\x10', byteorder='big')
1599+
16
1600+
sage: ZZ.from_bytes(b'\x00\x10', byteorder='little')
1601+
4096
1602+
sage: ZZ.from_bytes(b'\xfc\x00', byteorder='big', is_signed=True)
1603+
-1024
1604+
sage: ZZ.from_bytes(b'\xfc\x00', byteorder='big', is_signed=False)
1605+
64512
1606+
sage: ZZ.from_bytes([255, 0, 0], byteorder='big')
1607+
16711680
1608+
sage: type(_)
1609+
<class 'sage.rings.integer.Integer'>
1610+
"""
1611+
python_int = int.from_bytes(input_bytes, byteorder=byteorder, signed=is_signed)
1612+
return self(python_int)
1613+
15771614
ZZ = IntegerRing_class()
15781615
Z = ZZ
15791616

0 commit comments

Comments
 (0)