📄 mpi.c
字号:
} /* end mp_lcm() *//* }}} *//* {{{ mp_xgcd(a, b, g, x, y) *//* mp_xgcd(a, b, g, x, y) Compute g = (a, b) and values x and y satisfying Bezout's identity (that is, ax + by = g). This uses the extended binary GCD algorithm based on the Stein algorithm used for mp_gcd() */mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y){ mp_int gx, xc, yc, u, v, A, B, C, D; mp_int *clean[9]; mp_err res; int last = -1; if(mp_cmp_z(b) == 0) return MP_RANGE; /* Initialize all these variables we need */ if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP; clean[++last] = &u; if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP; clean[++last] = &v; if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP; clean[++last] = &gx; if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP; clean[++last] = &A; if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP; clean[++last] = &B; if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP; clean[++last] = &C; if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP; clean[++last] = &D; if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; clean[++last] = &xc; mp_abs(&xc, &xc); if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; clean[++last] = &yc; mp_abs(&yc, &yc); mp_set(&gx, 1); /* Divide by two until at least one of them is even */ while(mp_iseven(&xc) && mp_iseven(&yc)) { s_mp_div_2(&xc); s_mp_div_2(&yc); if((res = s_mp_mul_2(&gx)) != MP_OKAY) goto CLEANUP; } mp_copy(&xc, &u); mp_copy(&yc, &v); mp_set(&A, 1); mp_set(&D, 1); /* Loop through binary GCD algorithm */ for(;;) { while(mp_iseven(&u)) { s_mp_div_2(&u); if(mp_iseven(&A) && mp_iseven(&B)) { s_mp_div_2(&A); s_mp_div_2(&B); } else { if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; s_mp_div_2(&A); if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; s_mp_div_2(&B); } } while(mp_iseven(&v)) { s_mp_div_2(&v); if(mp_iseven(&C) && mp_iseven(&D)) { s_mp_div_2(&C); s_mp_div_2(&D); } else { if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; s_mp_div_2(&C); if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; s_mp_div_2(&D); } } if(mp_cmp(&u, &v) >= 0) { if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; } else { if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; } /* If we're done, copy results to output */ if(mp_cmp_z(&u) == 0) { if(x) if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; if(y) if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; if(g) if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; break; } } CLEANUP: while(last >= 0) mp_clear(clean[last--]); return res;} /* end mp_xgcd() *//* }}} *//* {{{ mp_invmod(a, m, c) *//* mp_invmod(a, m, c) Compute c = a^-1 (mod m), if there is an inverse for a (mod m). This is equivalent to the question of whether (a, m) = 1. If not, MP_UNDEF is returned, and there is no inverse. */mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c){ mp_int g, x; mp_err res; ARGCHK(a && m && c, MP_BADARG); if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) return MP_RANGE; if((res = mp_init(&g)) != MP_OKAY) return res; if((res = mp_init(&x)) != MP_OKAY) goto X; if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) goto CLEANUP; if(mp_cmp_d(&g, 1) != MP_EQ) { res = MP_UNDEF; goto CLEANUP; } res = mp_mod(&x, m, c); SIGN(c) = SIGN(a);CLEANUP: mp_clear(&x);X: mp_clear(&g); return res;} /* end mp_invmod() *//* }}} */#endif /* if MP_NUMTH *//* }}} *//*------------------------------------------------------------------------*//* {{{ mp_print(mp, ofp) */#if MP_IOFUNC/* mp_print(mp, ofp) Print a textual representation of the given mp_int on the output stream 'ofp'. Output is generated using the internal radix. */void mp_print(mp_int *mp, FILE *ofp){ int ix; if(mp == NULL || ofp == NULL) return; fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); for(ix = USED(mp) - 1; ix >= 0; ix--) { fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); }} /* end mp_print() */#endif /* if MP_IOFUNC *//* }}} *//*------------------------------------------------------------------------*//* {{{ More I/O Functions *//* {{{ mp_read_raw(mp, str, len) *//* mp_read_raw(mp, str, len) Read in a raw value (base 256) into the given mp_int */mp_err mp_read_raw(mp_int *mp, char *str, int len){ mp_err res; ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); if((res = mp_read_mag(mp, str + 1, len - 1)) == MP_OKAY) { /* Get sign from first byte */ if(str[0]) SIGN(mp) = MP_NEG; else SIGN(mp) = MP_ZPOS; } return res;} /* end mp_read_raw() *//* }}} *//* {{{ mp_raw_size(mp) */int mp_raw_size(mp_int *mp){ ARGCHK(mp != NULL, 0); return mp_mag_size(mp) + 1;} /* end mp_raw_size() *//* }}} *//* {{{ mp_toraw(mp, str) */mp_err mp_toraw(mp_int *mp, char *str){ ARGCHK(mp != NULL && str != NULL, MP_BADARG); /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */ str[0] = (char)SIGN(mp); return mp_tomag(mp, str + 1);} /* end mp_toraw() *//* }}} *//* {{{ mp_read_mag(mp, str, len) *//* mp_read_mag(mp, str, len) Read in an unsigned value (base 256) into the given mp_int */mp_err mp_read_mag(mp_int *mp, char *str, int len){ int ix; mp_err res; ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); mp_zero(mp); for(ix = 0; ix < len; ix++) { if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) return res; if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY) return res; } return MP_OKAY; } /* end mp_read_mag() *//* }}} *//* {{{ mp_mag_size(mp) */int mp_mag_size(mp_int *mp) { mp_digit topdig; int count; ARGCHK(mp != NULL, 0); count = (USED(mp) - 1) * sizeof(mp_digit); topdig = DIGIT(mp, USED(mp) - 1); while(topdig != 0) { ++count; topdig >>= CHAR_BIT; } return count;} /* end mp_mag_size() *//* }}} *//* {{{ mp_tomag(mp, str) */mp_err mp_tomag(mp_int *mp, char *str){ mp_digit *dp, *end, d; char *spos; ARGCHK(mp != NULL && str != NULL, MP_BADARG); dp = DIGITS(mp); end = dp + USED(mp) - 1; spos = str; /* Generate digits in reverse order */ while(dp < end) { int ix; d = *dp; for(ix = 0; ix < sizeof(mp_digit); ++ix) { *spos = d & UCHAR_MAX; d >>= CHAR_BIT; ++spos; } ++dp; } /* Now handle last digit specially, high order zeroes are not written */ d = *end; while(d != 0) { *spos = d & UCHAR_MAX; d >>= CHAR_BIT; ++spos; } /* Reverse everything to get digits in the correct order */ while(--spos > str) { char t = *str; *str = *spos; *spos = t; ++str; } return MP_OKAY;} /* end mp_tomag() *//* }}} *//* {{{ mp_read_radix(mp, str, radix) *//* mp_read_radix(mp, str, radix) Read an integer from the given string, and set mp to the resulting value. The input is presumed to be in base 10. Leading non-digit characters are ignored, and the function reads until a non-digit character or the end of the string. */mp_err mp_read_radix(mp_int *mp, char *str, int radix){ int ix = 0, val = 0; mp_err res; mp_sign sig = MP_ZPOS; ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, MP_BADARG); mp_zero(mp); /* Skip leading non-digit characters until a digit or '-' or '+' */ while(str[ix] && (s_mp_tovalue(str[ix], radix) < 0) && str[ix] != '-' && str[ix] != '+') { ++ix; } if(str[ix] == '-') { sig = MP_NEG; ++ix; } else if(str[ix] == '+') { sig = MP_ZPOS; /* this is the default anyway... */ ++ix; } while((val = s_mp_tovalue(str[ix], radix)) >= 0) { if((res = s_mp_mul_d(mp, radix)) != MP_OKAY) return res; if((res = s_mp_add_d(mp, val)) != MP_OKAY) return res; ++ix; } if(s_mp_cmp_d(mp, 0) == MP_EQ) SIGN(mp) = MP_ZPOS; else SIGN(mp) = sig; return MP_OKAY;} /* end mp_read_radix() *//* }}} *//* {{{ mp_radix_size(mp, radix) */int mp_radix_size(mp_int *mp, int radix){ ARGCHK(mp != NULL, 0); return mp_value_radix_size(USED(mp), DIGIT_BIT, radix);} /* end mp_radix_size() *//* }}} *//* {{{ mp_value_radix_size(num, qty, radix) */int mp_value_radix_size(int num, int qty, int radix){ ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); return s_mp_outlen(num * qty, radix);} /* end mp_value_radix_size() *//* }}} *//* {{{ mp_toradix(mp, str, radix) */mp_err mp_toradix(mp_int *mp, char *str, int radix){ int ix, pos = 0; ARGCHK(mp != NULL && str != NULL, MP_BADARG); ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); if(mp_cmp_z(mp) == MP_EQ) { str[0] = '0'; str[1] = '\0'; } else { mp_err res; mp_int tmp; mp_sign sgn; mp_digit rem, rdx = (mp_digit)radix; char ch; if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) return res; /* Save sign for later, and take absolute value */ sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; /* Generate output digits in reverse order */ while(mp_cmp_z(&tmp) != 0) { if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { mp_clear(&tmp); return res; } /* Generate digits, use capital letters */ ch = s_mp_todigit(rem, radix, 0); str[pos++] = ch; } /* Add - sign if original value was negative */ if(sgn == MP_NEG) str[pos++] = '-'; /* Add trailing NUL to end the string */ str[pos--] = '\0'; /* Reverse the digits and sign indicator */ ix = 0; while(ix < pos) { char tmp = str[ix]; str[ix] = str[pos]; str[pos] = tmp; ++ix; --pos; } mp_clear(&tmp); } return MP_OKAY;} /* end mp_toradix() *//* }}} *//* {{{ mp_tovalue(ch, r) */int mp_tovalue(char ch, int r){ return s_mp_tovalue(ch, r);} /* end mp_tovalue() *//* }}} *//* }}} *//* {{{ mp_strerror(ec) *//* mp_strerror(ec) Return a string describing the meaning of error code 'ec'. The string returned is allocated in static memory, so the caller should not attempt to modify or free the memory associated with this string. */const char *mp_strerror(mp_err ec){ int aec = (ec < 0) ? -ec : ec; /* Code values are negative, so the senses of these comparisons are accurate */ if(ec < MP_LAST_CODE || ec > MP_OKAY) { return mp_err_string[0]; /* unknown error code */ } else { return mp_err_string[aec + 1]; }} /* end mp_strerror() *//* }}} *//*========================================================================*//*------------------------------------------------------------------------*//* Static function definitions (internal use only) *//* {{{ Memory management *//* {{{ s_mp_grow(mp, min) *//* Make sure there are at least 'min' digits allocated to mp */mp_err s_mp_grow(mp_int *mp, mp_size min){ if(min > ALLOC(mp)) { mp_digit *tmp; /* Set min to next nearest default precision block size */ min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) return MP_MEM; s_mp_copy(DIGITS(mp), tmp, USED(mp));#if MP_CRYPTO s_mp_setz(DIGITS(mp), ALLOC(mp));#endif s_mp_free(DIGITS(mp)); DIGITS(mp) = tmp; ALLOC(mp) = min; } return MP_OKAY;} /* end s_mp_grow() *//* }}} *//* {{{ s_mp_pad(mp, min) *//* Make sure the used size of mp is at least 'min', growing if needed */mp_err s_mp_pad(mp_int *mp, mp_size min){ if(min > USED(mp)) { mp_err res; /* Make sure there is room to increase precision */ if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY) return res; /* Increase precision; should already be 0-filled */ USED(mp) = min; } return MP_OKAY;} /* end s_mp_pad() *//* }}} *//* {{{ s_mp_setz(dp, count) */#if MP_MACRO == 0/* Set 'count' digits pointed to by dp to be zeroes */void s_mp_setz(mp_digit *dp, mp_size count){#if MP_MEMSET == 0 int ix; for(ix = 0; ix < count; ix++) dp[ix] = 0;#else memset(dp, 0, count * sizeof(mp_digit));#endif} /* end s_mp_setz() */#endif/* }}} *//* {{{ s_mp_copy(sp, dp, count) */#if MP_MACRO == 0/* Copy 'count' digits from sp to dp */void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count){#if MP_MEMCPY == 0 int ix; for(ix = 0; ix < count; ix++) dp[ix] = sp[ix];#else memcpy(dp, sp, count * sizeof(mp_digit));#endif} /* end s_mp_copy() */#endif/* }}} */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -