void PAILLIER_KEY_PAIR()

in src/paillier.c [31:117]


void PAILLIER_KEY_PAIR(csprng *RNG, const octet *P, const octet* Q, PAILLIER_public_key *PUB, PAILLIER_private_key *PRIV)
{
    char oct[FS_2048];
    octet OCT = {0, FS_2048, oct};

    BIG_1024_58 n[FFLEN_2048];

    /* Private key */

    if (RNG!=NULL)
    {
        // p
        FF_2048_random(PRIV->p, RNG, HFLEN_2048);
        while (FF_2048_lastbits(PRIV->p, 2) != 3)
        {
            FF_2048_inc(PRIV->p, 1, HFLEN_2048);
        }
        while (!FF_2048_prime(PRIV->p, RNG, HFLEN_2048))
        {
            FF_2048_inc(PRIV->p, 4, HFLEN_2048);
        }

        // q
        FF_2048_random(PRIV->q, RNG, HFLEN_2048);
        while (FF_2048_lastbits(PRIV->q, 2) != 3)
        {
            FF_2048_inc(PRIV->q, 1, HFLEN_2048);
        }
        while (!FF_2048_prime(PRIV->q, RNG, HFLEN_2048))
        {
            FF_2048_inc(PRIV->q, 4, HFLEN_2048);
        }
    }
    else
    {
        FF_2048_fromOctet(PRIV->p, P, HFLEN_2048);
        FF_2048_fromOctet(PRIV->q, Q, HFLEN_2048);
    }

    // lp = p-1, lq = q-1
    FF_2048_copy(PRIV->lp, PRIV->p, HFLEN_2048);
    FF_2048_copy(PRIV->lq, PRIV->q, HFLEN_2048);
    FF_2048_dec(PRIV->lp, 1, HFLEN_2048);
    FF_2048_dec(PRIV->lq, 1, HFLEN_2048);

    /* Precomputations for Secret Key */

    // p^{-1}, q^{-1} mod 2^m for division trick
    FF_2048_zero(PRIV->invp, FFLEN_2048);
    FF_2048_zero(PRIV->invq, FFLEN_2048);
    FF_2048_invmod2m(PRIV->invp, PRIV->p, HFLEN_2048);
    FF_2048_invmod2m(PRIV->invq, PRIV->q, HFLEN_2048);

    // p^2, q^2
    FF_2048_sqr(PRIV->p2, PRIV->p, HFLEN_2048);
    FF_2048_sqr(PRIV->q2, PRIV->q, HFLEN_2048);
    FF_2048_norm(PRIV->p2, FFLEN_2048);
    FF_2048_norm(PRIV->q2, FFLEN_2048);

    // mp = (((g^(p-1) mod p^2) -1) / p)^(-1) mod p
    // Using g = n+1, g^(p-1) = 1 + n(p-1) mod p^2, i.e.
    // mp = (n(p-1)/p)^(-1) = -q^(-1) mod p

    // (-q)^(-1) mod p
    FF_2048_invmodp(PRIV->mp, PRIV->q, PRIV->p, HFLEN_2048);
    FF_2048_sub(PRIV->mp, PRIV->p, PRIV->mp, HFLEN_2048);
    FF_2048_norm(PRIV->mp, HFLEN_2048);

    // (-p)^(-1) mod q
    // Also use this to precompute p^(-1) mod q
    FF_2048_invmodp(PRIV->invpq, PRIV->p, PRIV->q, HFLEN_2048);
    FF_2048_sub(PRIV->mq, PRIV->q, PRIV->invpq, HFLEN_2048);
    FF_2048_norm(PRIV->mq, HFLEN_2048);

    /* Public Key */

    // n
    FF_2048_mul(n, PRIV->p, PRIV->q, HFLEN_2048);
    FF_2048_toOctet(&OCT, n, FFLEN_2048);
    FF_4096_zero(PUB->n, FFLEN_4096);
    FF_4096_fromOctet(PUB->n, &OCT, HFLEN_4096);
    OCT_empty(&OCT);

    // Precompute n^2 for public key
    FF_4096_sqr(PUB->n2, PUB->n, HFLEN_4096);
    FF_4096_norm(PUB->n2, FFLEN_4096);
}