in src/cg21/cg21_rp_pi_affp.c [499:776]
int PiAffp_Verify(PAILLIER_private_key *verifier_paillier_priv, PAILLIER_public_key *prover_paillier_pub,
PEDERSEN_PRIV *pedersen_priv, octet *C, octet *D, octet *X, octet *Y,
PiAffp_COMMITS *commits, octet *E, PiAffp_PROOFS *proofs){
// ------------ VARIABLE DEFINITION ---------
int fail;
BIG_1024_58 e[FFLEN_2048];
BIG_1024_58 n[FFLEN_2048];
BIG_1024_58 p_proof[FFLEN_2048];
BIG_1024_58 q_proof[FFLEN_2048];
BIG_1024_58 p_gt[FFLEN_2048];
BIG_1024_58 q_gt[FFLEN_2048];
BIG_1024_58 ws1[FFLEN_2048];
BIG_1024_58 ws2[FFLEN_2048];
BIG_1024_58 ws3[FFLEN_2048];
BIG_1024_58 CC[2 * FFLEN_2048];
BIG_1024_58 DD[2 * FFLEN_2048];
BIG_1024_58 dws[2 * FFLEN_2048];
BIG_512_60 ws4[FFLEN_4096];
BIG_512_60 ws5[HFLEN_4096];
BIG_512_60 ws6[FFLEN_4096];
BIG_512_60 dws2[2 * FFLEN_4096];
BIG_1024_58 q[HFLEN_2048]; //256 bits
BIG_1024_58 q2[FFLEN_2048]; //q^2
BIG_1024_58 q3[FFLEN_2048]; //q^3
BIG_1024_58 q5[FFLEN_2048]; //q^5
BIG_1024_58 q7[FFLEN_2048]; //q^7
char oct1[2 * FS_2048];
octet OCT1 = {0, sizeof(oct1), oct1};
char oct2[2 * FS_2048];
octet OCT2 = {0, sizeof(oct2), oct2};
char oct3[2 * FS_2048];
octet OCT3 = {0, sizeof(oct3), oct3};
// Curve order
CG21_GET_CURVE_ORDER(q);
FF_2048_sqr(q2, q, HFLEN_2048); // q^2
FF_2048_mul(q3, q, q2, HFLEN_2048); // q^3
FF_2048_mul(q5, q3, q2, FFLEN_2048); // q^5
FF_2048_mul(q7, q5, q2, FFLEN_2048); // q^7
// ------------ CHECK 'z1' IS IN [0, ..., q^3] and 'z2' IS IN [0, ..., q^7]------------
if (FF_2048_comp(proofs->z1, q3, FFLEN_2048) > 0 || FF_2048_comp(proofs->z2, q7, FFLEN_2048) > 0)
{
return PiAffp_INVALID_RANGE;
}
// load a 256-bit challenge octet e into 2048-bit big e
OCT_copy(&OCT1, E);
OCT_pad(&OCT1, FS_2048);
FF_2048_fromOctet(e, &OCT1, FFLEN_2048);
// ------------ VALIDATES THE PROOF - PART1 ----------
// Split check s^z1 * t^z3 * S^(-e) == E mod PQ using CRT
CG21_Pedersen_verify(p_proof, pedersen_priv, proofs->z1, proofs->z3, commits->S, e, pedersen_priv->mod.p, false);
CG21_Pedersen_verify(q_proof, pedersen_priv, proofs->z1, proofs->z3, commits->S, e, pedersen_priv->mod.q, false);
FF_2048_dmod(p_gt, commits->E, pedersen_priv->mod.p, HFLEN_2048);
FF_2048_dmod(q_gt, commits->E, pedersen_priv->mod.q, HFLEN_2048);
fail = (FF_2048_comp(p_gt, p_proof, HFLEN_2048) != 0) || (FF_2048_comp(q_gt, q_proof, HFLEN_2048) != 0);
if (fail)
{
// Clean memory
FF_2048_zero(p_gt, HFLEN_2048);
FF_2048_zero(q_gt, HFLEN_2048);
FF_2048_zero(p_proof, HFLEN_2048);
FF_2048_zero(q_proof, HFLEN_2048);
return PiAffp_INVALID_PROOF_P1;
}
// ------------ VALIDATES THE PROOF - PART2 ----------
// Split check s^z2 * t^z4 * T^(-e) == F mod PQ using CRT
CG21_Pedersen_verify(p_proof, pedersen_priv, proofs->z2, proofs->z4, commits->T, e, pedersen_priv->mod.p, 1);
CG21_Pedersen_verify(q_proof, pedersen_priv, proofs->z2, proofs->z4, commits->T, e, pedersen_priv->mod.q, 1);
FF_2048_dmod(p_gt, commits->F, pedersen_priv->mod.p, HFLEN_2048);
FF_2048_dmod(q_gt, commits->F, pedersen_priv->mod.q, HFLEN_2048);
fail = (FF_2048_comp(p_gt, p_proof, HFLEN_2048) != 0) || (FF_2048_comp(q_gt, q_proof, HFLEN_2048) != 0);
if (fail)
{
// ------------ CLEAR MEMORY ----------
FF_2048_zero(p_gt, HFLEN_2048);
FF_2048_zero(q_gt, HFLEN_2048);
FF_2048_zero(p_proof, HFLEN_2048);
FF_2048_zero(q_proof, HFLEN_2048);
return PiAffp_INVALID_PROOF_P2;
}
// ------------ VALIDATES THE PROOF - PART3 ----------
// Split check C^z1 * w^N0 * g^z2 * D^(-e) == A mod N0^2 using CRT
FF_2048_mul(n, verifier_paillier_priv->p, verifier_paillier_priv->q, HFLEN_2048); // n = p * q
FF_2048_fromOctet(CC, C, 2 * FFLEN_2048);
FF_2048_fromOctet(DD, D, 2 * FFLEN_2048);
// CRT: check modulo p^2
FF_2048_copy(ws3, verifier_paillier_priv->p2, FFLEN_2048); // ws3 := p^2
FF_2048_zero(ws1, FFLEN_2048);
FF_2048_copy(ws1, verifier_paillier_priv->p, HFLEN_2048); // ws1 := p
FF_2048_sub(ws3, ws3, ws1, FFLEN_2048); // ws3 := p^2 - p
//https://math.stackexchange.com/a/3099042
FF_2048_sub(ws3, ws3, e, FFLEN_2048); // ws3 := p^2 - p - e
FF_2048_norm(ws3, FFLEN_2048);
FF_2048_dmod(ws1, CC, verifier_paillier_priv->p2, FFLEN_2048); // ws1 = C mod p^2
FF_2048_dmod(ws2, DD, verifier_paillier_priv->p2, FFLEN_2048); // ws2 = D mod p^2
// p_proof := C^z1 * w^N0 * D^-e modulo p^2 = (C mod p^2)^e * w^N0 * (D mod p^2)^{p^2 - p - e} mod p^2
FF_2048_ct_pow_3(p_proof, ws1, proofs->z1, proofs->w, n, ws2, ws3,
verifier_paillier_priv->p2, FFLEN_2048, FFLEN_2048);
FF_2048_mul(dws, n, proofs->z2, FFLEN_2048); // dws := n * z2
FF_2048_dmod(ws1, dws, verifier_paillier_priv->p2, FFLEN_2048); // ws1 := (n * z2) mod p^2
FF_2048_inc(ws1, 1, FFLEN_2048); // ws1 := (n * z2) mod p^2 + 1
FF_2048_norm(ws1, FFLEN_2048);
// dws := ((n * z2) mod p^2 + 1) * p_proof
FF_2048_mul(dws, p_proof, ws1, FFLEN_2048);
FF_2048_dmod(p_proof, dws, verifier_paillier_priv->p2, FFLEN_2048); // dws := dws mod p^2
// CRT: check modulo q^2
FF_2048_copy(ws3, verifier_paillier_priv->q2, FFLEN_2048);
FF_2048_zero(ws1, FFLEN_2048);
FF_2048_copy(ws1, verifier_paillier_priv->q, HFLEN_2048);
FF_2048_sub(ws3, ws3, ws1, FFLEN_2048);
FF_2048_sub(ws3, ws3, e, FFLEN_2048);
FF_2048_norm(ws3, FFLEN_2048);
FF_2048_dmod(ws1, CC, verifier_paillier_priv->q2, FFLEN_2048);
FF_2048_dmod(ws2, DD, verifier_paillier_priv->q2, FFLEN_2048);
// // C^z1 * w^N0 * D^-e modulo q^2
FF_2048_ct_pow_3(q_proof, ws1, proofs->z1, proofs->w, n, ws2, ws3,
verifier_paillier_priv->q2, FFLEN_2048, FFLEN_2048);
FF_2048_zero(dws, 2 * FFLEN_2048);
FF_2048_mul(dws, n, proofs->z2, FFLEN_2048);
FF_2048_dmod(ws1, dws, verifier_paillier_priv->q2, FFLEN_2048);
FF_2048_inc(ws1, 1, FFLEN_2048);
FF_2048_zero(dws, 2 * FFLEN_2048);
FF_2048_mul(dws, q_proof, ws1, FFLEN_2048);
FF_2048_dmod(q_proof, dws, verifier_paillier_priv->q2, FFLEN_2048);
FF_2048_dmod(p_gt, commits->A, verifier_paillier_priv->p2, FFLEN_2048); // p_gt := A mod p^2
FF_2048_dmod(q_gt, commits->A, verifier_paillier_priv->q2, FFLEN_2048); // q_gt := A mod q^2
fail = (FF_2048_comp(p_gt, p_proof, FFLEN_2048) != 0) ||
(FF_2048_comp(q_gt, q_proof, FFLEN_2048) != 0);
if (fail)
{
// ------------ CLEAR MEMORY ----------
FF_2048_zero(p_gt, FFLEN_2048);
FF_2048_zero(q_gt, FFLEN_2048);
FF_2048_zero(p_proof, FFLEN_2048);
FF_2048_zero(q_proof, FFLEN_2048);
FF_2048_zero(ws1, FFLEN_2048);
FF_2048_zero(ws2, FFLEN_2048);
FF_2048_zero(ws3, FFLEN_2048);
FF_2048_zero(dws, 2 * FFLEN_2048);
return PiAffp_INVALID_PROOF_P3;
}
// ------------ VALIDATES THE PROOF - PART4 ----------
// (1+N1)^z1 * wx^N1 = Bx * X^e mod N1^2
FF_2048_toOctet(&OCT1, proofs->wx, FFLEN_2048);
OCT_pad(&OCT1, FS_4096);
FF_2048_toOctet(&OCT2, proofs->z1, FFLEN_2048);
OCT_pad(&OCT2, HFS_4096);
OCT_empty(&OCT3);
PAILLIER_ENCRYPT(NULL, prover_paillier_pub, &OCT2, &OCT3,&OCT1); // OCT3 := (1+N1)^z1 * wx^N1
OCT_pad(X, HFS_4096);
FF_4096_fromOctet(ws4, X, FFLEN_4096);
OCT_copy(&OCT1, E);
OCT_pad(&OCT1, FS_2048);
FF_4096_fromOctet(ws5, &OCT1, HFLEN_4096);
// ws4 := X^e mod N1^2
FF_4096_ct_pow(ws4, ws4, ws5, prover_paillier_pub->n2, FFLEN_4096, HFLEN_4096);
FF_2048_toOctet(&OCT1, commits->Bx, 2 * FFLEN_2048);
FF_4096_fromOctet(ws6,&OCT1, FFLEN_4096);
FF_4096_zero(dws2, 2 * FFLEN_4096);
FF_4096_mul(dws2, ws4, ws6, FFLEN_4096); // dws2 := (X^e mod N1^2) * Bx
FF_4096_dmod(ws4, dws2, prover_paillier_pub->n2, FFLEN_4096); // := (X^e mod N1^2) * Bx mod N1^2
FF_4096_fromOctet(ws6,&OCT3, FFLEN_4096);
fail = (FF_4096_comp(ws4, ws6, FFLEN_2048) != 0);
if (fail)
{
// ------------ CLEAR MEMORY ----------
FF_2048_zero(p_gt, FFLEN_2048);
FF_2048_zero(q_gt, FFLEN_2048);
FF_2048_zero(p_proof, FFLEN_2048);
FF_2048_zero(q_proof, FFLEN_2048);
FF_2048_zero(ws1, FFLEN_2048);
FF_2048_zero(ws2, FFLEN_2048);
FF_2048_zero(ws3, FFLEN_2048);
FF_2048_zero(dws, 2 * FFLEN_2048);
return PiAffp_INVALID_PROOF_P4;
}
// ------------ VALIDATES THE PROOF - PART5 ----------
// Gamma^z2 * wy^N1 = By * Y^e mod N1^2
FF_2048_toOctet(&OCT1, proofs->wy, FFLEN_2048);
OCT_pad(&OCT1, FS_4096);
FF_2048_toOctet(&OCT2, proofs->z2, FFLEN_2048);
OCT_pad(&OCT2, HFS_4096);
OCT_empty(&OCT3);
PAILLIER_ENCRYPT(NULL, prover_paillier_pub, &OCT2, &OCT3,&OCT1); // OCT3 := Gamma^z2 * wy^N1
OCT_pad(Y, HFS_4096);
FF_4096_fromOctet(ws4, Y, FFLEN_4096);
OCT_copy(&OCT1, E);
OCT_pad(&OCT1, FS_2048);
FF_4096_fromOctet(ws5, &OCT1, HFLEN_4096);
// ws4 := Y^e mod N1^2
FF_4096_ct_pow(ws4, ws4, ws5, prover_paillier_pub->n2, FFLEN_4096, HFLEN_4096);
FF_2048_toOctet(&OCT1, commits->By, 2 * FFLEN_2048);
FF_4096_fromOctet(ws6,&OCT1, FFLEN_4096);
FF_4096_zero(dws2, 2 * FFLEN_4096);
FF_4096_mul(dws2, ws4, ws6, FFLEN_4096); // (Y^e mod N1^2) * By
FF_4096_dmod(ws4, dws2, prover_paillier_pub->n2, FFLEN_4096); // (Y^e mod N1^2) * By mod N1^2
FF_4096_fromOctet(ws6,&OCT3, FFLEN_4096);
fail = (FF_4096_comp(ws4, ws6, FFLEN_2048) != 0);
// ------------ CLEAR MEMORY ----------
FF_2048_zero(p_gt, FFLEN_2048);
FF_2048_zero(q_gt, FFLEN_2048);
FF_2048_zero(p_proof, FFLEN_2048);
FF_2048_zero(q_proof, FFLEN_2048);
FF_2048_zero(ws1, FFLEN_2048);
FF_2048_zero(ws2, FFLEN_2048);
FF_2048_zero(ws3, FFLEN_2048);
FF_2048_zero(dws, 2 * FFLEN_2048);
if (fail)
return PiAffp_INVALID_PROOF_P5;
// recall: we already checked 'z1' is in [0, ..., q^3] and 'z2' is in[0, ..., q^7] above
return PiAffp_OK;
}