📄 mpi.c
字号:
/* mpi.c by Michael J. Fromberger <sting@linguist.dartmouth.edu> Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved Arbitrary precision integer arithmetic library $Id: mpi.c,v 1.22 2001/09/14 15:11:20 sting Exp sting $ */#include "mpi.h"#include <stdlib.h>#include <string.h>#include <ctype.h>#if MP_DEBUG#include <stdio.h>#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);}#else#define DIAG(T,V)#endif/* If MP_LOGTAB is not defined, use the math library to compute the logarithms on the fly. Otherwise, use the static table below. Pick which works best for your system. */#if MP_LOGTAB/* {{{ s_logv_2[] - log table for 2 in various bases *//* A table of the logs of 2 for various bases (the 0 and 1 entries of this table are meaningless and should not be referenced). This table is used to compute output lengths for the mp_toradix() function. Since a number n in radix r takes up about log_r(n) digits, we estimate the output size by taking the least integer greater than log_r(n), where: log_r(n) = log_2(n) * log_r(2) This table, therefore, is a table of log_r(2) for 2 <= r <= 36, which are the output bases supported. */#include "logtab.h"/* }}} */#define LOG_V_2(R) s_logv_2[(R)]#else#include <math.h>#define LOG_V_2(R) (log(2.0)/log(R))#endif/* Default precision for newly created mp_int's */static unsigned int s_mp_defprec = MP_DEFPREC;/* {{{ Digit arithmetic macros *//* When adding and multiplying digits, the results can be larger than can be contained in an mp_digit. Thus, an mp_word is used. These macros mask off the upper and lower digits of the mp_word (the mp_word may be more than 2 mp_digits wide, but we only concern ourselves with the low-order 2 mp_digits) If your mp_word DOES have more than 2 mp_digits, you need to uncomment the first line, and comment out the second. *//* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */#define CARRYOUT(W) ((W)>>DIGIT_BIT)#define ACCUM(W) ((W)&MP_DIGIT_MAX)/* }}} *//* {{{ Comparison constants */#define MP_LT -1#define MP_EQ 0#define MP_GT 1/* }}} *//* {{{ Constant strings *//* Constant strings returned by mp_strerror() */static const char *mp_err_string[] = { "unknown result code", /* say what? */ "boolean true", /* MP_OKAY, MP_YES */ "boolean false", /* MP_NO */ "out of memory", /* MP_MEM */ "argument out of range", /* MP_RANGE */ "invalid input parameter", /* MP_BADARG */ "result is undefined" /* MP_UNDEF */};/* Value to digit maps for radix conversion *//* s_dmap_1 - standard digits and letters */static const char *s_dmap_1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";#if 0/* s_dmap_2 - base64 ordering for digits */static const char *s_dmap_2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";#endif/* }}} *//* {{{ Static function declarations *//* If MP_MACRO is false, these will be defined as actual functions; otherwise, suitable macro definitions will be used. This works around the fact that ANSI C89 doesn't support an 'inline' keyword (although I hear C9x will ... about bloody time). At present, the macro definitions are identical to the function bodies, but they'll expand in place, instead of generating a function call. I chose these particular functions to be made into macros because some profiling showed they are called a lot on a typical workload, and yet they are primarily housekeeping. */#if MP_MACRO == 0 void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */ void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */ void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */ void s_mp_free(void *ptr); /* general free function */#else /* Even if these are defined as macros, we need to respect the settings of the MP_MEMSET and MP_MEMCPY configuration options... */ #if MP_MEMSET == 0 #define s_mp_setz(dp, count) \ {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} #else #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit)) #endif /* MP_MEMSET */ #if MP_MEMCPY == 0 #define s_mp_copy(sp, dp, count) \ {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} #else #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) #endif /* MP_MEMCPY */ #define s_mp_alloc(nb, ni) calloc(nb, ni) #define s_mp_free(ptr) {if(ptr) free(ptr);}#endif /* MP_MACRO */mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */void s_mp_clamp(mp_int *mp); /* clip leading zeroes */void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/void s_mp_div_2(mp_int *mp); /* divide by 2 in place */mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r); /* unsigned digit divide */mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu); /* Barrett reduction */mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */#if 0void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len); /* multiply buffers in place */#endif#if MP_SQUAREmp_err s_mp_sqr(mp_int *a); /* magnitude square */#else#define s_mp_sqr(a) s_mp_mul(a, a)#endifmp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */int s_mp_ispow2(mp_int *v); /* is v a power of 2? */int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */int s_mp_tovalue(char ch, int r); /* convert ch to value */char s_mp_todigit(int val, int r, int low); /* convert val to digit */int s_mp_outlen(int bits, int r); /* output length in bytes *//* }}} *//* {{{ Default precision manipulation */unsigned int mp_get_prec(void){ return s_mp_defprec;} /* end mp_get_prec() */void mp_set_prec(unsigned int prec){ if(prec == 0) s_mp_defprec = MP_DEFPREC; else s_mp_defprec = prec;} /* end mp_set_prec() *//* }}} *//*------------------------------------------------------------------------*//* {{{ mp_init(mp) *//* mp_init(mp) Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, MP_MEM if memory could not be allocated for the structure. */mp_err mp_init(mp_int *mp){ return mp_init_size(mp, s_mp_defprec);} /* end mp_init() *//* }}} *//* {{{ mp_init_array(mp[], count) */mp_err mp_init_array(mp_int mp[], int count){ mp_err res; int pos; ARGCHK(mp !=NULL && count > 0, MP_BADARG); for(pos = 0; pos < count; ++pos) { if((res = mp_init(&mp[pos])) != MP_OKAY) goto CLEANUP; } return MP_OKAY; CLEANUP: while(--pos >= 0) mp_clear(&mp[pos]); return res;} /* end mp_init_array() *//* }}} *//* {{{ mp_init_size(mp, prec) *//* mp_init_size(mp, prec) Initialize a new zero-valued mp_int with at least the given precision; returns MP_OKAY if successful, or MP_MEM if memory could not be allocated for the structure. */mp_err mp_init_size(mp_int *mp, mp_size prec){ ARGCHK(mp != NULL && prec > 0, MP_BADARG); if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) return MP_MEM; SIGN(mp) = MP_ZPOS; USED(mp) = 1; ALLOC(mp) = prec; return MP_OKAY;} /* end mp_init_size() *//* }}} *//* {{{ mp_init_copy(mp, from) *//* mp_init_copy(mp, from) Initialize mp as an exact copy of from. Returns MP_OKAY if successful, MP_MEM if memory could not be allocated for the new structure. */mp_err mp_init_copy(mp_int *mp, mp_int *from){ ARGCHK(mp != NULL && from != NULL, MP_BADARG); if(mp == from) return MP_OKAY; if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) return MP_MEM; s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); USED(mp) = USED(from); ALLOC(mp) = USED(from); SIGN(mp) = SIGN(from); return MP_OKAY;} /* end mp_init_copy() *//* }}} *//* {{{ mp_copy(from, to) *//* mp_copy(from, to) Copies the mp_int 'from' to the mp_int 'to'. It is presumed that 'to' has already been initialized (if not, use mp_init_copy() instead). If 'from' and 'to' are identical, nothing happens. */mp_err mp_copy(mp_int *from, mp_int *to){ ARGCHK(from != NULL && to != NULL, MP_BADARG); if(from == to) return MP_OKAY; { /* copy */ mp_digit *tmp; /* If the allocated buffer in 'to' already has enough space to hold all the used digits of 'from', we'll re-use it to avoid hitting the memory allocater more than necessary; otherwise, we'd have to grow anyway, so we just allocate a hunk and make the copy as usual */ if(ALLOC(to) >= USED(from)) { s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); } else { if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) return MP_MEM; s_mp_copy(DIGITS(from), tmp, USED(from)); if(DIGITS(to) != NULL) {#if MP_CRYPTO s_mp_setz(DIGITS(to), ALLOC(to));#endif s_mp_free(DIGITS(to)); } DIGITS(to) = tmp; ALLOC(to) = USED(from); } /* Copy the precision and sign from the original */ USED(to) = USED(from); SIGN(to) = SIGN(from); } /* end copy */ return MP_OKAY;} /* end mp_copy() *//* }}} *//* {{{ mp_exch(mp1, mp2) *//* mp_exch(mp1, mp2) Exchange mp1 and mp2 without allocating any intermediate memory (well, unless you count the stack space needed for this call and the locals it creates...). This cannot fail. */void mp_exch(mp_int *mp1, mp_int *mp2){#if MP_ARGCHK == 2 assert(mp1 != NULL && mp2 != NULL);#else if(mp1 == NULL || mp2 == NULL) return;#endif s_mp_exch(mp1, mp2);} /* end mp_exch() *//* }}} *//* {{{ mp_clear(mp) *//* mp_clear(mp) Release the storage used by an mp_int, and void its fields so that if someone calls mp_clear() again for the same int later, we won't get tollchocked. */void mp_clear(mp_int *mp){ if(mp == NULL) return; if(DIGITS(mp) != NULL) {#if MP_CRYPTO s_mp_setz(DIGITS(mp), ALLOC(mp));#endif s_mp_free(DIGITS(mp)); DIGITS(mp) = NULL; } USED(mp) = 0; ALLOC(mp) = 0;} /* end mp_clear() *//* }}} *//* {{{ mp_clear_array(mp[], count) */void mp_clear_array(mp_int mp[], int count){ ARGCHK(mp != NULL && count > 0, MP_BADARG); while(--count >= 0) mp_clear(&mp[count]);} /* end mp_clear_array() *//* }}} *//* {{{ mp_zero(mp) *//* mp_zero(mp) Set mp to zero. Does not change the allocated size of the structure, and therefore cannot fail (except on a bad argument, which we ignore) */void mp_zero(mp_int *mp){ if(mp == NULL) return; s_mp_setz(DIGITS(mp), ALLOC(mp)); USED(mp) = 1; SIGN(mp) = MP_ZPOS;} /* end mp_zero() *//* }}} *//* {{{ mp_set(mp, d) */void mp_set(mp_int *mp, mp_digit d){ if(mp == NULL) return; mp_zero(mp); DIGIT(mp, 0) = d;} /* end mp_set() *//* }}} *//* {{{ mp_set_int(mp, z) */mp_err mp_set_int(mp_int *mp, long z){ int ix; unsigned long v = abs(z); mp_err res; ARGCHK(mp != NULL, MP_BADARG); mp_zero(mp); if(z == 0) return MP_OKAY; /* shortcut for zero */ for(ix = sizeof(long) - 1; ix >= 0; ix--) { if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) return res; res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); if(res != MP_OKAY) return res; } if(z < 0) SIGN(mp) = MP_NEG; return MP_OKAY;} /* end mp_set_int() *//* }}} *//*------------------------------------------------------------------------*//* {{{ Digit arithmetic *//* {{{ mp_add_d(a, d, b) *//* mp_add_d(a, d, b) Compute the sum b = a + d, for a single digit d. Respects the sign of its primary addend (single digits are unsigned anyway). */mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b){ mp_err res = MP_OKAY; ARGCHK(a != NULL && b != NULL, MP_BADARG); if((res = mp_copy(a, b)) != MP_OKAY) return res; if(SIGN(b) == MP_ZPOS) { res = s_mp_add_d(b, d); } else if(s_mp_cmp_d(b, d) >= 0) { res = s_mp_sub_d(b, d); } else { SIGN(b) = MP_ZPOS; DIGIT(b, 0) = d - DIGIT(b, 0); } return res;} /* end mp_add_d() *//* }}} *//* {{{ mp_sub_d(a, d, b) *//* mp_sub_d(a, d, b) Compute the difference b = a - d, for a single digit d. Respects the sign of its subtrahend (single digits are unsigned anyway). */mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b){ mp_err res; ARGCHK(a != NULL && b != NULL, MP_BADARG); if((res = mp_copy(a, b)) != MP_OKAY) return res; if(SIGN(b) == MP_NEG) { if((res = s_mp_add_d(b, d)) != MP_OKAY) return res; } else if(s_mp_cmp_d(b, d) >= 0) { if((res = s_mp_sub_d(b, d)) != MP_OKAY) return res; } else { mp_neg(b, b); DIGIT(b, 0) = d - DIGIT(b, 0); SIGN(b) = MP_NEG; } if(s_mp_cmp_d(b, 0) == 0) SIGN(b) = MP_ZPOS; return MP_OKAY;} /* end mp_sub_d() *//* }}} *//* {{{ mp_mul_d(a, d, b) *//* mp_mul_d(a, d, b) Compute the product b = a * d, for a single digit d. Respects the sign of its multiplicand (single digits are unsigned anyway) */mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b){ mp_err res; ARGCHK(a != NULL && b != NULL, MP_BADARG); if(d == 0) { mp_zero(b); return MP_OKAY; } if((res = mp_copy(a, b)) != MP_OKAY) return res; res = s_mp_mul_d(b, d); return res;} /* end mp_mul_d() *//* }}} *//* {{{ mp_mul_2(a, c) */mp_err mp_mul_2(mp_int *a, mp_int *c){ mp_err res; ARGCHK(a != NULL && c != NULL, MP_BADARG); if((res = mp_copy(a, c)) != MP_OKAY) return res; return s_mp_mul_2(c);} /* end mp_mul_2() *//* }}} *//* {{{ mp_div_d(a, d, q, r) *//*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -