int main (int argc, char **argv) { gmp_randstate_ptr rands; unsigned long maxnbits, maxdbits, nbits, dbits; mpz_t n, d, q, r, tz, junk; mp_size_t maxnn, maxdn, nn, dn, clearn, i; mp_ptr np, dup, dnp, qp, rp, junkp; mp_limb_t t; gmp_pi1_t dinv; long count = COUNT; mp_ptr scratch; mp_limb_t ran; mp_size_t alloc, itch; mp_limb_t rran0, rran1, qran0, qran1; TMP_DECL; if (argc > 1) { char *end; count = strtol (argv[1], &end, 0); if (*end || count <= 0) { fprintf (stderr, "Invalid test count: %s.\n", argv[1]); return 1; } } maxdbits = MAX_DN; maxnbits = MAX_NN; tests_start (); rands = RANDS; mpz_init (n); mpz_init (d); mpz_init (q); mpz_init (r); mpz_init (tz); mpz_init (junk); maxnn = maxnbits / GMP_NUMB_BITS + 1; maxdn = maxdbits / GMP_NUMB_BITS + 1; TMP_MARK; qp = TMP_ALLOC_LIMBS (maxnn + 2) + 1; rp = TMP_ALLOC_LIMBS (maxnn + 2) + 1; dnp = TMP_ALLOC_LIMBS (maxdn); alloc = 1; scratch = __GMP_ALLOCATE_FUNC_LIMBS (alloc); for (test = -300; test < count; test++) { nbits = random_word (rands) % (maxnbits - GMP_NUMB_BITS) + 2 * GMP_NUMB_BITS; if (test < 0) dbits = (test + 300) % (nbits - 1) + 1; else dbits = random_word (rands) % (nbits - 1) % maxdbits + 1; #if RAND_UNIFORM #define RANDFUNC mpz_urandomb #else #define RANDFUNC mpz_rrandomb #endif do RANDFUNC (d, rands, dbits); while (mpz_sgn (d) == 0); dn = SIZ (d); dup = PTR (d); MPN_COPY (dnp, dup, dn); dnp[dn - 1] |= GMP_NUMB_HIGHBIT; if (test % 2 == 0) { RANDFUNC (n, rands, nbits); nn = SIZ (n); ASSERT_ALWAYS (nn >= dn); } else { do { RANDFUNC (q, rands, random_word (rands) % (nbits - dbits + 1)); RANDFUNC (r, rands, random_word (rands) % mpz_sizeinbase (d, 2)); mpz_mul (n, q, d); mpz_add (n, n, r); nn = SIZ (n); } while (nn > maxnn || nn < dn); } ASSERT_ALWAYS (nn <= maxnn); ASSERT_ALWAYS (dn <= maxdn); mpz_urandomb (junk, rands, nbits); junkp = PTR (junk); np = PTR (n); mpz_urandomb (tz, rands, 32); t = mpz_get_ui (tz); if (t % 17 == 0) { dnp[dn - 1] = GMP_NUMB_MAX; dup[dn - 1] = GMP_NUMB_MAX; } switch ((int) t % 16) { case 0: clearn = random_word (rands) % nn; for (i = clearn; i < nn; i++) np[i] = 0; break; case 1: mpn_sub_1 (np + nn - dn, dnp, dn, random_word (rands)); break; case 2: mpn_add_1 (np + nn - dn, dnp, dn, random_word (rands)); break; } if (dn >= 2) invert_pi1 (dinv, dnp[dn - 1], dnp[dn - 2]); rran0 = random_word (rands); rran1 = random_word (rands); qran0 = random_word (rands); qran1 = random_word (rands); qp[-1] = qran0; qp[nn - dn + 1] = qran1; rp[-1] = rran0; ran = random_word (rands); if ((double) (nn - dn) * dn < 1e5) { /* Test mpn_sbpi1_div_qr */ if (dn > 2) { MPN_COPY (rp, np, nn); if (nn > dn) MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_sbpi1_div_qr (qp, rp, nn, dnp, dn, dinv.inv32); check_one (qp, rp, np, nn, dnp, dn, "mpn_sbpi1_div_qr", 0); } /* Test mpn_sbpi1_divappr_q */ if (dn > 2) { MPN_COPY (rp, np, nn); if (nn > dn) MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_sbpi1_divappr_q (qp, rp, nn, dnp, dn, dinv.inv32); check_one (qp, NULL, np, nn, dnp, dn, "mpn_sbpi1_divappr_q", 1); } /* Test mpn_sbpi1_div_q */ if (dn > 2) { MPN_COPY (rp, np, nn); if (nn > dn) MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_sbpi1_div_q (qp, rp, nn, dnp, dn, dinv.inv32); check_one (qp, NULL, np, nn, dnp, dn, "mpn_sbpi1_div_q", 0); } /* Test mpn_sb_div_qr_sec */ itch = 3 * nn + 4; if (itch + 1 > alloc) { scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1); alloc = itch + 1; } scratch[itch] = ran; MPN_COPY (rp, np, nn); if (nn >= dn) MPN_COPY (qp, junkp, nn - dn + 1); mpn_sb_div_qr_sec (qp, rp, nn, dup, dn, scratch); ASSERT_ALWAYS (ran == scratch[itch]); check_one (qp, rp, np, nn, dup, dn, "mpn_sb_div_qr_sec", 0); /* Test mpn_sb_div_r_sec */ itch = nn + 2 * dn + 2; if (itch + 1 > alloc) { scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1); alloc = itch + 1; } scratch[itch] = ran; MPN_COPY (rp, np, nn); mpn_sb_div_r_sec (rp, nn, dup, dn, scratch); ASSERT_ALWAYS (ran == scratch[itch]); /* Note: Since check_one cannot cope with random-only functions, we pass qp[] from the previous function, mpn_sb_div_qr_sec. */ check_one (qp, rp, np, nn, dup, dn, "mpn_sb_div_r_sec", 0); } /* Test mpn_dcpi1_div_qr */ if (dn >= 6 && nn - dn >= 3) { MPN_COPY (rp, np, nn); if (nn > dn) MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_dcpi1_div_qr (qp, rp, nn, dnp, dn, &dinv); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - dn + 1] == qran1); ASSERT_ALWAYS (rp[-1] == rran0); check_one (qp, rp, np, nn, dnp, dn, "mpn_dcpi1_div_qr", 0); } /* Test mpn_dcpi1_divappr_q */ if (dn >= 6 && nn - dn >= 3) { MPN_COPY (rp, np, nn); if (nn > dn) MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_dcpi1_divappr_q (qp, rp, nn, dnp, dn, &dinv); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - dn + 1] == qran1); ASSERT_ALWAYS (rp[-1] == rran0); check_one (qp, NULL, np, nn, dnp, dn, "mpn_dcpi1_divappr_q", 1); } /* Test mpn_dcpi1_div_q */ if (dn >= 6 && nn - dn >= 3) { MPN_COPY (rp, np, nn); if (nn > dn) MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_dcpi1_div_q (qp, rp, nn, dnp, dn, &dinv); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - dn + 1] == qran1); ASSERT_ALWAYS (rp[-1] == rran0); check_one (qp, NULL, np, nn, dnp, dn, "mpn_dcpi1_div_q", 0); } /* Test mpn_mu_div_qr */ if (nn - dn > 2 && dn >= 2) { itch = mpn_mu_div_qr_itch (nn, dn, 0); if (itch + 1 > alloc) { scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1); alloc = itch + 1; } scratch[itch] = ran; MPN_COPY (qp, junkp, nn - dn); MPN_ZERO (rp, dn); rp[dn] = rran1; qp[nn - dn] = mpn_mu_div_qr (qp, rp, np, nn, dnp, dn, scratch); ASSERT_ALWAYS (ran == scratch[itch]); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - dn + 1] == qran1); ASSERT_ALWAYS (rp[-1] == rran0); ASSERT_ALWAYS (rp[dn] == rran1); check_one (qp, rp, np, nn, dnp, dn, "mpn_mu_div_qr", 0); } /* Test mpn_mu_divappr_q */ if (nn - dn > 2 && dn >= 2) { itch = mpn_mu_divappr_q_itch (nn, dn, 0); if (itch + 1 > alloc) { scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1); alloc = itch + 1; } scratch[itch] = ran; MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_mu_divappr_q (qp, np, nn, dnp, dn, scratch); ASSERT_ALWAYS (ran == scratch[itch]); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - dn + 1] == qran1); check_one (qp, NULL, np, nn, dnp, dn, "mpn_mu_divappr_q", 4); } /* Test mpn_mu_div_q */ if (nn - dn > 2 && dn >= 2) { itch = mpn_mu_div_q_itch (nn, dn, 0); if (itch + 1> alloc) { scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1); alloc = itch + 1; } scratch[itch] = ran; MPN_COPY (qp, junkp, nn - dn); qp[nn - dn] = mpn_mu_div_q (qp, np, nn, dnp, dn, scratch); ASSERT_ALWAYS (ran == scratch[itch]); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - dn + 1] == qran1); check_one (qp, NULL, np, nn, dnp, dn, "mpn_mu_div_q", 0); } if (1) { itch = nn + 1; if (itch + 1> alloc) { scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1); alloc = itch + 1; } scratch[itch] = ran; mpn_div_q (qp, np, nn, dup, dn, scratch); ASSERT_ALWAYS (ran == scratch[itch]); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - dn + 1] == qran1); check_one (qp, NULL, np, nn, dup, dn, "mpn_div_q", 0); } if (dn >= 2 && nn >= 2) { mp_limb_t qh; /* mpn_divrem_2 */ MPN_COPY (rp, np, nn); qp[nn - 2] = qp[nn-1] = qran1; qh = mpn_divrem_2 (qp, 0, rp, nn, dnp + dn - 2); ASSERT_ALWAYS (qp[nn - 2] == qran1); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - 1] == qran1); qp[nn - 2] = qh; check_one (qp, rp, np, nn, dnp + dn - 2, 2, "mpn_divrem_2", 0); /* Missing: divrem_2 with fraction limbs. */ /* mpn_div_qr_2 */ qp[nn - 2] = qran1; qh = mpn_div_qr_2 (qp, rp, np, nn, dup + dn - 2); ASSERT_ALWAYS (qp[nn - 2] == qran1); ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - 1] == qran1); qp[nn - 2] = qh; check_one (qp, rp, np, nn, dup + dn - 2, 2, "mpn_div_qr_2", 0); } } __GMP_FREE_FUNC_LIMBS (scratch, alloc); TMP_FREE; mpz_clear (n); mpz_clear (d); mpz_clear (q); mpz_clear (r); mpz_clear (tz); mpz_clear (junk); tests_end (); return 0; }

static int mpfr_rem1 (mpfr_ptr rem, long *quo, mpfr_rnd_t rnd_q, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd) { mpfr_exp_t ex, ey; int compare, inex, q_is_odd, sign, signx = MPFR_SIGN (x); mpz_t mx, my, r; int tiny = 0; MPFR_ASSERTD (rnd_q == MPFR_RNDN || rnd_q == MPFR_RNDZ); if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x) || MPFR_IS_SINGULAR (y))) { if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y) || MPFR_IS_INF (x) || MPFR_IS_ZERO (y)) { /* for remquo, quo is undefined */ MPFR_SET_NAN (rem); MPFR_RET_NAN; } else /* either y is Inf and x is 0 or non-special, or x is 0 and y is non-special, in both cases the quotient is zero. */ { if (quo) *quo = 0; return mpfr_set (rem, x, rnd); } } /* now neither x nor y is NaN, Inf or zero */ mpz_init (mx); mpz_init (my); mpz_init (r); ex = mpfr_get_z_2exp (mx, x); /* x = mx*2^ex */ ey = mpfr_get_z_2exp (my, y); /* y = my*2^ey */ /* to get rid of sign problems, we compute it separately: quo(-x,-y) = quo(x,y), rem(-x,-y) = -rem(x,y) quo(-x,y) = -quo(x,y), rem(-x,y) = -rem(x,y) thus quo = sign(x/y)*quo(|x|,|y|), rem = sign(x)*rem(|x|,|y|) */ sign = (signx == MPFR_SIGN (y)) ? 1 : -1; mpz_abs (mx, mx); mpz_abs (my, my); q_is_odd = 0; /* divide my by 2^k if possible to make operations mod my easier */ { unsigned long k = mpz_scan1 (my, 0); ey += k; mpz_fdiv_q_2exp (my, my, k); } if (ex <= ey) { /* q = x/y = mx/(my*2^(ey-ex)) */ /* First detect cases where q=0, to avoid creating a huge number my*2^(ey-ex): if sx = mpz_sizeinbase (mx, 2) and sy = mpz_sizeinbase (my, 2), we have x < 2^(ex + sx) and y >= 2^(ey + sy - 1), thus if ex + sx <= ey + sy - 1 the quotient is 0 */ if (ex + (mpfr_exp_t) mpz_sizeinbase (mx, 2) < ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) { tiny = 1; mpz_set (r, mx); mpz_set_ui (mx, 0); } else { mpz_mul_2exp (my, my, ey - ex); /* divide mx by my*2^(ey-ex) */ /* since mx > 0 and my > 0, we can use mpz_tdiv_qr in all cases */ mpz_tdiv_qr (mx, r, mx, my); /* 0 <= |r| <= |my|, r has the same sign as mx */ } if (rnd_q == MPFR_RNDN) q_is_odd = mpz_tstbit (mx, 0); if (quo) /* mx is the quotient */ { mpz_tdiv_r_2exp (mx, mx, WANTED_BITS); *quo = mpz_get_si (mx); } } else /* ex > ey */ { if (quo) /* remquo case */ /* for remquo, to get the low WANTED_BITS more bits of the quotient, we first compute R = X mod Y*2^WANTED_BITS, where X and Y are defined below. Then the low WANTED_BITS of the quotient are floor(R/Y). */ mpz_mul_2exp (my, my, WANTED_BITS); /* 2^WANTED_BITS*Y */ else if (rnd_q == MPFR_RNDN) /* remainder case */ /* Let X = mx*2^(ex-ey) and Y = my. Then both X and Y are integers. Assume X = R mod Y, then x = X*2^ey = R*2^ey mod (Y*2^ey=y). To be able to perform the rounding, we need the least significant bit of the quotient, i.e., one more bit in the remainder, which is obtained by dividing by 2Y. */ mpz_mul_2exp (my, my, 1); /* 2Y */ mpz_set_ui (r, 2); mpz_powm_ui (r, r, ex - ey, my); /* 2^(ex-ey) mod my */ mpz_mul (r, r, mx); mpz_mod (r, r, my); if (quo) /* now 0 <= r < 2^WANTED_BITS*Y */ { mpz_fdiv_q_2exp (my, my, WANTED_BITS); /* back to Y */ mpz_tdiv_qr (mx, r, r, my); /* oldr = mx*my + newr */ *quo = mpz_get_si (mx); q_is_odd = *quo & 1; } else if (rnd_q == MPFR_RNDN) /* now 0 <= r < 2Y in the remainder case */ { mpz_fdiv_q_2exp (my, my, 1); /* back to Y */ /* least significant bit of q */ q_is_odd = mpz_cmpabs (r, my) >= 0; if (q_is_odd) mpz_sub (r, r, my); } /* now 0 <= |r| < |my|, and if needed, q_is_odd is the least significant bit of q */ } if (mpz_cmp_ui (r, 0) == 0) { inex = mpfr_set_ui (rem, 0, MPFR_RNDN); /* take into account sign of x */ if (signx < 0) mpfr_neg (rem, rem, MPFR_RNDN); } else { if (rnd_q == MPFR_RNDN) { /* FIXME: the comparison 2*r < my could be done more efficiently at the mpn level */ mpz_mul_2exp (r, r, 1); /* if tiny=1, we should compare r with my*2^(ey-ex) */ if (tiny) { if (ex + (mpfr_exp_t) mpz_sizeinbase (r, 2) < ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) compare = 0; /* r*2^ex < my*2^ey */ else { mpz_mul_2exp (my, my, ey - ex); compare = mpz_cmpabs (r, my); } } else compare = mpz_cmpabs (r, my); mpz_fdiv_q_2exp (r, r, 1); compare = ((compare > 0) || ((rnd_q == MPFR_RNDN) && (compare == 0) && q_is_odd)); /* if compare != 0, we need to subtract my to r, and add 1 to quo */ if (compare) { mpz_sub (r, r, my); if (quo && (rnd_q == MPFR_RNDN)) *quo += 1; } } /* take into account sign of x */ if (signx < 0) mpz_neg (r, r); inex = mpfr_set_z_2exp (rem, r, ex > ey ? ey : ex, rnd); } if (quo) *quo *= sign; mpz_clear (mx); mpz_clear (my); mpz_clear (r); return inex; }

