static void CG21_PI_MOD_GEN_Xi()

in src/cg21/cg21_pi_mod.c [89:184]


static void CG21_PI_MOD_GEN_Xi(CG21_PIMOD_PROOF *pimodProof, CG21_PAILLIER_KEYS paillierKeys){
    bool ab_[4][2]={{0,0},{0,1},{1,0},{1,1}};
    BIG_512_60 yi_[HFLEN_4096];
    BIG_512_60 yMULw[FFLEN_4096];
    BIG_512_60 n_[FFLEN_4096];
    BIG_1024_58 r1[FFLEN_2048];
    BIG_1024_58 r2[FFLEN_2048];
    BIG_1024_58 r11[FFLEN_2048];
    BIG_1024_58 r22[FFLEN_2048];
    BIG_1024_58 yi_2048[FFLEN_2048];
    BIG_1024_58 n_2048[FFLEN_2048];

    char oct[2*FS_2048];
    octet OCT = {0, sizeof(oct), oct};

    FF_4096_zero(n_,FFLEN_4096);
    FF_4096_copy(n_,paillierKeys.paillier_pk.n,HFLEN_4096);

    // convert paillier_pk.n from BIG_512_60[HFLEN_4096] to BIG_1024_58[FFLEN_2048]
    FF_4096_toOctet(&OCT, paillierKeys.paillier_pk.n, HFLEN_4096);
    FF_2048_fromOctet(n_2048, &OCT, FFLEN_2048);

    // for each yi[i] we need to choose (ai,bi) from ab_ such that y'i has 4th root
    for (int i=0;i<CG21_PAILLIER_PROOF_ITERS;i++){

        // convert yi from BIG_1024_58[FFLEN_2048] to y_oct
        char oct2[2 * FS_2048];
        octet y_oct = {0, sizeof(oct2), oct2};
        FF_2048_toOctet(&y_oct, pimodProof->yi[i], FFLEN_2048);

        for (int j=0;j<4;j++){

            // convert y_oct to BIG_512_60[HFLEN_4096]
            FF_4096_zero(yi_, HFLEN_4096);
            FF_4096_fromOctet(yi_, &y_oct, HFLEN_4096);

            // if ai=1 -> (-1)^{ai} becomes -1 -> we compute -yi mod N = N - yi
            // note: if ai=0 -> (-1)^{ai} becomes 0 -> we don't need to do anything
            if (ab_[j][0]) {
                FF_4096_sub(yi_, paillierKeys.paillier_pk.n, yi_, HFLEN_4096);
                FF_4096_norm(yi_, HFLEN_4096);
            }

            // if bi=1 -> we compute yi = w * yi
            if (ab_[j][1]) {
                FF_4096_zero(yMULw, FFLEN_4096);
                FF_4096_mul(yMULw, yi_, pimodProof->w, HFLEN_4096);
                FF_4096_mod(yMULw, n_, FFLEN_4096);
                FF_4096_copy(yi_, yMULw, HFLEN_4096);
            }

            // convert yi_ from BIG_512_60[HFLEN_4096] to BIG_1024_58[FFLEN_2048]
            FF_4096_toOctet(&OCT, yi_, HFLEN_4096);
            FF_2048_fromOctet(yi_2048, &OCT, FFLEN_2048);

            // check whether yi_2048 has any square root in mod p and q
            bool rc1 = CG21_check_sqrt_exist(yi_2048, paillierKeys.paillier_sk.p);
            bool rc2 = CG21_check_sqrt_exist(yi_2048, paillierKeys.paillier_sk.q);

            if (rc1 && rc2){

                // 4th root of yi_2048 mod p
                CG21_sqrt(r1,yi_2048,paillierKeys.paillier_sk.p);
                CG21_sqrt(r11,r1,paillierKeys.paillier_sk.p);

                // 4th root of yi_2048 mod q
                CG21_sqrt(r2,yi_2048,paillierKeys.paillier_sk.q);
                CG21_sqrt(r22,r2,paillierKeys.paillier_sk.q);

                // combine r11 and r22 using CRT to get the final result xi
                FF_2048_crt(pimodProof->xi[i], r11, r22, paillierKeys.paillier_sk.p, paillierKeys.paillier_sk.invpq, n_2048, HFLEN_2048);

                // stores ai and bi values, verifier needs these values
                pimodProof->ab[i][0] = ab_[j][0];
                pimodProof->ab[i][1] = ab_[j][1];

                // don't need to check the other combinations of ai and bi
                break;
            }
        }
    }

    // clean up
    FF_4096_zero(yi_, HFLEN_4096);
    FF_4096_zero(yMULw, FFLEN_4096);
    FF_4096_zero(n_, FFLEN_4096);

    FF_2048_zero(r1, FFLEN_2048);
    FF_2048_zero(r2, HFLEN_2048);
    FF_2048_zero(r11, FFLEN_2048);
    FF_2048_zero(r22, HFLEN_2048);
    FF_2048_zero(yi_2048, FFLEN_2048);
    FF_2048_zero(n_2048, FFLEN_2048);

    OCT_clear(&OCT);
}