int fp_radix_size(fp_int *a, int radix, int *size) { int digs; fp_int t; fp_digit d; *size = 0; /* check range of the radix */ if (radix < 2 || radix > 64) { return FP_VAL; } /* quick out if its zero */ if (fp_iszero(a) == 1) { *size = 2; return FP_OKAY; } fp_init_copy(&t, a); /* if it is negative output a - */ if (t.sign == FP_NEG) { (*size)++; t.sign = FP_ZPOS; } digs = 0; while (fp_iszero (&t) == FP_NO) { fp_div_d (&t, (fp_digit) radix, &t, &d); (*size)++; } /* append a NULL so the string is properly terminated */ (*size)++; return FP_OKAY; }
void fp_to_unsigned_bin(fp_int *a, unsigned char *b) { int x; fp_int t; fp_init_copy(&t, a); x = 0; while (fp_iszero (&t) == FP_NO) { b[x++] = (unsigned char) (t.dp[0] & 255); fp_div_2d (&t, 8, &t, NULL); } fp_reverse (b, x); }
/* c = (a, b) */ void fp_gcd(fp_int *a, fp_int *b, fp_int *c) { fp_int u, v, r; /* either zero than gcd is the largest */ if (fp_iszero (a) == 1 && fp_iszero (b) == 0) { fp_abs (b, c); return; } if (fp_iszero (a) == 0 && fp_iszero (b) == 1) { fp_abs (a, c); return; } /* optimized. At this point if a == 0 then * b must equal zero too */ if (fp_iszero (a) == 1) { fp_zero(c); return; } /* sort inputs */ if (fp_cmp_mag(a, b) != FP_LT) { fp_init_copy(&u, a); fp_init_copy(&v, b); } else { fp_init_copy(&u, b); fp_init_copy(&v, a); } fp_zero(&r); while (fp_iszero(&v) == FP_NO) { fp_mod(&u, &v, &r); fp_copy(&v, &u); fp_copy(&r, &v); } fp_copy(&u, c); }
/* a/b => cb + d == a */ int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d) { fp_int q; fp_word w; fp_digit t; int ix; /* cannot divide by zero */ if (b == 0) { return FP_VAL; } /* quick outs */ if (b == 1 || fp_iszero(a) == 1) { if (d != NULL) { *d = 0; } if (c != NULL) { fp_copy(a, c); } return FP_OKAY; } /* power of two ? */ if (s_is_power_of_two(b, &ix) == 1) { if (d != NULL) { *d = a->dp[0] & ((((fp_digit)1)<<ix) - 1); } if (c != NULL) { fp_div_2d(a, ix, c, NULL); } return FP_OKAY; } /* no easy answer [c'est la vie]. Just division */ fp_init(&q); q.used = a->used; q.sign = a->sign; w = 0; for (ix = a->used - 1; ix >= 0; ix--) { w = (w << ((fp_word)DIGIT_BIT)) | ((fp_word)a->dp[ix]); if (w >= b) { t = (fp_digit)(w / b); w -= ((fp_word)t) * ((fp_word)b); } else { t = 0; } q.dp[ix] = (fp_digit)t; } if (d != NULL) { *d = (fp_digit)w; } if (c != NULL) { fp_clamp(&q); fp_copy(&q, c); } return FP_OKAY; }
int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) { char *s = buf; if (buf_size <= FPMIN_BUF_SIZE) { // FPMIN_BUF_SIZE is the minimum size needed to store any FP number. // If the buffer does not have enough room for this (plus null terminator) // then don't try to format the float. if (buf_size >= 2) { *s++ = '?'; } if (buf_size >= 1) { *s++ = '\0'; } return buf_size >= 2; } if (fp_signbit(f)) { *s++ = '-'; f = -f; } else { if (sign) { *s++ = sign; } } // buf_remaining contains bytes available for digits and exponent. // It is buf_size minus room for the sign and null byte. int buf_remaining = buf_size - 1 - (s - buf); if (fp_isspecial(f)) { char uc = fmt & 0x20; if (fp_isinf(f)) { *s++ = 'I' ^ uc; *s++ = 'N' ^ uc; *s++ = 'F' ^ uc; goto ret; } else if (fp_isnan(f)) { *s++ = 'N' ^ uc; *s++ = 'A' ^ uc; *s++ = 'N' ^ uc; ret: *s = '\0'; return s - buf; } } if (prec < 0) { prec = 6; } char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt fmt |= 0x20; // Force fmt to be lowercase char org_fmt = fmt; if (fmt == 'g' && prec == 0) { prec = 1; } int e, e1; int dec = 0; char e_sign = '\0'; int num_digits = 0; const FPTYPE *pos_pow = g_pos_pow; const FPTYPE *neg_pow = g_neg_pow; if (fp_iszero(f)) { e = 0; if (fmt == 'f') { // Truncate precision to prevent buffer overflow if (prec + 2 > buf_remaining) { prec = buf_remaining - 2; } num_digits = prec + 1; } else { // Truncate precision to prevent buffer overflow if (prec + 6 > buf_remaining) { prec = buf_remaining - 6; } if (fmt == 'e') { e_sign = '+'; } } } else if (fp_isless1(f)) { // We need to figure out what an integer digit will be used // in case 'f' is used (or we revert other format to it below). // As we just tested number to be <1, this is obviously 0, // but we can round it up to 1 below. char first_dig = '0'; if (f >= FPROUND_TO_ONE) { first_dig = '1'; } // Build negative exponent for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { if (*neg_pow > f) { e += e1; f *= *pos_pow; } } char e_sign_char = '-'; if (fp_isless1(f) && f >= FPROUND_TO_ONE) { f = FPCONST(1.0); if (e == 0) { e_sign_char = '+'; } } else if (fp_isless1(f)) { e++; f *= FPCONST(10.0); } // If the user specified 'g' format, and e is <= 4, then we'll switch // to the fixed format ('f') if (fmt == 'f' || (fmt == 'g' && e <= 4)) { fmt = 'f'; dec = -1; *s++ = first_dig; if (org_fmt == 'g') { prec += (e - 1); } // truncate precision to prevent buffer overflow if (prec + 2 > buf_remaining) { prec = buf_remaining - 2; } num_digits = prec; if (num_digits) { *s++ = '.'; while (--e && num_digits) { *s++ = '0'; num_digits--; } } } else { // For e & g formats, we'll be printing the exponent, so set the // sign. e_sign = e_sign_char; dec = 0; if (prec > (buf_remaining - FPMIN_BUF_SIZE)) { prec = buf_remaining - FPMIN_BUF_SIZE; if (fmt == 'g') { prec++; } } } } else { // Build positive exponent for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {
/* a/b => cb + d == a */ int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d) { fp_int q, x, y, t1, t2; int n, t, i, norm, neg; /* is divisor zero ? */ if (fp_iszero (b) == 1) { return FP_VAL; } /* if a < b then q=0, r = a */ if (fp_cmp_mag (a, b) == FP_LT) { if (d != NULL) { fp_copy (a, d); } if (c != NULL) { fp_zero (c); } return FP_OKAY; } fp_init(&q); q.used = a->used + 2; fp_init(&t1); fp_init(&t2); fp_init_copy(&x, a); fp_init_copy(&y, b); /* fix the sign */ neg = (a->sign == b->sign) ? FP_ZPOS : FP_NEG; x.sign = y.sign = FP_ZPOS; /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ norm = fp_count_bits(&y) % DIGIT_BIT; if (norm < (int)(DIGIT_BIT-1)) { norm = (DIGIT_BIT-1) - norm; fp_mul_2d (&x, norm, &x); fp_mul_2d (&y, norm, &y); } else { norm = 0; } /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ n = x.used - 1; t = y.used - 1; /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ fp_lshd (&y, n - t); /* y = y*b**{n-t} */ while (fp_cmp (&x, &y) != FP_LT) { ++(q.dp[n - t]); fp_sub (&x, &y, &x); } /* reset y by shifting it back down */ fp_rshd (&y, n - t); /* step 3. for i from n down to (t + 1) */ for (i = n; i >= (t + 1); i--) { if (i > x.used) { continue; } /* step 3.1 if xi == yt then set q{i-t-1} to b-1, * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ if (x.dp[i] == y.dp[t]) { q.dp[i - t - 1] = ((((fp_word)1) << DIGIT_BIT) - 1); } else { fp_word tmp; tmp = ((fp_word) x.dp[i]) << ((fp_word) DIGIT_BIT); tmp |= ((fp_word) x.dp[i - 1]); tmp /= ((fp_word) y.dp[t]); q.dp[i - t - 1] = (fp_digit) (tmp); } /* while (q{i-t-1} * (yt * b + y{t-1})) > xi * b**2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1); do { q.dp[i - t - 1] = (q.dp[i - t - 1] - 1); /* find left hand */ fp_zero (&t1); t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; t1.dp[1] = y.dp[t]; t1.used = 2; fp_mul_d (&t1, q.dp[i - t - 1], &t1); /* find right hand */ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; t2.dp[2] = x.dp[i]; t2.used = 3; } while (fp_cmp_mag(&t1, &t2) == FP_GT); /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ fp_mul_d (&y, q.dp[i - t - 1], &t1); fp_lshd (&t1, i - t - 1); fp_sub (&x, &t1, &x); /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ if (x.sign == FP_NEG) { fp_copy (&y, &t1); fp_lshd (&t1, i - t - 1); fp_add (&x, &t1, &x); q.dp[i - t - 1] = q.dp[i - t - 1] - 1; } } /* now q is the quotient and x is the remainder * [which we have to normalize] */ /* get sign before writing to c */ x.sign = x.used == 0 ? FP_ZPOS : a->sign; if (c != NULL) { fp_clamp (&q); fp_copy (&q, c); c->sign = neg; } if (d != NULL) { fp_div_2d (&x, norm, &x, NULL); /* the following is a kludge, essentially we were seeing the right remainder but with excess digits that should have been zero */ for (i = b->used; i < x.used; i++) { x.dp[i] = 0; } fp_clamp(&x); fp_copy (&x, d); } return FP_OKAY; }
/* c = 1/a (mod b) for odd b only */ int fp_invmod(fp_int *a, fp_int *b, fp_int *c) { fp_int x, y, u, v, B, D; int neg; /* 2. [modified] b must be odd */ if (fp_iseven (b) == FP_YES) { return fp_invmod_slow(a,b,c); } /* init all our temps */ fp_init(&x); fp_init(&y); fp_init(&u); fp_init(&v); fp_init(&B); fp_init(&D); /* x == modulus, y == value to invert */ fp_copy(b, &x); /* we need y = |a| */ fp_abs(a, &y); /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ fp_copy(&x, &u); fp_copy(&y, &v); fp_set (&D, 1); top: /* 4. while u is even do */ while (fp_iseven (&u) == FP_YES) { /* 4.1 u = u/2 */ fp_div_2 (&u, &u); /* 4.2 if B is odd then */ if (fp_isodd (&B) == FP_YES) { fp_sub (&B, &x, &B); } /* B = B/2 */ fp_div_2 (&B, &B); } /* 5. while v is even do */ while (fp_iseven (&v) == FP_YES) { /* 5.1 v = v/2 */ fp_div_2 (&v, &v); /* 5.2 if D is odd then */ if (fp_isodd (&D) == FP_YES) { /* D = (D-x)/2 */ fp_sub (&D, &x, &D); } /* D = D/2 */ fp_div_2 (&D, &D); } /* 6. if u >= v then */ if (fp_cmp (&u, &v) != FP_LT) { /* u = u - v, B = B - D */ fp_sub (&u, &v, &u); fp_sub (&B, &D, &B); } else { /* v - v - u, D = D - B */ fp_sub (&v, &u, &v); fp_sub (&D, &B, &D); } /* if not zero goto step 4 */ if (fp_iszero (&u) == FP_NO) { goto top; } /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (fp_cmp_d (&v, 1) != FP_EQ) { return FP_VAL; } /* b is now the inverse */ neg = a->sign; while (D.sign == FP_NEG) { fp_add (&D, b, &D); } fp_copy (&D, c); c->sign = neg; return FP_OKAY; }
static int fp_invmod_slow (fp_int * a, fp_int * b, fp_int * c) { fp_int x, y, u, v, A, B, C, D; int res; /* b cannot be negative */ if (b->sign == FP_NEG || fp_iszero(b) == 1) { return FP_VAL; } /* init temps */ fp_init(&x); fp_init(&y); fp_init(&u); fp_init(&v); fp_init(&A); fp_init(&B); fp_init(&C); fp_init(&D); /* x = a, y = b */ if ((res = fp_mod(a, b, &x)) != FP_OKAY) { return res; } fp_copy(b, &y); /* 2. [modified] if x,y are both even then return an error! */ if (fp_iseven (&x) == 1 && fp_iseven (&y) == 1) { return FP_VAL; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ fp_copy (&x, &u); fp_copy (&y, &v); fp_set (&A, 1); fp_set (&D, 1); top: /* 4. while u is even do */ while (fp_iseven (&u) == 1) { /* 4.1 u = u/2 */ fp_div_2 (&u, &u); /* 4.2 if A or B is odd then */ if (fp_isodd (&A) == 1 || fp_isodd (&B) == 1) { /* A = (A+y)/2, B = (B-x)/2 */ fp_add (&A, &y, &A); fp_sub (&B, &x, &B); } /* A = A/2, B = B/2 */ fp_div_2 (&A, &A); fp_div_2 (&B, &B); } /* 5. while v is even do */ while (fp_iseven (&v) == 1) { /* 5.1 v = v/2 */ fp_div_2 (&v, &v); /* 5.2 if C or D is odd then */ if (fp_isodd (&C) == 1 || fp_isodd (&D) == 1) { /* C = (C+y)/2, D = (D-x)/2 */ fp_add (&C, &y, &C); fp_sub (&D, &x, &D); } /* C = C/2, D = D/2 */ fp_div_2 (&C, &C); fp_div_2 (&D, &D); } /* 6. if u >= v then */ if (fp_cmp (&u, &v) != FP_LT) { /* u = u - v, A = A - C, B = B - D */ fp_sub (&u, &v, &u); fp_sub (&A, &C, &A); fp_sub (&B, &D, &B); } else { /* v - v - u, C = C - A, D = D - B */ fp_sub (&v, &u, &v); fp_sub (&C, &A, &C); fp_sub (&D, &B, &D); } /* if not zero goto step 4 */ if (fp_iszero (&u) == 0) goto top; /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (fp_cmp_d (&v, 1) != FP_EQ) { return FP_VAL; } /* if its too low */ while (fp_cmp_d(&C, 0) == FP_LT) { fp_add(&C, b, &C); } /* too big */ while (fp_cmp_mag(&C, b) != FP_LT) { fp_sub(&C, b, &C); } /* C is now the inverse */ fp_copy(&C, c); return FP_OKAY; }