static int hgcd_appr_valid_p (mpz_t a, mpz_t b, mp_size_t res0, struct hgcd_ref *ref, mpz_t ref_r0, mpz_t ref_r1, mp_size_t res1, struct hgcd_matrix *hgcd) { mp_size_t n = MAX (mpz_size (a), mpz_size (b)); mp_size_t s = n/2 + 1; mp_bitcnt_t dbits, abits, margin; mpz_t appr_r0, appr_r1, t, q; struct hgcd_ref appr; if (!res0) { if (!res1) return 1; fprintf (stderr, "mpn_hgcd_appr returned 1 when no reduction possible.\n"); return 0; } /* NOTE: No *_clear calls on error return, since we're going to abort anyway. */ mpz_init (t); mpz_init (q); hgcd_ref_init (&appr); mpz_init (appr_r0); mpz_init (appr_r1); if (mpz_size (ref_r0) <= s) { fprintf (stderr, "ref_r0 too small!!!: "); debug_mp (ref_r0, 16); return 0; } if (mpz_size (ref_r1) <= s) { fprintf (stderr, "ref_r1 too small!!!: "); debug_mp (ref_r1, 16); return 0; } mpz_sub (t, ref_r0, ref_r1); dbits = mpz_sizeinbase (t, 2); if (dbits > s*GMP_NUMB_BITS) { fprintf (stderr, "ref |r0 - r1| too large!!!: "); debug_mp (t, 16); return 0; } if (!res1) { mpz_set (appr_r0, a); mpz_set (appr_r1, b); } else { unsigned i; for (i = 0; i<2; i++) { unsigned j; for (j = 0; j<2; j++) { mp_size_t mn = hgcd->n; MPN_NORMALIZE (hgcd->p[i][j], mn); mpz_realloc (appr.m[i][j], mn); MPN_COPY (PTR (appr.m[i][j]), hgcd->p[i][j], mn); SIZ (appr.m[i][j]) = mn; } } mpz_mul (appr_r0, appr.m[1][1], a); mpz_mul (t, appr.m[0][1], b); mpz_sub (appr_r0, appr_r0, t); if (mpz_sgn (appr_r0) <= 0 || mpz_size (appr_r0) <= s) { fprintf (stderr, "appr_r0 too small: "); debug_mp (appr_r0, 16); return 0; } mpz_mul (appr_r1, appr.m[1][0], a); mpz_mul (t, appr.m[0][0], b); mpz_sub (appr_r1, t, appr_r1); if (mpz_sgn (appr_r1) <= 0 || mpz_size (appr_r1) <= s) { fprintf (stderr, "appr_r1 too small: "); debug_mp (appr_r1, 16); return 0; } } mpz_sub (t, appr_r0, appr_r1); abits = mpz_sizeinbase (t, 2); if (abits < dbits) { fprintf (stderr, "|r0 - r1| too small: "); debug_mp (t, 16); return 0; } /* We lose one bit each time we discard the least significant limbs. For the lehmer code, that can happen at most s * (GMP_NUMB_BITS) / (GMP_NUMB_BITS - 1) times. For the dc code, we lose an entire limb (or more?) for each level of recursion. */ margin = (n/2+1) * GMP_NUMB_BITS / (GMP_NUMB_BITS - 1); { mp_size_t rn; for (rn = n; ABOVE_THRESHOLD (rn, HGCD_APPR_THRESHOLD); rn = (rn + 1)/2) margin += GMP_NUMB_BITS; } if (verbose_flag && abits > dbits) fprintf (stderr, "n = %u: sbits = %u: ref #(r0-r1): %u, appr #(r0-r1): %u excess: %d, margin: %u\n", (unsigned) n, (unsigned) s*GMP_NUMB_BITS, (unsigned) dbits, (unsigned) abits, (int) abits - s * GMP_NUMB_BITS, (unsigned) margin); if (abits > s*GMP_NUMB_BITS + margin) { fprintf (stderr, "appr |r0 - r1| much larger than minimal (by %u bits, margin = %u bits)\n", (unsigned) (abits - s*GMP_NUMB_BITS), (unsigned) margin); return 0; } while (mpz_cmp (appr_r0, ref_r0) > 0 || mpz_cmp (appr_r1, ref_r1) > 0) { ASSERT (mpz_size (appr_r0) > s); ASSERT (mpz_size (appr_r1) > s); if (mpz_cmp (appr_r0, appr_r1) > 0) { if (!sdiv_qr (q, appr_r0, s, appr_r0, appr_r1)) break; mpz_addmul (appr.m[0][1], q, appr.m[0][0]); mpz_addmul (appr.m[1][1], q, appr.m[1][0]); } else { if (!sdiv_qr (q, appr_r1, s, appr_r1, appr_r0)) break; mpz_addmul (appr.m[0][0], q, appr.m[0][1]); mpz_addmul (appr.m[1][0], q, appr.m[1][1]); } } if (mpz_cmp (appr_r0, ref_r0) != 0 || mpz_cmp (appr_r1, ref_r1) != 0 || !hgcd_ref_equal (ref, &appr)) { fprintf (stderr, "appr_r0: "); debug_mp (appr_r0, 16); fprintf (stderr, "ref_r0: "); debug_mp (ref_r0, 16); fprintf (stderr, "appr_r1: "); debug_mp (appr_r1, 16); fprintf (stderr, "ref_r1: "); debug_mp (ref_r1, 16); return 0; } mpz_clear (t); mpz_clear (q); hgcd_ref_clear (&appr); mpz_clear (appr_r0); mpz_clear (appr_r1); return 1; }

static PyObject * GMPY_mpz_lucasv_mod(PyObject *self, PyObject *args) { /* Adaptation of algorithm found in http://joye.site88.net/papers/JQ96lucas.pdf * calculate v[k] (modulo n) of Lucas V sequence for p,q. * Note: p^2-4q=0 is not tested, not a proper Lucas sequence!! */ MPZ_Object *result = 0, *p, *q, *k, *n; size_t s = 0, j = 0; mpz_t vl, vh, ql, qh, tmp; if (PyTuple_Size(args) != 4) { TYPE_ERROR("lucasv_mod() requires 4 integer arguments"); return NULL; } mpz_init(vl); mpz_init(vh); mpz_init(ql); mpz_init(qh); mpz_init(tmp); p = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL); q = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL); k = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 2), NULL); n = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 3), NULL); if (!p || !q || !k || !n) { TYPE_ERROR("lucasv_mod() requires 4 integer arguments"); goto cleanup; } /* Check if p*p - 4*q == 0. */ mpz_mul(tmp, p->z, p->z); mpz_mul_ui(qh, q->z, 4); mpz_sub(tmp, tmp, qh); if (mpz_sgn(tmp) == 0) { VALUE_ERROR("invalid values for p,q in lucasv_mod()"); goto cleanup; } /* Check if k < 0. */ if (mpz_sgn(k->z) < 0) { VALUE_ERROR("invalid value for k in lucasv_mod()"); goto cleanup; } /* Check if n > 0. */ if (mpz_sgn(n->z) <= 0) { VALUE_ERROR("invalid value for n in lucasv_mod()"); goto cleanup; } mpz_set_si(vl, 2); mpz_set(vh, p->z); mpz_set_si(ql, 1); mpz_set_si(qh, 1); mpz_set_si(tmp,0); s = mpz_scan1(k->z, 0); for (j = mpz_sizeinbase(k->z,2)-1; j >= s+1; j--) { /* ql = ql*qh (mod n) */ mpz_mul(ql, ql, qh); mpz_mod(ql, ql, n->z); if (mpz_tstbit(k->z,j) == 1) { /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* vl = vh*vl - p*ql (mod n) */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* vh = vh*vh - 2*qh (mod n) */ mpz_mul(vh, vh, vh); mpz_mul_si(tmp, qh, 2); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); } else { /* qh = ql */ mpz_set(qh, ql); /* vh = vh*vl - p*ql (mod n) */ mpz_mul(vh, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); } } /* ql = ql*qh */ mpz_mul(ql, ql, qh); /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); /* ql = ql*qh */ mpz_mul(ql, ql, qh); for (j = 1; j <= s; j++) { /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* ql = ql*ql (mod n) */ mpz_mul(ql, ql, ql); mpz_mod(ql, ql, n->z); } if (!(result = GMPy_MPZ_New(NULL))) goto cleanup; /* vl contains our return value */ mpz_mod(result->z, vl, n->z); cleanup: mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); Py_XDECREF((PyObject*)p); Py_XDECREF((PyObject*)q); Py_XDECREF((PyObject*)k); Py_XDECREF((PyObject*)n); return (PyObject*)result; }

chunk_t mpz_to_n_autosize(const MP_INT *mp) { int bytes = (mpz_sizeinbase(mp, 2)+7)/8; return mpz_to_n(mp, bytes); }

void RSA::getPublicKey(char* buffer) { size_t count = (mpz_sizeinbase(m_n, 2) + 7) / 8; memset(buffer, 0, 128 - count); mpz_export(&buffer[128 - count], nullptr, 1, 1, 0, 0, m_n); }

