This is an automated email from the ASF dual-hosted git repository. sandreoli pushed a commit to branch add-phase5-api in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git
commit a643ae5810bc3ae45bb3c7a48dfb4ea7df6bef5f Author: Samuele Andreoli <[email protected]> AuthorDate: Fri Feb 7 11:53:15 2020 +0000 Add phase 5 API --- include/amcl/mpc.h | 71 ++++++++++++++++++++++++ src/mpc.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) diff --git a/include/amcl/mpc.h b/include/amcl/mpc.h index e23e6a8..8818ac7 100644 --- a/include/amcl/mpc.h +++ b/include/amcl/mpc.h @@ -33,6 +33,10 @@ under the License. extern "C" { #endif +#define MPC_OK 0 /**< Execution Successful */ +#define MPC_FAIL 71 /**< Failure */ +#define MPC_INVALID_ECP 72 /**< Input is not a valid point on the curve */ + /** \brief ECDSA Sign message * * Generate the ECDSA signature on message, M, with outputs (R,S) @@ -156,6 +160,73 @@ void MPC_SUM_S(octet *S1, octet *S2, octet *S); */ int MPC_SUM_PK(octet *PK1, octet *PK2, octet *PK); +/* MPC Phase 5 API */ + +/** \brief Generate Commitment for the MPC Phase 5 + * + * Calculate player Commitment (A, V) for MPC Phase 5 + * + * <ol> + * <li> \f$ \phi \in_R [0, \ldots, q] \f$ + * <li> \f$ \rho \in_R [0, \ldots, q] \f$ + * <li> \f$ V = \phi.G + s.R \f$ + * <li> \f$ A = \rho.G \f$ + * </ol> + * + * @param RNG csprng for random values generation + * @param R Reconciled R for the signature + * @param S Player signature share + * @param PHI Random value for the commitment. If RNG is null this is read + * @param RHO Random value for the commitment. If RNG is null this is read + * @param V First component of the player commitment. An ECP in compressed form + * @param A Second component of the player commitment. An ECP in compressed form + * @return Returns MPC_OK or an error code + */ +extern int MPC_PHASE5_commit(csprng *RNG, octet *R, octet *S, octet *PHI, octet *RHO, octet *V, octet *A); + +/** \brief Generate Proof for the MPC Phase 5 + * + * Calculate player Proof (U, T) for MPC Phase 5 + * + * <ol> + * <li> \f$ m = H(M) \f$ + * <li> \f$ A = A1 + A2 \f$ + * <li> \f$ V = V1 + V2 \f$ + * <li> \f$ U = \rho.(V - m.G - r.PK) \f$ + * <li> \f$ T = \phi.A \f$ + * </ol> + * + * @param PHI Random value used in the commitment + * @param RHO Random value used in the commitment + * @param V Array with the commitments V from both players. ECPs in compressed form + * @param A Array with the commitments A from both players. ECPs in compressed form + * @param PK Shared public key for MPC + * @param HM Hash of the message being signed + * @param RX x component of the reconciled R for the signature + * @param U First component of the player proof. An ECP in compressed form + * @param T Second component of the player proof. An ECP in compressed form + * @return Returns MPC_OK or an error code + */ +extern int MPC_PHASE5_prove(octet *PHI, octet *RHO, octet *V[2], octet *A[2], octet *PK, octet *HM, octet *RX, octet *U, octet *T); + +/** \brief Verify Proof for the MPC Phase 5 + * + * Combine player Proofs and verify the consistency of the signature shares + * This does NOT prove that the signature is valid. It only verifies that + * all players know the secret quantities used to generate their shares. + * + * <ol> + * <li> \f$ U = U1 + U2 \f$ + * <li> \f$ T = T1 + T2 \f$ + * <li> \f$ U \stackrel{?}{=} T \f$ + * </ol> + * + * @param U Array with the proofs U from both players. ECPs in compressed form + * @param T Array with the proofs T from both players. ECPs in compressed form + * @return Returns MPC_OK or an error code + */ +extern int MPC_PHASE5_verify(octet *U[2], octet *T[2]); + /*! \brief Write Paillier public key to octets * * @param PUB Paillier public key diff --git a/src/mpc.c b/src/mpc.c index d85f53f..82216f4 100644 --- a/src/mpc.c +++ b/src/mpc.c @@ -347,6 +347,164 @@ int MPC_SUM_PK(octet *PK1, octet *PK2, octet *PK) return 0; } +int MPC_PHASE5_commit(csprng *RNG, octet *R, octet *S, octet *PHI, octet *RHO, octet *V, octet *A) +{ + BIG_256_56 ws; + BIG_256_56 phi; + BIG_256_56 rho; + + ECP_SECP256K1 P1; + ECP_SECP256K1 P2; + + if (!ECP_SECP256K1_fromOctet(&P1, R)) + { + return MPC_INVALID_ECP; + } + + if (RNG != NULL) + { + BIG_256_56_rcopy(ws, CURVE_Order_SECP256K1); + BIG_256_56_randomnum(phi, ws, RNG); + BIG_256_56_randomnum(rho, ws, RNG); + + BIG_256_56_toBytes(PHI->val, phi); + BIG_256_56_toBytes(RHO->val, rho); + PHI->len = EGS_SECP256K1; + RHO->len = EGS_SECP256K1; + } + else + { + BIG_256_56_fromBytesLen(phi, PHI->val, PHI->len); + BIG_256_56_fromBytesLen(rho, RHO->val, RHO->len); + } + + // Compute V = phi.G + s.R + BIG_256_56_fromBytesLen(ws, S->val, S->len); + ECP_SECP256K1_generator(&P2); + + ECP_SECP256K1_mul2(&P1, &P2, ws, phi); + + // Compute A = rho.G + ECP_SECP256K1_mul(&P2, rho); + + // Output ECPs + ECP_SECP256K1_toOctet(V, &P1, 1); + ECP_SECP256K1_toOctet(A, &P2, 1); + + // Clean memory + BIG_256_56_zero(phi); + BIG_256_56_zero(rho); + BIG_256_56_zero(ws); + + return MPC_OK; +} + +int MPC_PHASE5_prove(octet *PHI, octet *RHO, octet *V[2], octet *A[2], octet *PK, octet *HM, octet *RX, octet *U, octet *T) +{ + BIG_256_56 m; + BIG_256_56 r; + BIG_256_56 ws; + + ECP_SECP256K1 V1; + ECP_SECP256K1 V2; + ECP_SECP256K1 A1; + ECP_SECP256K1 A2; + ECP_SECP256K1 K; + + if (!ECP_SECP256K1_fromOctet(&A1, A[0])) + { + return MPC_INVALID_ECP; + } + + if (!ECP_SECP256K1_fromOctet(&A2, A[1])) + { + return MPC_INVALID_ECP; + } + + if (!ECP_SECP256K1_fromOctet(&V1, V[0])) + { + return MPC_INVALID_ECP; + } + + if (!ECP_SECP256K1_fromOctet(&V2, V[1])) + { + return MPC_INVALID_ECP; + } + + if (!ECP_SECP256K1_fromOctet(&K, PK)) + { + return MPC_INVALID_ECP; + } + + // Compute A = phi.(A1 + A2) + BIG_256_56_fromBytesLen(ws, PHI->val, PHI->len); + ECP_SECP256K1_add(&A1, &A2); + ECP_SECP256K1_mul(&A1, ws); + + ECP_SECP256K1_toOctet(T, &A1, 1); + + // Compute V = rho.(V1 + V2 - m.G - r.PK) + BIG_256_56_fromBytesLen(m, HM->val, HM->len); + BIG_256_56_fromBytesLen(r, RX->val, RX->len); + BIG_256_56_fromBytesLen(ws, RHO->val, RHO->len); + + // K = - m.G - r.PK + ECP_SECP256K1_generator(&A1); + ECP_SECP256K1_neg(&A1); + ECP_SECP256K1_neg(&K); + ECP_SECP256K1_mul2(&K, &A1, r, m); + + // V = rho.(V1 + V2 + K) + ECP_SECP256K1_add(&V1, &V2); + ECP_SECP256K1_add(&V1, &K); + ECP_SECP256K1_mul(&V1, ws); + + ECP_SECP256K1_toOctet(U, &V1, 1); + + // Clean memory + BIG_256_56_zero(ws); + + return MPC_OK; +} + +int MPC_PHASE5_verify(octet *U[2], octet *T[2]) +{ + ECP_SECP256K1 U1; + ECP_SECP256K1 U2; + ECP_SECP256K1 T1; + ECP_SECP256K1 T2; + + if (!ECP_SECP256K1_fromOctet(&U1, U[0])) + { + return MPC_INVALID_ECP; + } + + if (!ECP_SECP256K1_fromOctet(&U2, U[1])) + { + return MPC_INVALID_ECP; + } + + if (!ECP_SECP256K1_fromOctet(&T1, T[0])) + { + return MPC_INVALID_ECP; + } + + if (!ECP_SECP256K1_fromOctet(&T2, T[1])) + { + return MPC_INVALID_ECP; + } + + ECP_SECP256K1_add(&U1, &U2); + ECP_SECP256K1_add(&T1, &T2); + + if (!ECP_SECP256K1_equals(&U1, &T1)) + { + return MPC_FAIL; + } + + return MPC_OK; +} + // Write Paillier public key to octets void MPC_DUMP_PAILLIER_PK(PAILLIER_public_key *PUB, octet *N, octet *G, octet *N2) {
