aboutsummaryrefslogtreecommitdiff
path: root/py/mpz.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2015-04-25 23:16:39 +0100
committerDamien George <damien.p.george@gmail.com>2015-04-25 23:16:39 +0100
commit271d18eb08ec488ee45f8e6cd852e8236074f082 (patch)
treef5ba5d1b28cb48e72334fb079a5d6ef148083970 /py/mpz.c
parent7c8b4c1a8b8278d864649c127857e34a6bd29504 (diff)
py: Support conversion of bignum to bytes.
This gets int.to_bytes working for bignum, and also struct.pack with 'q' and 'Q' args on 32-bit machines. Addresses issue #1155.
Diffstat (limited to 'py/mpz.c')
-rw-r--r--py/mpz.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/py/mpz.c b/py/mpz.c
index 241fa79be..3c20023bc 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -1425,6 +1425,40 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
return true;
}
+// writes at most len bytes to buf (so buf should be zeroed before calling)
+void mpz_as_bytes(const mpz_t *z, bool big_endian, mp_uint_t len, byte *buf) {
+ byte *b = buf;
+ if (big_endian) {
+ b += len;
+ }
+ mpz_dig_t *zdig = z->dig;
+ int bits = 0;
+ mpz_dbl_dig_t d = 0;
+ mpz_dbl_dig_t carry = 1;
+ for (mp_uint_t zlen = z->len; zlen > 0; --zlen) {
+ bits += DIG_SIZE;
+ d = (d << DIG_SIZE) | *zdig++;
+ for (; bits >= 8; bits -= 8, d >>= 8) {
+ mpz_dig_t val = d;
+ if (z->neg) {
+ d = (~d & 0xff) + carry;
+ carry = d >> 8;
+ }
+ if (big_endian) {
+ *--b = val;
+ if (b == buf) {
+ return;
+ }
+ } else {
+ *b++ = val;
+ if (b == buf + len) {
+ return;
+ }
+ }
+ }
+ }
+}
+
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mpz_as_float(const mpz_t *i) {
mp_float_t val = 0;