int main(){ mpz_t p; mpz_init(p); const char* p_hex = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"; assert(mpz_set_str(p, p_hex, 16) == 0); mpz_t q; assert(mpz_init_set_str(q, p_hex, 16) == 0); assert(mpz_cmp(p,q) == 0); char buffer[128]; assert(mpz_get_str(buffer,10,p) == buffer); printf("p = %s\n", buffer); printf("p = "); mpz_out_str(stdout,10,p); printf("\n"); gmp_printf("p = %Zd\n", p); int primality = mpz_probab_prime_p(p,50); // proba < 4^(-50) of being wrong switch(primality){ case 2: printf("p is definitely prime\n"); break; case 1: printf("p is very probably prime\n"); break; case 0: printf("p is composite\n"); break; default: assert(NULL); } mpz_sub_ui(q,p,50); assert(mpz_get_str(buffer,10,q) == buffer); printf("q = %s\n", buffer); printf("q = "); mpz_out_str(stdout,10,q); printf("\n"); mpz_nextprime(q,q); assert(mpz_get_str(buffer,10,q) == buffer); printf("q = %s\n", buffer); printf("q = "); mpz_out_str(stdout,10,q); printf("\n"); mpz_sub_ui(q,p,50); mpz_gcd(q,q,p); assert(mpz_get_str(buffer,10,q) == buffer); printf("q = %s\n", buffer); printf("q = "); mpz_out_str(stdout,10,q); printf("\n"); /* printf("please enter a number in hex:"); assert(mpz_inp_str(q, stdin, 16) != 0); printf("q = "); mpz_out_str(stdout,10,q); printf("\n"); printf("please do it again:");scanf("%s", buffer); assert(mpz_set_str(q,buffer,16) == 0); printf("q = "); mpz_out_str(stdout,10,q); printf("\n"); */ unsigned long a[20]; mpz_import(q,32,1,sizeof(a[0]),0,0,a); printf("q = "); mpz_out_str(stdout,16,q); printf("\n"); printf("size of p in base 16 is:%d\n", mpz_sizeinbase(p,2)); mpz_clear(q); mpz_clear(p); return 0; }

int mpz_probab_prime_p (mpz_srcptr n, int reps) { mp_limb_t r; /* Handle small and negative n. */ if (mpz_cmp_ui (n, 1000000L) <= 0) { int is_prime; if (mpz_sgn (n) < 0) { /* Negative number. Negate and call ourselves. */ mpz_t n2; mpz_init (n2); mpz_neg (n2, n); is_prime = mpz_probab_prime_p (n2, reps); mpz_clear (n2); return is_prime; } is_prime = isprime (mpz_get_ui (n)); return is_prime ? 2 : 0; } /* If n is now even, it is not a prime. */ if ((mpz_get_ui (n) & 1) == 0) return 0; #if defined (PP) /* Check if n has small factors. */ #if defined (PP_INVERTED) r = MPN_MOD_OR_PREINV_MOD_1 (PTR(n), SIZ(n), (mp_limb_t) PP, (mp_limb_t) PP_INVERTED); #else r = mpn_mod_1 (PTR(n), SIZ(n), (mp_limb_t) PP); #endif if (r % 3 == 0 #if BITS_PER_MP_LIMB >= 4 || r % 5 == 0 #endif #if BITS_PER_MP_LIMB >= 8 || r % 7 == 0 #endif #if BITS_PER_MP_LIMB >= 16 || r % 11 == 0 || r % 13 == 0 #endif #if BITS_PER_MP_LIMB >= 32 || r % 17 == 0 || r % 19 == 0 || r % 23 == 0 || r % 29 == 0 #endif #if BITS_PER_MP_LIMB >= 64 || r % 31 == 0 || r % 37 == 0 || r % 41 == 0 || r % 43 == 0 || r % 47 == 0 || r % 53 == 0 #endif ) { return 0; } #endif /* PP */ /* Do more dividing. We collect small primes, using umul_ppmm, until we overflow a single limb. We divide our number by the small primes product, and look for factors in the remainder. */ { unsigned long int ln2; unsigned long int q; mp_limb_t p1, p0, p; unsigned int primes[15]; int nprimes; nprimes = 0; p = 1; ln2 = mpz_sizeinbase (n, 2) / 30; ln2 = ln2 * ln2; for (q = PP_FIRST_OMITTED; q < ln2; q += 2) { if (isprime (q)) { umul_ppmm (p1, p0, p, q); if (p1 != 0) { r = mpn_mod_1 (PTR(n), SIZ(n), p); while (--nprimes >= 0) if (r % primes[nprimes] == 0) { ASSERT_ALWAYS (mpn_mod_1 (PTR(n), SIZ(n), (mp_limb_t) primes[nprimes]) == 0); return 0; } p = q; nprimes = 0; } else { p = p0; } primes[nprimes++] = q; } } } /* Perform a number of Miller-Rabin tests. */ return mpz_millerrabin (n, reps); }

/* Compute the first 2^m terms from the hypergeometric series with x = p / 2^r */ static int GENERIC (mpfr_ptr y, mpz_srcptr p, long r, int m) { unsigned long n,i,k,j,l; int is_p_one; mpz_t* P,*S; #ifdef A mpz_t *T; #endif mpz_t* ptoj; #ifdef R_IS_RATIONAL mpz_t* qtoj; mpfr_t tmp; #endif mp_exp_t diff, expo; mp_prec_t precy = MPFR_PREC(y); MPFR_TMP_DECL(marker); MPFR_TMP_MARK(marker); MPFR_CLEAR_FLAGS(y); n = 1UL << m; P = (mpz_t*) MPFR_TMP_ALLOC ((m+1) * sizeof(mpz_t)); S = (mpz_t*) MPFR_TMP_ALLOC ((m+1) * sizeof(mpz_t)); ptoj = (mpz_t*) MPFR_TMP_ALLOC ((m+1) * sizeof(mpz_t)); /* ptoj[i] = mantissa^(2^i) */ #ifdef A T = (mpz_t*) MPFR_TMP_ALLOC ((m+1) * sizeof(mpz_t)); #endif #ifdef R_IS_RATIONAL qtoj = (mpz_t*) MPFR_TMP_ALLOC ((m+1) * sizeof(mpz_t)); #endif for (i = 0 ; i <= m ; i++) { mpz_init (P[i]); mpz_init (S[i]); mpz_init (ptoj[i]); #ifdef R_IS_RATIONAL mpz_init (qtoj[i]); #endif #ifdef A mpz_init (T[i]); #endif } mpz_set (ptoj[0], p); #ifdef C # if C2 != 1 mpz_mul_ui (ptoj[0], ptoj[0], C2); # endif #endif is_p_one = mpz_cmp_ui(ptoj[0], 1) == 0; #ifdef A # ifdef B mpz_set_ui (T[0], A1 * B1); # else mpz_set_ui (T[0], A1); # endif #endif if (!is_p_one) for (i = 1 ; i < m ; i++) mpz_mul (ptoj[i], ptoj[i-1], ptoj[i-1]); #ifdef R_IS_RATIONAL mpz_set_si (qtoj[0], r); for (i = 1 ; i <= m ; i++) mpz_mul(qtoj[i], qtoj[i-1], qtoj[i-1]); #endif mpz_set_ui (P[0], 1); mpz_set_ui (S[0], 1); k = 0; for (i = 1 ; i < n ; i++) { k++; #ifdef A # ifdef B mpz_set_ui (T[k], (A1 + A2*i)*(B1+B2*i)); # else mpz_set_ui (T[k], A1 + A2*i); # endif #endif #ifdef C # ifdef NO_FACTORIAL mpz_set_ui (P[k], (C1 + C2 * (i-1))); mpz_set_ui (S[k], 1); # else mpz_set_ui (P[k], (i+1) * (C1 + C2 * (i-1))); mpz_set_ui (S[k], i+1); # endif #else # ifdef NO_FACTORIAL mpz_set_ui (P[k], 1); # else mpz_set_ui (P[k], i+1); # endif mpz_set (S[k], P[k]); #endif for (j = i+1, l = 0 ; (j & 1) == 0 ; l++, j>>=1, k--) { if (!is_p_one) mpz_mul (S[k], S[k], ptoj[l]); #ifdef A # ifdef B # if (A2*B2) != 1 mpz_mul_ui (P[k], P[k], A2*B2); # endif # else # if A2 != 1 mpz_mul_ui (P[k], P[k], A2); # endif #endif mpz_mul (S[k], S[k], T[k-1]); #endif mpz_mul (S[k-1], S[k-1], P[k]); #ifdef R_IS_RATIONAL mpz_mul (S[k-1], S[k-1], qtoj[l]); #else mpz_mul_2exp (S[k-1], S[k-1], r*(1<<l)); #endif mpz_add (S[k-1], S[k-1], S[k]); mpz_mul (P[k-1], P[k-1], P[k]); #ifdef A mpz_mul (T[k-1], T[k-1], T[k]); #endif } } diff = mpz_sizeinbase(S[0],2) - 2*precy; expo = diff; if (diff >= 0) mpz_div_2exp(S[0],S[0],diff); else mpz_mul_2exp(S[0],S[0],-diff); diff = mpz_sizeinbase(P[0],2) - precy; expo -= diff; if (diff >=0) mpz_div_2exp(P[0],P[0],diff); else mpz_mul_2exp(P[0],P[0],-diff); mpz_tdiv_q(S[0], S[0], P[0]); mpfr_set_z(y, S[0], GMP_RNDD); MPFR_SET_EXP (y, MPFR_GET_EXP (y) + expo); #ifdef R_IS_RATIONAL /* exact division */ mpz_div_ui (qtoj[m], qtoj[m], r); mpfr_init2 (tmp, MPFR_PREC(y)); mpfr_set_z (tmp, qtoj[m] , GMP_RNDD); mpfr_div (y, y, tmp, GMP_RNDD); mpfr_clear (tmp); #else mpfr_div_2ui(y, y, r*(i-1), GMP_RNDN); #endif for (i = 0 ; i <= m ; i++) { mpz_clear (P[i]); mpz_clear (S[i]); mpz_clear (ptoj[i]); #ifdef R_IS_RATIONAL mpz_clear (qtoj[i]); #endif #ifdef A mpz_clear (T[i]); #endif } MPFR_TMP_FREE (marker); return 0; }

uint32_t tpm_bn_bitsize(tpm_bn_t a) { return mpz_sizeinbase(a, 2); }

bool gfc_convert_boz (gfc_expr *expr, gfc_typespec *ts) { size_t buffer_size, boz_bit_size, ts_bit_size; int index; unsigned char *buffer; if (!expr->is_boz) return true; gcc_assert (expr->expr_type == EXPR_CONSTANT && expr->ts.type == BT_INTEGER); /* Don't convert BOZ to logical, character, derived etc. */ if (ts->type == BT_REAL) { buffer_size = size_float (ts->kind); ts_bit_size = buffer_size * 8; } else if (ts->type == BT_COMPLEX) { buffer_size = size_complex (ts->kind); ts_bit_size = buffer_size * 8 / 2; } else return true; /* Convert BOZ to the smallest possible integer kind. */ boz_bit_size = mpz_sizeinbase (expr->value.integer, 2); if (boz_bit_size > ts_bit_size) { gfc_error_now ("BOZ constant at %L is too large (%ld vs %ld bits)", &expr->where, (long) boz_bit_size, (long) ts_bit_size); return false; } for (index = 0; gfc_integer_kinds[index].kind != 0; ++index) { if ((unsigned) gfc_integer_kinds[index].bit_size >= ts_bit_size) break; } expr->ts.kind = gfc_integer_kinds[index].kind; buffer_size = MAX (buffer_size, size_integer (expr->ts.kind)); buffer = (unsigned char*)alloca (buffer_size); encode_integer (expr->ts.kind, expr->value.integer, buffer, buffer_size); mpz_clear (expr->value.integer); if (ts->type == BT_REAL) { mpfr_init (expr->value.real); gfc_interpret_float (ts->kind, buffer, buffer_size, expr->value.real); } else { mpfr_init (expr->value.complex.r); mpfr_init (expr->value.complex.i); gfc_interpret_complex (ts->kind, buffer, buffer_size, expr->value.complex.r, expr->value.complex.i); } expr->is_boz = 0; expr->ts.type = ts->type; expr->ts.kind = ts->kind; return true; }

/* f <- 1 - r/2! + r^2/4! + ... + (-1)^l r^l/(2l)! + ... Assumes |r| < 1/2, and f, r have the same precision. Returns e such that the error on f is bounded by 2^e ulps. */ static int mpfr_cos2_aux (mpfr_ptr f, mpfr_srcptr r) { mpz_t x, t, s; mpfr_exp_t ex, l, m; mpfr_prec_t p, q; unsigned long i, maxi, imax; MPFR_ASSERTD(mpfr_get_exp (r) <= -1); /* compute minimal i such that i*(i+1) does not fit in an unsigned long, assuming that there are no padding bits. */ maxi = 1UL << (CHAR_BIT * sizeof(unsigned long) / 2); if (maxi * (maxi / 2) == 0) /* test checked at compile time */ { /* can occur only when there are padding bits. */ /* maxi * (maxi-1) is representable iff maxi * (maxi / 2) != 0 */ do maxi /= 2; while (maxi * (maxi / 2) == 0); } mpz_init (x); mpz_init (s); mpz_init (t); ex = mpfr_get_z_2exp (x, r); /* r = x*2^ex */ /* remove trailing zeroes */ l = mpz_scan1 (x, 0); ex += l; mpz_fdiv_q_2exp (x, x, l); /* since |r| < 1, r = x*2^ex, and x is an integer, necessarily ex < 0 */ p = mpfr_get_prec (f); /* same than r */ /* bound for number of iterations */ imax = p / (-mpfr_get_exp (r)); imax += (imax == 0); q = 2 * MPFR_INT_CEIL_LOG2(imax) + 4; /* bound for (3l)^2 */ mpz_set_ui (s, 1); /* initialize sum with 1 */ mpz_mul_2exp (s, s, p + q); /* scale all values by 2^(p+q) */ mpz_set (t, s); /* invariant: t is previous term */ for (i = 1; (m = mpz_sizeinbase (t, 2)) >= q; i += 2) { /* adjust precision of x to that of t */ l = mpz_sizeinbase (x, 2); if (l > m) { l -= m; mpz_fdiv_q_2exp (x, x, l); ex += l; } /* multiply t by r */ mpz_mul (t, t, x); mpz_fdiv_q_2exp (t, t, -ex); /* divide t by i*(i+1) */ if (i < maxi) mpz_fdiv_q_ui (t, t, i * (i + 1)); else { mpz_fdiv_q_ui (t, t, i); mpz_fdiv_q_ui (t, t, i + 1); } /* if m is the (current) number of bits of t, we can consider that all operations on t so far had precision >= m, so we can prove by induction that the relative error on t is of the form (1+u)^(3l)-1, where |u| <= 2^(-m), and l=(i+1)/2 is the # of loops. Since |(1+x^2)^(1/x) - 1| <= 4x/3 for |x| <= 1/2, for |u| <= 1/(3l)^2, the absolute error is bounded by 4/3*(3l)*2^(-m)*t <= 4*l since |t| < 2^m. Therefore the error on s is bounded by 2*l*(l+1). */ /* add or subtract to s */ if (i % 4 == 1) mpz_sub (s, s, t); else mpz_add (s, s, t); } mpfr_set_z (f, s, MPFR_RNDN); mpfr_div_2ui (f, f, p + q, MPFR_RNDN); mpz_clear (x); mpz_clear (s); mpz_clear (t); l = (i - 1) / 2; /* number of iterations */ return 2 * MPFR_INT_CEIL_LOG2 (l + 1) + 1; /* bound is 2l(l+1) */ }

int check_specialcase(FILE *sieve_log, fact_obj_t *fobj) { //check for some special cases of input number //sieve_log is passed in already open, and should return open if (mpz_even_p(fobj->qs_obj.gmp_n)) { printf("input must be odd\n"); return 1; } if (mpz_probab_prime_p(fobj->qs_obj.gmp_n, NUM_WITNESSES)) { add_to_factor_list(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) logprint(sieve_log,"prp%d = %s\n", gmp_base10(fobj->qs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->qs_obj.gmp_n)); mpz_set_ui(fobj->qs_obj.gmp_n,1); return 1; } if (mpz_perfect_square_p(fobj->qs_obj.gmp_n)) { mpz_sqrt(fobj->qs_obj.gmp_n,fobj->qs_obj.gmp_n); add_to_factor_list(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) logprint(sieve_log,"prp%d = %s\n",gmp_base10(fobj->qs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->qs_obj.gmp_n)); add_to_factor_list(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) logprint(sieve_log,"prp%d = %s\n",gmp_base10(fobj->qs_obj.gmp_n), mpz_conv2str(&gstr1.s, 10, fobj->qs_obj.gmp_n)); mpz_set_ui(fobj->qs_obj.gmp_n,1); return 1; } if (mpz_perfect_power_p(fobj->qs_obj.gmp_n)) { if (VFLAG > 0) printf("input is a perfect power\n"); factor_perfect_power(fobj, fobj->qs_obj.gmp_n); if (sieve_log != NULL) { uint32 j; logprint(sieve_log,"input is a perfect power\n"); for (j=0; j<fobj->num_factors; j++) { uint32 k; for (k=0; k<fobj->fobj_factors[j].count; k++) { logprint(sieve_log,"prp%d = %s\n",gmp_base10(fobj->fobj_factors[j].factor), mpz_conv2str(&gstr1.s, 10, fobj->fobj_factors[j].factor)); } } } return 1; } if (mpz_sizeinbase(fobj->qs_obj.gmp_n,2) < 115) { //run MPQS, as SIQS doesn't work for smaller inputs //MPQS will take over the log file, so close it now. int i; // we've verified that the input is not odd or prime. also // do some very quick trial division before calling smallmpqs, which // does none of these things. for (i=1; i<25; i++) { if (mpz_tdiv_ui(fobj->qs_obj.gmp_n, spSOEprimes[i]) == 0) mpz_tdiv_q_ui(fobj->qs_obj.gmp_n, fobj->qs_obj.gmp_n, spSOEprimes[i]); } smallmpqs(fobj); return 1; //tells SIQS to not try to close the logfile } if (gmp_base10(fobj->qs_obj.gmp_n) > 140) { printf("input too big for SIQS\n"); return 1; } return 0; }

static PyObject * obf_encode_circuit(PyObject *self, PyObject *args) { PyObject *py_state, *py_ys, *py_xdegs; mpz_t tmp, c_star; mpz_t *alphas, *betas; int n, m, ydeg; int *indices, *pows; char *circuit, *fname; int fnamelen = sizeof(int) + 5; int idx_set_size; struct state *s; if (!PyArg_ParseTuple(args, "OsOOiii", &py_state, &circuit, &py_ys, &py_xdegs, &ydeg, &n,&m)){ fprintf(stderr,"!!!!!!!! NOT PARSING !!!!!!!!!!!!!!!!\n"); return NULL;} s = (struct state *) PyCapsule_GetPointer(py_state, NULL); if (s == NULL) return NULL; fname = (char *) malloc(sizeof(char) * fnamelen); if (fname == NULL) return NULL; int ierr,rank,world_size; ierr = MPI_Comm_rank ( MPI_COMM_WORLD, &rank ); ierr = MPI_Comm_size(MPI_COMM_WORLD,&world_size); struct clt_mlm_ser_enc* sent_mlm = stat_ser(&(s->mlm)); //broadcast_clt_mlm_ser_enc(sent_mlm); ser_stat( sent_mlm,&(s->mlm) ); mpz_init_set(s->nev, s->mlm.gs[0]); mpz_init_set(s->nchk, s->mlm.gs[1]); mpz_inits(c_star, tmp, NULL); rank = 0; world_size =1; int start_n_loop = rank*n/world_size; int stop_n_loop = (rank+1)*n/world_size; //int size_n_loop = start_n_loop - stop_n_loop; int start_m_loop = rank*m/world_size; int stop_m_loop = (rank+1)*m/world_size; //int size_m_loop = start_m_loop; alphas = (mpz_t *) malloc(sizeof(mpz_t) * n); #pragma omp parallel for for (int i = 0; i < n; ++i) { mpz_init(alphas[i]); mpz_urandomm(alphas[i], s->mlm.rng, s->nchk); } betas = (mpz_t *) malloc(sizeof(mpz_t) * m); #pragma omp parallel for for (int i = 0; i < m; ++i) { mpz_init(betas[i]); mpz_urandomm(betas[i], s->mlm.rng, s->nchk); } std::vector<std::vector<char> > alpha_send = mpz_arr_to_vec(alphas, n); std::vector<std::vector<char> > beta_send = mpz_arr_to_vec(betas, m); //broadcast_vec_vec(&alpha_send); //broadcast_vec_vec(&beta_send); vec_to_mpz_array(alphas,alpha_send); vec_to_mpz_array(betas,beta_send); fprintf(stderr,"Process %d has g[0] = %lu\n",rank,mpz_get_ui(s->mlm.gs[0])); fprintf(stderr,"Process %d has pzt = %lu\n",rank,mpz_get_ui(s->mlm.pzt)); fprintf(stderr,"Process %d has alpha = %lu\n",rank,mpz_get_ui(alphas[2])); // The index set is laid out as follows: // - The first 2 * n entries contain X_i,0 and X_i,1 // - The next n entries contain Z_i // - The next n entries contain W_i // - The final entry contains Y idx_set_size = 4 * n + 1; indices = (int *) malloc(sizeof(int) * idx_set_size); pows = (int *) malloc(sizeof(int) * idx_set_size); //MR fprintf(stderr, "m: %d , n: %d \n ", m,n); for (int i = start_n_loop; i <stop_n_loop ; ++i) { fprintf(stderr,"In loop: %d\n",i); mpz_t out, elems[2]; int deg; mpz_inits(out, elems[0], elems[1], NULL); deg = PyLong_AsLong(PyList_GET_ITEM(py_xdegs, i)); //MR //fprintf(stderr, "%d, " ,deg); set_indices_pows(indices, pows, 1, 2 * i, 1); mpz_set_ui(elems[0], 0); mpz_set(elems[1], alphas[i]); clt_mlm_encode(&s->mlm, out, 2, elems, 1, indices, pows); (void) snprintf(fname, fnamelen, "x_%d_0", i); (void) write_element(s->dir, out, fname); fprintf(stderr,"Past 1st encode In loop: %d\n",i); set_indices_pows(indices, pows, 1, 2 * i, 1); mpz_set_ui(elems[0], 1); mpz_set_ui(elems[1], 1); clt_mlm_encode(&s->mlm, out, 2, elems, 1, indices, pows); (void) snprintf(fname, fnamelen, "u_%d_0", i); (void) write_element(s->dir, out, fname); set_indices_pows(indices, pows, 1, 2 * i + 1, 1); mpz_set_ui(elems[0], 1); mpz_set(elems[1], alphas[i]); clt_mlm_encode(&s->mlm, out, 2, elems, 1, indices, pows); fprintf(stderr,"Past Third encode In loop: %d\n",i); (void) snprintf(fname, fnamelen, "x_%d_1", i); (void) write_element(s->dir, out, fname); set_indices_pows(indices, pows, 1, 2 * i + 1, 1); mpz_set_ui(elems[0], 1); mpz_set_ui(elems[1], 1); clt_mlm_encode(&s->mlm, out, 2, elems, 1, indices, pows); (void) snprintf(fname, fnamelen, "u_%d_1", i); (void) write_element(s->dir, out, fname); mpz_urandomm(elems[0], s->mlm.rng, s->nev); mpz_urandomm(elems[1], s->mlm.rng, s->nchk); set_indices_pows(indices, pows, 3, 2 * i + 1, deg, 2 * n + i, 1, 3 * n + i, 1); clt_mlm_encode(&s->mlm, out, 2, elems, 3, indices, pows); (void) snprintf(fname, fnamelen, "z_%d_0", i); (void) write_element(s->dir, out, fname); set_indices_pows(indices, pows, 1, 3 * n + i, 1); mpz_set_ui(elems[0], 0); clt_mlm_encode(&s->mlm, out, 2, elems, 1, indices, pows); (void) snprintf(fname, fnamelen, "w_%d_0", i); (void) write_element(s->dir, out, fname); mpz_urandomm(elems[0], s->mlm.rng, s->nev); mpz_urandomm(elems[1], s->mlm.rng, s->nchk); set_indices_pows(indices, pows, 3, 2 * i, deg, 2 * n + i, 1, 3 * n + i, 1); clt_mlm_encode(&s->mlm, out, 2, elems, 3, indices, pows); (void) snprintf(fname, fnamelen, "z_%d_1", i); (void) write_element(s->dir, out, fname); set_indices_pows(indices, pows, 1, 3 * n + i, 1); mpz_set_ui(elems[0], 0); clt_mlm_encode(&s->mlm, out, 2, elems, 1, indices, pows); (void) snprintf(fname, fnamelen, "w_%d_1", i); (void) write_element(s->dir, out, fname); mpz_clears(out, elems[0], elems[1], NULL); } set_indices_pows(indices, pows, 1, 4 * n, 1); for (int i = start_m_loop; i < stop_m_loop; ++i) { mpz_t out, elems[2]; mpz_inits(out, elems[0], elems[1], NULL); py_to_mpz(elems[0], PyList_GET_ITEM(py_ys, i)); if (mpz_sgn(elems[0]) == -1) { mpz_mod(elems[0], elems[0], s->nev); } mpz_set(elems[1], betas[i]); clt_mlm_encode(&s->mlm, out, 2, elems, 1, indices, pows); (void) snprintf(fname, fnamelen, "y_%d", i); (void) write_element(s->dir, out, fname); mpz_clears(out, elems[0], elems[1], NULL); } if(rank==0) { mpz_t elems[2]; mpz_init_set_ui(elems[0], 1); mpz_init_set_ui(elems[1], 1); clt_mlm_encode(&s->mlm, tmp, 2, elems, 1, indices, pows); (void) write_element(s->dir, tmp, "v"); mpz_clears(elems[0], elems[1], NULL); } if(rank==0){ struct circuit *c; c = circ_parse(circuit); { int circnamelen; char *circname; circnamelen = strlen(s->dir) + strlen("/circuit") + 2; circname = (char *) malloc(sizeof(char) * circnamelen); (void) snprintf(circname, circnamelen, "%s/circuit", s->dir); (void) circ_copy_circuit(circuit, circname); free(circname); } (void) circ_evaluate(c, alphas, betas, c_star, s->mlm.q); circ_cleanup(c); } //GET ALPHAS AND BETAS BACK TO ROOT! Maybe with a gather? if(rank==0){ { mpz_t elems[2]; // The C* encoding contains everything but the W_i symbols. // Here we calculate the appropriate indices and powers. for (int i = 0; i < n; ++i) { int deg; deg = PyLong_AsLong(PyList_GET_ITEM(py_xdegs, i)); // X_i,0^deg(x_i) indices[2 * i] = 2 * i; pows[2 * i] = deg; // X_i,1^deg(x_i) indices[2 * i + 1] = 2 * i + 1; pows[2 * i + 1] = deg; // Z_i indices[2 * n + i] = 2 * n + i; pows[2 * n + i] = 1; } // Y^deg(y) indices[3 * n] = 4 * n; pows[3 * n] = ydeg; // Encode against these indices/powers mpz_init_set_ui(elems[0], 0); mpz_init_set(elems[1], c_star); clt_mlm_encode(&s->mlm, tmp, 2, elems, 3 * n + 1, indices, pows); } (void) write_element(s->dir, tmp, "c_star"); } mpz_clears(c_star, tmp, NULL); fprintf(stderr,"QSIZE= %d\n",(mpz_sizeinbase(s->mlm.q, 2))); fprintf(stderr,"Process %d has finished its encoding work!\n",rank); MPI_Barrier(MPI_COMM_WORLD); Py_RETURN_NONE; }

int main (void) { FILE *out32 = fopen ("fpioconst-32", "w"); if (out32 == NULL) abort (); FILE *out64 = fopen ("fpioconst-64", "w"); if (out64 == NULL) abort (); FILE *outtable = fopen ("fpioconst-table", "w"); if (outtable == NULL) abort (); mpz_t p; mpz_init (p); for (int i = 0; i <= 14; i++) { int j = 1 << i; mpz_ui_pow_ui (p, 10, j - 1); int exp_m = mpz_sizeinbase (p, 2); mpz_ui_pow_ui (p, 10, j); int exp_p = mpz_sizeinbase (p, 2); int size32 = 2 + (exp_p + 31) / 32; int size64 = 1 + (exp_p + 63) / 64; uint32_t data32[size32]; uint64_t data64[size64]; memset (data32, 0, sizeof data32); memset (data64, 0, sizeof data64); mpz_export (data32 + 2, NULL, -1, 4, 0, 0, p); mpz_export (data64 + 1, NULL, -1, 8, 0, 0, p); if (i == 0) { fprintf (out32, "#define TENS_P%d_IDX\t0\n", i); fprintf (out64, "#define TENS_P%d_IDX\t0\n", i); } else { fprintf (out32, "#define TENS_P%d_IDX\t" "(TENS_P%d_IDX + TENS_P%d_SIZE)\n", i, i - 1, i - 1); fprintf (out64, "#define TENS_P%d_IDX\t" "(TENS_P%d_IDX + TENS_P%d_SIZE)\n", i, i - 1, i - 1); } fprintf (out32, "#define TENS_P%d_SIZE\t%d\n", i, size32); fprintf (out64, "#define TENS_P%d_SIZE\t%d\n", i, size64); for (int k = 0; k < size32; k++) { if (k == 0) fprintf (out32, " [TENS_P%d_IDX] = ", i); else if (k % 6 == 5) fprintf (out32, "\n "); else fprintf (out32, " "); fprintf (out32, "0x%08"PRIx32",", data32[k]); } for (int k = 0; k < size64; k++) { if (k == 0) fprintf (out64, " [TENS_P%d_IDX] = ", i); else if (k % 3 == 2) fprintf (out64, "\n "); else fprintf (out64, " "); fprintf (out64, "0x%016"PRIx64"ull,", data64[k]); } fprintf (out32, "\n\n"); fprintf (out64, "\n\n"); const char *t = (i >= 10 ? "\t" : "\t\t"); if (i == 0) fprintf (outtable, " { TENS_P%d_IDX, TENS_P%d_SIZE,%s%d,\t },\n", i, i, t, exp_p); else fprintf (outtable, " { TENS_P%d_IDX, TENS_P%d_SIZE,%s%d,\t%5d },\n", i, i, t, exp_p, exp_m); } if (fclose (out32) != 0) abort (); if (fclose (out64) != 0) abort (); if (fclose (outtable) != 0) abort (); return 0; }

int main() { unsigned int i,j,a,*SV; unsigned char logpi; int k,S,r,s1,s2,s,NS,logm,ptr,threshold,epri; long M,la,lptr; qsieve=gmpinit(-36,0); if(initv()<0) return 0; hmod=2*mlf+1; mpz_set_si(TA, hmod); while(!mpz_probab_prime_p(TA, qsieve->NTRY)) mpz_sub_ui(TA, TA, 2); //TT=不大于TT的素数 hmod=qsieve_getsize(TA); hmod2=hmod-2; for(k=0;k<hmod;k++) hash[k]=(-1); M=50*(long)mm; NS=(int)(M/SSIZE); if(M%SSIZE!=0) NS++; M=SSIZE*(long)NS; // M为不小于50*mm的SSIZE的倍数中最小的 from 以上四行 logm=0; la=M; while((la/=2)>0) logm++; // 以2为底 rp[0]=logp[0]=0; for(k=1;k<=mm;k++) //求k*N在每个素数下的二次剩余解，与每个素数的ln(pi) { r=mpz_tdiv_q_ui(TA, D, epr[k]); rp[k]=qsieve_sqrmp(r,epr[k]); logp[k]=0; r=epr[k]; while((r/=2)>0) logp[k]++; } r=mpz_tdiv_q_ui(TA, D, 8); if(r==5) logp[1]++; if(r==1) logp[1]+=2; threshold=logm+mpz_sizeinbase(R, 2)-2*logp[mm]; jj=0; nlp=0; mpz_mul_si(DG, D, 2); mpz_root(DG, DG, 2); mpz_set_si(TA, M); qsieve_divide(DG,TA,DG); mpz_root(DG, DG, 2); if(mpz_tdiv_q_ui(TA, DG, 2)==0) mpz_add_ui(DG, DG, 1); if(mpz_tdiv_q_ui(TA, DG, 4)==1) mpz_add_ui(DG, DG, 2); // 令DG等于大于等于DG的数中模4余3的最小的数 printf(" 0%"); while(1) //不断尝试新的多项式，可以并行计算 { r=qsieve->NTRY; qsieve->NTRY=1; do { do { mpz_add_ui(DG, DG, 4); } while(!(mpz_probab_prime_p(DG, qsieve->NTRY) ? TRUE : FALSE)); mpz_sub_ui(TA, DG, 1); mpz_tdiv_q_ui(TA, TA, 2); mpz_powm_sec(TA, D, TA, DG); } while(qsieve_getsize(TA)!=1); //直到DD是二次剩余 qsieve->NTRY=r; mpz_add_ui(TA, DG, 1); mpz_tdiv_q_ui(TA, TA, 4); mpz_powm_sec(B, D, TA, DG); mpz_neg(TA, D); qsieve_muladddiv(B,B,TA,DG,TA,TA); mpz_neg(TA, TA); mpz_mul_si(A, B, 2); qsieve_extgcd(A,DG,A,A,A); qsieve_muladddiv(A,TA,TA,DG,DG,A); mpz_mul(TA, A, DG); mpz_add(B, B, TA); mpz_mul(A, DG, DG); qsieve_extgcd(DG,D,IG,IG,IG); r1[0]=r2[0]=0; for(k=1;k<=mm;k++) //s1和s2是两个解 { s=mpz_tdiv_q_ui(TA, B, epr[k]); r=mpz_tdiv_q_ui(TA, A, epr[k]); r=qsieve_getinvers(r,epr[k]); s1=(epr[k]-s+rp[k]); s2=(epr[k]-s+epr[k]-rp[k]); if(s1 > s2) { int t = s1; s1 = s2; s2 = t; } r1[k]=(int)((((long long)s1)*((long long)r)) % ((long long)epr[k])); r2[k]=(int)((((long long)s2)*((long long)r)) % ((long long)epr[k])); } for(ptr=(-NS);ptr<NS;ptr++) { la=(long)ptr*SSIZE; SV=(unsigned int *)sieve; for(i=0; i<SSIZE/sizeof(int); i++) *SV++=0; for(k=1; k<=mm; k++) { epri=epr[k]; logpi=logp[k]; r=(int)(la%epri); s1=(r1[k]-r)%epri; if(s1<0) s1+=epri; s2=(r2[k]-r)%epri; if(s2<0) s2+=epri; /* 这部分是筛法的主要部分，数组下标表示多项式P(x)的参数x s1与s2是两个P(x)=0(mod p)的解 */ for(j=s1;j<SSIZE;j+=epri) sieve[j]+=logpi; if(s1==s2) continue; for(j=s2;j<SSIZE;j+=epri) sieve[j]+=logpi; } for(a=0;a<SSIZE;a++) //找那些没有被筛掉的数 { if(sieve[a]<threshold) continue; lptr=la+a; mpz_set_si(TA, lptr); S=0; mpz_mul(TA, A, TA); mpz_add(TA, TA, B); qsieve_muladddiv(TA,IG,TA,D,D,P); if(qsieve_getsize(P)<0) mpz_add(P, P, D); qsieve_muladddiv(P,P,P,D,D,V); mpz_abs(TA, TA); if(qsieve_compare(TA,R)<0) S=1; if(S==1) mpz_sub(V, D, V); if(V!=TA) mpz_set(TA, V); e[0]=S; for(k=1;k<=mm;k++) e[k]=0; if(!factored(lptr,TA)) continue; if(gotcha()) { mpz_gcd(P, TA, N); qsieve_getsize(P); printf("\b\b\b\b100%\nFactors are\n"); qsieve_outnum(P,stdout); qsieve_divide(N,P,N); qsieve_outnum(N,stdout); return 0; } } } } return 0; }

TYPE SCM_TO_TYPE_PROTO (SCM val) { if (SCM_I_INUMP (val)) { scm_t_signed_bits n = SCM_I_INUM (val); #if SIZEOF_TYPE != 0 && SIZEOF_TYPE > SIZEOF_SCM_T_BITS return n; #else if (n >= TYPE_MIN && n <= TYPE_MAX) return n; else { goto out_of_range; } #endif } else if (SCM_BIGP (val)) { if (TYPE_MIN >= SCM_MOST_NEGATIVE_FIXNUM && TYPE_MAX <= SCM_MOST_POSITIVE_FIXNUM) goto out_of_range; else if (TYPE_MIN >= LONG_MIN && TYPE_MAX <= LONG_MAX) { if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val))) { long n = mpz_get_si (SCM_I_BIG_MPZ (val)); #if SIZEOF_TYPE != 0 && SIZEOF_TYPE > SCM_SIZEOF_LONG return n; #else if (n >= TYPE_MIN && n <= TYPE_MAX) return n; else goto out_of_range; #endif } else goto out_of_range; } else { scm_t_intmax n; size_t count; if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2) > CHAR_BIT*sizeof (scm_t_uintmax)) goto out_of_range; mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0, SCM_I_BIG_MPZ (val)); if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0) { if (n < 0) goto out_of_range; } else { n = -n; if (n >= 0) goto out_of_range; } if (n >= TYPE_MIN && n <= TYPE_MAX) return n; else { out_of_range: scm_i_range_error (val, scm_from_signed_integer (TYPE_MIN), scm_from_signed_integer (TYPE_MAX)); return 0; } } } else { scm_wrong_type_arg_msg (NULL, 0, val, "exact integer"); return 0; } }

int scanhash_m7hash(int thr_id, uint32_t *pdata, const uint32_t *ptarget, uint64_t max_nonce, unsigned long *hashes_done) { uint32_t data[32] __attribute__((aligned(128))); uint32_t *data_p64 = data + (M7_MIDSTATE_LEN / sizeof(data[0])); uint32_t hash[8] __attribute__((aligned(32))); uint8_t bhash[7][64] __attribute__((aligned(32))); uint32_t hashtest[8] __attribute__((aligned(32))); uint32_t n = pdata[29] - 1; const uint32_t first_nonce = pdata[29]; char data_str[245], hash_str[65], target_str[65]; uint8_t *bdata = 0; mpz_t bns[7]; int rc = 0; for(int i=0; i < 7; i++){ mpz_init(bns[i]); } memcpy(data, pdata, 122); sph_sha256_context ctx_final_sha256; sph_sha256_context ctx_sha256; sph_sha512_context ctx_sha512; sph_keccak512_context ctx_keccak; sph_whirlpool_context ctx_whirlpool; sph_haval256_5_context ctx_haval; sph_tiger_context ctx_tiger; sph_ripemd160_context ctx_ripemd; sph_sha256_init(&ctx_sha256); sph_sha256 (&ctx_sha256, data, M7_MIDSTATE_LEN); sph_sha512_init(&ctx_sha512); sph_sha512 (&ctx_sha512, data, M7_MIDSTATE_LEN); sph_keccak512_init(&ctx_keccak); sph_keccak512 (&ctx_keccak, data, M7_MIDSTATE_LEN); sph_whirlpool_init(&ctx_whirlpool); sph_whirlpool (&ctx_whirlpool, data, M7_MIDSTATE_LEN); sph_haval256_5_init(&ctx_haval); sph_haval256_5 (&ctx_haval, data, M7_MIDSTATE_LEN); sph_tiger_init(&ctx_tiger); sph_tiger (&ctx_tiger, data, M7_MIDSTATE_LEN); sph_ripemd160_init(&ctx_ripemd); sph_ripemd160 (&ctx_ripemd, data, M7_MIDSTATE_LEN); sph_sha256_context ctx2_sha256; sph_sha512_context ctx2_sha512; sph_keccak512_context ctx2_keccak; sph_whirlpool_context ctx2_whirlpool; sph_haval256_5_context ctx2_haval; sph_tiger_context ctx2_tiger; sph_ripemd160_context ctx2_ripemd; do { data[29] = ++n; memset(bhash, 0, 7 * 64); ctx2_sha256 = ctx_sha256; sph_sha256 (&ctx2_sha256, data_p64, 122 - M7_MIDSTATE_LEN); sph_sha256_close(&ctx2_sha256, (void*)(bhash[0])); ctx2_sha512 = ctx_sha512; sph_sha512 (&ctx2_sha512, data_p64, 122 - M7_MIDSTATE_LEN); sph_sha512_close(&ctx2_sha512, (void*)(bhash[1])); ctx2_keccak = ctx_keccak; sph_keccak512 (&ctx2_keccak, data_p64, 122 - M7_MIDSTATE_LEN); sph_keccak512_close(&ctx2_keccak, (void*)(bhash[2])); ctx2_whirlpool = ctx_whirlpool; sph_whirlpool (&ctx2_whirlpool, data_p64, 122 - M7_MIDSTATE_LEN); sph_whirlpool_close(&ctx2_whirlpool, (void*)(bhash[3])); ctx2_haval = ctx_haval; sph_haval256_5 (&ctx2_haval, data_p64, 122 - M7_MIDSTATE_LEN); sph_haval256_5_close(&ctx2_haval, (void*)(bhash[4])); ctx2_tiger = ctx_tiger; sph_tiger (&ctx2_tiger, data_p64, 122 - M7_MIDSTATE_LEN); sph_tiger_close(&ctx2_tiger, (void*)(bhash[5])); ctx2_ripemd = ctx_ripemd; sph_ripemd160 (&ctx2_ripemd, data_p64, 122 - M7_MIDSTATE_LEN); sph_ripemd160_close(&ctx2_ripemd, (void*)(bhash[6])); for(int i=0; i < 7; i++){ set_one_if_zero(bhash[i]); mpz_set_uint512(bns[i],bhash[i]); } for(int i=6; i > 0; i--){ mpz_mul(bns[i-1], bns[i-1], bns[i]); } int bytes = mpz_sizeinbase(bns[0], 256); bdata = (uint8_t *)realloc(bdata, bytes); mpz_export((void *)bdata, NULL, -1, 1, 0, 0, bns[0]); sph_sha256_init(&ctx_final_sha256); sph_sha256 (&ctx_final_sha256, bdata, bytes); sph_sha256_close(&ctx_final_sha256, (void*)(hash)); rc = fulltest_m7hash(hash, ptarget); if (rc) { if (opt_debug) { bin2hex(hash_str, (unsigned char *)hash, 32); bin2hex(target_str, (unsigned char *)ptarget, 32); bin2hex(data_str, (unsigned char *)data, 122); applog(LOG_DEBUG, "DEBUG: [%d thread] Found share!\ndata %s\nhash %s\ntarget %s", thr_id, data_str, hash_str, target_str); } pdata[29] = data[29]; goto out; } } while (n < max_nonce && !work_restart[thr_id].restart); pdata[29] = n; out: for(int i=0; i < 7; i++){ mpz_clear(bns[i]); } *hashes_done = n - first_nonce + 1; free(bdata); return rc; }

void factor_perfect_power(fact_obj_t *fobj, mpz_t b) { // check if (b^1/i)^i == b for i = 2 to bitlen(b) uint32 bits = mpz_sizeinbase(b,2); uint32 i; FILE *flog; mpz_t base, ans; mpz_init(base); mpz_init(ans); //open the log file flog = fopen(fobj->flogname,"a"); if (flog == NULL) { printf("fopen error: %s\n", strerror(errno)); printf("could not open %s for writing\n",fobj->flogname); return; } for (i=2; i<bits; i++) { mpz_root(base, b, i); mpz_pow_ui(ans, base, i); if (mpz_cmp(ans, b) == 0) { // found a base. if (is_mpz_prp(base)) { uint32 j; //gmp_printf("\nAdding prime base %Zd to factor list...\n", base); for (j=0; j<i; j++) { add_to_factor_list(fobj, base); mpz_tdiv_q(b, b, base); logprint(flog,"prp%d = %s\n", gmp_base10(base), mpz_conv2str(&gstr1.s, 10, base)); } } else { // if composite, factor it and then multiply // all factors by i (the exponent). fact_obj_t *fobj_refactor; uint32 j; gmp_printf("\nFactoring composite base %Zd...\n", base); // load the new fobj with this number fobj_refactor = (fact_obj_t *)malloc(sizeof(fact_obj_t)); init_factobj(fobj_refactor); mpz_set(fobj_refactor->N, base); // recurse on factor factor(fobj_refactor); // add all factors found during the refactorization for (j=0; j< fobj_refactor->num_factors; j++) { int k, c; //gmp_printf("\nAdding prime base %Zd to factor list...\n", // fobj_refactor->fobj_factors[j].factor); for (k=0; k < fobj_refactor->fobj_factors[j].count; k++) { // add i copies of it, since this was a perfect power for (c = 0; c < i; c++) { add_to_factor_list(fobj, fobj_refactor->fobj_factors[j].factor); mpz_tdiv_q(b, b, fobj_refactor->fobj_factors[j].factor); logprint(flog,"prp%d = %s\n", gmp_base10(fobj_refactor->fobj_factors[j].factor), mpz_conv2str(&gstr1.s, 10, fobj_refactor->fobj_factors[j].factor)); } } } // free temps free_factobj(fobj_refactor); free(fobj_refactor); } break; } } mpz_clear(base); mpz_clear(ans); fclose(flog); return; }

unsigned nettle_mpz_sizeinbase_256_u(const mpz_t x) { return (mpz_sizeinbase(x,2) + 7) / 8; }

inline static int mpz_num_bytes(const mpz_t op) { return (mpz_sizeinbase(op, 2) + 7) / 8; }

static int count_bits(void *a) { LTC_ARGCHK(a != NULL); return mpz_sizeinbase(a, 2); }

int rsa_generate_keypair(struct rsa_public_key *pub, struct rsa_private_key *key, void *random_ctx, nettle_random_func *random, void *progress_ctx, nettle_progress_func *progress, unsigned n_size, unsigned e_size) { mpz_t p1; mpz_t q1; mpz_t phi; mpz_t tmp; if (e_size) { /* We should choose e randomly. Is the size reasonable? */ if ((e_size < 16) || (e_size >= n_size) ) return 0; } else { /* We have a fixed e. Check that it makes sense */ /* It must be odd */ if (!mpz_tstbit(pub->e, 0)) return 0; /* And 3 or larger */ if (mpz_cmp_ui(pub->e, 3) < 0) return 0; /* And size less than n */ if (mpz_sizeinbase(pub->e, 2) >= n_size) return 0; } if (n_size < RSA_MINIMUM_N_BITS) return 0; mpz_init(p1); mpz_init(q1); mpz_init(phi); mpz_init(tmp); /* Generate primes */ for (;;) { /* Generate p, such that gcd(p-1, e) = 1 */ for (;;) { nettle_random_prime(key->p, (n_size+1)/2, 1, random_ctx, random, progress_ctx, progress); mpz_sub_ui(p1, key->p, 1); /* If e was given, we must chose p such that p-1 has no factors in * common with e. */ if (e_size) break; mpz_gcd(tmp, pub->e, p1); if (mpz_cmp_ui(tmp, 1) == 0) break; else if (progress) progress(progress_ctx, 'c'); } if (progress) progress(progress_ctx, '\n'); /* Generate q, such that gcd(q-1, e) = 1 */ for (;;) { nettle_random_prime(key->q, n_size/2, 1, random_ctx, random, progress_ctx, progress); /* Very unlikely. */ if (mpz_cmp (key->q, key->p) == 0) continue; mpz_sub_ui(q1, key->q, 1); /* If e was given, we must chose q such that q-1 has no factors in * common with e. */ if (e_size) break; mpz_gcd(tmp, pub->e, q1); if (mpz_cmp_ui(tmp, 1) == 0) break; else if (progress) progress(progress_ctx, 'c'); } /* Now we have the primes. Is the product of the right size? */ mpz_mul(pub->n, key->p, key->q); assert (mpz_sizeinbase(pub->n, 2) == n_size); if (progress) progress(progress_ctx, '\n'); /* c = q^{-1} (mod p) */ if (mpz_invert(key->c, key->q, key->p)) /* This should succeed everytime. But if it doesn't, * we try again. */ break; else if (progress) progress(progress_ctx, '?'); } mpz_mul(phi, p1, q1); /* If we didn't have a given e, generate one now. */ if (e_size) { int retried = 0; for (;;) { nettle_mpz_random_size(pub->e, random_ctx, random, e_size); /* Make sure it's odd and that the most significant bit is * set */ mpz_setbit(pub->e, 0); mpz_setbit(pub->e, e_size - 1); /* Needs gmp-3, or inverse might be negative. */ if (mpz_invert(key->d, pub->e, phi)) break; if (progress) progress(progress_ctx, 'e'); retried = 1; } if (retried && progress) progress(progress_ctx, '\n'); } else { /* Must always succeed, as we already that e * doesn't have any common factor with p-1 or q-1. */ int res = mpz_invert(key->d, pub->e, phi); assert(res); } /* Done! Almost, we must compute the auxillary private values. */ /* a = d % (p-1) */ mpz_fdiv_r(key->a, key->d, p1); /* b = d % (q-1) */ mpz_fdiv_r(key->b, key->d, q1); /* c was computed earlier */ pub->size = key->size = (n_size + 7) / 8; assert(pub->size >= RSA_MINIMUM_N_OCTETS); mpz_clear(p1); mpz_clear(q1); mpz_clear(phi); mpz_clear(tmp); return 1; }

void generate_mod (int limb_bits, int nail_bits) { int numb_bits = limb_bits - nail_bits; int i, divisor; mpz_init_set_ui (pp, 0L); mpz_init_set_ui (pp_norm, 0L); mpz_init_set_ui (pp_inverted, 0L); /* no more than limb_bits many factors in a one limb modulus (and of course in reality nothing like that many) */ factor_alloc = limb_bits; factor = xmalloc (factor_alloc * sizeof (*factor)); rawfactor = xmalloc (factor_alloc * sizeof (*rawfactor)); if (numb_bits % 4 != 0) { strcpy (mod34_excuse, "GMP_NUMB_BITS % 4 != 0"); goto use_pp; } max_divisor = 2*limb_bits; max_divisor_bits = log2_ceil (max_divisor); if (numb_bits / 4 < max_divisor_bits) { /* Wind back to one limb worth of max_divisor, if that will let us use mpn_mod_34lsub1. */ max_divisor = limb_bits; max_divisor_bits = log2_ceil (max_divisor); if (numb_bits / 4 < max_divisor_bits) { strcpy (mod34_excuse, "GMP_NUMB_BITS / 4 too small"); goto use_pp; } } { /* Can use mpn_mod_34lsub1, find small factors of 2^mod34_bits-1. */ mpz_t m, q, r; int multiplicity; mod34_bits = (numb_bits / 4) * 3; /* mpn_mod_34lsub1 returns a full limb value, PERFSQR_MOD_34 folds it at the mod34_bits mark, adding the two halves for a remainder of at most mod34_bits+1 many bits */ mod_bits = mod34_bits + 1; mpz_init_set_ui (m, 1L); mpz_mul_2exp (m, m, mod34_bits); mpz_sub_ui (m, m, 1L); mpz_init (q); mpz_init (r); for (i = 3; i <= max_divisor; i++) { if (! isprime (i)) continue; mpz_tdiv_qr_ui (q, r, m, (unsigned long) i); if (mpz_sgn (r) != 0) continue; /* if a repeated prime is found it's used as an i^n in one factor */ divisor = 1; multiplicity = 0; do { if (divisor > max_divisor / i) break; multiplicity++; mpz_set (m, q); mpz_tdiv_qr_ui (q, r, m, (unsigned long) i); } while (mpz_sgn (r) == 0); assert (nrawfactor < factor_alloc); rawfactor[nrawfactor].divisor = i; rawfactor[nrawfactor].multiplicity = multiplicity; nrawfactor++; } mpz_clear (m); mpz_clear (q); mpz_clear (r); } if (nrawfactor <= 2) { mpz_t new_pp; sprintf (mod34_excuse, "only %d small factor%s", nrawfactor, nrawfactor == 1 ? "" : "s"); use_pp: /* reset to two limbs of max_divisor, in case the mpn_mod_34lsub1 code tried with just one */ max_divisor = 2*limb_bits; max_divisor_bits = log2_ceil (max_divisor); mpz_init (new_pp); nrawfactor = 0; mod_bits = MIN (numb_bits, limb_bits - max_divisor_bits); /* one copy of each small prime */ mpz_set_ui (pp, 1L); for (i = 3; i <= max_divisor; i++) { if (! isprime (i)) continue; mpz_mul_ui (new_pp, pp, (unsigned long) i); if (mpz_sizeinbase (new_pp, 2) > mod_bits) break; mpz_set (pp, new_pp); assert (nrawfactor < factor_alloc); rawfactor[nrawfactor].divisor = i; rawfactor[nrawfactor].multiplicity = 1; nrawfactor++; } /* Plus an extra copy of one or more of the primes selected, if that still fits in max_divisor and the total in mod_bits. Usually only 3 or 5 will be candidates */ for (i = nrawfactor-1; i >= 0; i--) { if (rawfactor[i].divisor > max_divisor / rawfactor[i].divisor) continue; mpz_mul_ui (new_pp, pp, (unsigned long) rawfactor[i].divisor); if (mpz_sizeinbase (new_pp, 2) > mod_bits) continue; mpz_set (pp, new_pp); rawfactor[i].multiplicity++; } mod_bits = mpz_sizeinbase (pp, 2); mpz_set (pp_norm, pp); while (mpz_sizeinbase (pp_norm, 2) < numb_bits) mpz_add (pp_norm, pp_norm, pp_norm); mpz_preinv_invert (pp_inverted, pp_norm, numb_bits); mpz_clear (new_pp); } /* start the factor array */ for (i = 0; i < nrawfactor; i++) { int j; assert (nfactor < factor_alloc); factor[nfactor].divisor = 1; for (j = 0; j < rawfactor[i].multiplicity; j++) factor[nfactor].divisor *= rawfactor[i].divisor; nfactor++; } combine: /* Combine entries in the factor array. Combine the smallest entry with the biggest one that will fit with it (ie. under max_divisor), then repeat that with the new smallest entry. */ qsort (factor, nfactor, sizeof (factor[0]), f_cmp_divisor); for (i = nfactor-1; i >= 1; i--) { if (factor[i].divisor <= max_divisor / factor[0].divisor) { factor[0].divisor *= factor[i].divisor; COLLAPSE_ELEMENT (factor, i, nfactor); goto combine; } } total_fraction = 1.0; for (i = 0; i < nfactor; i++) { mpz_init (factor[i].inverse); mpz_invert_ui_2exp (factor[i].inverse, (unsigned long) factor[i].divisor, (unsigned long) mod_bits); mpz_init (factor[i].mask); square_mask (factor[i].mask, factor[i].divisor); /* fraction of possible squares */ factor[i].fraction = (double) mpz_popcount (factor[i].mask) / factor[i].divisor; /* total fraction of possible squares */ total_fraction *= factor[i].fraction; } /* best tests first (ie. smallest fraction) */ qsort (factor, nfactor, sizeof (factor[0]), f_cmp_fraction); }

/* If x^y is exactly representable (with maybe a larger precision than z), round it in z and return the (mpc) inexact flag in [0, 10]. If x^y is not exactly representable, return -1. If intermediate computations lead to numbers of more than maxprec bits, then abort and return -2 (in that case, to avoid loops, mpc_pow_exact should be called again with a larger value of maxprec). Assume one of Re(x) or Im(x) is non-zero, and y is non-zero (y is real). */ static int mpc_pow_exact (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd, mp_prec_t maxprec) { mp_exp_t ec, ed, ey, emin, emax; mpz_t my, a, b, c, d, u; unsigned long int t; int ret = -2; mpz_init (my); mpz_init (a); mpz_init (b); mpz_init (c); mpz_init (d); mpz_init (u); ey = mpfr_get_z_exp (my, y); /* normalize so that my is odd */ t = mpz_scan1 (my, 0); ey += t; mpz_tdiv_q_2exp (my, my, t); if (mpfr_zero_p (MPC_RE(x))) { mpz_set_ui (c, 0); ec = 0; } else ec = mpfr_get_z_exp (c, MPC_RE(x)); if (mpfr_zero_p (MPC_IM(x))) { mpz_set_ui (d, 0); ed = ec; } else { ed = mpfr_get_z_exp (d, MPC_IM(x)); if (mpfr_zero_p (MPC_RE(x))) ec = ed; } /* x = c*2^ec + I * d*2^ed */ /* equalize the exponents of x */ if (ec < ed) { mpz_mul_2exp (d, d, ed - ec); if (mpz_sizeinbase (d, 2) > maxprec) goto end; ed = ec; } else if (ed < ec) { mpz_mul_2exp (c, c, ec - ed); if (mpz_sizeinbase (c, 2) > maxprec) goto end; ec = ed; } /* now ec=ed and x = (c + I * d) * 2^ec */ /* divide by two if possible */ if (mpz_cmp_ui (c, 0) == 0) { t = mpz_scan1 (d, 0); mpz_tdiv_q_2exp (d, d, t); ec += t; } else if (mpz_cmp_ui (d, 0) == 0) { t = mpz_scan1 (c, 0); mpz_tdiv_q_2exp (c, c, t); ec += t; } else /* neither c nor d is zero */ { unsigned long v; t = mpz_scan1 (c, 0); v = mpz_scan1 (d, 0); if (v < t) t = v; mpz_tdiv_q_2exp (c, c, t); mpz_tdiv_q_2exp (d, d, t); ec += t; } /* now either one of c, d is odd */ while (ey < 0) { /* check if x is a square */ if (ec & 1) { mpz_mul_2exp (c, c, 1); mpz_mul_2exp (d, d, 1); ec --; } /* now ec is even */ if (mpc_perfect_square_p (a, b, c, d) == 0) break; mpz_swap (a, c); mpz_swap (b, d); ec /= 2; ey ++; } if (ey < 0) { ret = -1; /* not representable */ goto end; } /* Now ey >= 0, it thus suffices to check that x^my is representable. If my > 0, this is always true. If my < 0, we first try to invert (c+I*d)*2^ec. */ if (mpz_cmp_ui (my, 0) < 0) { /* If my < 0, 1 / (c + I*d) = (c - I*d)/(c^2 + d^2), thus a sufficient condition is that c^2 + d^2 is a power of two, assuming |c| <> |d|. Assume a prime p <> 2 divides c^2 + d^2, then if p does not divide c or d, 1 / (c + I*d) cannot be exact. If p divides both c and d, then we can write c = p*c', d = p*d', and 1 / (c + I*d) = 1/p * 1/(c' + I*d'). This shows that if 1/(c+I*d) is exact, then 1/(c' + I*d') is exact too, and we are back to the previous case. In conclusion, a necessary and sufficient condition is that c^2 + d^2 is a power of two. */ /* FIXME: we could first compute c^2+d^2 mod a limb for example */ mpz_mul (a, c, c); mpz_addmul (a, d, d); t = mpz_scan1 (a, 0); if (mpz_sizeinbase (a, 2) != 1 + t) /* a is not a power of two */ { ret = -1; /* not representable */ goto end; } /* replace (c,d) by (c/(c^2+d^2), -d/(c^2+d^2)) */ mpz_neg (d, d); ec = -ec - t; mpz_neg (my, my); } /* now ey >= 0 and my >= 0, and we want to compute [(c + I * d) * 2^ec] ^ (my * 2^ey). We first compute [(c + I * d) * 2^ec]^my, then square ey times. */ t = mpz_sizeinbase (my, 2) - 1; mpz_set (a, c); mpz_set (b, d); ed = ec; /* invariant: (a + I*b) * 2^ed = ((c + I*d) * 2^ec)^trunc(my/2^t) */ while (t-- > 0) { unsigned long v, w; /* square a + I*b */ mpz_mul (u, a, b); mpz_mul (a, a, a); mpz_submul (a, b, b); mpz_mul_2exp (b, u, 1); ed *= 2; if (mpz_tstbit (my, t)) /* multiply by c + I*d */ { mpz_mul (u, a, c); mpz_submul (u, b, d); /* ac-bd */ mpz_mul (b, b, c); mpz_addmul (b, a, d); /* bc+ad */ mpz_swap (a, u); ed += ec; } /* remove powers of two in (a,b) */ if (mpz_cmp_ui (a, 0) == 0) { w = mpz_scan1 (b, 0); mpz_tdiv_q_2exp (b, b, w); ed += w; } else if (mpz_cmp_ui (b, 0) == 0) { w = mpz_scan1 (a, 0); mpz_tdiv_q_2exp (a, a, w); ed += w; } else { w = mpz_scan1 (a, 0); v = mpz_scan1 (b, 0); if (v < w) w = v; mpz_tdiv_q_2exp (a, a, w); mpz_tdiv_q_2exp (b, b, w); ed += w; } if (mpz_sizeinbase (a, 2) > maxprec || mpz_sizeinbase (b, 2) > maxprec) goto end; } /* now a+I*b = (c+I*d)^my */ while (ey-- > 0) { unsigned long sa, sb; /* square a + I*b */ mpz_mul (u, a, b); mpz_mul (a, a, a); mpz_submul (a, b, b); mpz_mul_2exp (b, u, 1); ed *= 2; /* divide by largest 2^n possible, to avoid many loops for e.g., (2+2*I)^16777216 */ sa = mpz_scan1 (a, 0); sb = mpz_scan1 (b, 0); sa = (sa <= sb) ? sa : sb; mpz_tdiv_q_2exp (a, a, sa); mpz_tdiv_q_2exp (b, b, sa); ed += sa; if (mpz_sizeinbase (a, 2) > maxprec || mpz_sizeinbase (b, 2) > maxprec) goto end; } /* save emin, emax */ emin = mpfr_get_emin (); emax = mpfr_get_emax (); mpfr_set_emin (mpfr_get_emin_min ()); mpfr_set_emax (mpfr_get_emax_max ()); ret = mpfr_set_z (MPC_RE(z), a, MPC_RND_RE(rnd)); ret = MPC_INEX(ret, mpfr_set_z (MPC_IM(z), b, MPC_RND_IM(rnd))); mpfr_mul_2si (MPC_RE(z), MPC_RE(z), ed, MPC_RND_RE(rnd)); mpfr_mul_2si (MPC_IM(z), MPC_IM(z), ed, MPC_RND_IM(rnd)); /* restore emin, emax */ mpfr_set_emin (emin); mpfr_set_emax (emax); end: mpz_clear (my); mpz_clear (a); mpz_clear (b); mpz_clear (c); mpz_clear (d); mpz_clear (u); return ret; }

int main() { srand(1337); // The primes we will perform trial division with on small integers. std::vector<uint32_t> primes; // Generate the trial division primes using a simple sieve. { uint32_t max = (uint32_t)ceil(sqrt(TRIAL_BOUND)) + 1; char *sieve = new char[max]; memset(sieve, 1, max); for(uint32_t p = 2; p < max; ++p) { if(!sieve[p]) continue; primes.push_back(p); for(uint32_t i = p; i < max; i += p) sieve[i] = 0; } delete[] sieve; } mpz_class N; // Read numbers to factor from stdin until EOF. while(std::cin >> N) { // This quadratic sieve implementation is designed to factor numbers no larger than 100 bits. if(mpz_sizeinbase(N.get_mpz_t(), 2) > 100) { std::cerr << N << " is too large\n" << std::endl; continue; } std::stack<mpz_class> factors; factors.push(N); while(!factors.empty()) { mpz_class factor = factors.top(); factors.pop(); // If the factor is prime, print it. if(mpz_probab_prime_p(factor.get_mpz_t(), 10)) { std::cout << factor << std::endl; continue; // Run trial division if factor is small. } else if(factor < TRIAL_BOUND) { uint32_t f = factor.get_ui(); for(uint32_t p = 0; p < primes.size(); ++p) { if(f % primes[p] == 0) { factors.push(primes[p]); factors.push(factor / primes[p]); break; } } } else { // Before we run quadratic sieve, check for small factors. bool found_factor = false; for(uint32_t p = 0; p < primes.size(); ++p) { if(mpz_divisible_ui_p(factor.get_mpz_t(), primes[p])) { factors.push(primes[p]); factors.push(factor / primes[p]); found_factor = true; break; } } if(found_factor) continue; // Quadratic sieve doesn't handle perferct powers very well, handle those separately. if(mpz_perfect_power_p(factor.get_mpz_t())) { mpz_class root, rem; // Check root remainders up half of the amount of bits in factor. uint32_t max = mpz_sizeinbase(factor.get_mpz_t(), 2) / 2; for(uint32_t n = 2; n < max; ++n) { mpz_rootrem(root.get_mpz_t(), rem.get_mpz_t(), factor.get_mpz_t(), n); if(rem == 0) { // Push the n root factors. for(uint32_t i = 0; i < n; ++i) factors.push(root); break; } } } else { mpz_class f = quadratic_sieve(factor); factors.push(f); factors.push(factor / f); } } } std::cout << std::endl; } return 0; }

static PyObject * GMPy_MPZ_is_aprcl_prime(PyObject *self, PyObject *other) { mpz_t N; s64_t T, U; int i, j, H, I, J, K, P, Q, W, X; int IV, InvX, LEVELnow, NP, PK, PL, PM, SW, VK, TestedQs, TestingQs; int QQ, T1, T3, U1, U3, V1, V3; int break_this = 0; MPZ_Object *tempx; if (!(tempx = GMPy_MPZ_From_Integer(other, NULL))) { TYPE_ERROR("is_aprcl_prime() requires 'mpz' argument"); return NULL; } mpz_init(N); mpz_set(N, tempx->z); Py_DECREF(tempx); /* make sure the input is >= 2 and odd */ if (mpz_cmp_ui(N, 2) < 0) Py_RETURN_FALSE; if (mpz_divisible_ui_p(N, 2)) { if (mpz_cmp_ui(N, 2) == 0) Py_RETURN_TRUE; else Py_RETURN_FALSE; } /* only three small exceptions for this implementation */ /* with this set of P and Q primes */ if (mpz_cmp_ui(N, 3) == 0) Py_RETURN_TRUE; if (mpz_cmp_ui(N, 7) == 0) Py_RETURN_TRUE; if (mpz_cmp_ui(N, 11) == 0) Py_RETURN_TRUE; /* If the input number is larger than 7000 decimal digits we will just return whether it is a BPSW (probable) prime */ NumberLength = mpz_sizeinbase(N, 10); if (NumberLength > 7000) { VALUE_ERROR("value too large to test"); return NULL; } allocate_vars(); mpz_set(TestNbr, N); mpz_set_si(biS, 0); j = PK = PL = PM = 0; for (J = 0; J < PWmax; J++) { /* aiJX[J] = 0; */ mpz_set_ui(aiJX[J], 0); } break_this = 0; /* GetPrimes2Test : */ for (i = 0; i < LEVELmax; i++) { /* biS[0] = 2; */ mpz_set_ui(biS, 2); for (j = 0; j < aiNQ[i]; j++) { Q = aiQ[j]; if (aiT[i]%(Q-1) != 0) continue; U = aiT[i] * Q; do { U /= Q; /* MultBigNbrByLong(biS, Q, biS, NumberLength); */ mpz_mul_ui(biS, biS, Q); } while (U % Q == 0); // Exit loop if S^2 > N. if (CompareSquare(biS, TestNbr) > 0) { /* break GetPrimes2Test; */ break_this = 1; break; } } /* End for j */ if (break_this) break; } /* End for i */ if (i == LEVELmax) { /* too big */ free_vars(); VALUE_ERROR("value too large to test"); return NULL; } LEVELnow = i; TestingQs = j; T = aiT[LEVELnow]; NP = aiNP[LEVELnow]; MainStart: for (;;) { for (i = 0; i < NP; i++) { P = aiP[i]; if (T%P != 0) continue; SW = TestedQs = 0; /* Q = W = (int) BigNbrModLong(TestNbr, P * P); */ Q = W = mpz_fdiv_ui(TestNbr, P * P); for (J = P - 2; J > 0; J--) { W = (W * Q) % (P * P); } if (P > 2 && W != 1) { SW = 1; } for (;;) { for (j = TestedQs; j <= TestingQs; j++) { Q = aiQ[j] - 1; /* G = aiG[j]; */ K = 0; while (Q % P == 0) { K++; Q /= P; } Q = aiQ[j]; if (K == 0) { continue; } PM = 1; for (I = 1; I < K; I++) { PM = PM * P; } PL = (P - 1) * PM; PK = P * PM; for (I = 0; I < PK; I++) { /* aiJ0[I] = aiJ1[I] = 0; */ mpz_set_ui(aiJ0[I], 0); mpz_set_ui(aiJ1[I], 0); } if (P > 2) { JacobiSum(0, P, PL, Q); } else { if (K != 1) { JacobiSum(0, P, PL, Q); for (I = 0; I < PK; I++) { /* aiJW[I] = 0; */ mpz_set_ui(aiJW[I], 0); } if (K != 2) { for (I = 0; I < PM; I++) { /* aiJW[I] = aiJ0[I]; */ mpz_set(aiJW[I], aiJ0[I]); } JacobiSum(1, P, PL, Q); for (I = 0; I < PM; I++) { /* aiJS[I] = aiJ0[I]; */ mpz_set(aiJS[I], aiJ0[I]); } JS_JW(PK, PL, PM, P); for (I = 0; I < PM; I++) { /* aiJ1[I] = aiJS[I]; */ mpz_set(aiJ1[I], aiJS[I]); } JacobiSum(2, P, PL, Q); for (I = 0; I < PK; I++) { /* aiJW[I] = 0; */ mpz_set_ui(aiJW[I], 0); } for (I = 0; I < PM; I++) { /* aiJS[I] = aiJ0[I]; */ mpz_set(aiJS[I], aiJ0[I]); } JS_2(PK, PL, PM, P); for (I = 0; I < PM; I++) { /* aiJ2[I] = aiJS[I]; */ mpz_set(aiJ2[I], aiJS[I]); } } } } /* aiJ00[0] = aiJ01[0] = 1; */ mpz_set_ui(aiJ00[0], 1); mpz_set_ui(aiJ01[0], 1); for (I = 1; I < PK; I++) { /* aiJ00[I] = aiJ01[I] = 0; */ mpz_set_ui(aiJ00[I], 0); mpz_set_ui(aiJ01[I], 0); } /* VK = (int) BigNbrModLong(TestNbr, PK); */ VK = mpz_fdiv_ui(TestNbr, PK); for (I = 1; I < PK; I++) { if (I % P != 0) { U1 = 1; U3 = I; V1 = 0; V3 = PK; while (V3 != 0) { QQ = U3 / V3; T1 = U1 - V1 * QQ; T3 = U3 - V3 * QQ; U1 = V1; U3 = V3; V1 = T1; V3 = T3; } aiInv[I] = (U1 + PK) % PK; } else { aiInv[I] = 0; } } if (P != 2) { for (IV = 0; IV <= 1; IV++) { for (X = 1; X < PK; X++) { for (I = 0; I < PK; I++) { /* aiJS[I] = aiJ0[I]; */ mpz_set(aiJS[I], aiJ0[I]); } if (X % P == 0) { continue; } if (IV == 0) { /* LongToBigNbr(X, biExp, NumberLength); */ mpz_set_ui(biExp, X); } else { /* LongToBigNbr(VK * X / PK, biExp, NumberLength); */ mpz_set_ui(biExp, (VK * X) / PK); if ((VK * X) / PK == 0) { continue; } } JS_E(PK, PL, PM, P); for (I = 0; I < PK; I++) { /* aiJW[I] = 0; */ mpz_set_ui(aiJW[I], 0); } InvX = aiInv[X]; for (I = 0; I < PK; I++) { J = (I * InvX) % PK; /* AddBigNbrModN(aiJW[J], aiJS[I], aiJW[J], TestNbr, NumberLength); */ mpz_add(aiJW[J], aiJW[J], aiJS[I]); } NormalizeJW(PK, PL, PM, P); if (IV == 0) { for (I = 0; I < PK; I++) { /* aiJS[I] = aiJ00[I]; */ mpz_set(aiJS[I], aiJ00[I]); } } else { for (I = 0; I < PK; I++) { /* aiJS[I] = aiJ01[I]; */ mpz_set(aiJS[I], aiJ01[I]); } } JS_JW(PK, PL, PM, P); if (IV == 0) { for (I = 0; I < PK; I++) { /* aiJ00[I] = aiJS[I]; */ mpz_set(aiJ00[I], aiJS[I]); } } else { for (I = 0; I < PK; I++) { /* aiJ01[I] = aiJS[I]; */ mpz_set(aiJ01[I], aiJS[I]); } } } /* end for X */ } /* end for IV */ } else { if (K == 1) { /* MultBigNbrByLongModN(1, Q, aiJ00[0], TestNbr, NumberLength); */ mpz_set_ui(aiJ00[0], Q); /* aiJ01[0] = 1; */ mpz_set_ui(aiJ01[0], 1); } else { if (K == 2) { if (VK == 1) { /* aiJ01[0] = 1; */ mpz_set_ui(aiJ01[0], 1); } /* aiJS[0] = aiJ0[0]; */ /* aiJS[1] = aiJ0[1]; */ mpz_set(aiJS[0], aiJ0[0]); mpz_set(aiJS[1], aiJ0[1]); JS_2(PK, PL, PM, P); if (VK == 3) { /* aiJ01[0] = aiJS[0]; */ /* aiJ01[1] = aiJS[1]; */ mpz_set(aiJ01[0], aiJS[0]); mpz_set(aiJ01[1], aiJS[1]); } /* MultBigNbrByLongModN(aiJS[0], Q, aiJ00[0], TestNbr, NumberLength); */ mpz_mul_ui(aiJ00[0], aiJS[0], Q); /* MultBigNbrByLongModN(aiJS[1], Q, aiJ00[1], TestNbr, NumberLength); */ mpz_mul_ui(aiJ00[1], aiJS[1], Q); } else { for (IV = 0; IV <= 1; IV++) { for (X = 1; X < PK; X += 2) { for (I = 0; I <= PM; I++) { /* aiJS[I] = aiJ1[I]; */ mpz_set(aiJS[I], aiJ1[I]); } if (X % 8 == 5 || X % 8 == 7) { continue; } if (IV == 0) { /* LongToBigNbr(X, biExp, NumberLength); */ mpz_set_ui(biExp, X); } else { /* LongToBigNbr(VK * X / PK, biExp, NumberLength); */ mpz_set_ui(biExp, VK * X / PK); if (VK * X / PK == 0) { continue; } } JS_E(PK, PL, PM, P); for (I = 0; I < PK; I++) { /* aiJW[I] = 0; */ mpz_set_ui(aiJW[I], 0); } InvX = aiInv[X]; for (I = 0; I < PK; I++) { J = I * InvX % PK; /* AddBigNbrModN(aiJW[J], aiJS[I], aiJW[J], TestNbr, NumberLength); */ mpz_add(aiJW[J], aiJW[J], aiJS[I]); } NormalizeJW(PK, PL, PM, P); if (IV == 0) { for (I = 0; I < PK; I++) { /* aiJS[I] = aiJ00[I]; */ mpz_set(aiJS[I], aiJ00[I]); } } else { for (I = 0; I < PK; I++) { /* aiJS[I] = aiJ01[I]; */ mpz_set(aiJS[I], aiJ01[I]); } } NormalizeJS(PK, PL, PM, P); JS_JW(PK, PL, PM, P); if (IV == 0) { for (I = 0; I < PK; I++) { /* aiJ00[I] = aiJS[I]; */ mpz_set(aiJ00[I], aiJS[I]); } } else { for (I = 0; I < PK; I++) { /* aiJ01[I] = aiJS[I]; */ mpz_set(aiJ01[I], aiJS[I]); } } } /* end for X */ if (IV == 0 || VK % 8 == 1 || VK % 8 == 3) { continue; } for (I = 0; I < PM; I++) { /* aiJW[I] = aiJ2[I]; */ /* aiJS[I] = aiJ01[I]; */ mpz_set(aiJW[I], aiJ2[I]); mpz_set(aiJS[I], aiJ01[I]); } for (; I < PK; I++) { /* aiJW[I] = aiJS[I] = 0; */ mpz_set_ui(aiJW[I], 0); mpz_set_ui(aiJS[I], 0); } JS_JW(PK, PL, PM, P); for (I = 0; I < PM; I++) { /* aiJ01[I] = aiJS[I]; */ mpz_set(aiJ01[I], aiJS[I]); } } /* end for IV */ } } } for (I = 0; I < PL; I++) { /* aiJS[I] = aiJ00[I]; */ mpz_set(aiJS[I], aiJ00[I]); } for (; I < PK; I++) { /* aiJS[I] = 0; */ mpz_set_ui(aiJS[I], 0); } /* DivBigNbrByLong(TestNbr, PK, biExp, NumberLength); */ mpz_fdiv_q_ui(biExp, TestNbr, PK); JS_E(PK, PL, PM, P); for (I = 0; I < PK; I++) { /* aiJW[I] = 0; */ mpz_set_ui(aiJW[I], 0); } for (I = 0; I < PL; I++) { for (J = 0; J < PL; J++) { /* MontgomeryMult(aiJS[I], aiJ01[J], biTmp); */ /* AddBigNbrModN(biTmp, aiJW[(I + J) % PK], aiJW[(I + J) % PK], TestNbr, NumberLength); */ mpz_mul(biTmp, aiJS[I], aiJ01[J]); mpz_add(aiJW[(I + J) % PK], biTmp, aiJW[(I + J) % PK]); } } NormalizeJW(PK, PL, PM, P); /* MatchingRoot : */ do { H = -1; W = 0; for (I = 0; I < PL; I++) { if (mpz_cmp_ui(aiJW[I], 0) != 0)/* (!BigNbrIsZero(aiJW[I])) */ { /* if (H == -1 && BigNbrAreEqual(aiJW[I], 1)) */ if (H == -1 && (mpz_cmp_ui(aiJW[I], 1) == 0)) { H = I; } else { H = -2; /* AddBigNbrModN(aiJW[I], MontgomeryMultR1, biTmp, TestNbr, NumberLength); */ mpz_add_ui(biTmp, aiJW[I], 1); mpz_mod(biTmp, biTmp, TestNbr); if (mpz_cmp_ui(biTmp, 0) == 0) /* (BigNbrIsZero(biTmp)) */ { W++; } } } } if (H >= 0) { /* break MatchingRoot; */ break; } if (W != P - 1) { /* Not prime */ free_vars(); Py_RETURN_FALSE; } for (I = 0; I < PM; I++) { /* AddBigNbrModN(aiJW[I], 1, biTmp, TestNbr, NumberLength); */ mpz_add_ui(biTmp, aiJW[I], 1); mpz_mod(biTmp, biTmp, TestNbr); if (mpz_cmp_ui(biTmp, 0) == 0) /* (BigNbrIsZero(biTmp)) */ { break; } } if (I == PM) { /* Not prime */ free_vars(); Py_RETURN_FALSE; } for (J = 1; J <= P - 2; J++) { /* AddBigNbrModN(aiJW[I + J * PM], 1, biTmp, TestNbr, NumberLength); */ mpz_add_ui(biTmp, aiJW[I + J * PM], 1); mpz_mod(biTmp, biTmp, TestNbr); if (mpz_cmp_ui(biTmp, 0) != 0)/* (!BigNbrIsZero(biTmp)) */ { /* Not prime */ free_vars(); Py_RETURN_FALSE; } } H = I + PL; } while (0); if (SW == 1 || H % P == 0) { continue; } if (P != 2) { SW = 1; continue; } if (K == 1) { if ((mpz_get_ui(TestNbr) & 3) == 1) { SW = 1; } continue; } // if (Q^((N-1)/2) mod N != N-1), N is not prime. /* MultBigNbrByLongModN(1, Q, biTmp, TestNbr, NumberLength); */ mpz_set_ui(biTmp, Q); mpz_mod(biTmp, biTmp, TestNbr); mpz_sub_ui(biT, TestNbr, 1); /* biT = n-1 */ mpz_divexact_ui(biT, biT, 2); /* biT = (n-1)/2 */ mpz_powm(biR, biTmp, biT, TestNbr); /* biR = Q^((n-1)/2) mod n */ mpz_add_ui(biTmp, biR, 1); mpz_mod(biTmp, biTmp, TestNbr); if (mpz_cmp_ui(biTmp, 0) != 0)/* (!BigNbrIsZero(biTmp)) */ { /* Not prime */ free_vars(); Py_RETURN_FALSE; } SW = 1; } /* end for j */ if (SW == 0) { TestedQs = TestingQs + 1; if (TestingQs < aiNQ[LEVELnow] - 1) { TestingQs++; Q = aiQ[TestingQs]; U = T * Q; do { /* MultBigNbrByLong(biS, Q, biS, NumberLength); */ mpz_mul_ui(biS, biS, Q); U /= Q; } while (U % Q == 0); continue; /* Retry */ } LEVELnow++; if (LEVELnow == LEVELmax) { free_vars(); // return mpz_bpsw_prp(N); /* Cannot tell */ VALUE_ERROR("maximum levels reached"); return NULL; } T = aiT[LEVELnow]; NP = aiNP[LEVELnow]; /* biS = 2; */ mpz_set_ui(biS, 2); for (J = 0; J <= aiNQ[LEVELnow]; J++) { Q = aiQ[J]; if (T%(Q-1) != 0) continue; U = T * Q; do { /* MultBigNbrByLong(biS, Q, biS, NumberLength); */ mpz_mul_ui(biS, biS, Q); U /= Q; } while (U % Q == 0); if (CompareSquare(biS, TestNbr) > 0) { TestingQs = J; /* continue MainStart; */ /* Retry from the beginning */ goto MainStart; } } /* end for J */ free_vars(); VALUE_ERROR("internal failure"); return NULL; } /* end if */ break; } /* end for (;;) */ } /* end for i */ // Final Test /* biR = 1 */ mpz_set_ui(biR, 1); /* biN <- TestNbr mod biS */ /* Compute N mod S */ mpz_fdiv_r(biN, TestNbr, biS); for (U = 1; U <= T; U++) { /* biR <- (biN * biR) mod biS */ mpz_mul(biR, biN, biR); mpz_mod(biR, biR, biS); if (mpz_cmp_ui(biR, 1) == 0) /* biR == 1 */ { /* Number is prime */ free_vars(); Py_RETURN_TRUE; } if (mpz_divisible_p(TestNbr, biR) && mpz_cmp(biR, TestNbr) < 0) /* biR < N and biR | TestNbr */ { /* Number is composite */ free_vars(); Py_RETURN_FALSE; } } /* End for U */ /* This should never be reached. */ free_vars(); SYSTEM_ERROR("Internal error: APR-CL error with final test."); return NULL; } }

// A quadratic sieve implementation for integers up to 100 bits. N must be composite. mpz_class quadratic_sieve(mpz_class &N) { std::vector<uint32_t> factor_base; mpz_class sqrt_N = sqrt(N); //const unsigned long sqrt_N_long = sqrt_N.get_ui(); // Set the smoothness bound. uint32_t B; { // Approximation of the natural logarithm of N. float log_N = mpz_sizeinbase(N.get_mpz_t(), 2) * log(2); // The optimal smoothness bound is exp((0.5 + o(1)) * sqrt(log(n)*log(log(n)))). B = (uint32_t)ceil(exp(0.56 * sqrt(log_N * log(log_N)))) + 300; } // Generate the factor base using a sieve. { char *sieve = new char[B + 1]; memset(sieve, 1, B + 1); for(unsigned long p = 2; p <= B; ++p) { if(!sieve[p]) continue; if(mpz_legendre(N.get_mpz_t(), mpz_class(p).get_mpz_t()) == 1) factor_base.push_back(p); for(unsigned long i = p; i <= B; i += p) sieve[i] = 0; } delete[] sieve; } std::vector<uint32_t> X; float *Y = new float[SIEVE_CHUNK]; std::vector<std::vector<uint32_t> > smooth; int fails = 0; // The sieve boundary. uint32_t min_x = 0; uint32_t max_x = SIEVE_CHUNK; // Calculate sieve index (where to start the sieve) for each factor base number. uint32_t **fb_indexes = new uint32_t*[2]; fb_indexes[0] = new uint32_t[factor_base.size()]; fb_indexes[1] = new uint32_t[factor_base.size()]; for(uint32_t p = 0; p < factor_base.size(); ++p) { // At what indexes do we start this sieve? Solve the congruence x^2 = n (mod p) to find out. // Results in two solutions, so we do two sieve iterations for each prime in the factor base. uint32_t idxs[2]; mpz_class temp = N % mpz_class(factor_base[p]); tonelli_shanks(temp.get_ui(), factor_base[p], idxs); temp = idxs[0] - sqrt_N; temp = ((temp % factor_base[p]) + factor_base[p]) % factor_base[p]; fb_indexes[0][p] = temp.get_ui(); temp = idxs[1] - sqrt_N; temp = ((temp % factor_base[p]) + factor_base[p]) % factor_base[p]; fb_indexes[1][p] = temp.get_ui(); } float last_estimate = 0; uint32_t next_estimate = 1; // Sieve new chunks until we have enough smooth numbers. while(smooth.size() < (factor_base.size() + 20)) { // Generate our Y vector for the sieve, containing log approximations that fit in machine words. for(uint32_t t = 1; t < SIEVE_CHUNK; ++t) { // Calculating a log estimate is expensive, so don't do it for every Y[t]. if(next_estimate <= (t + min_x)) { mpz_class y = (sqrt_N + t + min_x) * (sqrt_N + t + min_x) - N; // To estimate the 2 logarithm, just count the number of bits that v takes up. last_estimate = mpz_sizeinbase(y.get_mpz_t(), 2); // The higher t gets, the less the logarithm of Y[t] changes. next_estimate = next_estimate * 1.8 + 1; } Y[t] = last_estimate; } // Perform the actual sieve. for(uint32_t p = 0; p < factor_base.size(); ++p) { float lg = log(factor_base[p]) / log(2); for(uint32_t t = 0; t < 2; ++t) { while(fb_indexes[t][p] < max_x) { Y[fb_indexes[t][p] - min_x] -= lg; fb_indexes[t][p] += factor_base[p]; } // p = 2 only has one modular root. if(factor_base[p] == 2) break; } } // Factor all values whose logarithms were reduced to approximately zero using trial division. { float threshold = log(factor_base.back()) / log(2); for(uint32_t i = 0; i < SIEVE_CHUNK; ++i) { if(fabs(Y[i]) < threshold) { mpz_class y = (sqrt_N + i + min_x) * (sqrt_N + i + min_x) - N; smooth.push_back(std::vector<uint32_t>()); for(uint32_t p = 0; p < factor_base.size(); ++p) { while(mpz_divisible_ui_p(y.get_mpz_t(), factor_base[p])) { mpz_divexact_ui(y.get_mpz_t(), y.get_mpz_t(), factor_base[p]); smooth.back().push_back(p); } } if(y == 1) { // This V was indeed B-smooth. X.push_back(i + min_x); // Break out of trial division loop if we've found enou gh smooth numbers. if(smooth.size() >= (factor_base.size() + 20)) break; } else { // This V was apparently not B-smooth, remove it. smooth.pop_back(); ++fails; } } } } min_x += SIEVE_CHUNK; max_x += SIEVE_CHUNK; } uint64_t **matrix = new uint64_t*[factor_base.size()]; // The amount of words needed to accomodate a row in the augmented matrix. int row_words = (smooth.size() + sizeof(uint64_t)) / sizeof(uint64_t); for(uint32_t i = 0; i < factor_base.size(); ++i) { matrix[i] = new uint64_t[row_words]; memset(matrix[i], 0, row_words * sizeof(uint64_t)); } for(uint32_t s = 0; s < smooth.size(); ++s) { // For each factor in the smooth number, add the factor to the corresponding element in the matrix. for(uint32_t p = 0; p < smooth[s].size(); ++p) toggle_bit(s, matrix[smooth[s][p]]); } // Gauss elimination. The dimension of the augmented matrix is factor_base.size() x (smooth.size() + 1). { uint32_t i = 0, j = 0; while(i < factor_base.size() && j < (smooth.size() + 1)) { uint32_t maxi = i; // Find pivot element. for(uint32_t k = i + 1; k < factor_base.size(); ++k) { if(get_bit(j, matrix[k]) == 1) { maxi = k; break; } } if(get_bit(j, matrix[maxi]) == 1) { std::swap(matrix[i], matrix[maxi]); for(uint32_t u = i + 1; u < factor_base.size(); ++u) { if(get_bit(j, matrix[u]) == 1) { for(int32_t w = 0; w < row_words; ++w) matrix[u][w] ^= matrix[i][w]; } } ++i; } ++j; } } mpz_class a; mpz_class b; // A copy of matrix that we'll perform back-substitution on. uint64_t **back_matrix = new uint64_t*[factor_base.size()]; for(uint32_t i = 0; i < factor_base.size(); ++i) back_matrix[i] = new uint64_t[row_words]; uint32_t *x = new uint32_t[smooth.size()]; uint32_t *combination = new uint32_t[factor_base.size()]; // Loop until we've found a non-trivial factor. do { // Copy the gauss eliminated matrix. for(uint32_t i = 0; i < factor_base.size(); ++i) memcpy(back_matrix[i], matrix[i], row_words * sizeof(uint64_t)); // Clear the x vector. memset(x, 0, smooth.size() * sizeof(uint32_t)); // Perform back-substitution on our matrix that's now in row echelon form to get x. { int32_t i = factor_base.size() - 1; while(i >= 0) { // Count non-zero elements in current row. int32_t count = 0; int32_t current = -1; for(uint32_t c = 0; c < smooth.size(); ++c) { count += get_bit(c, back_matrix[i]); current = get_bit(c, back_matrix[i]) ? c : current; } // Empty row, advance to next. if(count == 0) { --i; continue; } // The system is underdetermined and we can choose x[current] freely. // To avoid the trivial solution we avoid always setting it to 0. uint32_t val = count > 1 ? rand() % 2 : get_bit(smooth.size(), back_matrix[i]); x[current] = val; for(int32_t u = 0; u <= i; ++u) { if(get_bit(current, back_matrix[u]) == 1) { if(val == 1) toggle_bit(smooth.size(), back_matrix[u]); unset_bit(current, back_matrix[u]); } } if(count == 1) --i; } } a = 1; b = 1; // The way to combine the factor base to get our square. memset(combination, 0, sizeof(uint32_t) * factor_base.size()); for(uint32_t i = 0; i < smooth.size(); ++i) { if(x[i] == 1) { for(uint32_t p = 0; p < smooth[i].size(); ++p) ++combination[smooth[i][p]]; b *= (X[i] + sqrt_N); } } for(uint32_t p = 0; p < factor_base.size(); ++p) { for(uint32_t i = 0; i < (combination[p] / 2); ++i) a *= factor_base[p]; } // If a = +/- b (mod N) we found a trivial factor, run the loop again to find a new a and b. } while(a % N == b % N || a % N == (- b) % N + N); b -= a; mpz_class factor; mpz_gcd(factor.get_mpz_t(), b.get_mpz_t(), N.get_mpz_t()); for(uint32_t i = 0; i < factor_base.size(); ++i) { delete[] matrix[i]; delete[] back_matrix[i]; } delete[] combination; delete[] Y; delete[] fb_indexes[0]; delete[] fb_indexes[1]; delete[] fb_indexes; delete[] matrix; delete[] back_matrix; delete[] x; return factor; }

int mpz_probab_prime_p (mpz_srcptr n, int reps) { mp_limb_t r; mpz_t n2; /* Handle small and negative n. */ if (mpz_cmp_ui (n, 1000000L) <= 0) { if (mpz_cmpabs_ui (n, 1000000L) <= 0) { int is_prime; unsigned long n0; n0 = mpz_get_ui (n); is_prime = n0 & (n0 > 1) ? isprime (n0) : n0 == 2; return is_prime ? 2 : 0; } /* Negative number. Negate and fall out. */ PTR(n2) = PTR(n); SIZ(n2) = -SIZ(n); n = n2; } /* If n is now even, it is not a prime. */ if (mpz_even_p (n)) return 0; #if defined (PP) /* Check if n has small factors. */ #if defined (PP_INVERTED) r = MPN_MOD_OR_PREINV_MOD_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP, (mp_limb_t) PP_INVERTED); #else r = mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP); #endif if (r % 3 == 0 #if GMP_LIMB_BITS >= 4 || r % 5 == 0 #endif #if GMP_LIMB_BITS >= 8 || r % 7 == 0 #endif #if GMP_LIMB_BITS >= 16 || r % 11 == 0 || r % 13 == 0 #endif #if GMP_LIMB_BITS >= 32 || r % 17 == 0 || r % 19 == 0 || r % 23 == 0 || r % 29 == 0 #endif #if GMP_LIMB_BITS >= 64 || r % 31 == 0 || r % 37 == 0 || r % 41 == 0 || r % 43 == 0 || r % 47 == 0 || r % 53 == 0 #endif ) { return 0; } #endif /* PP */ /* Do more dividing. We collect small primes, using umul_ppmm, until we overflow a single limb. We divide our number by the small primes product, and look for factors in the remainder. */ { unsigned long int ln2; unsigned long int q; mp_limb_t p1, p0, p; unsigned int primes[15]; int nprimes; nprimes = 0; p = 1; ln2 = mpz_sizeinbase (n, 2); /* FIXME: tune this limit */ for (q = PP_FIRST_OMITTED; q < ln2; q += 2) { if (isprime (q)) { umul_ppmm (p1, p0, p, q); if (p1 != 0) { r = MPN_MOD_OR_MODEXACT_1_ODD (PTR(n), (mp_size_t) SIZ(n), p); while (--nprimes >= 0) if (r % primes[nprimes] == 0) { ASSERT_ALWAYS (mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) primes[nprimes]) == 0); return 0; } p = q; nprimes = 0; } else { p = p0; } primes[nprimes++] = q; } } } /* Perform a number of Miller-Rabin tests. */ return mpz_millerrabin (n, reps); }

static void miller(element_t res, element_t P, element_t Q, element_t R, int n) { //collate divisions mp_bitcnt_t m; element_t v, vd; element_t Z; element_t a, b, c; element_t e0, e1; mpz_t q; element_ptr Zx, Zy; const element_ptr Px = curve_x_coord(P); const element_ptr Py = curve_y_coord(P); const element_ptr numx = curve_x_coord(Q); const element_ptr numy = curve_y_coord(Q); const element_ptr denomx = curve_x_coord(R); const element_ptr denomy = curve_y_coord(R); #define do_vertical(e, edenom) { \ element_sub(e0, numx, Zx); \ element_mul((e), (e), e0); \ \ element_sub(e0, denomx, Zx); \ element_mul((edenom), (edenom), e0); \ } #define do_tangent(e, edenom) { \ /*a = -slope_tangent(A.x, A.y); \ b = 1; \ c = -(A.y + a * A.x); \ but we multiply by 2*A.y to avoid division \ \ a = -Ax * (Ax + Ax + Ax + twicea_2) - a_4; \ This curve is special: \ a = -(3 Ax^2 + 2Ax) \ b = 2 * Ay \ c = -(2 Ay^2 + a Ax); */ \ \ if (element_is0(Zy)) { \ do_vertical((e), (edenom)); \ } else { \ element_square(a, Zx); \ element_mul_si(a, a, 3); \ element_add(a, a, Zx); \ element_add(a, a, Zx); \ element_neg(a, a); \ \ element_add(b, Zy, Zy); \ \ element_mul(e0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, e0); \ element_neg(c, c); \ \ element_mul(e0, a, numx); \ element_mul(e1, b, numy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((e), (e), e0); \ \ element_mul(e0, a, denomx); \ element_mul(e1, b, denomy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((edenom), (edenom), e0); \ } \ } #define do_line(e, edenom) { \ if (!element_cmp(Zx, Px)) { \ if (!element_cmp(Zy, Py)) { \ do_tangent((e), (edenom)); \ } else { \ do_vertical((e), (edenom)); \ } \ } else { \ element_sub(b, Px, Zx); \ element_sub(a, Zy, Py); \ element_mul(c, Zx, Py); \ element_mul(e0, Zy, Px); \ element_sub(c, c, e0); \ \ element_mul(e0, a, numx); \ element_mul(e1, b, numy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((e), (e), e0); \ \ element_mul(e0, a, denomx); \ element_mul(e1, b, denomy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((edenom), (edenom), e0); \ } \ } element_init(a, res->field); element_init(b, res->field); element_init(c, res->field); element_init(e0, res->field); element_init(e1, res->field); element_init(v, res->field); element_init(vd, res->field); element_init(Z, P->field); element_set(Z, P); Zx = curve_x_coord(Z); Zy = curve_y_coord(Z); element_set1(v); element_set1(vd); mpz_init(q); mpz_set_ui(q, n); m = (mp_bitcnt_t)mpz_sizeinbase(q, 2); m = (m > 2 ? m - 2 : 0); for (;;) { element_square(v, v); element_square(vd, vd); do_tangent(v, vd); element_double(Z, Z); do_vertical(vd, v); if (mpz_tstbit(q, m)) { do_line(v, vd); element_add(Z, Z, P); if (m) { do_vertical(vd, v); } } if (!m) break; m--; } mpz_clear(q); element_invert(vd, vd); element_mul(res, v, vd); element_clear(v); element_clear(vd); element_clear(Z); element_clear(a); element_clear(b); element_clear(c); element_clear(e0); element_clear(e1); #undef do_vertical #undef do_tangent #undef do_line }