/* 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 mp_priv.c * @brief Implementation of the m+1st price private outcome algorithm. * @author Markus Teich */ #include "platform.h" #include #include "crypto.h" #include "internals.h" #include "util.h" void mp_priv_prep_outcome (struct BRANDT_Auction *ad) { gcry_mpi_t factor = gcry_mpi_new (256); gcry_mpi_point_t subtr = gcry_mpi_point_new (0); 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 (building ladder of bids) */ for (uint16_t i = 0; i < ad->n; i++) { smc_sums_partial (tlta3[i], ad->alpha[i], ad->k, 1, 1); smc_sums_partial (tltb3[i], ad->beta[i], ad->k, 1, 1); for (uint16_t j = 0; j < ad->k; j++) { gcry_mpi_ec_sub (tlta2[i][j], tlta3[i][ad->k - 1], tlta3[i][j], ec_ctx); gcry_mpi_ec_sub (tltb2[i][j], tltb3[i][ad->k - 1], tltb3[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++) { /* 2L - 2I */ smc_sum (tmpa, &tlta2[0][j], ad->n, ad->k); smc_sum (tmpb, &tltb2[0][j], ad->n, ad->k); gcry_mpi_ec_mul (tlta1[j], GCRYMPI_CONST_TWO, tmpa, ec_ctx); gcry_mpi_ec_mul (tltb1[j], GCRYMPI_CONST_TWO, tmpb, ec_ctx); /* I */ smc_sum (tmpa, &ad->alpha[0][j], ad->n, ad->k); smc_sum (tmpb, &ad->beta[0][j], ad->n, ad->k); /* 2L - 2I + I = 2L - I */ gcry_mpi_ec_add (tlta1[j], tlta1[j], tmpa, ec_ctx); gcry_mpi_ec_add (tltb1[j], tltb1[j], tmpb, ec_ctx); } /* This check only works directly after the loop when tmpa/tmpb are still * the sum of the last row */ brandt_assert (! ec_point_cmp (tmpa, tlta1[ad->k - 1])); brandt_assert (! ec_point_cmp (tmpb, tltb1[ad->k - 1])); /* temporary lookup table for second summand (hide outcome from losers) */ gcry_mpi_set_ui (factor, ad->m); gcry_mpi_lshift (factor, factor, 1); gcry_mpi_add_ui (factor, factor, 2); for (uint16_t i = 0; i < ad->n; i++) { for (uint16_t j = 0; j < ad->k; j++) { gcry_mpi_ec_mul (tlta2[i][j], factor, tlta3[i][j], ec_ctx); gcry_mpi_ec_mul (tltb2[i][j], factor, tltb3[i][j], ec_ctx); } } /* temporary lookup table for subtrahend (getting M+1st highest bid) */ gcry_mpi_sub_ui (factor, factor, 1); gcry_mpi_ec_mul (subtr, factor, ec_gen, ec_ctx); /* compute gamma and delta */ 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_sub (tmpa, tmpa, subtr, ec_ctx); /* compute inner delta */ gcry_mpi_ec_add (tmpb, tltb1[j], tltb2[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_release (factor); gcry_mpi_point_release (subtr); 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); } struct BRANDT_Result * mp_priv_determine_outcome (struct BRANDT_Auction *ad, uint16_t *len) { struct BRANDT_Result *ret; int32_t price = -1; uint16_t winners = 0; uint16_t max_winners; 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); max_winners = ad->seller_mode ? ad->m : 1; ret = GNUNET_new_array (max_winners, struct BRANDT_Result); 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 (winners >= max_winners) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "libbrandt", "too many winners detected\n"); goto fail; } if (-1 != price && j != price) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "libbrandt", "multiple winning prices detected\n"); goto fail; } price = j; ret[winners].bidder = i; ret[winners].price = j / ad->n; ret[winners].status = BRANDT_bidder_won; winners++; } } } gcry_mpi_point_release (sum_gamma); gcry_mpi_point_release (sum_phi); if (ad->m <= ad->n && winners < max_winners && -1 != price) GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "libbrandt", "too few winners detected\n"); if (0 == winners) goto fail; if (len) *len = winners; return ret; fail: GNUNET_free (ret); return NULL; }