/** * Multiply x[0:xlen-1] and y[0:ylen-1], and * write the result to dest[0:xlen+ylen-1]. * The destination has to have space for xlen+ylen words, * even if the result might be one limb smaller. * This function requires that xlen >= ylen. * The destination must be distinct from either input operands. * All operands are unsigned. * This function is basically the same gmp's mpn_mul. */ public static void mul(int[] dest, int[] x, int xlen, int[] y, int ylen) { dest[xlen] = MPN.mul_1(dest, x, xlen, y[0]); for (int i = 1; i < ylen; i++) { long yword = (long)y[i] & 0xffffffffL; long carry = 0; for (int j = 0; j < xlen; j++) { carry += ((long)x[j] & 0xffffffffL) * yword + ((long)dest[i + j] & 0xffffffffL); dest[i + j] = (int)carry; carry = (long)(((ulong)carry) >> 32); } dest[i + xlen] = (int)carry; } }
/** Calculate Greatest Common Divisior of x[0:len-1] and y[0:len-1]. * Assumes both arguments are non-zero. * Leaves result in x, and returns len of result. * Also destroys y (actually sets it to a copy of the result). */ public static int gcd(int[] x, int[] y, int len) { int i, word; // Find sh such that both x and y are divisible by 2**sh. for (i = 0; ; i++) { word = x[i] | y[i]; if (word != 0) { // Must terminate, since x and y are non-zero. break; } } int initShiftWords = i; int initShiftBits = findLowestBit(word); // Logically: sh = initShiftWords * 32 + initShiftBits // Temporarily devide both x and y by 2**sh. len -= initShiftWords; MPN.rshift0(x, x, initShiftWords, len, initShiftBits); MPN.rshift0(y, y, initShiftWords, len, initShiftBits); int[] odd_arg; /* One of x or y which is odd. */ int[] other_arg; /* The other one can be even or odd. */ if ((x[0] & 1) != 0) { odd_arg = x; other_arg = y; } else { odd_arg = y; other_arg = x; } for (;;) { // Shift other_arg until it is odd; this doesn't // affect the gcd, since we divide by 2**k, which does not // divide odd_arg. for (i = 0; other_arg[i] == 0;) { i++; } if (i > 0) { int j; for (j = 0; j < len - i; j++) { other_arg[j] = other_arg[j + i]; } for ( ; j < len; j++) { other_arg[j] = 0; } } i = findLowestBit(other_arg[0]); if (i > 0) { MPN.rshift(other_arg, other_arg, 0, len, i); } // Now both odd_arg and other_arg are odd. // Subtract the smaller from the larger. // This does not change the result, since gcd(a-b,b)==gcd(a,b). i = MPN.cmp(odd_arg, other_arg, len); if (i == 0) { break; } if (i > 0) { // odd_arg > other_arg MPN.sub_n(odd_arg, odd_arg, other_arg, len); // Now odd_arg is even, so swap with other_arg; int[] tmp = odd_arg; odd_arg = other_arg; other_arg = tmp; } else { // other_arg > odd_arg MPN.sub_n(other_arg, other_arg, odd_arg, len); } while (odd_arg[len - 1] == 0 && other_arg[len - 1] == 0) { len--; } } if (initShiftWords + initShiftBits > 0) { if (initShiftBits > 0) { int sh_out = MPN.lshift(x, initShiftWords, x, len, initShiftBits); if (sh_out != 0) { x[(len++) + initShiftWords] = sh_out; } } else { for (i = len; --i >= 0;) { x[i + initShiftWords] = x[i]; } } for (i = initShiftWords; --i >= 0;) { x[i] = 0; } len += initShiftWords; } return(len); }
public static int set_str(int[] dest, byte[] str, int str_len, int _base) { int size = 0; if ((_base & (_base - 1)) == 0) { // The base is a power of 2. Read the input string from // least to most significant character/digit. */ int next_bitpos = 0; int bits_per_indigit = 0; for (int i = _base; (i >>= 1) != 0;) { bits_per_indigit++; } int res_digit = 0; for (int i = str_len; --i >= 0;) { int inp_digit = str[i]; res_digit |= inp_digit << next_bitpos; next_bitpos += bits_per_indigit; if (next_bitpos >= 32) { dest[size++] = res_digit; next_bitpos -= 32; res_digit = inp_digit >> (bits_per_indigit - next_bitpos); } } if (res_digit != 0) { dest[size++] = res_digit; } } else { // General case. The base is not a power of 2. int indigits_per_limb = MPN.chars_per_word(_base); int str_pos = 0; while (str_pos < str_len) { int chunk = str_len - str_pos; if (chunk > indigits_per_limb) { chunk = indigits_per_limb; } int res_digit = str[str_pos++]; int big_base = _base; while (--chunk > 0) { res_digit = res_digit * _base + str[str_pos++]; big_base *= _base; } int cy_limb; if (size == 0) { cy_limb = res_digit; } else { cy_limb = MPN.mul_1(dest, dest, size, big_base); cy_limb += MPN.add_1(dest, dest, size, res_digit); } if (cy_limb != 0) { dest[size++] = cy_limb; } } } return(size); }