You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sa...@apache.org on 2020/02/07 12:57:22 UTC
[incubator-milagro-MPC] 02/11: Add receiver zk proof
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 <sa...@yahoo.it>
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);
+}