/* $Id: mpz_raw.C,v 1.6 2001/03/13 00:06:51 dm Exp $ */ /* * * Copyright (C) 1998 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include "sysconf.h" #include "bigint.h" #define mpz_get_rawmag mpz_get_rawmag_be #define mpz_set_rawmag mpz_set_rawmag_be #undef min #define min(a, b) (((a) < (b)) ? (a) : (b)) static inline void assert_limb_size () { switch (0) case 0: case GMP_LIMB_SIZE == sizeof (mp_limb_t):; #if GMP_LIMB_SIZE != 2 && GMP_LIMB_SIZE != 4 && GMP_LIMB_SIZE != 8 # error Cannot handle size of GMP limbs #endif /* GMP_LIMB_SIZE not 2, 4 or 8 */ } #define COPYLIMB_BYTE(dst, src, SW, n) \ ((char *) (dst))[n] = ((char *) (src))[SW (n)] #if GMP_LIMB_SIZE == 2 # define COPYLIMB(dst, src, SW) \ do { \ COPYLIMB_BYTE (dst, src, SW, 0); \ COPYLIMB_BYTE (dst, src, SW, 1); \ } while (0) #elif GMP_LIMB_SIZE == 4 # define COPYLIMB(dst, src, SW) \ do { \ COPYLIMB_BYTE (dst, src, SW, 0); \ COPYLIMB_BYTE (dst, src, SW, 1); \ COPYLIMB_BYTE (dst, src, SW, 2); \ COPYLIMB_BYTE (dst, src, SW, 3); \ } while (0) #elif GMP_LIMB_SIZE == 8 # define COPYLIMB(dst, src, SW) \ do { \ COPYLIMB_BYTE (dst, src, SW, 0); \ COPYLIMB_BYTE (dst, src, SW, 1); \ COPYLIMB_BYTE (dst, src, SW, 2); \ COPYLIMB_BYTE (dst, src, SW, 3); \ COPYLIMB_BYTE (dst, src, SW, 4); \ COPYLIMB_BYTE (dst, src, SW, 5); \ COPYLIMB_BYTE (dst, src, SW, 6); \ COPYLIMB_BYTE (dst, src, SW, 7); \ } while (0) #else /* GMP_LIMB_SIZE != 2, 4 or 8 */ # error Cannot handle size of GMP limbs #endif /* GMP_LIMB_SIZE != 2, 4 or 8 */ #define LSWAP(n) ((n & -GMP_LIMB_SIZE) + GMP_LIMB_SIZE-1 - n % GMP_LIMB_SIZE) #ifdef WORDS_BIGENDIAN # define LE_POS(n) LSWAP(n) # define BE_POS(n) n #else /* !WORDS_BIGENDIAN */ # define LE_POS(n) n # define BE_POS(n) LSWAP(n) #endif /* !WORDS_BIGENDIAN */ size_t mpz_rawsize (const MP_INT *mp) { size_t nbits = mpz_sizeinbase2 (mp); if (nbits) return (nbits>>3) + 1; /* Not (nbits+7)/8, because we need sign bit */ else return 0; } void mpz_get_rawmag_le (char *buf, size_t size, const MP_INT *mp) { char *bp = buf; const mp_limb_t *sp = mp->_mp_d; const mp_limb_t *ep = sp + min (size / GMP_LIMB_SIZE, (size_t) ABS (mp->_mp_size)); while (sp < ep) { COPYLIMB (bp, sp, LE_POS); bp += GMP_LIMB_SIZE; sp++; } size_t n = size - (bp - buf); if (n < GMP_LIMB_SIZE && sp < mp->_mp_d + ABS (mp->_mp_size)) { mp_limb_t v = *sp; for (char *e = bp + n; bp < e; v >>= 8) *bp++ = v; } else bzero (bp, n); } void mpz_get_rawmag_be (char *buf, size_t size, const MP_INT *mp) { char *bp = buf + size; const mp_limb_t *sp = mp->_mp_d; const mp_limb_t *ep = sp + min (size / GMP_LIMB_SIZE, (size_t) ABS (mp->_mp_size)); while (sp < ep) { bp -= GMP_LIMB_SIZE; COPYLIMB (bp, sp, BE_POS); sp++; } size_t n = bp - buf; if (n < GMP_LIMB_SIZE && sp < mp->_mp_d + ABS (mp->_mp_size)) { mp_limb_t v = *sp; for (; bp > buf; v >>= 8) *--bp = v; } else bzero (buf, n); } void mpz_get_raw (char *buf, size_t size, const MP_INT *mp) { if (mp->_mp_size < 0) { mpz_t neg; mpz_init (neg); mpz_umod_2exp (neg, mp, size * 8); mpz_get_rawmag (buf, size, neg); mpz_clear (neg); } else mpz_get_rawmag (buf, size, mp); } void mpz_set_rawmag_le (MP_INT *mp, const char *buf, size_t size) { const char *bp = buf; size_t nlimbs = (size + sizeof (mp_limb_t)) / sizeof (mp_limb_t); mp_limb_t *sp; mp_limb_t *ep; mp->_mp_size = nlimbs; if (nlimbs > (u_long) mp->_mp_alloc) _mpz_realloc (mp, nlimbs); sp = mp->_mp_d; ep = sp + size / sizeof (mp_limb_t); while (sp < ep) { COPYLIMB (sp, bp, LE_POS); bp += GMP_LIMB_SIZE; sp++; } const char *ebp = buf + size; if (bp < ebp) { mp_limb_t v = (u_char) *--ebp; while (bp < ebp) v = v << 8 | (u_char) *--ebp; *sp++ = v; } while (sp > mp->_mp_d && !sp[-1]) sp--; mp->_mp_size = sp - mp->_mp_d; } void mpz_set_rawmag_be (MP_INT *mp, const char *buf, size_t size) { const char *bp = buf + size; size_t nlimbs = (size + sizeof (mp_limb_t)) / sizeof (mp_limb_t); mp_limb_t *sp; mp_limb_t *ep; mp->_mp_size = nlimbs; if (nlimbs > (u_long) mp->_mp_alloc) _mpz_realloc (mp, nlimbs); sp = mp->_mp_d; ep = sp + size / sizeof (mp_limb_t); while (sp < ep) { bp -= GMP_LIMB_SIZE; COPYLIMB (sp, bp, BE_POS); sp++; } if (bp > buf) { mp_limb_t v = (u_char) *buf++; while (bp > buf) { v <<= 8; v |= (u_char) *buf++; } *sp++ = v; } while (sp > mp->_mp_d && !sp[-1]) sp--; mp->_mp_size = sp - mp->_mp_d; } void mpz_set_raw (MP_INT *mp, const char *buf, size_t size) { mpz_set_rawmag (mp, buf, size); if (*buf & 0x80) { mp->_mp_size = - mp->_mp_size; mpz_umod_2exp (mp, mp, 8 * size); mp->_mp_size = - mp->_mp_size; } }