📄 mpi.c
字号:
d >>= 1; if((res = s_mp_sqr(&x)) != MP_OKAY) goto CLEANUP; } if(mp_iseven(b)) SIGN(&s) = SIGN(a); res = mp_copy(&s, c);CLEANUP: mp_clear(&x);X: mp_clear(&s); return res;} /* end mp_expt() *//* }}} *//* {{{ mp_2expt(a, k) *//* Compute a = 2^k */mp_err mp_2expt(mp_int *a, mp_digit k){ ARGCHK(a != NULL, MP_BADARG); return s_mp_2expt(a, k);} /* end mp_2expt() *//* }}} *//* {{{ mp_mod(a, m, c) *//* mp_mod(a, m, c) Compute c = a (mod m). Result will always be 0 <= c < m. */mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c){ mp_err res; int mag; ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); if(SIGN(m) == MP_NEG) return MP_RANGE; /* If |a| > m, we need to divide to get the remainder and take the absolute value. If |a| < m, we don't need to do any division, just copy and adjust the sign (if a is negative). If |a| == m, we can simply set the result to zero. This order is intended to minimize the average path length of the comparison chain on common workloads -- the most frequent cases are that |a| != m, so we do those first. */ if((mag = s_mp_cmp(a, m)) > 0) { if((res = mp_div(a, m, NULL, c)) != MP_OKAY) return res; if(SIGN(c) == MP_NEG) { if((res = mp_add(c, m, c)) != MP_OKAY) return res; } } else if(mag < 0) { if((res = mp_copy(a, c)) != MP_OKAY) return res; if(mp_cmp_z(a) < 0) { if((res = mp_add(c, m, c)) != MP_OKAY) return res; } } else { mp_zero(c); } return MP_OKAY;} /* end mp_mod() *//* }}} *//* {{{ mp_mod_d(a, d, c) *//* mp_mod_d(a, d, c) Compute c = a (mod d). Result will always be 0 <= c < d */mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c){ mp_err res; mp_digit rem; ARGCHK(a != NULL && c != NULL, MP_BADARG); if(s_mp_cmp_d(a, d) > 0) { if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) return res; } else { if(SIGN(a) == MP_NEG) rem = d - DIGIT(a, 0); else rem = DIGIT(a, 0); } if(c) *c = rem; return MP_OKAY;} /* end mp_mod_d() *//* }}} *//* {{{ mp_sqrt(a, b) *//* mp_sqrt(a, b) Compute the integer square root of a, and store the result in b. Uses an integer-arithmetic version of Newton's iterative linear approximation technique to determine this value; the result has the following two properties: b^2 <= a (b+1)^2 >= a It is a range error to pass a negative value. */mp_err mp_sqrt(mp_int *a, mp_int *b){ mp_int x, t; mp_err res; ARGCHK(a != NULL && b != NULL, MP_BADARG); /* Cannot take square root of a negative value */ if(SIGN(a) == MP_NEG) return MP_RANGE; /* Special cases for zero and one, trivial */ if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) return mp_copy(a, b); /* Initialize the temporaries we'll use below */ if((res = mp_init_size(&t, USED(a))) != MP_OKAY) return res; /* Compute an initial guess for the iteration as a itself */ if((res = mp_init_copy(&x, a)) != MP_OKAY) goto X;s_mp_rshd(&x, (USED(&x)/2)+1);mp_add_d(&x, 1, &x); for(;;) { /* t = (x * x) - a */ mp_copy(&x, &t); /* can't fail, t is big enough for original x */ if((res = mp_sqr(&t, &t)) != MP_OKAY || (res = mp_sub(&t, a, &t)) != MP_OKAY) goto CLEANUP; /* t = t / 2x */ s_mp_mul_2(&x); if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) goto CLEANUP; s_mp_div_2(&x); /* Terminate the loop, if the quotient is zero */ if(mp_cmp_z(&t) == MP_EQ) break; /* x = x - t */ if((res = mp_sub(&x, &t, &x)) != MP_OKAY) goto CLEANUP; } /* Copy result to output parameter */ mp_sub_d(&x, 1, &x); s_mp_exch(&x, b); CLEANUP: mp_clear(&x); X: mp_clear(&t); return res;} /* end mp_sqrt() *//* }}} *//* }}} *//*------------------------------------------------------------------------*//* {{{ Modular arithmetic */#if MP_MODARITH/* {{{ mp_addmod(a, b, m, c) *//* mp_addmod(a, b, m, c) Compute c = (a + b) mod m */mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c){ mp_err res; ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); if((res = mp_add(a, b, c)) != MP_OKAY) return res; if((res = mp_mod(c, m, c)) != MP_OKAY) return res; return MP_OKAY;}/* }}} *//* {{{ mp_submod(a, b, m, c) *//* mp_submod(a, b, m, c) Compute c = (a - b) mod m */mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c){ mp_err res; ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); if((res = mp_sub(a, b, c)) != MP_OKAY) return res; if((res = mp_mod(c, m, c)) != MP_OKAY) return res; return MP_OKAY;}/* }}} *//* {{{ mp_mulmod(a, b, m, c) *//* mp_mulmod(a, b, m, c) Compute c = (a * b) mod m */mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c){ mp_err res; ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); if((res = mp_mul(a, b, c)) != MP_OKAY) return res; if((res = mp_mod(c, m, c)) != MP_OKAY) return res; return MP_OKAY;}/* }}} *//* {{{ mp_sqrmod(a, m, c) */#if MP_SQUAREmp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c){ mp_err res; ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); if((res = mp_sqr(a, c)) != MP_OKAY) return res; if((res = mp_mod(c, m, c)) != MP_OKAY) return res; return MP_OKAY;} /* end mp_sqrmod() */#endif/* }}} *//* {{{ mp_exptmod(a, b, m, c) *//* mp_exptmod(a, b, m, c) Compute c = (a ** b) mod m. Uses a standard square-and-multiply method with modular reductions at each step. (This is basically the same code as mp_expt(), except for the addition of the reductions) The modular reductions are done using Barrett's algorithm (see s_mp_reduce() below for details) */mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c){ mp_int s, x, mu; mp_err res; mp_digit d, *db = DIGITS(b); mp_size ub = USED(b); int dig, bit; ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0) return MP_RANGE; if((res = mp_init(&s)) != MP_OKAY) return res; if((res = mp_init_copy(&x, a)) != MP_OKAY) goto X; if((res = mp_mod(&x, m, &x)) != MP_OKAY || (res = mp_init(&mu)) != MP_OKAY) goto MU; mp_set(&s, 1); /* mu = b^2k / m */ s_mp_add_d(&mu, 1); s_mp_lshd(&mu, 2 * USED(m)); if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY) goto CLEANUP; /* Loop over digits of b in ascending order, except highest order */ for(dig = 0; dig < (ub - 1); dig++) { d = *db++; /* Loop over the bits of the lower-order digits */ for(bit = 0; bit < DIGIT_BIT; bit++) { if(d & 1) { if((res = s_mp_mul(&s, &x)) != MP_OKAY) goto CLEANUP; if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) goto CLEANUP; } d >>= 1; if((res = s_mp_sqr(&x)) != MP_OKAY) goto CLEANUP; if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) goto CLEANUP; } } /* Now do the last digit... */ d = *db; while(d) { if(d & 1) { if((res = s_mp_mul(&s, &x)) != MP_OKAY) goto CLEANUP; if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) goto CLEANUP; } d >>= 1; if((res = s_mp_sqr(&x)) != MP_OKAY) goto CLEANUP; if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) goto CLEANUP; } s_mp_exch(&s, c); CLEANUP: mp_clear(&mu); MU: mp_clear(&x); X: mp_clear(&s); return res;} /* end mp_exptmod() *//* }}} *//* {{{ mp_exptmod_d(a, d, m, c) */mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c){ mp_int s, x; mp_err res; ARGCHK(a != NULL && c != NULL, MP_BADARG); if((res = mp_init(&s)) != MP_OKAY) return res; if((res = mp_init_copy(&x, a)) != MP_OKAY) goto X; mp_set(&s, 1); while(d != 0) { if(d & 1) { if((res = s_mp_mul(&s, &x)) != MP_OKAY || (res = mp_mod(&s, m, &s)) != MP_OKAY) goto CLEANUP; } d /= 2; if((res = s_mp_sqr(&x)) != MP_OKAY || (res = mp_mod(&x, m, &x)) != MP_OKAY) goto CLEANUP; } s_mp_exch(&s, c);CLEANUP: mp_clear(&x);X: mp_clear(&s); return res;} /* end mp_exptmod_d() *//* }}} */#endif /* if MP_MODARITH *//* }}} *//*------------------------------------------------------------------------*//* {{{ Comparison functions *//* {{{ mp_cmp_z(a) *//* mp_cmp_z(a) Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. */int mp_cmp_z(mp_int *a){ if(SIGN(a) == MP_NEG) return MP_LT; else if(USED(a) == 1 && DIGIT(a, 0) == 0) return MP_EQ; else return MP_GT;} /* end mp_cmp_z() *//* }}} *//* {{{ mp_cmp_d(a, d) *//* mp_cmp_d(a, d) Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d */int mp_cmp_d(mp_int *a, mp_digit d){ ARGCHK(a != NULL, MP_EQ); if(SIGN(a) == MP_NEG) return MP_LT; return s_mp_cmp_d(a, d);} /* end mp_cmp_d() *//* }}} *//* {{{ mp_cmp(a, b) */int mp_cmp(mp_int *a, mp_int *b){ ARGCHK(a != NULL && b != NULL, MP_EQ); if(SIGN(a) == SIGN(b)) { int mag; if((mag = s_mp_cmp(a, b)) == MP_EQ) return MP_EQ; if(SIGN(a) == MP_ZPOS) return mag; else return -mag; } else if(SIGN(a) == MP_ZPOS) { return MP_GT; } else { return MP_LT; }} /* end mp_cmp() *//* }}} *//* {{{ mp_cmp_mag(a, b) *//* mp_cmp_mag(a, b) Compares |a| <=> |b|, and returns an appropriate comparison result */int mp_cmp_mag(mp_int *a, mp_int *b){ ARGCHK(a != NULL && b != NULL, MP_EQ); return s_mp_cmp(a, b);} /* end mp_cmp_mag() *//* }}} *//* {{{ mp_cmp_int(a, z) *//* This just converts z to an mp_int, and uses the existing comparison routines. This is sort of inefficient, but it's not clear to me how frequently this wil get used anyway. For small positive constants, you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). */int mp_cmp_int(mp_int *a, long z){ mp_int tmp; int out; ARGCHK(a != NULL, MP_EQ); mp_init(&tmp); mp_set_int(&tmp, z); out = mp_cmp(a, &tmp); mp_clear(&tmp); return out;} /* end mp_cmp_int() *//* }}} *//* {{{ mp_isodd(a) *//* mp_isodd(a) Returns a true (non-zero) value if a is odd, false (zero) otherwise. */int mp_isodd(mp_int *a){ ARGCHK(a != NULL, 0); return (DIGIT(a, 0) & 1);} /* end mp_isodd() *//* }}} *//* {{{ mp_iseven(a) */int mp_iseven(mp_int *a){ return !mp_isodd(a);} /* end mp_iseven() *//* }}} *//* }}} *//*------------------------------------------------------------------------*//* {{{ Number theoretic functions */#if MP_NUMTH/* {{{ mp_gcd(a, b, c) *//* Like the old mp_gcd() function, except computes the GCD using the binary algorithm due to Josef Stein in 1961 (via Knuth). */mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c){ mp_err res; mp_int u, v, t; mp_size k = 0; ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) return MP_RANGE; if(mp_cmp_z(a) == MP_EQ) { return mp_copy(b, c); } else if(mp_cmp_z(b) == MP_EQ) { return mp_copy(a, c); } if((res = mp_init(&t)) != MP_OKAY) return res; if((res = mp_init_copy(&u, a)) != MP_OKAY) goto U; if((res = mp_init_copy(&v, b)) != MP_OKAY) goto V; SIGN(&u) = MP_ZPOS; SIGN(&v) = MP_ZPOS; /* Divide out common factors of 2 until at least 1 of a, b is even */ while(mp_iseven(&u) && mp_iseven(&v)) { s_mp_div_2(&u); s_mp_div_2(&v); ++k; } /* Initialize t */ if(mp_isodd(&u)) { if((res = mp_copy(&v, &t)) != MP_OKAY) goto CLEANUP; /* t = -v */ if(SIGN(&v) == MP_ZPOS) SIGN(&t) = MP_NEG; else SIGN(&t) = MP_ZPOS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -