/*-----------------------------------------------------------------------*/ uint squfof_one_cycle(squfof_data_t data, uint mult_idx, uint num_iter, out uint factor) { /* Perform one unit of work for SQUFOF with one multiplier */ uint sqrtn = data.sqrtn[mult_idx]; uint cutoff = data.cutoff[mult_idx]; uint num_saved = data.num_saved[mult_idx]; uint multiplier = 2 * multipliers[mult_idx]; uint coarse_cutoff = cutoff * multiplier; ushort[] saved = data.saved[mult_idx]; uint q0 = data.q0[mult_idx]; uint p1 = data.p1[mult_idx]; uint q1 = data.q1[mult_idx]; uint i, j; uint p0 = 0; uint sqrtq = 0; ulong scaledn; factor = 0; for (i = 0; i < num_iter; i++) { uint q, bits, tmp; /* compute (sqrtn+p1)/q1; since this is unity * more than half the time, special case the * division to save some effort */ tmp = sqrtn + p1 - q1; q = 1; if (tmp >= q1) { q += tmp / q1; } /* compute the next numerator and denominator */ p0 = q * q1 - p1; q0 = q0 + (p1 - p0) * q; /* In order to avoid trivial factorizations, * save q1 values that are small in a list. Only * values that do not contain factors of the * multiplier must be saved; however, the GCD * is 5x more expensive than all the rest of the * work performed in the loop. To avoid most GCDs, * only attempt one if q1 is less than the cutoff * times the full multiplier * * If the queue overflows (very rare), signal that * this multiplier failed and move on to another one */ if (q1 < coarse_cutoff) { tmp = q1 / IntegerMath.GreatestCommonDivisor(q1, multiplier); if (tmp < cutoff) { if (num_saved >= QSIZE) { data.failed[mult_idx] = true; return(i); } saved[num_saved++] = (ushort)tmp; } } /* if q0 is a perfect square, then the factorization * has probably succeeded. Most of the squareness * tests out there require multiple divisions and * complicated loops. We can approximate these tests * by doing two things: testing that the number of * trailing zeros in q0 is even, and then testing * if q0 shifted right this many places is 1 mod 8. */ bits = 0; tmp = q0; while ((tmp & 1) == 0) { bits++; tmp >>= 1; } if ((bits & 1) == 0 && ((tmp & 7) == 1)) { /* q0 is probably a perfect square. Take the * square root by cheating */ sqrtq = (uint)(Math.Sqrt((double)q0)); if (sqrtq * sqrtq == q0) { /* it *is* a perfect square. If it has * not appeared previously in the list * for this multiplier, then we're almost * finished */ for (j = 0; j < num_saved; j++) { if (saved[j] == sqrtq) { break; } } if (j == num_saved) { break; } } } /* perform the odd half of the SQUFOF cycle */ tmp = sqrtn + p0 - q0; q = 1; if (tmp >= q0) { q += tmp / q0; } p1 = q * q0 - p0; q1 = q1 + (p0 - p1) * q; if (q0 < coarse_cutoff) { tmp = q0 / IntegerMath.GreatestCommonDivisor(q0, multiplier); if (tmp < cutoff) { if (num_saved >= QSIZE) { data.failed[mult_idx] = true; return(i); } saved[num_saved++] = (ushort)tmp; } } } if (sqrtq == 1) { /* the above found a trivial factor, so this * multiplier has failed */ data.failed[mult_idx] = true; return(i); } else if (i == num_iter) { /* no square root found; save the parameters * and go on to the next multiplier */ data.q0[mult_idx] = q0; data.p1[mult_idx] = p1; data.q1[mult_idx] = q1; data.num_saved[mult_idx] = num_saved; return(i); } /* square root found; the algorithm cannot fail now. * Compute the inverse quadratic form and iterate */ q0 = sqrtq; p1 = p0 + sqrtq * ((sqrtn - p0) / sqrtq); scaledn = data.n * (ulong)multipliers[mult_idx]; q1 = (uint)((scaledn - (ulong)p1 * (ulong)p1) / (ulong)q0); while (true) { uint q, tmp; tmp = sqrtn + p1 - q1; q = 1; if (tmp >= q1) { q += tmp / q1; } p0 = q * q1 - p1; q0 = q0 + (p1 - p0) * q; if (p0 == p1) { q0 = q1; break; } tmp = sqrtn + p0 - q0; q = 1; if (tmp >= q0) { q += tmp / q0; } p1 = q * q0 - p0; q1 = q1 + (p0 - p1) * q; if (p0 == p1) { break; } } /* q0 is the factor of n. Remove factors that exist * in the multiplier and save whatever's left */ q0 = q0 / IntegerMath.GreatestCommonDivisor(q0, multiplier); factor = q0; return(i); }
public ShanksSquareForms() { data = new squfof_data_t(MAX_MULTIPLIERS, QSIZE); }