📄 libtommath.c
字号:
/* * Minimal code for RSA support from LibTomMath 0.41 * http://libtom.org/ * http://libtom.org/files/ltm-0.41.tar.bz2 * This library was released in public domain by Tom St Denis. * * The combination in this file may not use all of the optimized algorithms * from LibTomMath and may be considerable slower than the LibTomMath with its * default settings. The main purpose of having this version here is to make it * easier to build bignum.c wrapper without having to install and build an * external library. * * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this * libtommath.c file instead of using the external LibTomMath library. */#ifndef CHAR_BIT#define CHAR_BIT 8#endif#define BN_MP_INVMOD_C#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would * require BN_MP_EXPTMOD_FAST_C instead */#define BN_S_MP_MUL_DIGS_C#define BN_MP_INVMOD_SLOW_C#define BN_S_MP_SQR_C#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this * would require other than mp_reduce */#ifdef LTM_FAST/* Use faster div at the cost of about 1 kB */#define BN_MP_MUL_D_C/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */#define BN_MP_EXPTMOD_FAST_C#define BN_MP_MONTGOMERY_SETUP_C#define BN_FAST_MP_MONTGOMERY_REDUCE_C#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C#define BN_MP_MUL_2_C/* Include faster sqr at the cost of about 0.5 kB in code */#define BN_FAST_S_MP_SQR_C#else /* LTM_FAST */#define BN_MP_DIV_SMALL#define BN_MP_INIT_MULTI_C#define BN_MP_CLEAR_MULTI_C#define BN_MP_ABS_C#endif /* LTM_FAST *//* Current uses do not require support for negative exponent in exptmod, so we * can save about 1.5 kB in leaving out invmod. */#define LTM_NO_NEG_EXP/* from tommath.h */#ifndef MIN #define MIN(x,y) ((x)<(y)?(x):(y))#endif#ifndef MAX #define MAX(x,y) ((x)>(y)?(x):(y))#endif#define OPT_CAST(x)typedef unsigned long mp_digit;typedef u64 mp_word;#define DIGIT_BIT 28#define MP_28BIT#define XMALLOC os_malloc#define XFREE os_free#define XREALLOC os_realloc#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))#define MP_LT -1 /* less than */#define MP_EQ 0 /* equal to */#define MP_GT 1 /* greater than */#define MP_ZPOS 0 /* positive integer */#define MP_NEG 1 /* negative */#define MP_OKAY 0 /* ok result */#define MP_MEM -2 /* out of mem */#define MP_VAL -3 /* invalid input */#define MP_YES 1 /* yes response */#define MP_NO 0 /* no response */typedef int mp_err;/* define this to use lower memory usage routines (exptmods mostly) */#define MP_LOW_MEM/* default precision */#ifndef MP_PREC #ifndef MP_LOW_MEM #define MP_PREC 32 /* default digits of precision */ #else #define MP_PREC 8 /* default digits of precision */ #endif #endif/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))/* the infamous mp_int structure */typedef struct { int used, alloc, sign; mp_digit *dp;} mp_int;/* ---> Basic Manipulations <--- */#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)/* prototypes for copied functions */#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);static int s_mp_sqr(mp_int * a, mp_int * b);static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);#ifdef BN_MP_INIT_MULTI_Cstatic int mp_init_multi(mp_int *mp, ...);#endif#ifdef BN_MP_CLEAR_MULTI_Cstatic void mp_clear_multi(mp_int *mp, ...);#endifstatic int mp_lshd(mp_int * a, int b);static void mp_set(mp_int * a, mp_digit b);static void mp_clamp(mp_int * a);static void mp_exch(mp_int * a, mp_int * b);static void mp_rshd(mp_int * a, int b);static void mp_zero(mp_int * a);static int mp_mod_2d(mp_int * a, int b, mp_int * c);static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);static int mp_init_copy(mp_int * a, mp_int * b);static int mp_mul_2d(mp_int * a, int b, mp_int * c);#ifndef LTM_NO_NEG_EXPstatic int mp_div_2(mp_int * a, mp_int * b);static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);#endif /* LTM_NO_NEG_EXP */static int mp_copy(mp_int * a, mp_int * b);static int mp_count_bits(mp_int * a);static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);static int mp_mod(mp_int * a, mp_int * b, mp_int * c);static int mp_grow(mp_int * a, int size);static int mp_cmp_mag(mp_int * a, mp_int * b);#ifdef BN_MP_ABS_Cstatic int mp_abs(mp_int * a, mp_int * b);#endifstatic int mp_sqr(mp_int * a, mp_int * b);static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);static int mp_2expt(mp_int * a, int b);static int mp_reduce_setup(mp_int * a, mp_int * b);static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);static int mp_init_size(mp_int * a, int size);#ifdef BN_MP_EXPTMOD_FAST_Cstatic int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);#endif /* BN_MP_EXPTMOD_FAST_C */#ifdef BN_FAST_S_MP_SQR_Cstatic int fast_s_mp_sqr (mp_int * a, mp_int * b);#endif /* BN_FAST_S_MP_SQR_C */#ifdef BN_MP_MUL_D_Cstatic int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);#endif /* BN_MP_MUL_D_C *//* functions from bn_<func name>.c *//* reverse an array, used for radix code */static void bn_reverse (unsigned char *s, int len){ int ix, iy; unsigned char t; ix = 0; iy = len - 1; while (ix < iy) { t = s[ix]; s[ix] = s[iy]; s[iy] = t; ++ix; --iy; }}/* low level addition, based on HAC pp.594, Algorithm 14.7 */static int s_mp_add (mp_int * a, mp_int * b, mp_int * c){ mp_int *x; int olduse, res, min, max; /* find sizes, we let |a| <= |b| which means we have to sort * them. "x" will point to the input with the most digits */ if (a->used > b->used) { min = b->used; max = a->used; x = a; } else { min = a->used; max = b->used; x = b; } /* init result */ if (c->alloc < max + 1) { if ((res = mp_grow (c, max + 1)) != MP_OKAY) { return res; } } /* get old used digit count and set new one */ olduse = c->used; c->used = max + 1; { register mp_digit u, *tmpa, *tmpb, *tmpc; register int i; /* alias for digit pointers */ /* first input */ tmpa = a->dp; /* second input */ tmpb = b->dp; /* destination */ tmpc = c->dp; /* zero the carry */ u = 0; for (i = 0; i < min; i++) { /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ *tmpc = *tmpa++ + *tmpb++ + u; /* U = carry bit of T[i] */ u = *tmpc >> ((mp_digit)DIGIT_BIT); /* take away carry bit from T[i] */ *tmpc++ &= MP_MASK; } /* now copy higher words if any, that is in A+B * if A or B has more digits add those in */ if (min != max) { for (; i < max; i++) { /* T[i] = X[i] + U */ *tmpc = x->dp[i] + u; /* U = carry bit of T[i] */ u = *tmpc >> ((mp_digit)DIGIT_BIT); /* take away carry bit from T[i] */ *tmpc++ &= MP_MASK; } } /* add carry */ *tmpc++ = u; /* clear digits above oldused */ for (i = c->used; i < olduse; i++) { *tmpc++ = 0; } } mp_clamp (c); return MP_OKAY;}/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c){ int olduse, res, min, max; /* find sizes */ min = b->used; max = a->used; /* init result */ if (c->alloc < max) { if ((res = mp_grow (c, max)) != MP_OKAY) { return res; } } olduse = c->used; c->used = max; { register mp_digit u, *tmpa, *tmpb, *tmpc; register int i; /* alias for digit pointers */ tmpa = a->dp; tmpb = b->dp; tmpc = c->dp; /* set carry to zero */ u = 0; for (i = 0; i < min; i++) { /* T[i] = A[i] - B[i] - U */ *tmpc = *tmpa++ - *tmpb++ - u; /* U = carry bit of T[i] * Note this saves performing an AND operation since * if a carry does occur it will propagate all the way to the * MSB. As a result a single shift is enough to get the carry */ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); /* Clear carry from T[i] */ *tmpc++ &= MP_MASK; } /* now copy higher words if any, e.g. if A has more digits than B */ for (; i < max; i++) { /* T[i] = A[i] - U */ *tmpc = *tmpa++ - u; /* U = carry bit of T[i] */ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); /* Clear carry from T[i] */ *tmpc++ &= MP_MASK; } /* clear digits above used (since we may not have grown result above) */ for (i = c->used; i < olduse; i++) { *tmpc++ = 0; } } mp_clamp (c); return MP_OKAY;}/* init a new mp_int */static int mp_init (mp_int * a){ int i; /* allocate memory required and clear it */ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); if (a->dp == NULL) { return MP_MEM; } /* set the digits to zero */ for (i = 0; i < MP_PREC; i++) { a->dp[i] = 0; } /* set the used to zero, allocated digits to the default precision * and sign to positive */ a->used = 0; a->alloc = MP_PREC; a->sign = MP_ZPOS; return MP_OKAY;}/* clear one (frees) */static void mp_clear (mp_int * a){ int i; /* only do anything if a hasn't been freed previously */ if (a->dp != NULL) { /* first zero the digits */ for (i = 0; i < a->used; i++) { a->dp[i] = 0; } /* free ram */ XFREE(a->dp); /* reset members to make debugging easier */ a->dp = NULL; a->alloc = a->used = 0; a->sign = MP_ZPOS; }}/* high level addition (handles signs) */static int mp_add (mp_int * a, mp_int * b, mp_int * c){ int sa, sb, res; /* get sign of both inputs */ sa = a->sign; sb = b->sign; /* handle two cases, not four */ if (sa == sb) { /* both positive or both negative */ /* add their magnitudes, copy the sign */ c->sign = sa; res = s_mp_add (a, b, c); } else { /* one positive, the other negative */ /* subtract the one with the greater magnitude from */ /* the one of the lesser magnitude. The result gets */ /* the sign of the one with the greater magnitude. */ if (mp_cmp_mag (a, b) == MP_LT) { c->sign = sb; res = s_mp_sub (b, a, c); } else { c->sign = sa; res = s_mp_sub (a, b, c); } } return res;}/* high level subtraction (handles signs) */static int mp_sub (mp_int * a, mp_int * b, mp_int * c){ int sa, sb, res; sa = a->sign; sb = b->sign; if (sa != sb) { /* subtract a negative from a positive, OR */ /* subtract a positive from a negative. */ /* In either case, ADD their magnitudes, */ /* and use the sign of the first number. */ c->sign = sa; res = s_mp_add (a, b, c); } else { /* subtract a positive from a positive, OR */ /* subtract a negative from a negative. */ /* First, take the difference between their */ /* magnitudes, then... */ if (mp_cmp_mag (a, b) != MP_LT) { /* Copy the sign from the first */ c->sign = sa; /* The first has a larger or equal magnitude */ res = s_mp_sub (a, b, c); } else { /* The result has the *opposite* sign from */ /* the first number. */ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; /* The second has a larger magnitude */ res = s_mp_sub (b, a, c); } } return res;}/* high level multiplication (handles sign) */static int mp_mul (mp_int * a, mp_int * b, mp_int * c){ int res, neg; neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; /* use Toom-Cook? */#ifdef BN_MP_TOOM_MUL_C if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { res = mp_toom_mul(a, b, c); } else #endif#ifdef BN_MP_KARATSUBA_MUL_C /* use Karatsuba? */ if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { res = mp_karatsuba_mul (a, b, c); } else #endif { /* can we use the fast multiplier? * * The fast multiplier can be used if the output will * have less than MP_WARRAY digits and the number of * digits won't affect carry propagation */#ifdef BN_FAST_S_MP_MUL_DIGS_C int digs = a->used + b->used + 1; if ((digs < MP_WARRAY) && MIN(a->used, b->used) <= (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { res = fast_s_mp_mul_digs (a, b, c, digs); } else #endif#ifdef BN_S_MP_MUL_DIGS_C res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */#else#error mp_mul could fail res = MP_VAL;#endif } c->sign = (c->used > 0) ? neg : MP_ZPOS; return res;}/* d = a * b (mod c) */static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d){ int res; mp_int t; if ((res = mp_init (&t)) != MP_OKAY) { return res; } if ((res = mp_mul (a, b, &t)) != MP_OKAY) { mp_clear (&t); return res; } res = mp_mod (&t, c, d); mp_clear (&t); return res;}/* c = a mod b, 0 <= c < b */static int mp_mod (mp_int * a, mp_int * b, mp_int * c){ mp_int t; int res; if ((res = mp_init (&t)) != MP_OKAY) { return res; } if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { mp_clear (&t); return res; } if (t.sign != b->sign) { res = mp_add (b, &t, c); } else { res = MP_OKAY; mp_exch (&t, c); } mp_clear (&t); return res;}/* this is a shell function that calls either the normal or Montgomery * exptmod functions. Originally the call to the montgomery code was
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -