diff --git a/Makefile.am b/Makefile.am index 977a4d0..92674e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,8 @@ lib_LTLIBRARIES = \ libbrandt_la_SOURCES = \ brandt.c \ crypto.c \ + fp_priv.c \ + fp_pub.c \ util.c libbrandt_la_LIBADD = \ diff --git a/crypto.c b/crypto.c index b9f55db..3b5205a 100644 --- a/crypto.c +++ b/crypto.c @@ -58,11 +58,11 @@ struct zkp_challenge_0og { }; -static gcry_ctx_t ec_ctx; -static gcry_mpi_point_t ec_gen; -static gcry_mpi_point_t ec_zero; -static gcry_mpi_t ec_n; -static struct GNUNET_CRYPTO_EccDlogContext *ec_dlogctx; +gcry_ctx_t ec_ctx = NULL; +gcry_mpi_point_t ec_gen = NULL; +gcry_mpi_point_t ec_zero = NULL; +gcry_mpi_t ec_n = NULL; +struct GNUNET_CRYPTO_EccDlogContext *ec_dlogctx = NULL; /** @@ -553,7 +553,7 @@ smc_init3 (uint16_t size1, uint16_t size2, uint16_t size3) * @param[in] stepo The amount of items to advance in @a out each step. Can be * used to store the sum in multi-dimensional arrays. */ -static void +void smc_sums_partial (gcry_mpi_point_t out[], gcry_mpi_point_t in[], uint16_t len, @@ -577,7 +577,7 @@ smc_sums_partial (gcry_mpi_point_t out[], * @param[in] step The amount of items to advance in @a in each step. Can be * used to sum over multi-dimensional arrays. */ -static void +void smc_sum (gcry_mpi_point_t out, gcry_mpi_point_t in[], uint16_t len, @@ -813,970 +813,6 @@ quit: } -void -fp_pub_prep_outcome (struct BRANDT_Auction *ad) -{ - gcry_mpi_t coeff = gcry_mpi_copy (GCRYMPI_CONST_ONE); - gcry_mpi_point_t tmp = gcry_mpi_point_new (0); - gcry_mpi_point_t *tlta1; - gcry_mpi_point_t *tltb1; - gcry_mpi_point_t **tlta2; - gcry_mpi_point_t **tltb2; - - ad->gamma2 = smc_init2 (ad->n, ad->k); - brandt_assert (ad->gamma2); - - ad->delta2 = smc_init2 (ad->n, ad->k); - brandt_assert (ad->delta2); - - ad->tmpa1 = smc_init1 (ad->k); - brandt_assert (ad->tmpa1); - - ad->tmpb1 = smc_init1 (ad->k); - brandt_assert (ad->tmpb1); - - /* create temporary lookup tables with partial sums */ - tlta1 = smc_init1 (ad->k); - tltb1 = smc_init1 (ad->k); - tlta2 = smc_init2 (ad->n, ad->k); - tltb2 = smc_init2 (ad->n, ad->k); - - /* temporary lookup table for sum of bid vectors */ - for (uint16_t i = 0; i < ad->n; i++) - { - smc_sums_partial (tlta2[i], ad->alpha[i], ad->k, 1, 1); - smc_sums_partial (tltb2[i], ad->beta[i], ad->k, 1, 1); - for (uint16_t j = 0; j < ad->k; j++) - { - gcry_mpi_ec_sub (tlta2[i][j], - tlta2[i][ad->k - 1], - tlta2[i][j], - ec_ctx); - gcry_mpi_ec_sub (tltb2[i][j], - tltb2[i][ad->k - 1], - tltb2[i][j], - ec_ctx); - } - brandt_assert (!ec_point_cmp (ec_zero, tlta2[i][ad->k - 1])); - brandt_assert (!ec_point_cmp (ec_zero, tltb2[i][ad->k - 1])); - } - for (uint16_t j = 0; j < ad->k; j++) - { - smc_sum (tlta1[j], &tlta2[0][j], ad->n, ad->k); - smc_sum (tltb1[j], &tltb2[0][j], ad->n, ad->k); - } - smc_free2 (tlta2, ad->n, ad->k); - smc_free2 (tltb2, ad->n, ad->k); - brandt_assert (!ec_point_cmp (ec_zero, tlta1[ad->k - 1])); - brandt_assert (!ec_point_cmp (ec_zero, tltb1[ad->k - 1])); - - /* initialize tmp array with zeroes, since we are calculating a sum */ - for (uint16_t j = 0; j < ad->k; j++) - { - ec_point_copy (ad->tmpa1[j], ec_zero); - ec_point_copy (ad->tmpb1[j], ec_zero); - } - /* store the \sum_{i=1}^n2^{i-1}b_i in tmp1 until outcome determination, - * since it is needed each time a gamma,delta pair is received from another - * bidder */ - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - gcry_mpi_ec_mul (tmp, coeff, ad->alpha[i][j], ec_ctx); - gcry_mpi_ec_add (ad->tmpa1[j], ad->tmpa1[j], tmp, ec_ctx); - gcry_mpi_ec_mul (tmp, coeff, ad->beta[i][j], ec_ctx); - gcry_mpi_ec_add (ad->tmpb1[j], ad->tmpb1[j], tmp, ec_ctx); - } - gcry_mpi_lshift (coeff, coeff, 1); - } - - for (uint16_t j = 0; j < ad->k; j++) - { - /* copy unmasked outcome to all other bidder layers so they don't - * have to be recomputed to check the ZK proof_2dle's from other - * bidders when receiving their outcome messages */ - for (uint16_t a = 0; a < ad->n; a++) - { - ec_point_copy (ad->gamma2[a][j], tlta1[j]); - ec_point_copy (ad->delta2[a][j], tltb1[j]); - } - } - - gcry_mpi_release (coeff); - gcry_mpi_point_release (tmp); - smc_free1 (tlta1, ad->k); - smc_free1 (tltb1, ad->k); -} - - -/** - * fp_pub_compute_outcome computes the outcome for first price auctions with a - * public outcome and packs it into a message buffer together with proofs of - * correctnes. - * - * @param[in] ad Pointer to the BRANDT_Auction struct to operate on - * @param[out] buflen Size of the returned message buffer in bytes - * @return A buffer containing the encrypted outcome vectors - * which needs to be broadcast - */ -unsigned char * -fp_pub_compute_outcome (struct BRANDT_Auction *ad, size_t *buflen) -{ - unsigned char *ret; - unsigned char *cur; - gcry_mpi_point_t tmpa = gcry_mpi_point_new (0); - gcry_mpi_point_t tmpb = gcry_mpi_point_new (0); - struct msg_head *head; - struct ec_mpi *gamma; - struct ec_mpi *delta; - struct proof_2dle *proof2; - - brandt_assert (ad && buflen); - - *buflen = (sizeof (*head) + - ad->k * (sizeof (*gamma) + - sizeof (*delta) + - sizeof (*proof2))); - ret = GNUNET_new_array (*buflen, unsigned char); - - head = (struct msg_head *)ret; - head->prot_version = htonl (0); - head->msg_type = htonl (msg_outcome); - cur = ret + sizeof (*head); - - for (uint16_t j = 0; j < ad->k; j++) - { - gamma = (struct ec_mpi *)cur; - delta = &((struct ec_mpi *)cur)[1]; - proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); - - ec_point_copy (tmpa, ad->gamma2[ad->i][j]); - ec_point_copy (tmpb, ad->delta2[ad->i][j]); - - /* apply random masking for losing bidders */ - smc_zkp_2dle (ad->gamma2[ad->i][j], - ad->delta2[ad->i][j], - tmpa, - tmpb, - NULL, - proof2); - - ec_point_serialize (gamma, ad->gamma2[ad->i][j]); - ec_point_serialize (delta, ad->delta2[ad->i][j]); - - /* add winner determination for own gamma,delta */ - gcry_mpi_ec_add (ad->gamma2[ad->i][j], - ad->gamma2[ad->i][j], - ad->tmpa1[j], - ec_ctx); - gcry_mpi_ec_add (ad->delta2[ad->i][j], - ad->delta2[ad->i][j], - ad->tmpb1[j], - ec_ctx); - - cur += sizeof (*gamma) + sizeof (*delta) + sizeof (*proof2); - } - - gcry_mpi_point_release (tmpa); - gcry_mpi_point_release (tmpb); - return ret; -} - - -int -fp_pub_recv_outcome (struct BRANDT_Auction *ad, - const unsigned char *buf, - size_t buflen, - uint16_t sender) -{ - int ret = 0; - const unsigned char *cur = buf; - struct proof_2dle *proof2; - gcry_mpi_point_t gamma = gcry_mpi_point_new (0); - gcry_mpi_point_t delta = gcry_mpi_point_new (0); - - brandt_assert (ad && buf); - - if (buflen != (ad->k * (2 * sizeof (struct ec_mpi) + sizeof (*proof2)))) - { - weprintf ("wrong size of received outcome"); - goto quit; - } - - for (uint16_t j = 0; j < ad->k; j++) - { - ec_point_parse (gamma, (struct ec_mpi *)cur); - ec_point_parse (delta, &((struct ec_mpi *)cur)[1]); - proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); - if (smc_zkp_2dle_check (gamma, - delta, - ad->gamma2[sender][j], - ad->delta2[sender][j], - proof2)) - { - weprintf ("wrong zkp2 for gamma, delta received"); - goto quit; - } - ec_point_copy (ad->gamma2[sender][j], gamma); - ec_point_copy (ad->delta2[sender][j], delta); - - /* add winner determination summand */ - gcry_mpi_ec_add (ad->gamma2[sender][j], - ad->gamma2[sender][j], - ad->tmpa1[j], - ec_ctx); - gcry_mpi_ec_add (ad->delta2[sender][j], - ad->delta2[sender][j], - ad->tmpb1[j], - ec_ctx); - - cur += 2 * sizeof (struct ec_mpi) + sizeof (*proof2); - } - - ret = 1; -quit: - gcry_mpi_point_release (gamma); - gcry_mpi_point_release (delta); - return ret; -} - - -void -fp_pub_prep_decryption (struct BRANDT_Auction *ad) -{ - gcry_mpi_point_t tmp = gcry_mpi_point_new (0); - - ad->phi2 = smc_init2 (ad->n, ad->k); - brandt_assert (ad->phi2); - - for (uint16_t j = 0; j < ad->k; j++) - { - smc_sum (tmp, &ad->delta2[0][j], ad->n, ad->k); - - /* copy still encrypted outcome to all other bidder layers so they - * don't have to be recomputed to check the ZK proof_2dle's from - * other bidders when receiving their outcome decryption messages */ - for (uint16_t a = 0; a < ad->n; a++) - ec_point_copy (ad->phi2[a][j], tmp); - } - - gcry_mpi_point_release (tmp); -} - - -/** - * fp_pub_decrypt_outcome decrypts part of the outcome and packs it into a - * message buffer together with proofs of correctnes. - * - * @param[in] ad Pointer to the BRANDT_Auction struct to operate on - * @param[out] buflen Size of the returned message buffer in bytes - * @return A buffer containing the own share of the decrypted outcome - * which needs to be broadcast - */ -unsigned char * -fp_pub_decrypt_outcome (struct BRANDT_Auction *ad, size_t *buflen) -{ - unsigned char *ret; - unsigned char *cur; - gcry_mpi_point_t tmp = gcry_mpi_point_new (0); - struct msg_head *head; - struct ec_mpi *phi; - struct proof_2dle *proof2; - - brandt_assert (ad && buflen); - - *buflen = (sizeof (*head) + ad->k * (sizeof (*phi) + sizeof (*proof2))); - ret = GNUNET_new_array (*buflen, unsigned char); - - head = (struct msg_head *)ret; - head->prot_version = htonl (0); - head->msg_type = htonl (msg_decrypt); - cur = ret + sizeof (*head); - - for (uint16_t j = 0; j < ad->k; j++) - { - phi = (struct ec_mpi *)cur; - proof2 = (struct proof_2dle *)(cur + sizeof (*phi)); - - ec_point_copy (tmp, ad->phi2[ad->i][j]); - - /* decrypt outcome component and prove the correct key was used */ - smc_zkp_2dle (ad->phi2[ad->i][j], - NULL, - tmp, - ec_gen, - ad->x, - proof2); - - ec_point_serialize (phi, ad->phi2[ad->i][j]); - - cur += sizeof (*phi) + sizeof (*proof2); - } - - gcry_mpi_point_release (tmp); - return ret; -} - - -int -fp_pub_recv_decryption (struct BRANDT_Auction *ad, - const unsigned char *buf, - size_t buflen, - uint16_t sender) -{ - int ret = 0; - const unsigned char *cur = buf; - struct proof_2dle *proof2; - gcry_mpi_point_t phi = gcry_mpi_point_new (0); - - brandt_assert (ad && buf); - - if (buflen != (ad->k * (sizeof (struct ec_mpi) + sizeof (*proof2)))) - { - weprintf ("wrong size of received outcome decryption"); - goto quit; - } - - for (uint16_t j = 0; j < ad->k; j++) - { - ec_point_parse (phi, (struct ec_mpi *)cur); - proof2 = (struct proof_2dle *)(cur + sizeof (struct ec_mpi)); - if (smc_zkp_2dle_check (phi, - ad->y[sender], - ad->phi2[sender][j], - ec_gen, - proof2)) - { - weprintf ("wrong zkp2 for phi, y received"); - goto quit; - } - ec_point_copy (ad->phi2[sender][j], phi); - cur += sizeof (struct ec_mpi) + sizeof (*proof2); - } - - ret = 1; -quit: - gcry_mpi_point_release (phi); - return ret; -} - - -struct BRANDT_Result * -fp_pub_determine_outcome (struct BRANDT_Auction *ad, - uint16_t *len) -{ - struct BRANDT_Result *ret; - int32_t price = -1; - int32_t winner = -1; - int dlogi = -1; - gcry_mpi_point_t sum_gamma = gcry_mpi_point_new (0); - gcry_mpi_point_t sum_phi = gcry_mpi_point_new (0); - - brandt_assert (ad); - - for (uint16_t j = ad->k - 1; j >= 0; j--) - { - smc_sum (sum_gamma, &ad->gamma2[0][j], ad->n, ad->k); - smc_sum (sum_phi, &ad->phi2[0][j], ad->n, ad->k); - gcry_mpi_ec_sub (sum_gamma, sum_gamma, sum_phi, ec_ctx); - /* first non-zero component determines the price */ - if (ec_point_cmp (sum_gamma, ec_zero)) - { - price = j; - break; - } - } - - dlogi = GNUNET_CRYPTO_ecc_dlog (ec_dlogctx, sum_gamma); - brandt_assert (dlogi > 0); - - /* all bidders participated with a multiplicative share */ - dlogi /= ad->n; - - /* can only support up to bits(dlogi) bidders */ - brandt_assert (sizeof (int) * 8 - 1 >= ad->n); - for (uint16_t i = 0; i < ad->n; i++) - { - /* first set bit determines the winner */ - if (dlogi & (1 << i)) - { - winner = i; - break; - } - } - - gcry_mpi_point_release (sum_gamma); - gcry_mpi_point_release (sum_phi); - - if (-1 == winner || -1 == price) - return NULL; - - ret = GNUNET_new (struct BRANDT_Result); - ret->bidder = winner; - ret->price = price; - ret->status = BRANDT_bidder_won; - if (len) - *len = 1; - return ret; -} - - -void -fp_priv_prep_outcome (struct BRANDT_Auction *ad) -{ - gcry_mpi_point_t tmpa = gcry_mpi_point_new (0); - gcry_mpi_point_t tmpb = gcry_mpi_point_new (0); - gcry_mpi_point_t *tlta1; - gcry_mpi_point_t *tltb1; - gcry_mpi_point_t **tlta2; - gcry_mpi_point_t **tltb2; - gcry_mpi_point_t **tlta3; - gcry_mpi_point_t **tltb3; - - ad->gamma3 = smc_init3 (ad->n, ad->n, ad->k); - brandt_assert (ad->gamma3); - - ad->delta3 = smc_init3 (ad->n, ad->n, ad->k); - brandt_assert (ad->delta3); - - /* create temporary lookup tables with partial sums */ - tlta1 = smc_init1 (ad->k); - tltb1 = smc_init1 (ad->k); - tlta2 = smc_init2 (ad->n, ad->k); - tltb2 = smc_init2 (ad->n, ad->k); - tlta3 = smc_init2 (ad->n, ad->k); - tltb3 = smc_init2 (ad->n, ad->k); - - /* temporary lookup table for first summand (no one has a higher bid) */ - for (uint16_t i = 0; i < ad->n; i++) - { - smc_sums_partial (tlta2[i], ad->alpha[i], ad->k, 1, 1); - smc_sums_partial (tltb2[i], ad->beta[i], ad->k, 1, 1); - for (uint16_t j = 0; j < ad->k; j++) - { - gcry_mpi_ec_sub (tlta3[i][j], - tlta2[i][ad->k - 1], - tlta2[i][j], - ec_ctx); - gcry_mpi_ec_sub (tltb3[i][j], - tltb2[i][ad->k - 1], - tltb2[i][j], - ec_ctx); - } - brandt_assert (!ec_point_cmp (ec_zero, tlta3[i][ad->k - 1])); - brandt_assert (!ec_point_cmp (ec_zero, tltb3[i][ad->k - 1])); - } - for (uint16_t j = 0; j < ad->k; j++) - { - smc_sum (tlta1[j], &tlta3[0][j], ad->n, ad->k); - smc_sum (tltb1[j], &tltb3[0][j], ad->n, ad->k); - } - brandt_assert (!ec_point_cmp (ec_zero, tlta1[ad->k - 1])); - brandt_assert (!ec_point_cmp (ec_zero, tltb1[ad->k - 1])); - /* \todo: merge into one nested i,j loop and one nested j,i loop? */ - - /* temporary lookup table for second summand (my bid is not lower) */ - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - gcry_mpi_ec_sub (tlta2[i][j], tlta2[i][j], ad->alpha[i][j], ec_ctx); - gcry_mpi_ec_sub (tltb2[i][j], tltb2[i][j], ad->beta[i][j], ec_ctx); - } - brandt_assert (!ec_point_cmp (ec_zero, tlta2[i][0])); - brandt_assert (!ec_point_cmp (ec_zero, tltb2[i][0])); - } - - /* temporary lookup table for third summand (no one with a lower index has - * the same bid) */ - for (uint16_t j = 0; j < ad->k; j++) - { - smc_sums_partial (&tlta3[0][j], &ad->alpha[0][j], ad->n, ad->k, ad->k); - smc_sums_partial (&tltb3[0][j], &ad->beta[0][j], ad->n, ad->k, ad->k); - for (uint16_t i = 0; i < ad->n; i++) - { - gcry_mpi_ec_sub (tlta3[i][j], tlta3[i][j], ad->alpha[i][j], ec_ctx); - gcry_mpi_ec_sub (tltb3[i][j], tltb3[i][j], ad->beta[i][j], ec_ctx); - } - brandt_assert (!ec_point_cmp (ec_zero, tlta3[0][j])); - brandt_assert (!ec_point_cmp (ec_zero, tltb3[0][j])); - } - - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - /* compute inner gamma */ - gcry_mpi_ec_add (tmpa, tlta1[j], tlta2[i][j], ec_ctx); - gcry_mpi_ec_add (tmpa, tmpa, tlta3[i][j], ec_ctx); - - /* compute inner delta */ - gcry_mpi_ec_add (tmpb, tltb1[j], tltb2[i][j], ec_ctx); - gcry_mpi_ec_add (tmpb, tmpb, tltb3[i][j], ec_ctx); - - /* copy unmasked outcome to all other bidder layers so they don't - * have to be recomputed to check the ZK proof_2dle's from other - * bidders when receiving their outcome messages */ - for (uint16_t a = 0; a < ad->n; a++) - { - ec_point_copy (ad->gamma3[a][i][j], tmpa); - ec_point_copy (ad->delta3[a][i][j], tmpb); - } - } - } - - gcry_mpi_point_release (tmpa); - gcry_mpi_point_release (tmpb); - smc_free1 (tlta1, ad->k); - smc_free1 (tltb1, ad->k); - smc_free2 (tlta2, ad->n, ad->k); - smc_free2 (tltb2, ad->n, ad->k); - smc_free2 (tlta3, ad->n, ad->k); - smc_free2 (tltb3, ad->n, ad->k); -} - - -/** - * fp_priv_compute_outcome computes encrypted outcome shares and packs them into - * a message buffer together with proofs of correctnes. - * - * @param[in] ad Pointer to the BRANDT_Auction struct to operate on - * @param[out] buflen Size of the returned message buffer in bytes - * @return A buffer containing the encrypted outcome vectors - * which needs to be broadcast - */ -unsigned char * -fp_priv_compute_outcome (struct BRANDT_Auction *ad, size_t *buflen) -{ - unsigned char *ret; - unsigned char *cur; - struct msg_head *head; - gcry_mpi_point_t tmpa = gcry_mpi_point_new (0); - gcry_mpi_point_t tmpb = gcry_mpi_point_new (0); - struct ec_mpi *gamma; - struct ec_mpi *delta; - struct proof_2dle *proof2; - - brandt_assert (ad && buflen); - - *buflen = (sizeof (*head) + /* msg header */ - ad->n * ad->k * /* nk * (gamma, delta, proof2) */ - (sizeof (*gamma) + sizeof (*delta) + sizeof (*proof2))); - ret = GNUNET_new_array (*buflen, unsigned char); - - head = (struct msg_head *)ret; - head->prot_version = htonl (0); - head->msg_type = htonl (msg_outcome); - cur = ret + sizeof (*head); - - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - gamma = (struct ec_mpi *)cur; - delta = &((struct ec_mpi *)cur)[1]; - proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); - - ec_point_copy (tmpa, ad->gamma3[ad->i][i][j]); - ec_point_copy (tmpb, ad->delta3[ad->i][i][j]); - - /* apply random masking for losing bidders */ - smc_zkp_2dle (ad->gamma3[ad->i][i][j], - ad->delta3[ad->i][i][j], - tmpa, - tmpb, - NULL, - proof2); - - ec_point_serialize (gamma, ad->gamma3[ad->i][i][j]); - ec_point_serialize (delta, ad->delta3[ad->i][i][j]); - - cur += sizeof (*gamma) + sizeof (*delta) + sizeof (*proof2); - } - } - - gcry_mpi_point_release (tmpa); - gcry_mpi_point_release (tmpb); - return ret; -} - - -int -fp_priv_recv_outcome (struct BRANDT_Auction *ad, - const unsigned char *buf, - size_t buflen, - uint16_t sender) -{ - int ret = 0; - const unsigned char *cur = buf; - struct proof_2dle *proof2; - gcry_mpi_point_t gamma = gcry_mpi_point_new (0); - gcry_mpi_point_t delta = gcry_mpi_point_new (0); - - brandt_assert (ad && buf); - - if (buflen != (ad->n * ad->k * - (2 * sizeof (struct ec_mpi) + sizeof (*proof2)))) - { - weprintf ("wrong size of received outcome"); - goto quit; - } - - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - ec_point_parse (gamma, (struct ec_mpi *)cur); - ec_point_parse (delta, &((struct ec_mpi *)cur)[1]); - proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); - if (smc_zkp_2dle_check (gamma, - delta, - ad->gamma3[sender][i][j], - ad->delta3[sender][i][j], - proof2)) - { - weprintf ("wrong zkp2 for gamma, delta received"); - goto quit; - } - ec_point_copy (ad->gamma3[sender][i][j], gamma); - ec_point_copy (ad->delta3[sender][i][j], delta); - cur += 2 * sizeof (struct ec_mpi) + sizeof (*proof2); - } - } - - ret = 1; -quit: - gcry_mpi_point_release (gamma); - gcry_mpi_point_release (delta); - return ret; -} - - -void -fp_priv_prep_decryption (struct BRANDT_Auction *ad) -{ - gcry_mpi_point_t tmp = gcry_mpi_point_new (0); - - ad->phi3 = smc_init3 (ad->n, ad->n, ad->k); - brandt_assert (ad->phi3); - - ad->phiproofs3 = GNUNET_new_array_3d (ad->n, - ad->n, - ad->k, - struct proof_2dle); - brandt_assert (ad->phiproofs3); - - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - smc_sum (tmp, &ad->delta3[0][i][j], ad->n, ad->n * ad->k); - - /* copy still encrypted outcome to all other bidder layers so they - * don't have to be recomputed to check the ZK proof_2dle's from - * other bidders when receiving their outcome decryption messages */ - for (uint16_t a = 0; a < ad->n; a++) - ec_point_copy (ad->phi3[a][i][j], tmp); - } - } - - gcry_mpi_point_release (tmp); -} - - -static unsigned char * -fp_priv_decrypt_outcome_seller (struct BRANDT_Auction *ad, size_t *buflen) -{ - unsigned char *ret; - unsigned char *cur; - struct msg_head *head; - gcry_mpi_point_t tmp = gcry_mpi_point_new (0); - struct ec_mpi *phi; - struct proof_2dle *proof2; - - *buflen = (sizeof (*head) + - (ad->n - 1) * ad->n * ad->k * (sizeof (*phi) + - sizeof (*proof2))); - ret = GNUNET_new_array (*buflen, unsigned char); - - head = (struct msg_head *)ret; - head->prot_version = htonl (0); - head->msg_type = htonl (msg_decrypt); - cur = ret + sizeof (*head); - - for (uint16_t h = 0; h < ad->n; h++) - { - for (uint16_t i = 0; i < ad->n; i++) - { - /* don't reveal outcome to losing bidders */ - if (h == i) - continue; - - for (uint16_t j = 0; j < ad->k; j++) - { - phi = (struct ec_mpi *)cur; - proof2 = (struct proof_2dle *)(cur + sizeof (*phi)); - - ec_point_serialize (phi, ad->phi3[h][i][j]); - memcpy (proof2, &ad->phiproofs3[h][i][j], sizeof (*proof2)); - - cur += sizeof (*phi) + sizeof (*proof2); - } - } - } - - gcry_mpi_point_release (tmp); - return ret; -} - - -static unsigned char * -fp_priv_decrypt_outcome_bidder (struct BRANDT_Auction *ad, size_t *buflen) -{ - unsigned char *ret; - unsigned char *cur; - struct msg_head *head; - gcry_mpi_point_t tmp = gcry_mpi_point_new (0); - struct ec_mpi *phi; - struct proof_2dle *proof2; - - *buflen = (sizeof (*head) + - ad->n * ad->k * (sizeof (*phi) + sizeof (*proof2))); - ret = GNUNET_new_array (*buflen, unsigned char); - - head = (struct msg_head *)ret; - head->prot_version = htonl (0); - head->msg_type = htonl (msg_decrypt); - cur = ret + sizeof (*head); - - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - phi = (struct ec_mpi *)cur; - proof2 = (struct proof_2dle *)(cur + sizeof (*phi)); - - ec_point_copy (tmp, ad->phi3[ad->i][i][j]); - - /* decrypt outcome component and prove the correct key was used */ - smc_zkp_2dle (ad->phi3[ad->i][i][j], - NULL, - tmp, - ec_gen, - ad->x, - proof2); - - ec_point_serialize (phi, ad->phi3[ad->i][i][j]); - - cur += sizeof (*phi) + sizeof (*proof2); - } - } - - gcry_mpi_point_release (tmp); - return ret; -} - - -/** - * fp_priv_decrypt_outcome decrypts the own shares of the outcome and packs them - * into a message buffer together with proofs of correctnes. When this is called - * as the seller it will not decrypt anything, but just create the message - * buffer from all received decryption shares to broadcast back to all bidders. - * - * @param[in] ad Pointer to the BRANDT_Auction struct to operate on - * @param[out] buflen Size of the returned message buffer in bytes - * @return A buffer containing the share of the decrypted outcome - * which needs to be broadcast - */ -unsigned char * -fp_priv_decrypt_outcome (struct BRANDT_Auction *ad, size_t *buflen) -{ - brandt_assert (ad && buflen); - if (ad->seller_mode) - return fp_priv_decrypt_outcome_seller (ad, buflen); - else - return fp_priv_decrypt_outcome_bidder (ad, buflen); -} - - -static int -fp_priv_recv_decryption_seller (struct BRANDT_Auction *ad, - const unsigned char *buf, - size_t buflen, - uint16_t sender) -{ - int ret = 0; - const unsigned char *cur = buf; - struct proof_2dle *proof2; - gcry_mpi_point_t phi = gcry_mpi_point_new (0); - - if (buflen != (ad->n * ad->k * (sizeof (struct ec_mpi) + sizeof (*proof2)))) - { - weprintf ("wrong size of received outcome decryption from bidder"); - goto quit; - } - - for (uint16_t i = 0; i < ad->n; i++) - { - for (uint16_t j = 0; j < ad->k; j++) - { - ec_point_parse (phi, (struct ec_mpi *)cur); - proof2 = (struct proof_2dle *)(cur + sizeof (struct ec_mpi)); - if (smc_zkp_2dle_check (phi, - ad->y[sender], - ad->phi3[sender][i][j], - ec_gen, - proof2)) - { - weprintf ("wrong zkp2 for phi, y received from bidder"); - goto quit; - } - - /* store proof. we need to rebroadcast it to the other bidders */ - memcpy (&ad->phiproofs3[sender][i][j], proof2, sizeof (*proof2)); - - ec_point_copy (ad->phi3[sender][i][j], phi); - cur += sizeof (struct ec_mpi) + sizeof (*proof2); - } - } - - ret = 1; -quit: - gcry_mpi_point_release (phi); - return ret; -} - - -static int -fp_priv_recv_decryption_bidder (struct BRANDT_Auction *ad, - const unsigned char *buf, - size_t buflen, - uint16_t sender) -{ - int ret = 0; - const unsigned char *cur = buf; - struct proof_2dle *proof2; - gcry_mpi_point_t phi = gcry_mpi_point_new (0); - - if (buflen != ((ad->n - 1) * ad->n * ad->k * (sizeof (struct ec_mpi) + - sizeof (*proof2)))) - { - weprintf ("wrong size of received outcome decryption from seller"); - goto quit; - } - - for (uint16_t h = 0; h < ad->n; h++) - { - for (uint16_t i = 0; i < ad->n; i++) - { - /* those combinations are not sent by the seller */ - if (h == i) - continue; - - /* we already have our own phi values */ - if (h == ad->i) - { - cur += ad->k * (sizeof (struct ec_mpi) + sizeof (*proof2)); - continue; - } - - for (uint16_t j = 0; j < ad->k; j++) - { - ec_point_parse (phi, (struct ec_mpi *)cur); - proof2 = (struct proof_2dle *)(cur + sizeof (struct ec_mpi)); - if (smc_zkp_2dle_check (phi, - ad->y[h], - ad->phi3[h][i][j], - ec_gen, - proof2)) - { - weprintf ("wrong zkp2 for phi, y received from seller"); - goto quit; - } - ec_point_copy (ad->phi3[h][i][j], phi); - cur += sizeof (struct ec_mpi) + sizeof (*proof2); - } - } - } - - ret = 1; -quit: - gcry_mpi_point_release (phi); - return ret; -} - - -int -fp_priv_recv_decryption (struct BRANDT_Auction *ad, - const unsigned char *buf, - size_t buflen, - uint16_t sender) -{ - brandt_assert (ad && buf); - if (ad->seller_mode) - return fp_priv_recv_decryption_seller (ad, buf, buflen, sender); - else - return fp_priv_recv_decryption_bidder (ad, buf, buflen, sender); -} - - -struct BRANDT_Result * -fp_priv_determine_outcome (struct BRANDT_Auction *ad, - uint16_t *len) -{ - struct BRANDT_Result *ret; - int32_t price = -1; - int32_t winner = -1; - gcry_mpi_point_t sum_gamma = gcry_mpi_point_new (0); - gcry_mpi_point_t sum_phi = gcry_mpi_point_new (0); - - brandt_assert (ad); - - for (uint16_t i = 0; i < ad->n; i++) - { - if (!ad->seller_mode && i != ad->i) - continue; - - for (uint16_t j = 0; j < ad->k; j++) - { - smc_sum (sum_gamma, &ad->gamma3[0][i][j], ad->n, ad->n * ad->k); - smc_sum (sum_phi, &ad->phi3[0][i][j], ad->n, ad->n * ad->k); - gcry_mpi_ec_sub (sum_gamma, sum_gamma, sum_phi, ec_ctx); - if (!ec_point_cmp (sum_gamma, ec_zero)) - { - if (-1 != price) - { - weprintf ("multiple winning prices detected"); - return NULL; - } - if (-1 != winner) - { - weprintf ("multiple winners detected"); - return NULL; - } - price = j; - winner = i; - } - } - } - - gcry_mpi_point_release (sum_gamma); - gcry_mpi_point_release (sum_phi); - - if (-1 == winner || -1 == price) - return NULL; - - ret = GNUNET_new (struct BRANDT_Result); - ret->bidder = winner; - ret->price = price; - ret->status = BRANDT_bidder_won; - if (len) - *len = 1; - return ret; -} - - /** * smc_zkp_dl creates a proof of knowledge of @a x with \f$v = xg\f$ where * \f$g\f$ is the base point on Ed25519. diff --git a/crypto.h b/crypto.h index e9338f4..b4344da 100644 --- a/crypto.h +++ b/crypto.h @@ -41,6 +41,9 @@ struct ec_mpi { unsigned char data[256 / 8]; }; +void ec_point_serialize (struct ec_mpi *dst, const gcry_mpi_point_t src); +void ec_point_parse (gcry_mpi_point_t dst, const struct ec_mpi *src); + gcry_mpi_point_t *smc_init1 (uint16_t size1); gcry_mpi_point_t **smc_init2 (uint16_t size1, uint16_t size2); gcry_mpi_point_t ***smc_init3 (uint16_t size1, uint16_t size2, uint16_t size3); @@ -51,6 +54,16 @@ void smc_free3 (gcry_mpi_point_t ***dst, uint16_t size2, uint16_t size3); +void smc_sums_partial (gcry_mpi_point_t out[], + gcry_mpi_point_t in[], + uint16_t len, + uint16_t stepi, + uint16_t stepo); +void smc_sum (gcry_mpi_point_t out, + gcry_mpi_point_t in[], + uint16_t len, + uint16_t step); + void ec_point_copy (gcry_mpi_point_t dst, const gcry_mpi_point_t src); int ec_point_cmp (const gcry_mpi_point_t a, const gcry_mpi_point_t b); void ec_skey_create (gcry_mpi_t skey); diff --git a/fp_priv.c b/fp_priv.c new file mode 100644 index 0000000..c96f969 --- /dev/null +++ b/fp_priv.c @@ -0,0 +1,584 @@ +/* This file is part of libbrandt. + * Copyright (C) 2016 GNUnet e.V. + * + * libbrandt is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libbrandt is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * libbrandt. If not, see . + */ + +/** + * @file fp_pub.c + * @brief Implementation of the first price public outcome algorithm. + * @author Markus Teich + */ + +#include "platform.h" + +#include + +#include "crypto.h" +#include "internals.h" +#include "util.h" + + +void +fp_priv_prep_outcome (struct BRANDT_Auction *ad) +{ + gcry_mpi_point_t tmpa = gcry_mpi_point_new (0); + gcry_mpi_point_t tmpb = gcry_mpi_point_new (0); + gcry_mpi_point_t *tlta1; + gcry_mpi_point_t *tltb1; + gcry_mpi_point_t **tlta2; + gcry_mpi_point_t **tltb2; + gcry_mpi_point_t **tlta3; + gcry_mpi_point_t **tltb3; + + ad->gamma3 = smc_init3 (ad->n, ad->n, ad->k); + brandt_assert (ad->gamma3); + + ad->delta3 = smc_init3 (ad->n, ad->n, ad->k); + brandt_assert (ad->delta3); + + /* create temporary lookup tables with partial sums */ + tlta1 = smc_init1 (ad->k); + tltb1 = smc_init1 (ad->k); + tlta2 = smc_init2 (ad->n, ad->k); + tltb2 = smc_init2 (ad->n, ad->k); + tlta3 = smc_init2 (ad->n, ad->k); + tltb3 = smc_init2 (ad->n, ad->k); + + /* temporary lookup table for first summand (no one has a higher bid) */ + for (uint16_t i = 0; i < ad->n; i++) + { + smc_sums_partial (tlta2[i], ad->alpha[i], ad->k, 1, 1); + smc_sums_partial (tltb2[i], ad->beta[i], ad->k, 1, 1); + for (uint16_t j = 0; j < ad->k; j++) + { + gcry_mpi_ec_sub (tlta3[i][j], + tlta2[i][ad->k - 1], + tlta2[i][j], + ec_ctx); + gcry_mpi_ec_sub (tltb3[i][j], + tltb2[i][ad->k - 1], + tltb2[i][j], + ec_ctx); + } + brandt_assert (!ec_point_cmp (ec_zero, tlta3[i][ad->k - 1])); + brandt_assert (!ec_point_cmp (ec_zero, tltb3[i][ad->k - 1])); + } + for (uint16_t j = 0; j < ad->k; j++) + { + smc_sum (tlta1[j], &tlta3[0][j], ad->n, ad->k); + smc_sum (tltb1[j], &tltb3[0][j], ad->n, ad->k); + } + brandt_assert (!ec_point_cmp (ec_zero, tlta1[ad->k - 1])); + brandt_assert (!ec_point_cmp (ec_zero, tltb1[ad->k - 1])); + /* \todo: merge into one nested i,j loop and one nested j,i loop? */ + + /* temporary lookup table for second summand (my bid is not lower) */ + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + gcry_mpi_ec_sub (tlta2[i][j], tlta2[i][j], ad->alpha[i][j], ec_ctx); + gcry_mpi_ec_sub (tltb2[i][j], tltb2[i][j], ad->beta[i][j], ec_ctx); + } + brandt_assert (!ec_point_cmp (ec_zero, tlta2[i][0])); + brandt_assert (!ec_point_cmp (ec_zero, tltb2[i][0])); + } + + /* temporary lookup table for third summand (no one with a lower index has + * the same bid) */ + for (uint16_t j = 0; j < ad->k; j++) + { + smc_sums_partial (&tlta3[0][j], &ad->alpha[0][j], ad->n, ad->k, ad->k); + smc_sums_partial (&tltb3[0][j], &ad->beta[0][j], ad->n, ad->k, ad->k); + for (uint16_t i = 0; i < ad->n; i++) + { + gcry_mpi_ec_sub (tlta3[i][j], tlta3[i][j], ad->alpha[i][j], ec_ctx); + gcry_mpi_ec_sub (tltb3[i][j], tltb3[i][j], ad->beta[i][j], ec_ctx); + } + brandt_assert (!ec_point_cmp (ec_zero, tlta3[0][j])); + brandt_assert (!ec_point_cmp (ec_zero, tltb3[0][j])); + } + + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + /* compute inner gamma */ + gcry_mpi_ec_add (tmpa, tlta1[j], tlta2[i][j], ec_ctx); + gcry_mpi_ec_add (tmpa, tmpa, tlta3[i][j], ec_ctx); + + /* compute inner delta */ + gcry_mpi_ec_add (tmpb, tltb1[j], tltb2[i][j], ec_ctx); + gcry_mpi_ec_add (tmpb, tmpb, tltb3[i][j], ec_ctx); + + /* copy unmasked outcome to all other bidder layers so they don't + * have to be recomputed to check the ZK proof_2dle's from other + * bidders when receiving their outcome messages */ + for (uint16_t a = 0; a < ad->n; a++) + { + ec_point_copy (ad->gamma3[a][i][j], tmpa); + ec_point_copy (ad->delta3[a][i][j], tmpb); + } + } + } + + gcry_mpi_point_release (tmpa); + gcry_mpi_point_release (tmpb); + smc_free1 (tlta1, ad->k); + smc_free1 (tltb1, ad->k); + smc_free2 (tlta2, ad->n, ad->k); + smc_free2 (tltb2, ad->n, ad->k); + smc_free2 (tlta3, ad->n, ad->k); + smc_free2 (tltb3, ad->n, ad->k); +} + + +/** + * fp_priv_compute_outcome computes encrypted outcome shares and packs them into + * a message buffer together with proofs of correctnes. + * + * @param[in] ad Pointer to the BRANDT_Auction struct to operate on + * @param[out] buflen Size of the returned message buffer in bytes + * @return A buffer containing the encrypted outcome vectors + * which needs to be broadcast + */ +unsigned char * +fp_priv_compute_outcome (struct BRANDT_Auction *ad, size_t *buflen) +{ + unsigned char *ret; + unsigned char *cur; + struct msg_head *head; + gcry_mpi_point_t tmpa = gcry_mpi_point_new (0); + gcry_mpi_point_t tmpb = gcry_mpi_point_new (0); + struct ec_mpi *gamma; + struct ec_mpi *delta; + struct proof_2dle *proof2; + + brandt_assert (ad && buflen); + + *buflen = (sizeof (*head) + /* msg header */ + ad->n * ad->k * /* nk * (gamma, delta, proof2) */ + (sizeof (*gamma) + sizeof (*delta) + sizeof (*proof2))); + ret = GNUNET_new_array (*buflen, unsigned char); + + head = (struct msg_head *)ret; + head->prot_version = htonl (0); + head->msg_type = htonl (msg_outcome); + cur = ret + sizeof (*head); + + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + gamma = (struct ec_mpi *)cur; + delta = &((struct ec_mpi *)cur)[1]; + proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); + + ec_point_copy (tmpa, ad->gamma3[ad->i][i][j]); + ec_point_copy (tmpb, ad->delta3[ad->i][i][j]); + + /* apply random masking for losing bidders */ + smc_zkp_2dle (ad->gamma3[ad->i][i][j], + ad->delta3[ad->i][i][j], + tmpa, + tmpb, + NULL, + proof2); + + ec_point_serialize (gamma, ad->gamma3[ad->i][i][j]); + ec_point_serialize (delta, ad->delta3[ad->i][i][j]); + + cur += sizeof (*gamma) + sizeof (*delta) + sizeof (*proof2); + } + } + + gcry_mpi_point_release (tmpa); + gcry_mpi_point_release (tmpb); + return ret; +} + + +int +fp_priv_recv_outcome (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender) +{ + int ret = 0; + const unsigned char *cur = buf; + struct proof_2dle *proof2; + gcry_mpi_point_t gamma = gcry_mpi_point_new (0); + gcry_mpi_point_t delta = gcry_mpi_point_new (0); + + brandt_assert (ad && buf); + + if (buflen != (ad->n * ad->k * + (2 * sizeof (struct ec_mpi) + sizeof (*proof2)))) + { + weprintf ("wrong size of received outcome"); + goto quit; + } + + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + ec_point_parse (gamma, (struct ec_mpi *)cur); + ec_point_parse (delta, &((struct ec_mpi *)cur)[1]); + proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); + if (smc_zkp_2dle_check (gamma, + delta, + ad->gamma3[sender][i][j], + ad->delta3[sender][i][j], + proof2)) + { + weprintf ("wrong zkp2 for gamma, delta received"); + goto quit; + } + ec_point_copy (ad->gamma3[sender][i][j], gamma); + ec_point_copy (ad->delta3[sender][i][j], delta); + cur += 2 * sizeof (struct ec_mpi) + sizeof (*proof2); + } + } + + ret = 1; +quit: + gcry_mpi_point_release (gamma); + gcry_mpi_point_release (delta); + return ret; +} + + +void +fp_priv_prep_decryption (struct BRANDT_Auction *ad) +{ + gcry_mpi_point_t tmp = gcry_mpi_point_new (0); + + ad->phi3 = smc_init3 (ad->n, ad->n, ad->k); + brandt_assert (ad->phi3); + + ad->phiproofs3 = GNUNET_new_array_3d (ad->n, + ad->n, + ad->k, + struct proof_2dle); + brandt_assert (ad->phiproofs3); + + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + smc_sum (tmp, &ad->delta3[0][i][j], ad->n, ad->n * ad->k); + + /* copy still encrypted outcome to all other bidder layers so they + * don't have to be recomputed to check the ZK proof_2dle's from + * other bidders when receiving their outcome decryption messages */ + for (uint16_t a = 0; a < ad->n; a++) + ec_point_copy (ad->phi3[a][i][j], tmp); + } + } + + gcry_mpi_point_release (tmp); +} + + +static unsigned char * +fp_priv_decrypt_outcome_seller (struct BRANDT_Auction *ad, size_t *buflen) +{ + unsigned char *ret; + unsigned char *cur; + struct msg_head *head; + gcry_mpi_point_t tmp = gcry_mpi_point_new (0); + struct ec_mpi *phi; + struct proof_2dle *proof2; + + *buflen = (sizeof (*head) + + (ad->n - 1) * ad->n * ad->k * (sizeof (*phi) + + sizeof (*proof2))); + ret = GNUNET_new_array (*buflen, unsigned char); + + head = (struct msg_head *)ret; + head->prot_version = htonl (0); + head->msg_type = htonl (msg_decrypt); + cur = ret + sizeof (*head); + + for (uint16_t h = 0; h < ad->n; h++) + { + for (uint16_t i = 0; i < ad->n; i++) + { + /* don't reveal outcome to losing bidders */ + if (h == i) + continue; + + for (uint16_t j = 0; j < ad->k; j++) + { + phi = (struct ec_mpi *)cur; + proof2 = (struct proof_2dle *)(cur + sizeof (*phi)); + + ec_point_serialize (phi, ad->phi3[h][i][j]); + memcpy (proof2, &ad->phiproofs3[h][i][j], sizeof (*proof2)); + + cur += sizeof (*phi) + sizeof (*proof2); + } + } + } + + gcry_mpi_point_release (tmp); + return ret; +} + + +static unsigned char * +fp_priv_decrypt_outcome_bidder (struct BRANDT_Auction *ad, size_t *buflen) +{ + unsigned char *ret; + unsigned char *cur; + struct msg_head *head; + gcry_mpi_point_t tmp = gcry_mpi_point_new (0); + struct ec_mpi *phi; + struct proof_2dle *proof2; + + *buflen = (sizeof (*head) + + ad->n * ad->k * (sizeof (*phi) + sizeof (*proof2))); + ret = GNUNET_new_array (*buflen, unsigned char); + + head = (struct msg_head *)ret; + head->prot_version = htonl (0); + head->msg_type = htonl (msg_decrypt); + cur = ret + sizeof (*head); + + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + phi = (struct ec_mpi *)cur; + proof2 = (struct proof_2dle *)(cur + sizeof (*phi)); + + ec_point_copy (tmp, ad->phi3[ad->i][i][j]); + + /* decrypt outcome component and prove the correct key was used */ + smc_zkp_2dle (ad->phi3[ad->i][i][j], + NULL, + tmp, + ec_gen, + ad->x, + proof2); + + ec_point_serialize (phi, ad->phi3[ad->i][i][j]); + + cur += sizeof (*phi) + sizeof (*proof2); + } + } + + gcry_mpi_point_release (tmp); + return ret; +} + + +/** + * fp_priv_decrypt_outcome decrypts the own shares of the outcome and packs them + * into a message buffer together with proofs of correctnes. When this is called + * as the seller it will not decrypt anything, but just create the message + * buffer from all received decryption shares to broadcast back to all bidders. + * + * @param[in] ad Pointer to the BRANDT_Auction struct to operate on + * @param[out] buflen Size of the returned message buffer in bytes + * @return A buffer containing the share of the decrypted outcome + * which needs to be broadcast + */ +unsigned char * +fp_priv_decrypt_outcome (struct BRANDT_Auction *ad, size_t *buflen) +{ + brandt_assert (ad && buflen); + if (ad->seller_mode) + return fp_priv_decrypt_outcome_seller (ad, buflen); + else + return fp_priv_decrypt_outcome_bidder (ad, buflen); +} + + +static int +fp_priv_recv_decryption_seller (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender) +{ + int ret = 0; + const unsigned char *cur = buf; + struct proof_2dle *proof2; + gcry_mpi_point_t phi = gcry_mpi_point_new (0); + + if (buflen != (ad->n * ad->k * (sizeof (struct ec_mpi) + sizeof (*proof2)))) + { + weprintf ("wrong size of received outcome decryption from bidder"); + goto quit; + } + + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + ec_point_parse (phi, (struct ec_mpi *)cur); + proof2 = (struct proof_2dle *)(cur + sizeof (struct ec_mpi)); + if (smc_zkp_2dle_check (phi, + ad->y[sender], + ad->phi3[sender][i][j], + ec_gen, + proof2)) + { + weprintf ("wrong zkp2 for phi, y received from bidder"); + goto quit; + } + + /* store proof. we need to rebroadcast it to the other bidders */ + memcpy (&ad->phiproofs3[sender][i][j], proof2, sizeof (*proof2)); + + ec_point_copy (ad->phi3[sender][i][j], phi); + cur += sizeof (struct ec_mpi) + sizeof (*proof2); + } + } + + ret = 1; +quit: + gcry_mpi_point_release (phi); + return ret; +} + + +static int +fp_priv_recv_decryption_bidder (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender) +{ + int ret = 0; + const unsigned char *cur = buf; + struct proof_2dle *proof2; + gcry_mpi_point_t phi = gcry_mpi_point_new (0); + + if (buflen != ((ad->n - 1) * ad->n * ad->k * (sizeof (struct ec_mpi) + + sizeof (*proof2)))) + { + weprintf ("wrong size of received outcome decryption from seller"); + goto quit; + } + + for (uint16_t h = 0; h < ad->n; h++) + { + for (uint16_t i = 0; i < ad->n; i++) + { + /* those combinations are not sent by the seller */ + if (h == i) + continue; + + /* we already have our own phi values */ + if (h == ad->i) + { + cur += ad->k * (sizeof (struct ec_mpi) + sizeof (*proof2)); + continue; + } + + for (uint16_t j = 0; j < ad->k; j++) + { + ec_point_parse (phi, (struct ec_mpi *)cur); + proof2 = (struct proof_2dle *)(cur + sizeof (struct ec_mpi)); + if (smc_zkp_2dle_check (phi, + ad->y[h], + ad->phi3[h][i][j], + ec_gen, + proof2)) + { + weprintf ("wrong zkp2 for phi, y received from seller"); + goto quit; + } + ec_point_copy (ad->phi3[h][i][j], phi); + cur += sizeof (struct ec_mpi) + sizeof (*proof2); + } + } + } + + ret = 1; +quit: + gcry_mpi_point_release (phi); + return ret; +} + + +int +fp_priv_recv_decryption (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender) +{ + brandt_assert (ad && buf); + if (ad->seller_mode) + return fp_priv_recv_decryption_seller (ad, buf, buflen, sender); + else + return fp_priv_recv_decryption_bidder (ad, buf, buflen, sender); +} + + +struct BRANDT_Result * +fp_priv_determine_outcome (struct BRANDT_Auction *ad, + uint16_t *len) +{ + struct BRANDT_Result *ret; + int32_t price = -1; + int32_t winner = -1; + gcry_mpi_point_t sum_gamma = gcry_mpi_point_new (0); + gcry_mpi_point_t sum_phi = gcry_mpi_point_new (0); + + brandt_assert (ad); + + for (uint16_t i = 0; i < ad->n; i++) + { + if (!ad->seller_mode && i != ad->i) + continue; + + for (uint16_t j = 0; j < ad->k; j++) + { + smc_sum (sum_gamma, &ad->gamma3[0][i][j], ad->n, ad->n * ad->k); + smc_sum (sum_phi, &ad->phi3[0][i][j], ad->n, ad->n * ad->k); + gcry_mpi_ec_sub (sum_gamma, sum_gamma, sum_phi, ec_ctx); + if (!ec_point_cmp (sum_gamma, ec_zero)) + { + if (-1 != price) + { + weprintf ("multiple winning prices detected"); + return NULL; + } + if (-1 != winner) + { + weprintf ("multiple winners detected"); + return NULL; + } + price = j; + winner = i; + } + } + } + + gcry_mpi_point_release (sum_gamma); + gcry_mpi_point_release (sum_phi); + + if (-1 == winner || -1 == price) + return NULL; + + ret = GNUNET_new (struct BRANDT_Result); + ret->bidder = winner; + ret->price = price; + ret->status = BRANDT_bidder_won; + if (len) + *len = 1; + return ret; +} diff --git a/fp_pub.c b/fp_pub.c new file mode 100644 index 0000000..eb0cfe1 --- /dev/null +++ b/fp_pub.c @@ -0,0 +1,438 @@ +/* This file is part of libbrandt. + * Copyright (C) 2016 GNUnet e.V. + * + * libbrandt is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libbrandt is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * libbrandt. If not, see . + */ + +/** + * @file fp_pub.c + * @brief Implementation of the first price public outcome algorithm. + * @author Markus Teich + */ + +#include "platform.h" + +#include + +#include "crypto.h" +#include "internals.h" +#include "util.h" + + +void +fp_pub_prep_outcome (struct BRANDT_Auction *ad) +{ + gcry_mpi_t coeff = gcry_mpi_copy (GCRYMPI_CONST_ONE); + gcry_mpi_point_t tmp = gcry_mpi_point_new (0); + gcry_mpi_point_t *tlta1; + gcry_mpi_point_t *tltb1; + gcry_mpi_point_t **tlta2; + gcry_mpi_point_t **tltb2; + + ad->gamma2 = smc_init2 (ad->n, ad->k); + brandt_assert (ad->gamma2); + + ad->delta2 = smc_init2 (ad->n, ad->k); + brandt_assert (ad->delta2); + + ad->tmpa1 = smc_init1 (ad->k); + brandt_assert (ad->tmpa1); + + ad->tmpb1 = smc_init1 (ad->k); + brandt_assert (ad->tmpb1); + + /* create temporary lookup tables with partial sums */ + tlta1 = smc_init1 (ad->k); + tltb1 = smc_init1 (ad->k); + tlta2 = smc_init2 (ad->n, ad->k); + tltb2 = smc_init2 (ad->n, ad->k); + + /* temporary lookup table for sum of bid vectors */ + for (uint16_t i = 0; i < ad->n; i++) + { + smc_sums_partial (tlta2[i], ad->alpha[i], ad->k, 1, 1); + smc_sums_partial (tltb2[i], ad->beta[i], ad->k, 1, 1); + for (uint16_t j = 0; j < ad->k; j++) + { + gcry_mpi_ec_sub (tlta2[i][j], + tlta2[i][ad->k - 1], + tlta2[i][j], + ec_ctx); + gcry_mpi_ec_sub (tltb2[i][j], + tltb2[i][ad->k - 1], + tltb2[i][j], + ec_ctx); + } + brandt_assert (!ec_point_cmp (ec_zero, tlta2[i][ad->k - 1])); + brandt_assert (!ec_point_cmp (ec_zero, tltb2[i][ad->k - 1])); + } + for (uint16_t j = 0; j < ad->k; j++) + { + smc_sum (tlta1[j], &tlta2[0][j], ad->n, ad->k); + smc_sum (tltb1[j], &tltb2[0][j], ad->n, ad->k); + } + smc_free2 (tlta2, ad->n, ad->k); + smc_free2 (tltb2, ad->n, ad->k); + brandt_assert (!ec_point_cmp (ec_zero, tlta1[ad->k - 1])); + brandt_assert (!ec_point_cmp (ec_zero, tltb1[ad->k - 1])); + + /* initialize tmp array with zeroes, since we are calculating a sum */ + for (uint16_t j = 0; j < ad->k; j++) + { + ec_point_copy (ad->tmpa1[j], ec_zero); + ec_point_copy (ad->tmpb1[j], ec_zero); + } + /* store the \sum_{i=1}^n2^{i-1}b_i in tmp1 until outcome determination, + * since it is needed each time a gamma,delta pair is received from another + * bidder */ + for (uint16_t i = 0; i < ad->n; i++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + gcry_mpi_ec_mul (tmp, coeff, ad->alpha[i][j], ec_ctx); + gcry_mpi_ec_add (ad->tmpa1[j], ad->tmpa1[j], tmp, ec_ctx); + gcry_mpi_ec_mul (tmp, coeff, ad->beta[i][j], ec_ctx); + gcry_mpi_ec_add (ad->tmpb1[j], ad->tmpb1[j], tmp, ec_ctx); + } + gcry_mpi_lshift (coeff, coeff, 1); + } + + for (uint16_t j = 0; j < ad->k; j++) + { + /* copy unmasked outcome to all other bidder layers so they don't + * have to be recomputed to check the ZK proof_2dle's from other + * bidders when receiving their outcome messages */ + for (uint16_t a = 0; a < ad->n; a++) + { + ec_point_copy (ad->gamma2[a][j], tlta1[j]); + ec_point_copy (ad->delta2[a][j], tltb1[j]); + } + } + + gcry_mpi_release (coeff); + gcry_mpi_point_release (tmp); + smc_free1 (tlta1, ad->k); + smc_free1 (tltb1, ad->k); +} + + +/** + * fp_pub_compute_outcome computes the outcome for first price auctions with a + * public outcome and packs it into a message buffer together with proofs of + * correctnes. + * + * @param[in] ad Pointer to the BRANDT_Auction struct to operate on + * @param[out] buflen Size of the returned message buffer in bytes + * @return A buffer containing the encrypted outcome vectors + * which needs to be broadcast + */ +unsigned char * +fp_pub_compute_outcome (struct BRANDT_Auction *ad, size_t *buflen) +{ + unsigned char *ret; + unsigned char *cur; + gcry_mpi_point_t tmpa = gcry_mpi_point_new (0); + gcry_mpi_point_t tmpb = gcry_mpi_point_new (0); + struct msg_head *head; + struct ec_mpi *gamma; + struct ec_mpi *delta; + struct proof_2dle *proof2; + + brandt_assert (ad && buflen); + + *buflen = (sizeof (*head) + + ad->k * (sizeof (*gamma) + + sizeof (*delta) + + sizeof (*proof2))); + ret = GNUNET_new_array (*buflen, unsigned char); + + head = (struct msg_head *)ret; + head->prot_version = htonl (0); + head->msg_type = htonl (msg_outcome); + cur = ret + sizeof (*head); + + for (uint16_t j = 0; j < ad->k; j++) + { + gamma = (struct ec_mpi *)cur; + delta = &((struct ec_mpi *)cur)[1]; + proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); + + ec_point_copy (tmpa, ad->gamma2[ad->i][j]); + ec_point_copy (tmpb, ad->delta2[ad->i][j]); + + /* apply random masking for losing bidders */ + smc_zkp_2dle (ad->gamma2[ad->i][j], + ad->delta2[ad->i][j], + tmpa, + tmpb, + NULL, + proof2); + + ec_point_serialize (gamma, ad->gamma2[ad->i][j]); + ec_point_serialize (delta, ad->delta2[ad->i][j]); + + /* add winner determination for own gamma,delta */ + gcry_mpi_ec_add (ad->gamma2[ad->i][j], + ad->gamma2[ad->i][j], + ad->tmpa1[j], + ec_ctx); + gcry_mpi_ec_add (ad->delta2[ad->i][j], + ad->delta2[ad->i][j], + ad->tmpb1[j], + ec_ctx); + + cur += sizeof (*gamma) + sizeof (*delta) + sizeof (*proof2); + } + + gcry_mpi_point_release (tmpa); + gcry_mpi_point_release (tmpb); + return ret; +} + + +int +fp_pub_recv_outcome (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender) +{ + int ret = 0; + const unsigned char *cur = buf; + struct proof_2dle *proof2; + gcry_mpi_point_t gamma = gcry_mpi_point_new (0); + gcry_mpi_point_t delta = gcry_mpi_point_new (0); + + brandt_assert (ad && buf); + + if (buflen != (ad->k * (2 * sizeof (struct ec_mpi) + sizeof (*proof2)))) + { + weprintf ("wrong size of received outcome"); + goto quit; + } + + for (uint16_t j = 0; j < ad->k; j++) + { + ec_point_parse (gamma, (struct ec_mpi *)cur); + ec_point_parse (delta, &((struct ec_mpi *)cur)[1]); + proof2 = (struct proof_2dle *)(cur + 2 * sizeof (struct ec_mpi)); + if (smc_zkp_2dle_check (gamma, + delta, + ad->gamma2[sender][j], + ad->delta2[sender][j], + proof2)) + { + weprintf ("wrong zkp2 for gamma, delta received"); + goto quit; + } + ec_point_copy (ad->gamma2[sender][j], gamma); + ec_point_copy (ad->delta2[sender][j], delta); + + /* add winner determination summand */ + gcry_mpi_ec_add (ad->gamma2[sender][j], + ad->gamma2[sender][j], + ad->tmpa1[j], + ec_ctx); + gcry_mpi_ec_add (ad->delta2[sender][j], + ad->delta2[sender][j], + ad->tmpb1[j], + ec_ctx); + + cur += 2 * sizeof (struct ec_mpi) + sizeof (*proof2); + } + + ret = 1; +quit: + gcry_mpi_point_release (gamma); + gcry_mpi_point_release (delta); + return ret; +} + + +void +fp_pub_prep_decryption (struct BRANDT_Auction *ad) +{ + gcry_mpi_point_t tmp = gcry_mpi_point_new (0); + + ad->phi2 = smc_init2 (ad->n, ad->k); + brandt_assert (ad->phi2); + + for (uint16_t j = 0; j < ad->k; j++) + { + smc_sum (tmp, &ad->delta2[0][j], ad->n, ad->k); + + /* copy still encrypted outcome to all other bidder layers so they + * don't have to be recomputed to check the ZK proof_2dle's from + * other bidders when receiving their outcome decryption messages */ + for (uint16_t a = 0; a < ad->n; a++) + ec_point_copy (ad->phi2[a][j], tmp); + } + + gcry_mpi_point_release (tmp); +} + + +/** + * fp_pub_decrypt_outcome decrypts part of the outcome and packs it into a + * message buffer together with proofs of correctnes. + * + * @param[in] ad Pointer to the BRANDT_Auction struct to operate on + * @param[out] buflen Size of the returned message buffer in bytes + * @return A buffer containing the own share of the decrypted outcome + * which needs to be broadcast + */ +unsigned char * +fp_pub_decrypt_outcome (struct BRANDT_Auction *ad, size_t *buflen) +{ + unsigned char *ret; + unsigned char *cur; + gcry_mpi_point_t tmp = gcry_mpi_point_new (0); + struct msg_head *head; + struct ec_mpi *phi; + struct proof_2dle *proof2; + + brandt_assert (ad && buflen); + + *buflen = (sizeof (*head) + ad->k * (sizeof (*phi) + sizeof (*proof2))); + ret = GNUNET_new_array (*buflen, unsigned char); + + head = (struct msg_head *)ret; + head->prot_version = htonl (0); + head->msg_type = htonl (msg_decrypt); + cur = ret + sizeof (*head); + + for (uint16_t j = 0; j < ad->k; j++) + { + phi = (struct ec_mpi *)cur; + proof2 = (struct proof_2dle *)(cur + sizeof (*phi)); + + ec_point_copy (tmp, ad->phi2[ad->i][j]); + + /* decrypt outcome component and prove the correct key was used */ + smc_zkp_2dle (ad->phi2[ad->i][j], + NULL, + tmp, + ec_gen, + ad->x, + proof2); + + ec_point_serialize (phi, ad->phi2[ad->i][j]); + + cur += sizeof (*phi) + sizeof (*proof2); + } + + gcry_mpi_point_release (tmp); + return ret; +} + + +int +fp_pub_recv_decryption (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender) +{ + int ret = 0; + const unsigned char *cur = buf; + struct proof_2dle *proof2; + gcry_mpi_point_t phi = gcry_mpi_point_new (0); + + brandt_assert (ad && buf); + + if (buflen != (ad->k * (sizeof (struct ec_mpi) + sizeof (*proof2)))) + { + weprintf ("wrong size of received outcome decryption"); + goto quit; + } + + for (uint16_t j = 0; j < ad->k; j++) + { + ec_point_parse (phi, (struct ec_mpi *)cur); + proof2 = (struct proof_2dle *)(cur + sizeof (struct ec_mpi)); + if (smc_zkp_2dle_check (phi, + ad->y[sender], + ad->phi2[sender][j], + ec_gen, + proof2)) + { + weprintf ("wrong zkp2 for phi, y received"); + goto quit; + } + ec_point_copy (ad->phi2[sender][j], phi); + cur += sizeof (struct ec_mpi) + sizeof (*proof2); + } + + ret = 1; +quit: + gcry_mpi_point_release (phi); + return ret; +} + + +struct BRANDT_Result * +fp_pub_determine_outcome (struct BRANDT_Auction *ad, + uint16_t *len) +{ + struct BRANDT_Result *ret; + int32_t price = -1; + int32_t winner = -1; + int dlogi = -1; + gcry_mpi_point_t sum_gamma = gcry_mpi_point_new (0); + gcry_mpi_point_t sum_phi = gcry_mpi_point_new (0); + + brandt_assert (ad); + + for (uint16_t j = ad->k - 1; j >= 0; j--) + { + smc_sum (sum_gamma, &ad->gamma2[0][j], ad->n, ad->k); + smc_sum (sum_phi, &ad->phi2[0][j], ad->n, ad->k); + gcry_mpi_ec_sub (sum_gamma, sum_gamma, sum_phi, ec_ctx); + /* first non-zero component determines the price */ + if (ec_point_cmp (sum_gamma, ec_zero)) + { + price = j; + break; + } + } + + dlogi = GNUNET_CRYPTO_ecc_dlog (ec_dlogctx, sum_gamma); + brandt_assert (dlogi > 0); + + /* all bidders participated with a multiplicative share */ + dlogi /= ad->n; + + /* can only support up to bits(dlogi) bidders */ + brandt_assert (sizeof (int) * 8 - 1 >= ad->n); + for (uint16_t i = 0; i < ad->n; i++) + { + /* first set bit determines the winner */ + if (dlogi & (1 << i)) + { + winner = i; + break; + } + } + + gcry_mpi_point_release (sum_gamma); + gcry_mpi_point_release (sum_phi); + + if (-1 == winner || -1 == price) + return NULL; + + ret = GNUNET_new (struct BRANDT_Result); + ret->bidder = winner; + ret->price = price; + ret->status = BRANDT_bidder_won; + if (len) + *len = 1; + return ret; +} diff --git a/internals.h b/internals.h index 2b88b6f..373c3d4 100644 --- a/internals.h +++ b/internals.h @@ -164,4 +164,10 @@ struct BRANDT_Auction { gcry_mpi_point_t *tmpb1; /** used for temporary storage, size: k */ }; +extern gcry_ctx_t ec_ctx; +extern gcry_mpi_point_t ec_gen; +extern gcry_mpi_point_t ec_zero; +extern gcry_mpi_t ec_n; +extern struct GNUNET_CRYPTO_EccDlogContext *ec_dlogctx; + #endif /* ifndef _BRANDT_INTERNALS_H */