📄 mpi.c
字号:
mp_clear(&qp); } if(r) *r = rem; return res;} /* end mp_div_d() *//* }}} *//* {{{ mp_div_2(a, c) *//* mp_div_2(a, c) Compute c = a / 2, disregarding the remainder. */mp_err mp_div_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; s_mp_div_2(c); return MP_OKAY;} /* end mp_div_2() *//* }}} *//* {{{ mp_expt_d(a, d, b) */mp_err mp_expt_d(mp_int *a, mp_digit d, 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; DIGIT(&s, 0) = 1; while(d != 0) { if(d & 1) { if((res = s_mp_mul(&s, &x)) != MP_OKAY) goto CLEANUP; } d >>= 1; if((res = s_mp_sqr(&x)) != MP_OKAY) goto CLEANUP; } s_mp_exch(&s, c);CLEANUP: mp_clear(&x);X: mp_clear(&s); return res;} /* end mp_expt_d() *//* }}} *//* }}} *//*------------------------------------------------------------------------*//* {{{ Full arithmetic *//* {{{ mp_abs(a, b) *//* mp_abs(a, b) Compute b = |a|. 'a' and 'b' may be identical. */mp_err mp_abs(mp_int *a, mp_int *b){ mp_err res; ARGCHK(a != NULL && b != NULL, MP_BADARG); if((res = mp_copy(a, b)) != MP_OKAY) return res; SIGN(b) = MP_ZPOS; return MP_OKAY;} /* end mp_abs() *//* }}} *//* {{{ mp_neg(a, b) *//* mp_neg(a, b) Compute b = -a. 'a' and 'b' may be identical. */mp_err mp_neg(mp_int *a, mp_int *b){ mp_err res; ARGCHK(a != NULL && b != NULL, MP_BADARG); if((res = mp_copy(a, b)) != MP_OKAY) return res; if(s_mp_cmp_d(b, 0) == MP_EQ) SIGN(b) = MP_ZPOS; else SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; return MP_OKAY;} /* end mp_neg() *//* }}} *//* {{{ mp_add(a, b, c) *//* mp_add(a, b, c) Compute c = a + b. All parameters may be identical. */mp_err mp_add(mp_int *a, mp_int *b, mp_int *c){ mp_err res; int cmp; ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ /* Commutativity of addition lets us do this in either order, so we avoid having to use a temporary even if the result is supposed to replace the output */ if(c == b) { if((res = s_mp_add(c, a)) != MP_OKAY) return res; } else { if(c != a && (res = mp_copy(a, c)) != MP_OKAY) return res; if((res = s_mp_add(c, b)) != MP_OKAY) return res; } } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */ /* If the output is going to be clobbered, we will use a temporary variable; otherwise, we'll do it without touching the memory allocator at all, if possible */ if(c == b) { mp_int tmp; if((res = mp_init_copy(&tmp, a)) != MP_OKAY) return res; if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { mp_clear(&tmp); return res; } s_mp_exch(&tmp, c); mp_clear(&tmp); } else { if(c != a && (res = mp_copy(a, c)) != MP_OKAY) return res; if((res = s_mp_sub(c, b)) != MP_OKAY) return res; } } else if(cmp == 0) { /* different sign, a == b */ mp_zero(c); return MP_OKAY; } else { /* different sign: a < b */ /* See above... */ if(c == a) { mp_int tmp; if((res = mp_init_copy(&tmp, b)) != MP_OKAY) return res; if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { mp_clear(&tmp); return res; } s_mp_exch(&tmp, c); mp_clear(&tmp); } else { if(c != b && (res = mp_copy(b, c)) != MP_OKAY) return res; if((res = s_mp_sub(c, a)) != MP_OKAY) return res; } } if(USED(c) == 1 && DIGIT(c, 0) == 0) SIGN(c) = MP_ZPOS; return MP_OKAY;} /* end mp_add() *//* }}} *//* {{{ mp_sub(a, b, c) *//* mp_sub(a, b, c) Compute c = a - b. All parameters may be identical. */mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c){ mp_err res; int cmp; ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); if(SIGN(a) != SIGN(b)) { if(c == a) { if((res = s_mp_add(c, b)) != MP_OKAY) return res; } else { if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) return res; if((res = s_mp_add(c, a)) != MP_OKAY) return res; SIGN(c) = SIGN(a); } } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ if(c == b) { mp_int tmp; if((res = mp_init_copy(&tmp, a)) != MP_OKAY) return res; if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { mp_clear(&tmp); return res; } s_mp_exch(&tmp, c); mp_clear(&tmp); } else { if(c != a && ((res = mp_copy(a, c)) != MP_OKAY)) return res; if((res = s_mp_sub(c, b)) != MP_OKAY) return res; } } else if(cmp == 0) { /* Same sign, equal magnitude */ mp_zero(c); return MP_OKAY; } else { /* Same sign, b > a */ if(c == a) { mp_int tmp; if((res = mp_init_copy(&tmp, b)) != MP_OKAY) return res; if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { mp_clear(&tmp); return res; } s_mp_exch(&tmp, c); mp_clear(&tmp); } else { if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) return res; if((res = s_mp_sub(c, a)) != MP_OKAY) return res; } SIGN(c) = !SIGN(b); } if(USED(c) == 1 && DIGIT(c, 0) == 0) SIGN(c) = MP_ZPOS; return MP_OKAY;} /* end mp_sub() *//* }}} *//* {{{ mp_mul(a, b, c) *//* mp_mul(a, b, c) Compute c = a * b. All parameters may be identical. */mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c){ mp_err res; mp_sign sgn; ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; if((res = mp_copy(a, c)) != MP_OKAY) return res; if((res = s_mp_mul(c, b)) != MP_OKAY) return res; if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ) SIGN(c) = MP_ZPOS; else SIGN(c) = sgn; return MP_OKAY;} /* end mp_mul() *//* }}} *//* {{{ mp_sqr(a, b) */#if MP_SQUAREmp_err mp_sqr(mp_int *a, mp_int *b){ mp_err res; ARGCHK(a != NULL && b != NULL, MP_BADARG); if((res = mp_copy(a, b)) != MP_OKAY) return res; if((res = s_mp_sqr(b)) != MP_OKAY) return res; SIGN(b) = MP_ZPOS; return MP_OKAY;} /* end mp_sqr() */#endif/* }}} *//* {{{ mp_div(a, b, q, r) *//* mp_div(a, b, q, r) Compute q = a / b and r = a mod b. Input parameters may be re-used as output parameters. If q or r is NULL, that portion of the computation will be discarded (although it will still be computed) Pay no attention to the hacker behind the curtain. */mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r){ mp_err res; mp_int qtmp, rtmp; int cmp; ARGCHK(a != NULL && b != NULL, MP_BADARG); if(mp_cmp_z(b) == MP_EQ) return MP_RANGE; /* If a <= b, we can compute the solution without division, and avoid any memory allocation */ if((cmp = s_mp_cmp(a, b)) < 0) { if(r) { if((res = mp_copy(a, r)) != MP_OKAY) return res; } if(q) mp_zero(q); return MP_OKAY; } else if(cmp == 0) { /* Set quotient to 1, with appropriate sign */ if(q) { int qneg = (SIGN(a) != SIGN(b)); mp_set(q, 1); if(qneg) SIGN(q) = MP_NEG; } if(r) mp_zero(r); return MP_OKAY; } /* If we get here, it means we actually have to do some division */ /* Set up some temporaries... */ if((res = mp_init_copy(&qtmp, a)) != MP_OKAY) return res; if((res = mp_init_copy(&rtmp, b)) != MP_OKAY) goto CLEANUP; if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY) goto CLEANUP; /* Compute the signs for the output */ SIGN(&rtmp) = SIGN(a); /* Sr = Sa */ if(SIGN(a) == SIGN(b)) SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */ else SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */ if(s_mp_cmp_d(&qtmp, 0) == MP_EQ) SIGN(&qtmp) = MP_ZPOS; if(s_mp_cmp_d(&rtmp, 0) == MP_EQ) SIGN(&rtmp) = MP_ZPOS; /* Copy output, if it is needed */ if(q) s_mp_exch(&qtmp, q); if(r) s_mp_exch(&rtmp, r);CLEANUP: mp_clear(&rtmp); mp_clear(&qtmp); return res;} /* end mp_div() *//* }}} *//* {{{ mp_div_2d(a, d, q, r) */mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r){ mp_err res; ARGCHK(a != NULL, MP_BADARG); if(q) { if((res = mp_copy(a, q)) != MP_OKAY) return res; s_mp_div_2d(q, d); } if(r) { if((res = mp_copy(a, r)) != MP_OKAY) return res; s_mp_mod_2d(r, d); } return MP_OKAY;} /* end mp_div_2d() *//* }}} *//* {{{ mp_expt(a, b, c) *//* mp_expt(a, b, c) Compute c = a ** b, that is, raise a to the b power. Uses a standard iterative square-and-multiply technique. */mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c){ mp_int s, x; mp_err res; mp_digit d; mp_size dig; int bit; ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); if(mp_cmp_z(b) < 0) return MP_RANGE; if((res = mp_init(&s)) != MP_OKAY) return res; mp_set(&s, 1); if((res = mp_init_copy(&x, a)) != MP_OKAY) goto X; /* Loop over low-order digits in ascending order */ for(dig = 0; dig < (USED(b) - 1); dig++) { d = DIGIT(b, dig); /* Loop over bits of each non-maximal digit */ for(bit = 0; bit < DIGIT_BIT; bit++) { if(d & 1) { if((res = s_mp_mul(&s, &x)) != MP_OKAY) goto CLEANUP; } d >>= 1; if((res = s_mp_sqr(&x)) != MP_OKAY) goto CLEANUP; } } /* Consider now the last digit... */ d = DIGIT(b, dig); while(d) { if(d & 1) { if((res = s_mp_mul(&s, &x)) != MP_OKAY) goto CLEANUP; } 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -