- pgen px, py;
- mp *pp;
- mp *g = MP_NEW;
- grand *gr = fibrand_create(0);
- int rcx, rcy;
- int fail = BBSEV_OK;
- size_t sz;
-
- /* --- Initialize @p@ and @q@ --- *
- *
- * Divide both by two, and make the results odd.
- */
-
- p = mp_lsr(MP_NEW, p, 1); p->v[0] |= 1;
- q = mp_lsr(MP_NEW, q, 1); q->v[0] |= 1;
-
- /* --- Set up the search for @p@ --- *
- *
- * I want a prime %$p$% such that %$(p - 1)/2$% has no small factors.
- */
-
- rcx = pgen_create(&px, p); mp_drop(p);
- rcy = pgen_muladd(&py, &px, 2, 1);
-
- if (proc && (fail = proc(BBSEV_FINDP, 0, arg)) != 0)
- goto fail_0;
-
- sz = mp_bits(py.m);
- for (;;) {
- if (rcx != PGEN_COMPOSITE && rcy != PGEN_COMPOSITE) {
- if (rcy != PGEN_PRIME) {
- rabin r;
- int i;
-
- if (proc && (fail = proc(BBSEV_TRYP, py.m, arg)) != 0)
- break;
- rabin_create(&r, py.m);
- for (i = 0; i < 5; i++) {
- g = mprand(g, sz, gr, 1);
- if ((rcy = rabin_test(&r, g)) == PGEN_COMPOSITE)
- break;
- if (proc && (fail = proc(BBSEV_PASSP, py.m, arg)) != 0)
- break;
- }
- rabin_destroy(&r);
- if (fail)
- goto fail_0;
- if (i < 5) {
- if (proc && (fail = proc(BBSEV_FAILP, py.m, arg)) != 0)
- goto fail_0;
- if (n) {
- n--;
- if (!n) {
- fail = BBSEV_FAILP;
- goto fail_0;
- }
- }
- }
- }
-
- if (rcy != PGEN_COMPOSITE)
- break;
- }
- rcx = pgen_step(&px, 2);
- rcy = pgen_step(&py, 4);
- }
-
- if (proc && (fail = proc(BBSEV_GOODP, py.m, arg)) != 0)
- goto fail_0;
-
- /* --- I now have a @p@ (and a %$(p - 1)/2$%) --- */
-
- pp = MP_COPY(px.m); pgen_destroy(&px);
- p = MP_COPY(py.m); pgen_destroy(&py);
-
- /* --- Next trick is to generate @q@ --- *
- *
- * I don't care about small factors of %$(q - 1)/2$%, just that it's
- * relatively prime to %$(p - 1)/2$%.
- */
-
- {
- mp *m = mp_lsl(MP_NEW, q, 1);
- m->v[0] |= 1;
- rcx = pgen_create(&px, m);
- mp_drop(m);
- }
-
- if (proc && (fail = proc(BBSEV_FINDQ, 0, arg)) != 0)
- goto fail_1;
-
- for (;;) {
- if (rcx != PGEN_COMPOSITE) {
- int ok;
-
- /* --- Ensure that %$(p - 1)/2$% and %$(q - 1)/2$% are coprime --- */
-
- mp_gcd(&g, 0, 0, pp, q);
- ok = MP_CMP(g, ==, MP_ONE);
-
- if (ok && rcx != PGEN_PRIME) {
- rabin r;
- int i;
-
- if (proc && (fail = proc(BBSEV_TRYQ, px.m, arg)) != 0)
- break;
- rabin_create(&r, px.m);
- for (i = 0; i < 5; i++) {
- g = mprand(g, sz, gr, 1);
- if ((rcx = rabin_test(&r, g)) == PGEN_COMPOSITE)
- break;
- if (proc && (fail = proc(BBSEV_PASSQ, px.m, arg)) != 0)
- break;
- }
- rabin_destroy(&r);
- if (fail)
- goto fail_1;
- if (i < 5) {
- if (proc && (fail = proc(BBSEV_FAILQ, px.m, arg)) != 0)
- goto fail_1;
- if (n) {
- n--;
- if (!n) {
- fail = BBSEV_FAILQ;
- goto fail_1;
- }
- }
- }
- }
-
- if (ok && rcx != PGEN_COMPOSITE)
- break;
- }
-
- q = mp_add(q, q, MP_TWO);
- rcx = pgen_step(&px, 4);
- }
-
- if (proc && (fail = proc(BBSEV_GOODQ, px.m, arg)) != 0)
- goto fail_1;
-
- /* --- Done --- */
-
- mp_drop(g);
- mp_drop(q);
- mp_drop(pp);
- q = MP_COPY(px.m);
- bp->p = p;
- bp->q = q;
- pgen_destroy(&px);
- bp->n = mp_mul(MP_NEW, p, q);
- gr->ops->destroy(gr);
- return (0);
-
- /* --- Failed --- */
-
-fail_1:
- pgen_destroy(&px);
- mp_drop(p);
- mp_drop(pp);
- mp_drop(g);
- gr->ops->destroy(gr);
- return (fail);
-
-fail_0:
- if (g)
- mp_drop(g);
- pgen_destroy(&px);
- pgen_destroy(&py);
- mp_drop(q);
- gr->ops->destroy(gr);
- return (fail);
+ rabin rb;
+ pgen_safejumpctx j;
+ gcdctx g;
+ unsigned nb = nbits/2;
+ mp *x = MP_NEW;
+
+ /* --- Generate @p@ --- */
+
+ if ((x = strongprime_setup("p", x, &j.jq, nb, r, n, event, ectx)) == 0)
+ goto fail_x;
+ bp->p = pgen("p", MP_NEW, x, event, ectx, n, pgen_safejump, &j,
+ rabin_iters(nb), pgen_test, &rb);
+ pfilt_destroy(&j.jq);
+ if (!bp->p)
+ goto fail_p;
+
+ /* --- Generate @q@ --- */
+
+ nb = nbits - nb;
+ if ((x = strongprime_setup("q", x, &g.jp, nb, r, n, event, ectx)) == 0)
+ goto fail_q;
+ g.r = mp_lsr(MP_NEW, bp->p, 1);
+ bp->q = pgen("q", MP_NEW, x, event, ectx, n, gcdstep, &g,
+ rabin_iters(nb), pgen_test, &rb);
+ pfilt_destroy(&g.jp);
+ mp_drop(g.r);
+ if (!bp->q)
+ goto fail_q;
+
+ /* --- Compute @n@ --- */
+
+ bp->n = mp_mul(MP_NEW, bp->p, bp->q);
+ mp_drop(x);
+ return (PGEN_DONE);
+
+ /* --- Tidy up if things went wrong --- */
+
+fail_q:
+ mp_drop(bp->p);
+fail_p:
+ mp_drop(x);
+fail_x:
+ return (PGEN_ABORT);