📄 mpi.c
字号:
/* {{{ s_mp_alloc(nb, ni) */#if MP_MACRO == 0/* Allocate ni records of nb bytes each, and return a pointer to that */void *s_mp_alloc(size_t nb, size_t ni){ return calloc(nb, ni);} /* end s_mp_alloc() */#endif/* }}} *//* {{{ s_mp_free(ptr) */#if MP_MACRO == 0/* Free the memory pointed to by ptr */void s_mp_free(void *ptr){ if(ptr) free(ptr);} /* end s_mp_free() */#endif/* }}} *//* {{{ s_mp_clamp(mp) *//* Remove leading zeroes from the given value */void s_mp_clamp(mp_int *mp){ mp_size du = USED(mp); mp_digit *zp = DIGITS(mp) + du - 1; while(du > 1 && !*zp--) --du; USED(mp) = du;} /* end s_mp_clamp() *//* }}} *//* {{{ s_mp_exch(a, b) *//* Exchange the data for a and b; (b, a) = (a, b) */void s_mp_exch(mp_int *a, mp_int *b){ mp_int tmp; tmp = *a; *a = *b; *b = tmp;} /* end s_mp_exch() *//* }}} *//* }}} *//* {{{ Arithmetic helpers *//* {{{ s_mp_lshd(mp, p) *//* Shift mp leftward by p digits, growing if needed, and zero-filling the in-shifted digits at the right end. This is a convenient alternative to multiplication by powers of the radix */ mp_err s_mp_lshd(mp_int *mp, mp_size p){ mp_err res; mp_size pos; mp_digit *dp; int ix; if(p == 0) return MP_OKAY; if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) return res; pos = USED(mp) - 1; dp = DIGITS(mp); /* Shift all the significant figures over as needed */ for(ix = pos - p; ix >= 0; ix--) dp[ix + p] = dp[ix]; /* Fill the bottom digits with zeroes */ for(ix = 0; ix < p; ix++) dp[ix] = 0; return MP_OKAY;} /* end s_mp_lshd() *//* }}} *//* {{{ s_mp_rshd(mp, p) *//* Shift mp rightward by p digits. Maintains the invariant that digits above the precision are all zero. Digits shifted off the end are lost. Cannot fail. */void s_mp_rshd(mp_int *mp, mp_size p){ mp_size ix; mp_digit *dp; if(p == 0) return; /* Shortcut when all digits are to be shifted off */ if(p >= USED(mp)) { s_mp_setz(DIGITS(mp), ALLOC(mp)); USED(mp) = 1; SIGN(mp) = MP_ZPOS; return; } /* Shift all the significant figures over as needed */ dp = DIGITS(mp); for(ix = p; ix < USED(mp); ix++) dp[ix - p] = dp[ix]; /* Fill the top digits with zeroes */ ix -= p; while(ix < USED(mp)) dp[ix++] = 0; /* Strip off any leading zeroes */ s_mp_clamp(mp);} /* end s_mp_rshd() *//* }}} *//* {{{ s_mp_div_2(mp) *//* Divide by two -- take advantage of radix properties to do it fast */void s_mp_div_2(mp_int *mp){ s_mp_div_2d(mp, 1);} /* end s_mp_div_2() *//* }}} *//* {{{ s_mp_mul_2(mp) */mp_err s_mp_mul_2(mp_int *mp){ mp_size ix; mp_digit kin = 0, kout, *dp = DIGITS(mp); mp_err res; /* Shift digits leftward by 1 bit */ for(ix = 0; ix < USED(mp); ix++) { kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; dp[ix] = (dp[ix] << 1) | kin; kin = kout; } /* Deal with rollover from last digit */ if(kin) { if(ix >= ALLOC(mp)) { if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) return res; dp = DIGITS(mp); } dp[ix] = kin; USED(mp) += 1; } return MP_OKAY;} /* end s_mp_mul_2() *//* }}} *//* {{{ s_mp_mod_2d(mp, d) *//* Remainder the integer by 2^d, where d is a number of bits. This amounts to a bitwise AND of the value, and does not require the full division code */void s_mp_mod_2d(mp_int *mp, mp_digit d){ unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); unsigned int ix; mp_digit dmask, *dp = DIGITS(mp); if(ndig >= USED(mp)) return; /* Flush all the bits above 2^d in its digit */ dmask = (1 << nbit) - 1; dp[ndig] &= dmask; /* Flush all digits above the one with 2^d in it */ for(ix = ndig + 1; ix < USED(mp); ix++) dp[ix] = 0; s_mp_clamp(mp);} /* end s_mp_mod_2d() *//* }}} *//* {{{ s_mp_mul_2d(mp, d) *//* Multiply by the integer 2^d, where d is a number of bits. This amounts to a bitwise shift of the value, and does not require the full multiplication code. */mp_err s_mp_mul_2d(mp_int *mp, mp_digit d){ mp_err res; mp_digit save, next, mask, *dp; mp_size used; mp_size ix; if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) return res; dp = DIGITS(mp); used = USED(mp); d %= DIGIT_BIT; mask = (1 << d) - 1; /* If the shift requires another digit, make sure we've got one to work with */ if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { if((res = s_mp_grow(mp, used + 1)) != MP_OKAY) return res; dp = DIGITS(mp); } /* Do the shifting... */ save = 0; for(ix = 0; ix < used; ix++) { next = (dp[ix] >> (DIGIT_BIT - d)) & mask; dp[ix] = (dp[ix] << d) | save; save = next; } /* If, at this point, we have a nonzero carryout into the next digit, we'll increase the size by one digit, and store it... */ if(save) { dp[used] = save; USED(mp) += 1; } s_mp_clamp(mp); return MP_OKAY;} /* end s_mp_mul_2d() *//* }}} *//* {{{ s_mp_div_2d(mp, d) *//* Divide the integer by 2^d, where d is a number of bits. This amounts to a bitwise shift of the value, and does not require the full division code (used in Barrett reduction, see below) */void s_mp_div_2d(mp_int *mp, mp_digit d){ int ix; mp_digit save, next, mask, *dp = DIGITS(mp); s_mp_rshd(mp, d / DIGIT_BIT); d %= DIGIT_BIT; mask = (1 << d) - 1; save = 0; for(ix = USED(mp) - 1; ix >= 0; ix--) { next = dp[ix] & mask; dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); save = next; } s_mp_clamp(mp);} /* end s_mp_div_2d() *//* }}} *//* {{{ s_mp_norm(a, b) *//* s_mp_norm(a, b) Normalize a and b for division, where b is the divisor. In order that we might make good guesses for quotient digits, we want the leading digit of b to be at least half the radix, which we accomplish by multiplying a and b by a constant. This constant is returned (so that it can be divided back out of the remainder at the end of the division process). We multiply by the smallest power of 2 that gives us a leading digit at least half the radix. By choosing a power of 2, we simplify the multiplication and division steps to simple shifts. */mp_digit s_mp_norm(mp_int *a, mp_int *b){ mp_digit t, d = 0; t = DIGIT(b, USED(b) - 1); while(t < (RADIX / 2)) { t <<= 1; ++d; } if(d != 0) { s_mp_mul_2d(a, d); s_mp_mul_2d(b, d); } return d;} /* end s_mp_norm() *//* }}} *//* }}} *//* {{{ Primitive digit arithmetic *//* {{{ s_mp_add_d(mp, d) *//* Add d to |mp| in place */mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */{ mp_word w, k = 0; mp_size ix = 1, used = USED(mp); mp_digit *dp = DIGITS(mp); w = dp[0] + d; dp[0] = ACCUM(w); k = CARRYOUT(w); while(ix < used && k) { w = dp[ix] + k; dp[ix] = ACCUM(w); k = CARRYOUT(w); ++ix; } if(k != 0) { mp_err res; if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) return res; DIGIT(mp, ix) = k; } return MP_OKAY;} /* end s_mp_add_d() *//* }}} *//* {{{ s_mp_sub_d(mp, d) *//* Subtract d from |mp| in place, assumes |mp| > d */mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */{ mp_word w, b = 0; mp_size ix = 1, used = USED(mp); mp_digit *dp = DIGITS(mp); /* Compute initial subtraction */ w = (RADIX + dp[0]) - d; b = CARRYOUT(w) ? 0 : 1; dp[0] = ACCUM(w); /* Propagate borrows leftward */ while(b && ix < used) { w = (RADIX + dp[ix]) - b; b = CARRYOUT(w) ? 0 : 1; dp[ix] = ACCUM(w); ++ix; } /* Remove leading zeroes */ s_mp_clamp(mp); /* If we have a borrow out, it's a violation of the input invariant */ if(b) return MP_RANGE; else return MP_OKAY;} /* end s_mp_sub_d() *//* }}} *//* {{{ s_mp_mul_d(a, d) *//* Compute a = a * d, single digit multiplication */mp_err s_mp_mul_d(mp_int *a, mp_digit d){ mp_word w, k = 0; mp_size ix, max; mp_err res; mp_digit *dp = DIGITS(a); /* Single-digit multiplication will increase the precision of the output by at most one digit. However, we can detect when this will happen -- if the high-order digit of a, times d, gives a two-digit result, then the precision of the result will increase; otherwise it won't. We use this fact to avoid calling s_mp_pad() unless absolutely necessary. */ max = USED(a); w = dp[max - 1] * d; if(CARRYOUT(w) != 0) { if((res = s_mp_pad(a, max + 1)) != MP_OKAY) return res; dp = DIGITS(a); } for(ix = 0; ix < max; ix++) { w = (dp[ix] * d) + k; dp[ix] = ACCUM(w); k = CARRYOUT(w); } /* If there is a precision increase, take care of it here; the above test guarantees we have enough storage to do this safely. */ if(k) { dp[max] = k; USED(a) = max + 1; } s_mp_clamp(a); return MP_OKAY; } /* end s_mp_mul_d() *//* }}} *//* {{{ s_mp_div_d(mp, d, r) *//* s_mp_div_d(mp, d, r) Compute the quotient mp = mp / d and remainder r = mp mod d, for a single digit d. If r is null, the remainder will be discarded. */mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r){ mp_word w = 0, t; mp_int quot; mp_err res; mp_digit *dp = DIGITS(mp), *qp; int ix; if(d == 0) return MP_RANGE; /* Make room for the quotient */ if((res = mp_init_size(", USED(mp))) != MP_OKAY) return res; USED(") = USED(mp); /* so clamping will work below */ qp = DIGITS("); /* Divide without subtraction */ for(ix = USED(mp) - 1; ix >= 0; ix--) { w = (w << DIGIT_BIT) | dp[ix]; if(w >= d) { t = w / d; w = w % d; } else { t = 0; } qp[ix] = t; } /* Deliver the remainder, if desired */ if(r) *r = w; s_mp_clamp("); mp_exch(", mp); mp_clear("); return MP_OKAY;} /* end s_mp_div_d() *//* }}} *//* }}} *//* {{{ Primitive full arithmetic *//* {{{ s_mp_add(a, b) *//* Compute a = |a| + |b| */mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */{ mp_word w = 0; mp_digit *pa, *pb; mp_size ix, used = USED(b); mp_err res; /* Make sure a has enough precision for the output value */ if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY) return res; /* Add up all digits up to the precision of b. If b had initially the same precision as a, or greater, we took care of it by the padding step above, so there is no problem. If b had initially less precision, we'll have to make sure the carry out is duly propagated upward among the higher-order digits of the sum. */ pa = DIGITS(a); pb = DIGITS(b); for(ix = 0; ix < used; ++ix) { w += *pa + *pb++; *pa++ = ACCUM(w); w = CARRYOUT(w); } /* If we run out of 'b' digits before we're actually done, make sure the carries get propagated upward... */ used = USED(a); while(w && ix < used) { w += *pa; *pa++ = ACCUM(w); w = CARRYOUT(w); ++ix; } /* If there's an overall carry out, increase precision and include it. We could have done this initially, but why touch the memory allocator unless we're sure we have to? */ if(w) { if((res = s_mp_pad(a, used + 1)) != MP_OKAY) return res; DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */ } return MP_OKAY;} /* end s_mp_add() *//* }}} *//* {{{ s_mp_sub(a, b) *//* Compute a = |a| - |b|, assumes |a| >= |b| */mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */{ mp_word w = 0; mp_digit *pa, *pb; mp_size ix, used = USED(b); /* Subtract and propagate borrow. Up to the precision of b, this accounts for the digits of b; after that, we just make sure the carries get to the right place. This saves having to pad b out to the precision of a just to make the loops work right... */ pa = DIGITS(a); pb = DIGITS(b); for(ix = 0; ix < used; ++ix) { w = (RADIX + *pa) - w - *pb++; *pa++ = ACCUM(w); w = CARRYOUT(w) ? 0 : 1; } used = USED(a); while(ix < used) { w = RADIX + *pa - w; *pa++ = ACCUM(w); w = CARRYOUT(w) ? 0 : 1; ++ix; } /* Clobber any leading zeroes we created */ s_mp_clamp(a); /* If there was a borrow out, then |b| > |a| in violation of our input invariant. We've already done the work, but we'll at least complain about it... */ if(w) return MP_RANGE; else return MP_OKAY;} /* end s_mp_sub() *//* }}} *//* {{{ s_mp_mul(a, b) *//* Compute a = |a| * |b| */mp_err s_mp_mul(mp_int *a, mp_int *b){ mp_word w, k = 0; mp_int tmp; mp_err res; mp_size ix, jx, ua = USED(a), ub = USED(b); mp_digit *pa, *pb, *pt, *pbt; if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY) return res; /* This has the effect of left-padding with zeroes... */ USED(&tmp) = ua + ub; /* We're going to need the base value each iteration */ pbt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -