blob: 55eabb67e5386a47e19e60983274cc6a79443b36 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#include <string.h>
#include "amcl/mta.h"
#include "amcl/mpc.h"
#include "amcl/commitments.h"
#include "amcl/factoring_zk.h"
#include "amcl/schnorr.h"
/* Example of the full flow */
typedef struct
{
PAILLIER_private_key paillier_sk;
PAILLIER_public_key paillier_pk;
PAILLIER_public_key paillier_cpk;
COMMITMENTS_BC_priv_modulus bc_sm;
COMMITMENTS_BC_pub_modulus bc_pm;
COMMITMENTS_BC_pub_modulus bc_cpm;
octet *SK;
octet *PK;
octet *CPK;
octet *FPK;
} key_material;
// Safe primes for BC Setup
char *A_P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
char *A_Q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835";
char *B_P_hex = "efa013403e9ea93daf97f1dd4b42eba602410e048852b20cd448d51793ac2ee725e79eaac82d22cdd6cfb966cba62904a26da47d7a6085fba194e24eddbc92f66a0bd990c8cb9abf98fff48d52d33215d68f6f030cd9440f85987b2ab44332646ea38bc218fedc83a24cf57b7615c0fc9289778f7ba60f4ed71c7c3c571054fb";
char *B_Q_hex = "f95b9d7027be3950de9a050eba7301d5234ad89bf260d47e94a724b49759ab9a8fca22fe484e5e5ddf0845734cd3322d271e146e1e6eed6e16a2740c294097cd65deeacbfa563cce42065720836d421bcfd73c6dcab3aa0c4d480ac445e9ba11fb7825559b29ab4f9f6f079acbd0dc5c38702f386b3c95107540195a4508401b";
int generate_key_material(csprng *RNG, key_material *km, octet *P, octet *Q)
{
int rc;
char pk[2 * EFS_SECP256K1 + 1];
octet PK = {0, sizeof(pk), pk};
char out[2][FS_2048];
octet OUT1 = {0, sizeof(out[0]), out[0]};
octet OUT2 = {0, sizeof(out[1]), out[1]};
ECP_SECP256K1 ECP;
// ECDSA Key Pair
printf("\n\tGenerate ECDSA key pair\n");
rc = ECP_SECP256K1_KEY_PAIR_GENERATE(RNG, km->SK, &PK);
if (rc != 0)
{
return rc;
}
rc = ECP_SECP256K1_PUBLIC_KEY_VALIDATE(&PK);
if (rc != 0)
{
return rc;
}
ECP_SECP256K1_fromOctet(&ECP, &PK);
ECP_SECP256K1_toOctet(km->PK, &ECP, true);
printf("\t\tSK = ");
OCT_output(km->SK);
printf("\t\tPK = ");
OCT_output(km->PK);
// Paillier Key pair
printf("\n\tGenerate Paillier key pair. Associated primes\n");
PAILLIER_KEY_PAIR(RNG, NULL, NULL, &km->paillier_pk, &km->paillier_sk);
FF_2048_toOctet(&OUT1, km->paillier_sk.p, HFLEN_2048);
FF_2048_toOctet(&OUT2, km->paillier_sk.q, HFLEN_2048);
printf("\t\tP = ");
OCT_output(&OUT1);
printf("\t\tQ = ");
OCT_output(&OUT2);
// BC modulus
printf("\n\tGenerate BC modulus\n");
COMMITMENTS_BC_setup(RNG, &km->bc_sm, P, Q, NULL, NULL);
COMMITMENTS_BC_export_public_modulus(&km->bc_pm, &km->bc_sm);
FF_2048_toOctet(&OUT1, km->bc_sm.P, HFLEN_2048);
FF_2048_toOctet(&OUT2, km->bc_sm.Q, HFLEN_2048);
printf("\t\tP = ");
OCT_output(&OUT1);
printf("\t\tQ = ");
OCT_output(&OUT2);
FF_2048_toOctet(&OUT1, km->bc_sm.b0, FFLEN_2048);
FF_2048_toOctet(&OUT2, km->bc_sm.b1, FFLEN_2048);
printf("\t\tB0 = ");
OCT_output(&OUT1);
printf("\t\tB1 = ");
OCT_output(&OUT2);
return MPC_OK;
}
void key_material_zkp(csprng *RNG, key_material *km, octet *C, octet *P, octet *E, octet *Y)
{
char r[EGS_SECP256K1];
octet R = {0, sizeof(r), r};
char s_e[EGS_SECP256K1];
octet S_E = {0, sizeof(s_e), s_e};
FACTORING_ZK_modulus m;
/* Prove knowledge of DLOG PK = s.G */
SCHNORR_commit(RNG, &R, C);
SCHNORR_challenge(km->PK, C, &S_E);
SCHNORR_prove(&R, &S_E, km->SK, P);
printf("\n\tProve knowledge of ECDSA sk\n");
printf("\t\tC = ");
OCT_output(C);
printf("\t\tE = ");
OCT_output(&S_E);
printf("\t\tP = ");
OCT_output(P);
OCT_clear(&R);
/* Prove knowledge of factorization of the Paillier modulus */
FF_2048_copy(m.p, km->paillier_sk.p, HFLEN_2048);
FF_2048_copy(m.q, km->paillier_sk.q, HFLEN_2048);
FF_2048_mul(m.n, m.p, m.q, HFLEN_2048);
FACTORING_ZK_prove(&m, RNG, NULL, E, Y);
printf("\n\tProve knowledge of the Paillier Secret Key\n");
printf("\t\tE = ");
OCT_output(E);
printf("\t\tY = ");
OCT_output(Y);
FACTORING_ZK_kill_modulus(&m);
}
int key_material_verify_zkp(key_material *km, octet *C, octet *P, octet *E, octet *Y)
{
int rc;
char s_e[EGS_SECP256K1];
octet S_E = {0, sizeof(s_e), s_e};
char n[FS_2048];
octet N = {0, sizeof(n), n};
/* Verify Schnorr Proof for counterparty PK */
printf("\n\tVerify Proof of knowledge of ECDSA sk\n");
SCHNORR_challenge(km->CPK, C, &S_E);
rc = SCHNORR_verify(km->CPK, C, &S_E, P);
if (rc != SCHNORR_OK)
{
return rc;
}
printf("\t\tSuccess\n");
/* Verify Factoring Proof for Paillier PK */
printf("\n\tVerify Proof of knowledge of Paillier sk\n");
PAILLIER_PK_toOctet(&N, &km->paillier_cpk);
rc = FACTORING_ZK_verify(&N, E, Y);
if (rc != FACTORING_ZK_OK)
{
return rc;
}
printf("\t\tSuccess\n");
return MPC_OK;
}
/* Key Setup.
*
* Step 1. Generate ECDSA key pair, Paillier key pair and Bit Commitment modulus
* Setp 1A. Commit to ECDSA public Key, generating commitment and decommitment values.
* Step 1B. Transmit Paillier public key, Bit Commitment public modulus and the commitment value
*
* Upon receipt of the commitment value from the other party:
*
* Step 2. Decommit value for counterparty PK. Abort if it fails
* Step 2A. Combine public keys
*
* Step 3. Produce ZKP of correctness of key material and transmit
* Step 4. Verify counterparty proof of correctness of key material
*/
void key_setup(csprng *RNG, key_material *alice_km, key_material *bob_km)
{
int rc;
char safe_p[HFS_2048];
octet SAFE_P = {0, sizeof(safe_p), safe_p};
char safe_q[HFS_2048];
octet SAFE_Q = {0, sizeof(safe_q), safe_q};
// Octets for Non Malleable Commitments
char commit_r[2][SHA256];
octet A_COMMIT_R = {0, sizeof(commit_r[0]), commit_r[0]};
octet B_COMMIT_R = {0, sizeof(commit_r[1]), commit_r[1]};
char commit_c[2][SHA256];
octet A_COMMIT_C = {0, sizeof(commit_c[0]), commit_c[0]};
octet B_COMMIT_C = {0, sizeof(commit_c[1]), commit_c[1]};
// Octets for Key Setup ZKPs
char kzkp_c[2][EFS_SECP256K1 + 1];
octet A_KZKP_C = {0, sizeof(kzkp_c[0]), kzkp_c[0]};
octet B_KZKP_C = {0, sizeof(kzkp_c[1]), kzkp_c[1]};
char kzkp_p[2][EGS_SECP256K1];
octet A_KZKP_P = {0, sizeof(kzkp_p[0]), kzkp_p[0]};
octet B_KZKP_P = {0, sizeof(kzkp_p[1]), kzkp_p[1]};
char kzkp_e[2][SHA256];
octet A_KZKP_E = {0, sizeof(kzkp_e[0]), kzkp_e[0]};
octet B_KZKP_E = {0, sizeof(kzkp_e[1]), kzkp_e[1]};
char kzkp_y[2][FS_2048];
octet A_KZKP_Y = {0, sizeof(kzkp_y[0]), kzkp_y[0]};
octet B_KZKP_Y = {0, sizeof(kzkp_y[1]), kzkp_y[1]};
// Octet for paillier PK transmission
char paillier_pk[FS_2048];
octet PAILLIER_PK = {0, sizeof(paillier_pk), paillier_pk};
/* Alice - generate key material and commitment */
printf("\n[Alice] Generate key material\n");
OCT_fromHex(&SAFE_P, A_P_hex);
OCT_fromHex(&SAFE_Q, A_Q_hex);
rc = generate_key_material(RNG, alice_km, &SAFE_P, &SAFE_Q);
if (rc != MPC_OK)
{
printf("\nFAILURE generating Alice key material. rc %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\n[Alice] Commit to generated PK\n");
COMMITMENTS_NM_commit(RNG, alice_km->PK, &A_COMMIT_R, &A_COMMIT_C);
printf("\tR = ");
OCT_output(&A_COMMIT_R);
printf("\tC = ");
OCT_output(&A_COMMIT_C);
printf("\n[Alice] Transmit commitment C\n");
// Transmit commitment C, Paillier PK and BC [u] modulus
PAILLIER_PK_toOctet(&PAILLIER_PK, &alice_km->paillier_pk);
PAILLIER_PK_fromOctet(&bob_km->paillier_cpk, &PAILLIER_PK);
COMMITMENTS_BC_export_public_modulus(&bob_km->bc_cpm, &alice_km->bc_sm);
/* Bob - generate key material and commitment */
printf("\n[Bob] Generate key material\n");
OCT_fromHex(&SAFE_P, B_P_hex);
OCT_fromHex(&SAFE_Q, B_Q_hex);
rc = generate_key_material(RNG, bob_km, &SAFE_P, &SAFE_Q);
if (rc != MPC_OK)
{
printf("\nFAILURE generating Bob key material. rc %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\n[Bob] Commit to generated PK\n");
COMMITMENTS_NM_commit(RNG, bob_km->PK, &B_COMMIT_R, &B_COMMIT_C);
printf("\tR = ");
OCT_output(&A_COMMIT_R);
printf("\tC = ");
OCT_output(&A_COMMIT_C);
printf("\n[Bob] Transmit commitment C\n");
// Transmit commitment C, Paillier PK and BC public modulus
PAILLIER_PK_toOctet(&PAILLIER_PK, &bob_km->paillier_pk);
PAILLIER_PK_fromOctet(&alice_km->paillier_cpk, &PAILLIER_PK);
COMMITMENTS_BC_export_public_modulus(&alice_km->bc_cpm, &bob_km->bc_sm);
/* Alice/Bob - transmit decommitment strings and message */
printf("\n[Alice] Transmit decommitment value R and PK\n");
printf("\n[Bob] Transmit decommitment value R and PK\n");
OCT_copy(alice_km->CPK, bob_km->PK);
OCT_copy(bob_km->CPK, alice_km->PK);
/* Alice - decommit Bob PK and combine */
printf("\n[Alice] Decommit Bob PK and combine full PK\n");
rc = COMMITMENTS_NM_decommit(alice_km->CPK, &B_COMMIT_R, &B_COMMIT_C);
if (rc != COMMITMENTS_OK)
{
printf("\n FAILURE decommitting Bob PK\n");
exit(EXIT_FAILURE);
}
printf("\tDecommitment successful\n");
rc = MPC_SUM_PK(alice_km->PK, alice_km->CPK, alice_km->FPK);
if (rc != MPC_OK)
{
printf("\nFAILURE combining ECDSA PK for Alice\n");
exit(EXIT_FAILURE);
}
printf("\tCombined PK = ");
OCT_output(alice_km->FPK);
/* Bob - decommit Alice PK */
printf("\n[Bob] Decommit Alice PK and combine full PK\n");
rc = COMMITMENTS_NM_decommit(bob_km->CPK, &A_COMMIT_R, &A_COMMIT_C);
if (rc != COMMITMENTS_OK)
{
printf("\n FAILURE decommitting Alice PK\n");
exit(EXIT_FAILURE);
}
printf("\tDecommitment successful\n");
rc = MPC_SUM_PK(bob_km->PK, bob_km->CPK, bob_km->FPK);
if (rc != MPC_OK)
{
printf("\nFAILURE combining ECDSA PK for Bob\n");
exit(EXIT_FAILURE);
}
printf("\tCombined PK = ");
OCT_output(bob_km->FPK);
/* Alice - generate key material ZKP */
printf("\n[Alice] Prove correctness of key material\n");
key_material_zkp(RNG, alice_km, &A_KZKP_C, &A_KZKP_P, &A_KZKP_E, &A_KZKP_Y);
printf("\n[Alice] Transmit C, P, E, Y\n");
/* Bob - generate key material ZKP */
printf("\n[Bob] Prove correctness of key material\n");
key_material_zkp(RNG, bob_km, &B_KZKP_C, &B_KZKP_P, &B_KZKP_E, &B_KZKP_Y);
printf("\n[Bob] Transmit C, P, E, Y\n");
/* Alice/Bob - verify key material ZKP */
printf("\n[Alice] Verify Key Material ZKP\n");
rc = key_material_verify_zkp(alice_km, &B_KZKP_C, &B_KZKP_P, &B_KZKP_E, &B_KZKP_Y);
if (rc != MPC_OK)
{
printf("\n FAILURE invalid ZKP for Bob key material. rc %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\n[Bob] Verify Key Material ZKP\n");
rc = key_material_verify_zkp(bob_km, &A_KZKP_C, &A_KZKP_P, &A_KZKP_E, &A_KZKP_Y);
if (rc != MPC_OK)
{
printf("\n FAILURE invalid ZKP for Alice key material. rc %d\n", rc);
exit(EXIT_FAILURE);
}
}
/* Perform MTA with Range Proof and Receiver ZK Proof
*
* Step 1. Alice encrypts its share and proves it is in the appropriate range in ZK
* Step 2. Bob verifies the ZK proof and aborts if the verification fails
* Step 2A. Bob homomorphically multiplies its share and adds an obfuscation value z
* Step 2B. Bob proves knowledge of z and range of its share
* Step 3. Alice verifies the ZK proof and aborts if the verification fails
* Step 3A. Alice decrypts the obfuscated product.
*/
void mta(csprng *RNG, key_material *alice_km, key_material *bob_km, octet *K, octet *GAMMA, octet *ALPHA, octet *BETA, char *alice_name, char *bob_name)
{
int rc;
char ca[FS_4096];
octet CA = {0, sizeof(ca), ca};
char cb[FS_4096];
octet CB = {0, sizeof(cb), cb};
char r[FS_4096];
octet R = {0, sizeof(r), r};
char z[EGS_SECP256K1];
octet Z = {0, sizeof(z), z};
char e[EGS_SECP256K1];
octet E = {0, sizeof(e), e};
MTA_RP_commitment alice_rp_c;
MTA_RP_commitment_rv alice_rp_rv;
MTA_RP_proof alice_rp_proof;
MTA_ZK_commitment bob_zk_c;
MTA_ZK_commitment_rv bob_zk_rv;
MTA_ZK_proof bob_zk_proof;
char out[5][FS_4096];
octet OUT1 = {0, sizeof(out[0]), out[0]};
octet OUT2 = {0, sizeof(out[1]), out[1]};
octet OUT3 = {0, sizeof(out[2]), out[2]};
octet OUT4 = {0, sizeof(out[3]), out[3]};
octet OUT5 = {0, sizeof(out[4]), out[4]};
/* Alice - Initiate MTA protocol and generate Range Proof */
printf("\n[%s] MTA Pass 1 with Range Proof\n", alice_name);
MPC_MTA_CLIENT1(RNG, &alice_km->paillier_pk, K, &CA, &R);
printf("\tCA = ");
OCT_output(&CA);
printf("\n\tRange Proof\n");
MTA_RP_commit(RNG, &alice_km->paillier_sk, &alice_km->bc_cpm, K, &alice_rp_c, &alice_rp_rv);
MTA_RP_challenge(&alice_km->paillier_pk, &alice_km->bc_cpm, &CA, &alice_rp_c, &E);
MTA_RP_prove(&alice_km->paillier_sk, &alice_rp_rv, K, &R, &E, &alice_rp_proof);
MTA_RP_commitment_toOctets(&OUT1, &OUT2, &OUT3, &alice_rp_c);
printf("\t\tZ = ");
OCT_output(&OUT1);
printf("\t\tU = ");
OCT_output(&OUT2);
printf("\t\tW = ");
OCT_output(&OUT3);
printf("\t\tE = ");
OCT_output(&E);
MTA_RP_proof_toOctets(&OUT1, &OUT2, &OUT3, &alice_rp_proof);
printf("\t\tS = ");
OCT_output(&OUT1);
printf("\t\tS1 = ");
OCT_output(&OUT2);
printf("\t\tS2 = ");
OCT_output(&OUT3);
MTA_RP_commitment_rv_kill(&alice_rp_rv);
OCT_clear(&R);
// Transmit CA, Commitment and Proof
printf("\n[%s] Transmit CA and proof (Z, U, W, S, S1, S2)\n", alice_name);
/* Bob - Verify Range Proof and perform second step of MTA protocol */
OCT_clear(&E);
MTA_RP_challenge(&bob_km->paillier_cpk, &bob_km->bc_pm, &CA, &alice_rp_c, &E);
printf("\n[%s] Verify proof\n", bob_name);
printf("\tE = ");
OCT_output(&E);
rc = MTA_RP_verify(&bob_km->paillier_cpk, &bob_km->bc_sm, &CA, &E, &alice_rp_c, &alice_rp_proof);
if (rc != MTA_OK)
{
printf("FAILURE %s - MTA Invalid %s Range Proof. rc %d\n", bob_name, alice_name, rc);
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[%s] MTA Pass 2 with ZK Proof\n", bob_name);
MPC_MTA_SERVER(RNG, &bob_km->paillier_cpk, GAMMA, &CA, &Z, &R, &CB, BETA);
printf("\tCB = ");
OCT_output(&CB);
printf("\tBETA = ");
OCT_output(BETA);
printf("\n\tZK Proof\n");
MTA_ZK_commit(RNG, &bob_km->paillier_cpk, &bob_km->bc_cpm, GAMMA, &Z, &CA, &bob_zk_c, &bob_zk_rv);
MTA_ZK_challenge(&bob_km->paillier_cpk, &bob_km->bc_cpm, &CA, &CB, &bob_zk_c, &E);
MTA_ZK_prove(&bob_km->paillier_cpk, &bob_zk_rv, GAMMA, &Z, &R, &E, &bob_zk_proof);
MTA_ZK_commitment_toOctets(&OUT1, &OUT2, &OUT3, &OUT4, &OUT5, &bob_zk_c);
printf("\t\tZ = ");
OCT_output(&OUT1);
printf("\t\tZ1 = ");
OCT_output(&OUT2);
printf("\t\tT = ");
OCT_output(&OUT3);
printf("\t\tV = ");
OCT_output(&OUT4);
printf("\t\tW = ");
OCT_output(&OUT5);
printf("\t\tE = ");
OCT_output(&E);
MTA_ZK_proof_toOctets(&OUT1, &OUT2, &OUT3, &OUT4, &OUT5, &bob_zk_proof);
printf("\t\tS = ");
OCT_output(&OUT1);
printf("\t\tS1 = ");
OCT_output(&OUT2);
printf("\t\tS2 = ");
OCT_output(&OUT3);
printf("\t\tT1 = ");
OCT_output(&OUT4);
printf("\t\tT2 = ");
OCT_output(&OUT5);
MTA_ZK_commitment_rv_kill(&bob_zk_rv);
OCT_clear(&R);
OCT_clear(&Z);
// Transmit CB, Commitment and Proof
printf("\n[%s] Transmit CB and proof (Z, Z1, T, V, W, S, S1, S2, T1, T2)\n", bob_name);
/* Alice - Verify ZK proof and perform last step of MTA protocol */
OCT_clear(&E);
MTA_ZK_challenge(&alice_km->paillier_pk, &alice_km->bc_pm, &CA, &CB, &bob_zk_c, &E);
printf("\n[%s] Verify proof\n", alice_name);
printf("\tE = ");
OCT_output(&E);
rc = MTA_ZK_verify(&alice_km->paillier_sk, &alice_km->bc_sm, &CA, &CB, &E, &bob_zk_c, &bob_zk_proof);
if (rc != MTA_OK)
{
printf("FAILURE %s - MTA Invalid %s ZK Proof. rc %d\n", alice_name, bob_name, rc);
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[%s] MTA Pass 3\n", alice_name);
MPC_MTA_CLIENT2(&alice_km->paillier_sk, &CB, ALPHA);
printf("ALPHA = ");
OCT_output(ALPHA);
}
/* Perform MTAWC with Range Proof and Receiver ZK Proof
*
* Step 1. Alice encrypts its share and proves it is in the appropriate range in ZK
* Step 2. Bob verifies the ZK proof and aborts if the verification fails
* Step 2A. Bob homomorphically multiplies its share and adds an obfuscation value z
* Step 2B. Bob proves knowledge of z and range of its share. It also proves that its
* share is the exponent of a known DLOG.
* Step 3. Alice verifies the ZK proof and aborts if the verification fails
* Step 3A. Alice decrypts the obfuscated product.
*/
void mtawc(csprng *RNG, key_material *alice_km, key_material *bob_km, octet *K, octet *ALPHA, octet *BETA, char *alice_name, char *bob_name)
{
int rc;
char ca[FS_4096];
octet CA = {0, sizeof(ca), ca};
char cb[FS_4096];
octet CB = {0, sizeof(cb), cb};
char r[FS_4096];
octet R = {0, sizeof(r), r};
char z[EGS_SECP256K1];
octet Z = {0, sizeof(z), z};
char e[EGS_SECP256K1];
octet E = {0, sizeof(e), e};
MTA_RP_commitment alice_rp_c;
MTA_RP_commitment_rv alice_rp_rv;
MTA_RP_proof alice_rp_proof;
MTA_ZKWC_commitment bob_zk_c;
MTA_ZKWC_commitment_rv bob_zk_rv;
MTA_ZKWC_proof bob_zk_proof;
char out[6][FS_4096];
octet OUT1 = {0, sizeof(out[0]), out[0]};
octet OUT2 = {0, sizeof(out[1]), out[1]};
octet OUT3 = {0, sizeof(out[2]), out[2]};
octet OUT4 = {0, sizeof(out[3]), out[3]};
octet OUT5 = {0, sizeof(out[4]), out[4]};
octet OUT6 = {0, sizeof(out[5]), out[5]};
/* Alice - Initiate MTA protocol and generate Range Proof */
printf("\n[%s] MTAWC Pass 1 with Range Proof\n", alice_name);
MPC_MTA_CLIENT1(RNG, &alice_km->paillier_pk, K, &CA, &R);
printf("\tCA = ");
OCT_output(&CA);
printf("\n\tRange Proof\n");
MTA_RP_commit(RNG, &alice_km->paillier_sk, &alice_km->bc_cpm, K, &alice_rp_c, &alice_rp_rv);
MTA_RP_challenge(&alice_km->paillier_pk, &alice_km->bc_cpm, &CA, &alice_rp_c, &E);
MTA_RP_prove(&alice_km->paillier_sk, &alice_rp_rv, K, &R, &E, &alice_rp_proof);
MTA_RP_commitment_rv_kill(&alice_rp_rv);
MTA_RP_commitment_toOctets(&OUT1, &OUT2, &OUT3, &alice_rp_c);
printf("\t\tZ = ");
OCT_output(&OUT1);
printf("\t\tU = ");
OCT_output(&OUT2);
printf("\t\tW = ");
OCT_output(&OUT3);
printf("\t\tE = ");
OCT_output(&E);
MTA_RP_proof_toOctets(&OUT1, &OUT2, &OUT3, &alice_rp_proof);
printf("\t\tS = ");
OCT_output(&OUT1);
printf("\t\tS1 = ");
OCT_output(&OUT2);
printf("\t\tS2 = ");
OCT_output(&OUT3);
MTA_RP_commitment_rv_kill(&alice_rp_rv);
OCT_clear(&R);
// Transmit CA, Commitment and Proof
printf("\n[%s] Transmit CA and proof (Z, U, W, S, S1, S2)\n", alice_name);
/* Bob - Verify Range Proof and perform second step of MTAWC protocol */
OCT_clear(&E);
MTA_RP_challenge(&bob_km->paillier_cpk, &bob_km->bc_pm, &CA, &alice_rp_c, &E);
printf("\n[%s] Verify proof\n", bob_name);
printf("\tE = ");
OCT_output(&E);
rc = MTA_RP_verify(&bob_km->paillier_cpk, &bob_km->bc_sm, &CA, &E, &alice_rp_c, &alice_rp_proof);
if (rc != MTA_OK)
{
printf("FAILURE %s - MTAWC Invalid %s Range Proof. rc %d\n", bob_name, alice_name, rc);
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[%s] MTAWC Pass 2 with ZK Proof\n", bob_name);
MPC_MTA_SERVER(RNG, &bob_km->paillier_cpk, bob_km->SK, &CA, &Z, &R, &CB, BETA);
printf("\tCB = ");
OCT_output(&CB);
printf("\tBETA = ");
OCT_output(BETA);
printf("\n\tZK Proof\n");
MTA_ZKWC_commit(RNG, &bob_km->paillier_cpk, &bob_km->bc_cpm, bob_km->SK, &Z, &CA, &bob_zk_c, &bob_zk_rv);
MTA_ZKWC_challenge(&bob_km->paillier_cpk, &bob_km->bc_cpm, &CA, &CB, bob_km->PK, &bob_zk_c, &E);
MTA_ZKWC_prove(&bob_km->paillier_cpk, &bob_zk_rv, bob_km->SK, &Z, &R, &E, &bob_zk_proof);
MTA_ZKWC_commitment_toOctets(&OUT1, &OUT2, &OUT3, &OUT4, &OUT5, &OUT6, &bob_zk_c);
printf("\t\tU = ");
OCT_output(&OUT1);
printf("\t\tZ = ");
OCT_output(&OUT2);
printf("\t\tZ1 = ");
OCT_output(&OUT3);
printf("\t\tT = ");
OCT_output(&OUT4);
printf("\t\tV = ");
OCT_output(&OUT5);
printf("\t\tW = ");
OCT_output(&OUT6);
printf("\t\tE = ");
OCT_output(&E);
MTA_ZKWC_proof_toOctets(&OUT1, &OUT2, &OUT3, &OUT4, &OUT5, &bob_zk_proof);
printf("\t\tS = ");
OCT_output(&OUT1);
printf("\t\tS1 = ");
OCT_output(&OUT2);
printf("\t\tS2 = ");
OCT_output(&OUT3);
printf("\t\tT1 = ");
OCT_output(&OUT4);
printf("\t\tT2 = ");
OCT_output(&OUT5);
MTA_ZKWC_commitment_rv_kill(&bob_zk_rv);
OCT_clear(&R);
OCT_clear(&Z);
// Transmit CB, Commitment and Proof
printf("\n[%s] Transmit CB and proof (Z, Z1, T, V, W, S, S1, S2, T1, T2)\n", bob_name);
/* Alice - Verify ZK proof and perform last step of MTAWC protocol */
OCT_clear(&E);
MTA_ZKWC_challenge(&alice_km->paillier_pk, &alice_km->bc_pm, &CA, &CB, alice_km->CPK, &bob_zk_c, &E);
printf("\n[%s] Verify proof\n", alice_name);
printf("\tE = ");
OCT_output(&E);
rc = MTA_ZKWC_verify(&alice_km->paillier_sk, &alice_km->bc_sm, &CA, &CB, alice_km->CPK, &E, &bob_zk_c, &bob_zk_proof);
if (rc != MTA_OK)
{
printf("FAILURE %s - MTAWC Invalid %s ZK Proof. rc %d\n", alice_name, bob_name, rc);
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[%s] MTAWC Pass 3\n", alice_name);
MPC_MTA_CLIENT2(&alice_km->paillier_sk, &CB, ALPHA);
printf("ALPHA = ");
OCT_output(ALPHA);
}
/* Phase 5 interactive proof of consistency of the signature shares
*
* Step 1. Each player generates random values phi and rho and commitments
* V, A and commits to the value (V, A)
* Step 2. The values (V, A) are decommited and the players prove they are
* well formed
* Step 2A. The well formedness proofs are transmitted and verified
* Step 3. Each player generates a proof for the commitments (V, A) and transmits
* a commitment to the proof
* Step 3A. The proofs are decommitted and verified
*/
void phase5(csprng *RNG, octet *RP1, octet *RP2, octet *R1, octet *R2, octet *HM, octet *S1, octet *S2, octet *PK)
{
int rc;
char rho[2][EGS_SECP256K1];
octet RHO1 = {0, sizeof(rho[0]), rho[0]};
octet RHO2 = {0, sizeof(rho[1]), rho[1]};
char phi[2][EGS_SECP256K1];
octet PHI1 = {0, sizeof(phi[0]), phi[0]};
octet PHI2 = {0, sizeof(phi[1]), phi[1]};
char v[2][EFS_SECP256K1 + 1];
octet V1 = {0, sizeof(v[0]), v[0]};
octet V2 = {0, sizeof(v[1]), v[1]};
octet *V[2] = {&V1, &V2};
char a[2][EFS_SECP256K1 + 1];
octet A1 = {0, sizeof(a[0]), a[0]};
octet A2 = {0, sizeof(a[1]), a[1]};
octet *A[2] = {&A1, &A2};
char u[2][EFS_SECP256K1 + 1];
octet U1 = {0, sizeof(u[0]), u[0]};
octet U2 = {0, sizeof(u[1]), u[1]};
octet *U[2] = {&U1, &U2};
char t[2][EFS_SECP256K1 + 1];
octet T1 = {0, sizeof(t[0]), t[0]};
octet T2 = {0, sizeof(t[1]), t[1]};
octet *T[2] = {&T1, &T2};
// Octets for Non Malleable Commitments
char double_ecp[2 * EFS_SECP256K1 + 2];
octet DOUBLE_ECP = {0, sizeof(double_ecp), double_ecp};
char commit_r[2][SHA256];
octet A_COMMIT_R = {0, sizeof(commit_r[0]), commit_r[0]};
octet B_COMMIT_R = {0, sizeof(commit_r[1]), commit_r[1]};
char commit_c[2][SHA256];
octet A_COMMIT_C = {0, sizeof(commit_c[0]), commit_c[0]};
octet B_COMMIT_C = {0, sizeof(commit_c[1]), commit_c[1]};
// Octets for Schnorr Proofs
char schnorr_r[2][EGS_SECP256K1];
octet SCHNORR_R1 = {0, sizeof(schnorr_r[0]), schnorr_r[0]};
octet SCHNORR_R2 = {0, sizeof(schnorr_r[1]), schnorr_r[1]};
char schnorr_e[2][EGS_SECP256K1];
octet SCHNORR_E1 = {0, sizeof(schnorr_e[0]), schnorr_e[0]};
octet SCHNORR_E2 = {0, sizeof(schnorr_e[1]), schnorr_e[1]};
char schnorr_c[2][EFS_SECP256K1 + 1];
octet SCHNORR_C1 = {0, sizeof(schnorr_c[0]), schnorr_c[0]};
octet SCHNORR_C2 = {0, sizeof(schnorr_c[1]), schnorr_c[1]};
char schnorr_p[2][EGS_SECP256K1];
octet SCHNORR_P1 = {0, sizeof(schnorr_p[0]), schnorr_p[0]};
octet SCHNORR_P2 = {0, sizeof(schnorr_p[1]), schnorr_p[1]};
char schnorr_a[2][EGS_SECP256K1];
octet SCHNORR_A1 = {0, sizeof(schnorr_a[0]), schnorr_a[0]};
octet SCHNORR_A2 = {0, sizeof(schnorr_a[1]), schnorr_a[1]};
char schnorr_b[2][EGS_SECP256K1];
octet SCHNORR_B1 = {0, sizeof(schnorr_b[0]), schnorr_b[0]};
octet SCHNORR_B2 = {0, sizeof(schnorr_b[1]), schnorr_b[1]};
char schnorr_d[2][EFS_SECP256K1 + 1];
octet SCHNORR_D1 = {0, sizeof(schnorr_d[0]), schnorr_d[0]};
octet SCHNORR_D2 = {0, sizeof(schnorr_d[1]), schnorr_d[1]};
char schnorr_t[2][EGS_SECP256K1];
octet SCHNORR_T1 = {0, sizeof(schnorr_t[0]), schnorr_t[0]};
octet SCHNORR_T2 = {0, sizeof(schnorr_t[1]), schnorr_t[1]};
char schnorr_u[2][EGS_SECP256K1];
octet SCHNORR_U1 = {0, sizeof(schnorr_u[0]), schnorr_u[0]};
octet SCHNORR_U2 = {0, sizeof(schnorr_u[1]), schnorr_u[1]};
/* Alice - commitment */
printf("\n[Alice] Generate commitment (V, A) for Phase5 proof and nm commit to it\n");
rc = MPC_PHASE5_commit(RNG, RP1, S1, &PHI1, &RHO1, &V1, &A1);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE Alice Phase5 commit rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tPHI = ");
OCT_output(&PHI1);
printf("\tRHO = ");
OCT_output(&RHO1);
printf("\tV = ");
OCT_output(&V1);
printf("\tA = ");
OCT_output(&A1);
// Generate commitment to V, A
printf("\n\tCommitment\n");
OCT_copy(&DOUBLE_ECP, &V1);
OCT_joctet(&DOUBLE_ECP, &A1);
COMMITMENTS_NM_commit(RNG, &DOUBLE_ECP, &A_COMMIT_R, &A_COMMIT_C);
printf("\t\tR = ");
OCT_output(&A_COMMIT_R);
printf("\t\tC = ");
OCT_output(&A_COMMIT_C);
printf("\n[Alice] Transmit C value for the (V, A) NM commitment\n");
/* Bob - commitment */
printf("\n[Bob] Generate commitment (V, A) for Phase5 proof and nm commit to it\n");
rc = MPC_PHASE5_commit(RNG, RP2, S2, &PHI2, &RHO2, &V2, &A2);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE Bob Phase5 commit rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tPHI = ");
OCT_output(&PHI2);
printf("\tRHO = ");
OCT_output(&RHO2);
printf("\tV = ");
OCT_output(&V2);
printf("\tA = ");
OCT_output(&A2);
// Generate commitment to V, A
printf("\n\tCommitment\n");
OCT_copy(&DOUBLE_ECP, &V2);
OCT_joctet(&DOUBLE_ECP, &A2);
COMMITMENTS_NM_commit(RNG, &DOUBLE_ECP, &B_COMMIT_R, &B_COMMIT_C);
printf("\t\tR = ");
OCT_output(&B_COMMIT_R);
printf("\t\tC = ");
OCT_output(&B_COMMIT_C);
printf("\n[Bob] Transmit C value for the (V, A) NM commitment\n");
// Decommit commitments
printf("\n[Alice] Transmit decommitment value R and (V, A)\n");
printf("\n[Bob] Transmit decommitment value R and (V, A)\n");
printf("\n[Alice] Decommit Bob (V, A)\n");
OCT_copy(&DOUBLE_ECP, &V2);
OCT_joctet(&DOUBLE_ECP, &A2);
rc = COMMITMENTS_NM_decommit(&DOUBLE_ECP, &B_COMMIT_R, &B_COMMIT_C);
if (rc != COMMITMENTS_OK)
{
printf("\nFAILURE - Invalid Bob (V, A) commitment\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[Bob] Decommit Alice (V, A)\n");
OCT_copy(&DOUBLE_ECP, &V1);
OCT_joctet(&DOUBLE_ECP, &A1);
rc = COMMITMENTS_NM_decommit(&DOUBLE_ECP, &A_COMMIT_R, &A_COMMIT_C);
if (rc != COMMITMENTS_OK)
{
printf("\nFAILURE - Invalid Alice (V, A) commitment\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
/* Alice/Bob - Prove well formedness of commitments (V, A) */
printf("\n[Alice] Generate DSchnorr Proof for PHI, SK, V\n");
SCHNORR_D_commit(RNG, RP1, &SCHNORR_A1, &SCHNORR_B1, &SCHNORR_D1);
SCHNORR_D_challenge(RP1, &V1, &SCHNORR_D1, &SCHNORR_E1);
SCHNORR_D_prove(&SCHNORR_A1, &SCHNORR_B1, &SCHNORR_E1, S1, &PHI1, &SCHNORR_T1, &SCHNORR_U1);
printf("\tD = ");
OCT_output(&SCHNORR_D1);
printf("\tE = ");
OCT_output(&SCHNORR_E1);
printf("\tT = ");
OCT_output(&SCHNORR_T1);
printf("\tU = ");
OCT_output(&SCHNORR_U1);
printf("\n[Alice] Generate Schnorr Proof for A, RHO\n");
SCHNORR_commit(RNG, &SCHNORR_R1, &SCHNORR_C1);
SCHNORR_challenge(&A1, &SCHNORR_C1, &SCHNORR_E1);
SCHNORR_prove(&SCHNORR_R1, &SCHNORR_E1, &RHO1, &SCHNORR_P1);
printf("\tC = ");
OCT_output(&SCHNORR_C1);
printf("\tE = ");
OCT_output(&SCHNORR_E1);
printf("\tP = ");
OCT_output(&SCHNORR_P1);
printf("\n[Alice] Transmit proofs (D, T, U) and (C, P)\n");
printf("\n[Bob] Generate DSchnorr Proof for PHI, SK, V\n");
SCHNORR_D_commit(RNG, RP2, &SCHNORR_A2, &SCHNORR_B2, &SCHNORR_D2);
SCHNORR_D_challenge(RP2, &V2, &SCHNORR_D2, &SCHNORR_E2);
SCHNORR_D_prove(&SCHNORR_A2, &SCHNORR_B2, &SCHNORR_E2, S2, &PHI2, &SCHNORR_T2, &SCHNORR_U2);
printf("\tC = ");
OCT_output(&SCHNORR_D2);
printf("\tE = ");
OCT_output(&SCHNORR_E2);
printf("\tT = ");
OCT_output(&SCHNORR_T2);
printf("\tU = ");
OCT_output(&SCHNORR_U2);
printf("\n[Bob] Generate Schnorr Proof for A, RHO\n");
SCHNORR_commit(RNG, &SCHNORR_R2, &SCHNORR_C2);
SCHNORR_challenge(&A2, &SCHNORR_C2, &SCHNORR_E2);
SCHNORR_prove(&SCHNORR_R2, &SCHNORR_E2, &RHO2, &SCHNORR_P2);
printf("\tC = ");
OCT_output(&SCHNORR_C2);
printf("\tE = ");
OCT_output(&SCHNORR_E2);
printf("\tP = ");
OCT_output(&SCHNORR_P2);
printf("\n[Bob] Transmit proofs (D, T, U) and (C, P)\n");
printf("\n[Alice] Verify well formedness of Bob commitment (V, A)\n");
printf("\tVerify Proof for V\n");
SCHNORR_D_challenge(RP2, &V2, &SCHNORR_D2, &SCHNORR_E2);
printf("\t\tE = ");
OCT_output(&SCHNORR_E2);
rc = SCHNORR_D_verify(RP2, &V2, &SCHNORR_D2, &SCHNORR_E2, &SCHNORR_T2, &SCHNORR_U2);
if (rc != SCHNORR_OK)
{
printf("\nFAILURE - Invalid Bob V DSchnorr proof rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\t\tSuccess\n");
printf("\n\tVerify Proof for A\n");
SCHNORR_challenge(&A2, &SCHNORR_C2, &SCHNORR_E2);
printf("\t\tE = ");
OCT_output(&SCHNORR_E2);
rc = SCHNORR_verify(&A2, &SCHNORR_C2, &SCHNORR_E2, &SCHNORR_P2);
if (rc != SCHNORR_OK)
{
printf("\nFAILURE - Invalid Bob A Schnorr proof rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\t\tSuccess\n");
printf("\n[Bob] Verify well formedness of Alice commitment (V, A)\n");
printf("\tVerify Proof for V\n");
SCHNORR_D_challenge(RP1, &V1, &SCHNORR_D1, &SCHNORR_E1);
printf("\t\tE = ");
OCT_output(&SCHNORR_E1);
rc = SCHNORR_D_verify(RP1, &V1, &SCHNORR_D1, &SCHNORR_E1, &SCHNORR_T1, &SCHNORR_U1);
if (rc != SCHNORR_OK)
{
printf("\nFAILURE - Invalid Alice V DSchnorr proof rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\t\tSuccess\n");
printf("\n\tVerify Proof for A\n");
SCHNORR_challenge(&A1, &SCHNORR_C1, &SCHNORR_E1);
printf("\t\tE = ");
OCT_output(&SCHNORR_E1);
rc = SCHNORR_verify(&A1, &SCHNORR_C1, &SCHNORR_E1, &SCHNORR_P1);
if (rc != SCHNORR_OK)
{
printf("\nFAILURE - Invalid Alice A Schnorr proof\n");
exit(EXIT_FAILURE);
}
printf("\t\tSuccess\n");
/* Alice/Bob - proof */
printf("\n[Alice] Generate and commit to proof for commitments {V1, V2} and {A1, A2}\n");
rc = MPC_PHASE5_prove(&PHI1, &RHO1, V, A, PK, HM, R1, &U1, &T1);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE Alice Phase5 prove rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tU = ");
OCT_output(&U1);
printf("\tT = ");
OCT_output(&T1);
// Generate commitment to U, T
printf("\n\tCommitment\n");
OCT_copy(&DOUBLE_ECP, &U1);
OCT_joctet(&DOUBLE_ECP, &T1);
COMMITMENTS_NM_commit(RNG, &DOUBLE_ECP, &A_COMMIT_R, &A_COMMIT_C);
printf("\t\tR = ");
OCT_output(&A_COMMIT_R);
printf("\t\tC = ");
OCT_output(&A_COMMIT_C);
printf("\n[Alice] Transmit C value for the (U, T) NM commitment\n");
printf("\n[Bob] Generate and proof for commitments {V1, V2} and {A1, A2}\n");
rc = MPC_PHASE5_prove(&PHI2, &RHO2, V, A, PK, HM, R2, &U2, &T2);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE Alice Phase5 prove rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tU = ");
OCT_output(&U2);
printf("\tT = ");
OCT_output(&T2);
// Generate commitment to U, T
printf("\n\tCommitment\n");
OCT_copy(&DOUBLE_ECP, &U2);
OCT_joctet(&DOUBLE_ECP, &T2);
COMMITMENTS_NM_commit(RNG, &DOUBLE_ECP, &B_COMMIT_R, &B_COMMIT_C);
printf("\t\tR = ");
OCT_output(&B_COMMIT_R);
printf("\t\tC = ");
OCT_output(&B_COMMIT_C);
printf("\n[Bob] Transmit C value for the (U, T) NM commitment\n");
// Decommit proofs
printf("\n[Alice] Transmit decommitment value R and (U, T)\n");
printf("\n[Bob] Transmit decommitment value R and (U, T)\n");
printf("\n[Alice] Decommit Bob (U, T)\n");
OCT_copy(&DOUBLE_ECP, &U2);
OCT_joctet(&DOUBLE_ECP, &T2);
rc = COMMITMENTS_NM_decommit(&DOUBLE_ECP, &B_COMMIT_R, &B_COMMIT_C);
if (rc != COMMITMENTS_OK)
{
printf("\nFAILURE - Invalid Bob (U, T) commitment\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[Bob] Decommit Alice (U, T)\n");
OCT_copy(&DOUBLE_ECP, &U1);
OCT_joctet(&DOUBLE_ECP, &T1);
rc = COMMITMENTS_NM_decommit(&DOUBLE_ECP, &A_COMMIT_R, &A_COMMIT_C);
if (rc != COMMITMENTS_OK)
{
printf("\nFAILURE - Invalid Alice (U, T) commitment\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
/* Alice/Bob - verify, same for both */
printf("\n[Alice - Bob] Verify proof {T1, T2}, {U1, U2}\n");
rc = MPC_PHASE5_verify(U, T);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE Alice/Bob Phase5 verify rc: %d\n", rc);
exit(EXIT_FAILURE);
}
}
/* Signature.
*
* Step 1. Each player generates random k, gamma and commits to gamma.G
* Step 2. Each player performs a MTA with shares k_i, gamma_j
* Step 2A. Each player performs a MTAWC with shares k_i, sk_j
* Step 3. Each player sums the output of the MTA runs with the product k_i * gamma_i
* Step 3A. The values from Step 3 are shared and combined by each player
* Step 4. The values gamma_i.G are revealed and combined with the value from Step 3A
* to compute the R component of the signature
* Step 5. Each player sums the outputs of the MTAWC runs with the product k_i * sk_i
* Step 5A. Each player uses the value from Step 5 to compute its share of the s component of the signature
* Step 5B. The players engage in the Phase5 ZKP to check the consistency of the signature shares
* Step 5C. The players broadcast their signature shares and verify that the reconciled signature is valid
*/
void signature(csprng *RNG, octet *M, key_material *alice_km, key_material *bob_km)
{
int rc;
// Random generation
BIG_256_56 q;
BIG_256_56 k1;
BIG_256_56 k2;
char oct_k[2][EGS_SECP256K1];
octet K1 = {0, sizeof(oct_k[0]), oct_k[0]};
octet K2 = {0, sizeof(oct_k[1]), oct_k[1]};
char gamma[2][EGS_SECP256K1];
octet GAMMA1 = {0, sizeof(gamma[0]), gamma[0]};
octet GAMMA2 = {0, sizeof(gamma[1]), gamma[1]};
char gammapt[2][EFS_SECP256K1 + 1];
octet GAMMAPT1 = {0, sizeof(gammapt[0]), gammapt[0]};
octet GAMMAPT2 = {0, sizeof(gammapt[1]), gammapt[1]};
// Octets for Non Malleable Commitments
char commit_r[2][SHA256];
octet A_COMMIT_R = {0, sizeof(commit_r[0]), commit_r[0]};
octet B_COMMIT_R = {0, sizeof(commit_r[1]), commit_r[1]};
char commit_c[2][SHA256];
octet A_COMMIT_C = {0, sizeof(commit_c[0]), commit_c[0]};
octet B_COMMIT_C = {0, sizeof(commit_c[1]), commit_c[1]};
// Octets for Schnorr Proofs
char schnorr_r[2][EGS_SECP256K1];
octet SCHNORR_R1 = {0, sizeof(schnorr_r[0]), schnorr_r[0]};
octet SCHNORR_R2 = {0, sizeof(schnorr_r[1]), schnorr_r[1]};
char schnorr_e[2][EGS_SECP256K1];
octet SCHNORR_E1 = {0, sizeof(schnorr_e[0]), schnorr_e[0]};
octet SCHNORR_E2 = {0, sizeof(schnorr_e[1]), schnorr_e[1]};
char schnorr_c[2][EFS_SECP256K1 + 1];
octet SCHNORR_C1 = {0, sizeof(schnorr_c[0]), schnorr_c[0]};
octet SCHNORR_C2 = {0, sizeof(schnorr_c[1]), schnorr_c[1]};
char schnorr_p[2][EGS_SECP256K1];
octet SCHNORR_P1 = {0, sizeof(schnorr_p[0]), schnorr_p[0]};
octet SCHNORR_P2 = {0, sizeof(schnorr_p[1]), schnorr_p[1]};
// Octets for MTA/WC
char alpha[2][EGS_SECP256K1];
octet ALPHA1 = {0, sizeof(alpha[0]), alpha[0]};
octet ALPHA2 = {0, sizeof(alpha[1]), alpha[1]};
char beta[2][EGS_SECP256K1];
octet BETA1 = {0, sizeof(beta[0]), beta[0]};
octet BETA2 = {0, sizeof(beta[1]), beta[1]};
// Octets for reconciliation
char delta[2][EGS_SECP256K1];
octet DELTA1 = {0, sizeof(delta[0]), delta[0]};
octet DELTA2 = {0, sizeof(delta[1]), delta[1]};
char ikgamma[2][EGS_SECP256K1];
octet IKGAMMA1 = {0, sizeof(ikgamma[0]), ikgamma[0]};
octet IKGAMMA2 = {0, sizeof(ikgamma[1]), ikgamma[1]};
char sigr[2][EGS_SECP256K1];
octet SIGR1 = {0, sizeof(sigr[0]), sigr[0]};
octet SIGR2 = {0, sizeof(sigr[1]), sigr[1]};
char sigrp[2][EFS_SECP256K1 + 1];
octet SIGRP1 = {0, sizeof(sigrp[0]), sigrp[0]};
octet SIGRP2 = {0, sizeof(sigrp[1]), sigrp[1]};
char sigma[2][EGS_SECP256K1];
octet SIGMA1 = {0, sizeof(sigma[0]), sigma[0]};
octet SIGMA2 = {0, sizeof(sigma[1]), sigma[1]};
char hm[SHA256];
octet HM = {0, sizeof(hm), hm};
char sigs[3][EGS_SECP256K1];
octet SIGS1 = {0, sizeof(sigs[0]), sigs[0]};
octet SIGS2 = {0, sizeof(sigs[1]), sigs[1]};
octet SIGS = {0, sizeof(sigs[2]), sigs[2]};
// ECP conversion workspace
char ncp[2 * EFS_SECP256K1 + 1];
octet NCP = {0, sizeof(ncp), ncp};
ECP_SECP256K1 P;
BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
/* Alice - Generate k and gamma and commit to gamma.G */
printf("\n[Alice] Generate random K and GAMMA and commit to GAMMA.G\n");
BIG_256_56_randomnum(k1, q, RNG);
BIG_256_56_toBytes(K1.val, k1);
K1.len = EGS_SECP256K1;
ECP_SECP256K1_KEY_PAIR_GENERATE(RNG, &GAMMA1, &NCP);
ECP_SECP256K1_fromOctet(&P, &NCP);
ECP_SECP256K1_toOctet(&GAMMAPT1, &P, true);
printf("\tK = ");
OCT_output(&K1);
printf("\tGAMMA = ");
OCT_output(&GAMMA1);
printf("\tGAMMA.G = ");
OCT_output(&GAMMAPT1);
COMMITMENTS_NM_commit(RNG, &GAMMAPT1, &A_COMMIT_R, &A_COMMIT_C);
printf("\n\tCommitment\n");
printf("\t\tR = ");
OCT_output(&A_COMMIT_R);
printf("\t\tC = ");
OCT_output(&A_COMMIT_C);
// Transmit commitment C
printf("\n[Alice] Transmit commitment value C\n");
/* Bob - Generate k and gamma and commit to gamma.G */
printf("\n[Bob] Generate random K and GAMMA and commit to GAMMA.G\n");
BIG_256_56_randomnum(k2, q, RNG);
BIG_256_56_toBytes(K2.val, k2);
K2.len = EGS_SECP256K1;
ECP_SECP256K1_KEY_PAIR_GENERATE(RNG, &GAMMA2, &NCP);
ECP_SECP256K1_fromOctet(&P, &NCP);
ECP_SECP256K1_toOctet(&GAMMAPT2, &P, true);
printf("\tK = ");
OCT_output(&K2);
printf("\tGAMMA = ");
OCT_output(&GAMMA2);
printf("\tGAMMA.G = ");
OCT_output(&GAMMAPT2);
COMMITMENTS_NM_commit(RNG, &GAMMAPT2, &B_COMMIT_R, &B_COMMIT_C);
printf("\n\tCommitment\n");
printf("\t\tR = ");
OCT_output(&B_COMMIT_R);
printf("\t\tC = ");
OCT_output(&B_COMMIT_C);
// Transmit commitment C
printf("\n[Bob] Transmit commitment value C\n");
/* Alice/Bob - Initiate MTA with shares k1, gamma2 and k2, gamma1 */
printf("\n[Alice-Bob] Run MTA with K1, GAMMA2\n");
mta(RNG, alice_km, bob_km, &K1, &GAMMA2, &ALPHA1, &BETA2, "Alice", "Bob");
printf("\n[Bob-Alice] Run MTA with K2, GAMMA1\n");
mta(RNG, bob_km, alice_km, &K2, &GAMMA1, &ALPHA2, &BETA1, "Bob", "Alice");
/* Alice/Bob - combine received shares to compute an additive share of kgamma */
printf("\n[Alice] Recombine additive shares to compute K1*GAMMA1 + ALPHA1 + BETA1\n");
MPC_SUM_MTA(&K1, &GAMMA1, &ALPHA1, &BETA1, &DELTA1);
printf("\tDELTA = ");
OCT_output(&DELTA1);
printf("\n[Bob] Recombine additive shares to compute K2*GAMMA2 + ALPHA2 + BETA2\n");
MPC_SUM_MTA(&K2, &GAMMA2, &ALPHA2, &BETA2, &DELTA2);
printf("\tDELTA = ");
OCT_output(&DELTA2);
/* Alice/Bob - Initiate MTAWC with shares k1, sk1 and k2, sk2 */
printf("\n[Alice-Bob] Run MTAWC with K1, SK2\n");
mtawc(RNG, alice_km, bob_km, &K1, &ALPHA1, &BETA2, "Alice", "Bob");
printf("\n[Bob-Alice] Run MTAWC with K2, SK1\n");
mtawc(RNG, bob_km, alice_km, &K2, &ALPHA2, &BETA1, "Bob", "Alice");
/* Alice/Bob - combine received shares to compute an additive share of kw */
printf("\n[Alice] Recombine additive shares to compute K1*SK1 + ALPHA1 + BETA1\n");
MPC_SUM_MTA(&K1, alice_km->SK, &ALPHA1, &BETA1, &SIGMA1);
printf("\tSIGMA = ");
OCT_output(&SIGMA1);
printf("\n[Bob] Recombine additive shares to compute K2*SK2 + ALPHA2 + BETA2\n");
MPC_SUM_MTA(&K2, bob_km->SK, &ALPHA2, &BETA2, &SIGMA2);
printf("\tSIGMA = ");
OCT_output(&SIGMA2);
/* Alice/Bob - broadcast DELTA1, DELTA2 and compute (kgamma)^(-1) */
printf("\n[Alice] Transmit share of DELTA\n");
printf("\n[Bob] Transmit share of DELTA\n");
printf("\n[Alice] Combine DELTA shares and invert modulo curve order\n");
MPC_INVKGAMMA(&DELTA1, &DELTA2, &IKGAMMA1);
printf("\tIKGAMMA = ");
OCT_output(&IKGAMMA1);
printf("\n[Bob] Combine DELTA shares and invert modulo curve order\n");
MPC_INVKGAMMA(&DELTA1, &DELTA2, &IKGAMMA2);
printf("\tIKGAMMA = ");
OCT_output(&IKGAMMA2);
/* Alice - transmit decommitment and message for gamma.G and prove knowldege of gamma */
printf("\n[Alice] Generate Schnorr Proof for DLOG GAMMA, GAMMA.G\n");
SCHNORR_commit(RNG, &SCHNORR_R1, &SCHNORR_C1);
SCHNORR_challenge(&GAMMAPT1, &SCHNORR_C1, &SCHNORR_E1);
SCHNORR_prove(&SCHNORR_R1, &SCHNORR_E1, &GAMMA1, &SCHNORR_P1);
printf("\tC = ");
OCT_output(&SCHNORR_C1);
printf("\tE = ");
OCT_output(&SCHNORR_E1);
printf("\tP = ");
OCT_output(&SCHNORR_P1);
printf("\n[Alice] Transmit GAMMA.G with decommitment R and proof (C, P)\n");
/* Bob - transmit decommitment and message for gamma.G and prove knowldege of gamma */
printf("\n[Bob] Generate Schnorr Proof for DLOG GAMMA, GAMMA.G\n");
SCHNORR_commit(RNG, &SCHNORR_R2, &SCHNORR_C2);
SCHNORR_challenge(&GAMMAPT2, &SCHNORR_C2, &SCHNORR_E2);
SCHNORR_prove(&SCHNORR_R2, &SCHNORR_E2, &GAMMA2, &SCHNORR_P2);
printf("\tC = ");
OCT_output(&SCHNORR_C2);
printf("\tE = ");
OCT_output(&SCHNORR_E2);
printf("\tP = ");
OCT_output(&SCHNORR_P2);
printf("\n[Bob] Transmit GAMMA.G with decommitment R and proof (C, P)\n");
/* Alice - verify decommitment of gamma.G and Schnorr Proof */
printf("\n[Alice] Decommit GAMMA.G received from Bob\n");
rc = COMMITMENTS_NM_decommit(&GAMMAPT2, &B_COMMIT_R, &B_COMMIT_C);
if (rc != MPC_OK)
{
printf("\nFAILURE - Invalid Bob gamma.G commitment\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[Alice] Verify Schnorr Proof for GAMMA.G\n");
OCT_clear(&SCHNORR_E2);
SCHNORR_challenge(&GAMMAPT2, &SCHNORR_C2, &SCHNORR_E2);
printf("\tE = ");
OCT_output(&SCHNORR_E2);
rc = SCHNORR_verify(&GAMMAPT2, &SCHNORR_C2, &SCHNORR_E2, &SCHNORR_P2);
if (rc != SCHNORR_OK)
{
printf("\nFAILURE - Invalid Bob gamma.G Schnorr proof\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
/* Bob - verify decommitment of gamma.G and Schnorr Proof */
printf("\n[Bob] Decommit GAMMA.G received from Alice\n");
rc = COMMITMENTS_NM_decommit(&GAMMAPT1, &A_COMMIT_R, &A_COMMIT_C);
if (rc != COMMITMENTS_OK)
{
printf("\nFAILURE - Invalid Alice gamma.G commitment\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
printf("\n[Bob] Verify Schnorr Proof for GAMMA.G\n");
OCT_clear(&SCHNORR_E1);
SCHNORR_challenge(&GAMMAPT1, &SCHNORR_C1, &SCHNORR_E1);
printf("\tE = ");
OCT_output(&SCHNORR_E1);
rc = SCHNORR_verify(&GAMMAPT1, &SCHNORR_C1, &SCHNORR_E1, &SCHNORR_P1);
if (rc != SCHNORR_OK)
{
printf("\nFAILURE - Invalid Alice gamma.G Schnorr proof\n");
exit(EXIT_FAILURE);
}
printf("\tSuccess\n");
/* Alice/Bob - reconcile R and get x component */
printf("\n[Alice] Reconcile R component of the signature\n");
rc = MPC_R(&IKGAMMA1, &GAMMAPT1, &GAMMAPT2, &SIGR1, &SIGRP1);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE Alice recombining R rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tR = ");
OCT_output(&SIGR1);
printf("\tRP = ");
OCT_output(&SIGRP1);
printf("\n[Bob] Reconcile R component of the signature\n");
rc = MPC_R(&IKGAMMA1, &GAMMAPT1, &GAMMAPT2, &SIGR2, &SIGRP2);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE Bob recombinig R rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tR = ");
OCT_output(&SIGR2);
printf("\tRP = ");
OCT_output(&SIGRP2);
/* Alice/Bob - compute shares for S */
MPC_HASH(HASH_TYPE_SECP256K1, M, &HM);
printf("\n[Alice] Generate share for signature S component\n");
rc = MPC_S(&HM, &SIGR1, &K1, &SIGMA1, &SIGS1);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE computing Alice S share rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tS = ");
OCT_output(&SIGS1);
printf("\n[Bob] Generate share for signature S component\n");
rc = MPC_S(&HM, &SIGR2, &K2, &SIGMA2, &SIGS2);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE computing Bob S share rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tS = ");
OCT_output(&SIGS2);
/* Phase 5 */
printf("\n[Alice-Bob] Interactively prove consistency of S shares\n");
phase5(RNG, &SIGRP1, &SIGRP2, &SIGR1, &SIGR2, &HM, &SIGS1, &SIGS2, alice_km->FPK);
/* Alice/Bob - broadcast shares and combine */
printf("\n[Alice-Bob] Reconcile S component of signature\n");
MPC_SUM_S(&SIGS1, &SIGS2, &SIGS);
printf("\tS = ");
OCT_output(&SIGS);
/* Check signature validity */
printf("\n[Alice-Bob] Verify reconciled signature\n");
rc = MPC_ECDSA_VERIFY(&HM, alice_km->FPK, &SIGR1, &SIGS);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE invalid Alice rc: %d\n", rc);
exit(EXIT_FAILURE);
}
rc = MPC_ECDSA_VERIFY(&HM, bob_km->FPK, &SIGR2, &SIGS);
if (rc != MPC_OK)
{
fprintf(stderr, "FAILURE invalid Bob signature rc: %d\n", rc);
exit(EXIT_FAILURE);
}
printf("\tSignature valid\n");
printf("\nSignature\n");
printf("\tR = ");
OCT_output(&SIGR1);
printf("\tS = ");
OCT_output(&SIGS);
}
int main()
{
key_material alice_km;
char a_sk[EGS_SECP256K1];
char a_pk[EFS_SECP256K1 + 1];
char a_cpk[EFS_SECP256K1 + 1];
char a_fpk[EFS_SECP256K1 + 1];
octet A_SK = {0, sizeof(a_sk), a_sk};
octet A_PK = {0, sizeof(a_pk), a_pk};
octet A_CPK = {0, sizeof(a_cpk), a_cpk};
octet A_FPK = {0, sizeof(a_fpk), a_fpk};
alice_km.SK = &A_SK;
alice_km.PK = &A_PK;
alice_km.CPK = &A_CPK;
alice_km.FPK = &A_FPK;
key_material bob_km;
char b_sk[EGS_SECP256K1];
char b_pk[EFS_SECP256K1 + 1];
char b_cpk[EFS_SECP256K1 + 1];
char b_fpk[EFS_SECP256K1 + 1];
octet B_SK = {0, sizeof(b_sk), b_sk};
octet B_PK = {0, sizeof(b_pk), b_pk};
octet B_CPK = {0, sizeof(b_cpk), b_cpk};
octet B_FPK = {0, sizeof(b_fpk), b_fpk};
bob_km.SK = &B_SK;
bob_km.PK = &B_PK;
bob_km.CPK = &B_CPK;
bob_km.FPK = &B_FPK;
// Deterministic RNG for example
char seed[32] = {0};
csprng RNG;
RAND_seed(&RNG, 32, seed);
printf("MPC full flow example\n");
// Key setup phase
printf("\n ** Key Setup **\n");
key_setup(&RNG, &alice_km, &bob_km);
// Signature phase
printf("\n ** Signature **\n");
char* msg = "BANANA";
octet MSG = {0, sizeof(msg), msg};
printf("\nSign message '%s'\n", msg);
signature(&RNG, &MSG, &alice_km, &bob_km);
printf("\nDone\n");
}