/* bi_residue() is technically the same as bi_mod(), but it uses the * appropriate reduction technique (which is bi_mod() when doing classical * reduction). */ // #define bi_residue(A, B) bi_mod(A, B) internal bigint bi_square(bigint B) { return(this.bi_multiply(B.bi_copy(), B)); }
/* @brief Does both division and modulo calculations. * Used extensively when doing classical reduction. * @param ctx [in] The bigint session context. * @param u [in] A bigint which is the numerator. * @param v [in] Either the denominator or the modulus depending on the mode. * @param is_mod [n] Determines if this is a normal division (0) or a reduction * (1). * @return The result of the division/reduction. */ internal bigint bi_divide(bigint u, bigint v, bool is_mod) { int n = v.size; int m = u.size - n; int j = 0; int orig_u_size = u.size; byte mod_offset = this.mod_offset; uint d; uint q_dash; /* if doing reduction and we are < mod, then return mod */ if (is_mod && bi_compare(v, u) > 0) { bi_free(v); return(u); } bigint quotient = this.Allocate((short)(m + 1)); bigint tmp_u = this.Allocate((short)(n + 1)); v = v.trim(); /* make sure we have no leading 0's */ d = (uint)((ulong)COMP_RADIX / ((ulong)v.V1 + 1)); /* clear things to start with */ quotient.comps.Zeroize(); /* normalise */ if (d > 1) { u = bi_int_multiply(u, d); if (is_mod) { v = bi_normalised_mod[mod_offset]; } else { v = bi_int_multiply(v, d); } } if (orig_u_size == u.size) /* new digit position u0 */ { u.more_comps((short)(orig_u_size + 1)); } do { /* get a temporary short version of u */ Buffer.BlockCopy(u.comps, u.size - n - 1 - j, tmp_u.comps, 0, sizeof(uint) * (n + 1)); /* calculate q' */ if (tmp_u.U(0) == v.V1) { q_dash = (uint)(COMP_RADIX - 1); } else { q_dash = (uint)(((ulong)tmp_u.U(0) * COMP_RADIX + tmp_u.U(1)) / v.V1); if ((v.size > 1) && (0 != v.V2)) { /* we are implementing the following: * if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - * q_dash*V1)*COMP_RADIX) + U(2))) ... */ uint inner = (uint)((ulong)COMP_RADIX * tmp_u.U(0) + tmp_u.U(1) - (ulong)q_dash * v.V1); if ((ulong)v.V2 * q_dash > (ulong)inner * COMP_RADIX + tmp_u.U(2)) { q_dash--; } } } /* multiply and subtract */ if (0 != q_dash) { bool is_negative; tmp_u = bi_subtract(tmp_u, bi_int_multiply(v.bi_copy(), q_dash), out is_negative); tmp_u.more_comps((short)(n + 1)); quotient.SetQ(j, q_dash); /* add back */ if (is_negative) { quotient.SetQ(j, quotient.GetQ(j) - 1); tmp_u = bi_add(tmp_u, v.bi_copy()); /* lop off the carry */ tmp_u.size--; v.size--; } } else { quotient.SetQ(j, 0); } /* copy back to u */ Buffer.BlockCopy(tmp_u.comps, 0, u.comps, u.size - n - 1 - j, sizeof(uint) * (n + 1)); } while (++j <= m); bi_free(tmp_u); bi_free(v); if (is_mod) /* get the remainder */ { bi_free(quotient); return(bi_int_divide(u.trim(), d)); } else /* get the quotient */ { bi_free(u); return(quotient.trim()); } }