This is an automated email from the ASF dual-hosted git repository. sandreoli pushed a commit to branch add-mta-zk-proofs in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git
commit 9a02171b725cdbf5eb659b1e0e76a5b0d40ad0a6 Author: Samuele Andreoli <[email protected]> AuthorDate: Wed Feb 5 09:57:24 2020 +0000 Add receiver zk proof --- include/amcl/mta.h | 175 +++++++++++++++++++++++++ src/mta.c | 369 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 544 insertions(+) diff --git a/include/amcl/mta.h b/include/amcl/mta.h index e4053a4..0db289b 100644 --- a/include/amcl/mta.h +++ b/include/amcl/mta.h @@ -254,6 +254,181 @@ extern void MTA_RP_proof_fromOctets(MTA_RP_proof *p, octet *S, octet *S1, octet */ extern void MTA_RP_commitment_rv_kill(MTA_RP_commitment_rv *rv); +/** \brief Secret random values for the receiver ZKP commitment */ +typedef struct +{ + BIG_1024_58 alpha[FFLEN_2048]; /**< Random value in \f$ [0, \ldots, q^3] \f$ */ + BIG_1024_58 beta[FFLEN_2048]; /**< Random value in \f$ [0, \ldots, N] \f$ */ + BIG_1024_58 gamma[FFLEN_2048]; /**< Random value in \f$ [0, \ldots, N] \f$ */ + BIG_1024_58 rho[FFLEN_2048 + HFLEN_2048]; /**< Random value in \f$ [0, \ldots, \tilde{N}q] \f$ */ + BIG_1024_58 rho1[FFLEN_2048 + HFLEN_2048]; /**< Random value in \f$ [0, \ldots, \tilde{N}q^3] \f$ */ + BIG_1024_58 sigma[FFLEN_2048 + HFLEN_2048]; /**< Random value in \f$ [0, \ldots, \tilde{N}q] \f$ */ + BIG_1024_58 tau[FFLEN_2048 + HFLEN_2048]; /**< Random value in \f$ [0, \ldots, \tilde{N}q] \f$ */ +} MTA_ZK_commitment_rv; + +/** \brief Public commitment for the Receiver ZKP */ +typedef struct +{ + BIG_1024_58 z[FFLEN_2048]; /**< Commitment to h1, h2, x using rho */ + BIG_1024_58 z1[FFLEN_2048]; /**< Auxiliary Commitment to h1, h2, binding alpha and rho1 */ + BIG_1024_58 t[FFLEN_2048]; /**< Commitment to h1, h2, y using sigma */ + BIG_1024_58 v[2 * FFLEN_2048]; /**< Commitment to paillier PK and c1 using alpha and gamma */ + BIG_1024_58 w[FFLEN_2048]; /**< Auxiliary Commitment to h1, h2, binding gamma and tau */ +} MTA_ZK_commitment; + +/** \brief Range Proof for the Receiver ZKP */ +typedef struct +{ + BIG_1024_58 s[FFLEN_2048]; /**< Proof of knowledge of the Paillier r value */ + BIG_1024_58 s1[FFLEN_2048]; /**< Proof of knowledge of x. It must be less than q^3 */ + BIG_1024_58 s2[FFLEN_2048 + HFLEN_2048]; /**< Auxiliary proof of knowledge for x */ + BIG_1024_58 t1[FFLEN_2048]; /**< Proof of knowledge of y */ + BIG_1024_58 t2[FFLEN_2048 + HFLEN_2048]; /**< Auxiliary proof of knowledge for y */ +} MTA_ZK_proof; + +/** \brief Commitment Generation for Receiver ZKP + * + * Generate a commitment for the values x, y and c1 + * + * <ol> + * <li> \f$ \alpha \in_R [0, \ldots, q^3]\f$ + * <li> \f$ \beta \in_R [0, \ldots, N]\f$ + * <li> \f$ \gamma \in_R [0, \ldots, N]\f$ + * <li> \f$ \rho \in_R [0, \ldots, q\tilde{N}]\f$ + * <li> \f$ \rho_1 \in_R [0, \ldots, q^{3}\tilde{N}]\f$ + * <li> \f$ \sigma \in_R [0, \ldots, q\tilde{N}]\f$ + * <li> \f$ \tau \in_R [0, \ldots, q\tilde{N}]\f$ + * <li> \f$ z = h_1^{x}h_2^{\rho} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$ + * <li> \f$ z_1 = h_1^{\alpha}h_2^{\rho_1} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$ + * <li> \f$ t = h_1^{y}h_2^{\sigma} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$ + * <li> \f$ w = h_1^{\gamma}h_2^{\tau} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$ + * <li> \f$ v = c1^{\alpha}g^{\gamma}\beta^{N} \text{ }\mathrm{mod}\text{ }N^2 \f$ + * </ol> + * + * @param RNG csprng for random generation + * @param key Paillier key used to encrypt C1 + * @param mod Public BC modulus of the verifier + * @param X Message to prove knowledge and range + * @param Y Message to prove knowledge + * @param C1 Base Paillier Ciphertext + * @param c Destinaton commitment + * @param rv Random values associated to the commitment. If RNG is NULL this is read + */ +extern void MTA_ZK_commit(csprng *RNG, PAILLIER_public_key *key, COMMITMENTS_BC_pub_modulus *mod, octet *X, octet *Y, octet *C1, MTA_ZK_commitment *c, MTA_ZK_commitment_rv *rv); + +/** \brief Deterministic Challenge generations for Receiver ZKP + * + * Generate a challenge binding together public parameters and commitment + * + * <ol> + * <li> \f$ e = H( g | \tilde{N} | h_1 | h_2 | q | c_1 | c_2 | z | z1 | t | v | w ) \f$ + * </ol> + * + * @param key Public Paillier key of the prover + * @param mod Public BC modulus of the verifier + * @param C1 Base Paillier Ciphertext + * @param C2 New Paillier Ciphertext to prove knowledge and range + * @param c Commitment of the prover + * @param E Destination challenge + */ +extern void MTA_ZK_challenge(PAILLIER_public_key *key, COMMITMENTS_BC_pub_modulus *mod, octet *C1, octet *C2, MTA_ZK_commitment *c, octet *E); + +/** \brief Proof generation for Receiver ZKP + * + * Generate a proof of knowledge of x, y and a range proof for x + * + * <ol> + * <li> \f$ s = \beta r^e \text{ }\mathrm{mod}\text{ }N \f$ + * <li> \f$ s_1 = ex + \alpha \f$ + * <li> \f$ s_2 = e\rho + \rho_1 \f$ + * <li> \f$ t_1 = ey + \gamma \f$ + * <li> \f$ t_2 = e\sigma + \tau \f$ + * </ol> + * + * @param key Private Paillier key of the prover + * @param rv Random values associated to the commitment + * @param X Message to prove knowledge and range + * @param Y Message to prove knowledge + * @param R Random value used in the Paillier addition + * @param E Generated challenge + * @param p Destination proof + */ +extern void MTA_ZK_prove(PAILLIER_public_key *key, MTA_ZK_commitment_rv *rv, octet *X, octet *Y, octet *R, octet *E, MTA_ZK_proof *p); + +// TODO go from here + +/** \brief Verify a Proof for Receiver ZKP + * + * Verify the proof of knowledge of x, y associated to c1, c2 and of x range + * + * <ol> + * <li> \f$ s_1 \stackrel{?}{\leq} q^3 \f$ + * <li> \f$ z_1 \stackrel{?}{=} h_1^{s_1}h_2^{s_2}z^{-e} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$ + * <li> \f$ w \stackrel{?}{=} h_1^{t_1}h_2^{t_2}t^{-e} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$ + * <li> \f$ v \stackrel{?}{=} c1^{s_1}s^{N}g^{t_1}c2^{-e} \text{ }\mathrm{mod}\text{ }N^2 \f$ + * </ol> + * + * @param key Public Paillier key of the prover + * @param mod Private BC modulus of the verifier + * @param C1 Base Paillier Ciphertext + * @param C2 New Paillier Ciphertext to prove knowledge and range + * @param E Generated challenge + * @param c Received commitment + * @param p Received proof + * @return MTA_OK if the proof is valid, MTA_FAIL otherwise + */ +extern int MTA_ZK_verify(PAILLIER_private_key *key, COMMITMENTS_BC_priv_modulus *mod, octet *C1, octet *C2, octet *E, MTA_ZK_commitment *c, MTA_ZK_proof *p); + +/** \brief Dump the commitment to octets + * + * @param Z Destination Octet for the z component of the commitment. FS_2048 long + * @param Z1 Destination Octet for the z1 component of the commitment. FS_2048 long + * @param T Destination Octet for the t component of the commitment. FS_2048 long + * @param V Destination Octet for the v component of the commitment. FS_4096 long + * @param W Destination Octet for the w component of the commitment. FS_2048 long + * @param c Commitment to export + */ +extern void MTA_ZK_commitment_toOctets(octet *Z, octet *Z1, octet *T, octet *V, octet *W, MTA_ZK_commitment *c); + +/** \brief Read the commitments from octets + * + * @param c Destination commitment + * @param Z Destination Octet for the z component of the commitment. FS_2048 long + * @param Z1 Destination Octet for the z1 component of the commitment. FS_2048 long + * @param T Destination Octet for the t component of the commitment. FS_2048 long + * @param V Destination Octet for the v component of the commitment. FS_4096 long + * @param W Destination Octet for the w component of the commitment. FS_2048 long + */ +extern void MTA_ZK_commitment_fromOctets(MTA_ZK_commitment *c, octet *Z, octet *Z1, octet *T, octet *V, octet *W); + +/** \brief Dump the proof to octets + * + * @param S Destination Octet for the s component of the proof. FS_2048 long + * @param S1 Destination Octet for the s1 component of the proof. HFS_2048 long + * @param S2 Destination Octet for the s2 component of the proof. FS_2048 + HFS_2048 long + * @param T1 Destination Octet for the t1 component of the proof. FS_2048 long + * @param T2 Destination Octet for the t2 component of the proof. FS_2048 + HFS_2048 long + * @param p Proof to export + */ +extern void MTA_ZK_proof_toOctets(octet *S, octet *S1, octet *S2, octet *T1, octet *T2, MTA_ZK_proof *p); + +/** \brief Read the commitments from octets + * + * @param p Destination proof + * @param S Octet with the s component of the proof + * @param S1 Octet with the s1 component of the proof + * @param S2 Octet with the s2 component of the proof + * @param T1 Octet with the t1 component of the proof + * @param T2 Octet with the t2 component of the proof + */ +extern void MTA_ZK_proof_fromOctets(MTA_ZK_proof *p, octet *S, octet *S1, octet *S2, octet *T1, octet *T2); + +/** \brief Clean the memory containing the random values + * + * @param rv Random values to clean + */ +extern void MTA_ZK_commitment_rv_kill(MTA_ZK_commitment_rv *rv); + #ifdef __cplusplus } #endif diff --git a/src/mta.c b/src/mta.c index e1d725b..5fa3a31 100644 --- a/src/mta.c +++ b/src/mta.c @@ -145,6 +145,28 @@ void hash_RP_params(hash256 *sha, PAILLIER_public_key *key, COMMITMENTS_BC_pub_m OCT_hash(sha, &OCT); } +// Update the provided hash with the data for the MTA ZK commitment +void hash_ZK_commitment(hash256 *sha, MTA_ZK_commitment *c) +{ + char oct[2 * FS_2048]; + octet OCT = {0, sizeof(oct), oct}; + + FF_2048_toOctet(&OCT, c->z, FFLEN_2048); + OCT_hash(sha, &OCT); + + FF_2048_toOctet(&OCT, c->z1, FFLEN_2048); + OCT_hash(sha, &OCT); + + FF_2048_toOctet(&OCT, c->t, FFLEN_2048); + OCT_hash(sha, &OCT); + + FF_2048_toOctet(&OCT, c->v, 2 * FFLEN_2048); + OCT_hash(sha, &OCT); + + FF_2048_toOctet(&OCT, c->w, FFLEN_2048); + OCT_hash(sha, &OCT); +} + /* MTA descriptions */ // Client MTA first pass @@ -645,3 +667,350 @@ void MTA_RP_commitment_rv_kill(MTA_RP_commitment_rv *rv) FF_2048_zero(rv->gamma, FFLEN_2048 + HFLEN_2048); FF_2048_zero(rv->rho, FFLEN_2048 + HFLEN_2048); } + +void MTA_ZK_commit(csprng *RNG, PAILLIER_public_key *key, COMMITMENTS_BC_pub_modulus *mod, octet *X, octet *Y, octet *C1, MTA_ZK_commitment *c, MTA_ZK_commitment_rv *rv) +{ + BIG_1024_58 q[HFLEN_2048]; + BIG_1024_58 q3[FFLEN_2048]; + BIG_1024_58 tws[FFLEN_2048 + HFLEN_2048]; + + BIG_512_60 alpha[HFLEN_4096]; + BIG_512_60 beta[FFLEN_4096]; + BIG_512_60 gamma[HFLEN_4096]; + BIG_512_60 ws[FFLEN_4096]; + + char oct[2 * FS_2048]; + octet OCT = {0, sizeof(oct), oct}; + + // Curve order + OCT_fromHex(&OCT, curve_order_hex); + FF_2048_zero(q, HFLEN_2048); + BIG_512_60_fromBytesLen(q[0],OCT.val,OCT.len); + + // Zero out beta since it's needed regardless of RNG + FF_4096_zero(beta, FFLEN_4096); + + if (RNG != NULL) + { + // Generate alpha in [0, .., q^3] + FF_2048_sqr(q3, q, HFLEN_2048); + FF_2048_mul(q3, q, q3, HFLEN_2048); + + FF_2048_zero(rv->alpha, FFLEN_2048); + FF_2048_random(rv->alpha, RNG, HFLEN_2048); + FF_2048_mod(rv->alpha, q3, HFLEN_2048); + + // Generate beta in [0, .., N] + FF_4096_randomnum(beta, key->n, RNG, HFLEN_4096); + FF_4096_toOctet(&OCT, beta, HFLEN_4096); + FF_2048_fromOctet(rv->beta, &OCT, FFLEN_2048); + + // Generate gamma in [0, .., N] + FF_4096_randomnum(gamma, key->n, RNG, HFLEN_4096); + FF_4096_toOctet(&OCT, gamma, HFLEN_4096); + FF_2048_fromOctet(rv->gamma, &OCT, FFLEN_2048); + + // Generate rho, tau, sigma in [0, .., Nt * q] + FF_2048_amul(tws, q, HFLEN_2048, mod->N, FFLEN_2048); + FF_2048_random(rv->rho, RNG, FFLEN_2048 + HFLEN_2048); + FF_2048_mod(rv->rho, tws, FFLEN_2048 + HFLEN_2048); + + FF_2048_random(rv->tau, RNG, FFLEN_2048 + HFLEN_2048); + FF_2048_mod(rv->tau, tws, FFLEN_2048 + HFLEN_2048); + + FF_2048_random(rv->sigma, RNG, FFLEN_2048 + HFLEN_2048); + FF_2048_mod(rv->sigma, tws, FFLEN_2048 + HFLEN_2048); + + // Generate rho1 in [0, .., Nt * q^3] + FF_2048_amul(tws, q3, HFLEN_2048, mod->N, FFLEN_2048); + FF_2048_random(rv->rho1, RNG, FFLEN_2048 + HFLEN_2048); + FF_2048_mod(rv->rho1, tws, FFLEN_2048 + HFLEN_2048); + } + else + { + FF_2048_toOctet(&OCT, rv->beta, FFLEN_2048); + FF_4096_fromOctet(beta, &OCT, HFLEN_4096); + + FF_2048_toOctet(&OCT, rv->gamma, FFLEN_2048); + FF_4096_fromOctet(gamma, &OCT, HFLEN_4096); + } + + // Compute z = h1^x * h2^rho mod Nt + OCT_copy(&OCT, X); + OCT_pad(&OCT, HFS_2048); + FF_2048_zero(tws, FFLEN_2048 + HFLEN_2048); + FF_2048_fromOctet(tws, &OCT, HFLEN_2048); + FF_2048_skpow2(c->z, mod->b0, tws, mod->b1, rv->rho, mod->N, FFLEN_2048, FFLEN_2048 + HFLEN_2048); + + // Compute t = h1^y * h2^sigma mod Nt + OCT_copy(&OCT, Y); + OCT_pad(&OCT, HFS_2048); + FF_2048_fromOctet(tws, &OCT, HFLEN_2048); + FF_2048_skpow2(c->t, mod->b0, tws, mod->b1, rv->sigma, mod->N, FFLEN_2048, FFLEN_2048 + HFLEN_2048); + + // Compute z1 = h1^alpha * h2^rho1 mod Nt and + FF_2048_copy(tws, rv->alpha, HFLEN_2048); + FF_2048_skpow2(c->z1, mod->b0, tws, mod->b1, rv->rho1, mod->N, FFLEN_2048, FFLEN_2048 + HFLEN_2048); + + // Compute w = h1^gamma * h2^tau mod Nt + FF_2048_copy(tws, rv->gamma, FFLEN_2048); + FF_2048_skpow2(c->w, mod->b0, tws, mod->b1, rv->tau, mod->N, FFLEN_2048, FFLEN_2048 + HFLEN_2048); + + // Compute v = c1^alpha * g^gamma * beta^N mod n2 + FF_4096_fromOctet(ws, C1, FFLEN_4096); + + FF_2048_toOctet(&OCT, rv->alpha, HFLEN_2048); + OCT_pad(&OCT, HFS_4096); + FF_4096_fromOctet(alpha, &OCT, HFLEN_4096); + + FF_4096_skpow3(ws, ws, alpha, key->g, gamma, beta, key->n, key->n2, FFLEN_4096, HFLEN_4096); + + FF_4096_toOctet(&OCT, ws, FFLEN_4096); + FF_2048_fromOctet(c->v, &OCT, 2 * FFLEN_2048); + + // Clean memory + FF_4096_zero(alpha, HFLEN_4096); + FF_4096_zero(beta, FFLEN_4096); + FF_4096_zero(gamma, HFLEN_4096); +} + +void MTA_ZK_challenge(PAILLIER_public_key *key, COMMITMENTS_BC_pub_modulus *mod, octet *C1, octet *C2, MTA_ZK_commitment *c, octet *E) +{ + hash256 sha; + + char oct[2*FS_2048]; + octet OCT = {0, sizeof(oct), oct}; + + BIG_256_56 q; + BIG_256_56 t; + + // Load curve order + BIG_256_56_rcopy(q, CURVE_Order_SECP256K1); + + HASH256_init(&sha); + + /* Bind to public parameters */ + hash_RP_params(&sha, key, mod, q); + + /* Bind to proof input */ + OCT_hash(&sha, C1); + OCT_hash(&sha, C2); + + /* Bind to proof commitment */ + hash_ZK_commitment(&sha, c); + + /* Output */ + HASH256_hash(&sha, OCT.val); + BIG_256_56_fromBytesLen(t, OCT.val, SHA256); + BIG_256_56_mod(t, q); + + BIG_256_56_toBytes(E->val, t); + E->len = MODBYTES_256_56; +} + +void MTA_ZK_prove(PAILLIER_public_key *key, MTA_ZK_commitment_rv *rv, octet *X, octet *Y, octet *R, octet *E, MTA_ZK_proof *p) +{ + BIG_1024_58 hws[HFLEN_2048]; + BIG_1024_58 ws[FFLEN_2048]; + BIG_1024_58 dws[2*FFLEN_2048]; + + BIG_1024_58 n[FFLEN_2048]; + BIG_1024_58 e[HFLEN_2048]; + + char oct[2*FS_2048]; + octet OCT = {0, sizeof(oct), oct}; + + OCT_copy(&OCT, E); + OCT_pad(&OCT, HFS_2048); + FF_2048_fromOctet(e, &OCT, HFLEN_2048); + + // Compute s = beta * r^e mod N + OCT_copy(&OCT, R); + FF_2048_fromOctet(dws, &OCT, 2*FFLEN_2048); + + FF_4096_toOctet(&OCT, key->n, HFLEN_4096); + FF_2048_fromOctet(n, &OCT, FFLEN_2048); + + FF_2048_dmod(ws, dws, n, FFLEN_2048); + FF_2048_skpow(ws, ws, e, n, FFLEN_2048, HFLEN_2048); + FF_2048_mul(dws, rv->beta, ws, FFLEN_2048); + FF_2048_dmod(p->s, dws, n, FFLEN_2048); + + // Compute s1 = e*x + alpha + OCT_copy(&OCT, X); + OCT_pad(&OCT, HFS_2048); + FF_2048_fromOctet(hws, &OCT, HFLEN_2048); + + FF_2048_zero(p->s1, FFLEN_2048); + + FF_2048_mul(ws, e, hws, HFLEN_2048); + FF_2048_copy(p->s1, rv->alpha, HFLEN_2048); + FF_2048_add(p->s1, p->s1, ws, HFLEN_2048); + FF_2048_norm(p->s1, HFLEN_2048); + + // Compute s2 = e*rho + rho1 + FF_2048_amul(dws, e, HFLEN_2048, rv->rho, FFLEN_2048 + HFLEN_2048); + FF_2048_copy(p->s2, rv->rho1, FFLEN_2048 + HFLEN_2048); + FF_2048_add(p->s2, p->s2, dws, FFLEN_2048 + HFLEN_2048); + FF_2048_norm(p->s2, FFLEN_2048 + HFLEN_2048); + + // Compute t1 = e*y + gamma + OCT_copy(&OCT, Y); + OCT_pad(&OCT, HFS_2048); + FF_2048_fromOctet(hws, &OCT, HFLEN_2048); + + FF_2048_mul(ws, e, hws, HFLEN_2048); + FF_2048_copy(p->t1, rv->gamma, FFLEN_2048); + FF_2048_add(p->t1, p->t1, ws, FFLEN_2048); + FF_2048_norm(p->t1, FFLEN_2048); + + // Compute s2 = e*sigma + tau + FF_2048_amul(dws, e, HFLEN_2048, rv->sigma, FFLEN_2048 + HFLEN_2048); + FF_2048_copy(p->t2, rv->tau, FFLEN_2048 + HFLEN_2048); + FF_2048_add(p->t2, p->t2, dws, FFLEN_2048 + HFLEN_2048); + FF_2048_norm(p->t2, FFLEN_2048 + HFLEN_2048); + + // Clean memory + FF_2048_zero(hws, HFLEN_2048); + FF_2048_zero(ws , FFLEN_2048); + FF_2048_zero(dws, 2 * FFLEN_2048); +} + +int MTA_ZK_verify(PAILLIER_private_key *key, COMMITMENTS_BC_priv_modulus *mod, octet *C1, octet *C2, octet *E, MTA_ZK_commitment *c, MTA_ZK_proof *p) +{ + BIG_1024_58 e[FFLEN_2048]; + BIG_1024_58 q[HFLEN_2048]; + BIG_1024_58 n[FFLEN_2048]; + BIG_1024_58 g[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 c1[2 * FFLEN_2048]; + BIG_1024_58 c2[2 * FFLEN_2048]; + + BIG_1024_58 ws1[FFLEN_2048]; + BIG_1024_58 ws2[FFLEN_2048]; + + char oct[2*FS_2048]; + octet OCT = {0, sizeof(oct), oct}; + + // Check if s1 < q^3 + OCT_fromHex(&OCT, curve_order_hex); + OCT_pad(&OCT, HFS_2048); + FF_2048_fromOctet(q, &OCT, HFLEN_2048); + FF_2048_sqr(ws1, q, HFLEN_2048); + FF_2048_mul(ws1, ws1, q, HFLEN_2048); + + if (FF_2048_comp(p->s1, ws1, HFLEN_2048) > 0) + { + return MTA_FAIL; + } + + OCT_copy(&OCT, E); + OCT_pad(&OCT, FS_2048); + FF_2048_fromOctet(e, &OCT, FFLEN_2048); + + // Split check b0^s1 * b1^s2 * z^(-e) == z1 mod PQ using CRT + MTA_triple_power(p_proof, mod->b0, mod->b1, p->s1, p->s2, c->z, e, mod->P, 0); + MTA_triple_power(q_proof, mod->b0, mod->b1, p->s1, p->s2, c->z, e, mod->Q, 0); + + FF_2048_dmod(p_gt, c->z1, mod->P, HFLEN_2048); + FF_2048_dmod(q_gt, c->z1, mod->Q, HFLEN_2048); + + if ((FF_2048_comp(p_gt, p_proof, HFLEN_2048) != 0) || (FF_2048_comp(q_gt, q_proof, HFLEN_2048) != 0)) + { + return MTA_FAIL; + } + + // Split check if b0^t1 * b1^t2 * t^(-e) == w mod PQ using CRT + MTA_triple_power(p_proof, mod->b0, mod->b1, p->t1, p->t2, c->t, e, mod->P, 1); + MTA_triple_power(q_proof, mod->b0, mod->b1, p->t1, p->t2, c->t, e, mod->Q, 1); + + FF_2048_dmod(p_gt, c->w, mod->P, HFLEN_2048); + FF_2048_dmod(q_gt, c->w, mod->Q, HFLEN_2048); + + if ((FF_2048_comp(p_gt, p_proof, HFLEN_2048) != 0) || (FF_2048_comp(q_gt, q_proof, HFLEN_2048) != 0)) + { + return MTA_FAIL; + } + + // Split check c1^s1 * s^N * g^t1 * c2^(-e) == v mod N^2 using CRT + FF_2048_mul(n, key->p, key->q, HFLEN_2048); + FF_2048_copy(g, n, FFLEN_2048); + FF_2048_inc(g, 1, FFLEN_2048); + + FF_2048_fromOctet(c1, C1, 2 * FFLEN_2048); + FF_2048_fromOctet(c2, C2, 2 * FFLEN_2048); + + FF_2048_dmod(ws1, c1, key->p2, FFLEN_2048); + FF_2048_dmod(ws2, c2, key->p2, FFLEN_2048); + FF_2048_invmodp(ws2, ws2, key->p2, FFLEN_2048); + FF_2048_pow4(p_proof, ws1, p->s1, p->s, n, g, p->t1, ws2, e, key->p2, FFLEN_2048, FFLEN_2048); + + FF_2048_dmod(ws1, c1, key->q2, FFLEN_2048); + FF_2048_dmod(ws2, c2, key->q2, FFLEN_2048); + FF_2048_invmodp(ws2, ws2, key->q2, FFLEN_2048); + FF_2048_pow4(q_proof, ws1, p->s1, p->s, n, g, p->t1, ws2, e, key->q2, FFLEN_2048, FFLEN_2048); + + FF_2048_dmod(p_gt, c->v, key->p2, FFLEN_2048); + FF_2048_dmod(q_gt, c->v, key->q2, FFLEN_2048); + + if ((FF_2048_comp(p_gt, p_proof, FFLEN_2048) != 0) || (FF_2048_comp(q_gt, q_proof, FFLEN_2048) != 0)) + { + return MTA_FAIL; + } + + return MTA_OK; +} + +void MTA_ZK_commitment_toOctets(octet *Z, octet *Z1, octet *T, octet *V, octet *W, MTA_ZK_commitment *c) +{ + FF_2048_toOctet(Z, c->z, FFLEN_2048); + FF_2048_toOctet(Z1, c->z1,FFLEN_2048); + FF_2048_toOctet(T, c->t, FFLEN_2048); + FF_2048_toOctet(V, c->v, 2 * FFLEN_2048); + FF_2048_toOctet(W, c->w, FFLEN_2048); +} + +void MTA_ZK_commitment_fromOctets(MTA_ZK_commitment *c, octet *Z, octet *Z1, octet *T, octet *V, octet *W) +{ + FF_2048_fromOctet(c->z, Z, FFLEN_2048); + FF_2048_fromOctet(c->z1, Z1, FFLEN_2048); + FF_2048_fromOctet(c->t, T, FFLEN_2048); + FF_2048_fromOctet(c->v, V, 2 * FFLEN_2048); + FF_2048_fromOctet(c->w, W, FFLEN_2048); +} + +void MTA_ZK_proof_toOctets(octet *S, octet *S1, octet *S2, octet *T1, octet *T2, MTA_ZK_proof *p) +{ + FF_2048_toOctet(S, p->s, FFLEN_2048); + FF_2048_toOctet(S1, p->s1, HFLEN_2048); + FF_2048_toOctet(S2, p->s2, FFLEN_2048 + HFLEN_2048); + FF_2048_toOctet(T1, p->t1, FFLEN_2048); + FF_2048_toOctet(T2, p->t2, FFLEN_2048 + HFLEN_2048); +} + +void MTA_ZK_proof_fromOctets(MTA_ZK_proof *p, octet *S, octet *S1, octet *S2, octet *T1, octet *T2) +{ + FF_2048_zero(p->s1, FFLEN_2048); + + FF_2048_fromOctet(p->s, S, FFLEN_2048); + FF_2048_fromOctet(p->s1, S1, HFLEN_2048); + FF_2048_fromOctet(p->s2, S2, FFLEN_2048 + HFLEN_2048); + FF_2048_fromOctet(p->t1, T1, FFLEN_2048); + FF_2048_fromOctet(p->t2, T2, FFLEN_2048 + HFLEN_2048); +} + +void MTA_ZK_commitment_rv_kill(MTA_ZK_commitment_rv *rv) +{ + FF_2048_zero(rv->alpha, HFLEN_2048); + FF_2048_zero(rv->beta, FFLEN_2048); + FF_2048_zero(rv->gamma, FFLEN_2048); + FF_2048_zero(rv->rho, FFLEN_2048 + HFLEN_2048); + FF_2048_zero(rv->rho1, FFLEN_2048 + HFLEN_2048); + FF_2048_zero(rv->sigma, FFLEN_2048 + HFLEN_2048); + FF_2048_zero(rv->tau, FFLEN_2048 + HFLEN_2048); +}
