diff --git a/Makefile.am b/Makefile.am index e0b6356..9b80791 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,6 +10,7 @@ libbrandt_la_SOURCES = \ fp_priv.c \ fp_pub.c \ mp_priv.c \ + mp_pub.c \ util.c libbrandt_la_LIBADD = \ diff --git a/brandt.c b/brandt.c index a05731d..ce41541 100644 --- a/brandt.c +++ b/brandt.c @@ -68,7 +68,7 @@ BRANDT_bidder_start (struct BRANDT_Auction *auction, outcome = auction->outcome_public ? outcome_public : outcome_private; if (auction_mPlusFirstPrice == atype && n <= auction->m) - { /* fewer bidders than items to sell. every bidder won with lowest price */ + { /* fewer bidders than items to sell. every bidder won with lowest price */ struct BRANDT_Result *res; if (auction->outcome_public) { @@ -138,7 +138,8 @@ seller_start (void *arg) } else if (ad->n <= ad->m) { - struct BRANDT_Result *res = GNUNET_new_array (ad->n, struct BRANDT_Result); + struct BRANDT_Result *res = GNUNET_new_array (ad->n, + struct BRANDT_Result); weprintf ("less bidders than needed, selling for lowest price"); for (uint16_t i = 0; i < ad->n; i++) @@ -346,14 +347,23 @@ BRANDT_destroy (struct BRANDT_Auction *auction) smc_free2 (auction->alpha, auction->n, auction->k); smc_free2 (auction->beta, auction->n, auction->k); smc_free2 (auction->gamma2, auction->n, auction->k); - smc_free3 (auction->gamma3, auction->n, auction->n, auction->k); smc_free2 (auction->delta2, auction->n, auction->k); - smc_free3 (auction->delta3, auction->n, auction->n, auction->k); smc_free2 (auction->phi2, auction->n, auction->k); - smc_free3 (auction->phi3, auction->n, auction->n, auction->k); free (auction->phiproofs3); smc_free1 (auction->tmpa1, auction->k); smc_free1 (auction->tmpb1, auction->k); + if (auction->m > 0 && auction->outcome_public) + { + smc_free3 (auction->gamma3, auction->n, 2, auction->k); + smc_free3 (auction->delta3, auction->n, 2, auction->k); + smc_free3 (auction->phi3, auction->n, 2, auction->k); + } + else + { + smc_free3 (auction->gamma3, auction->n, auction->n, auction->k); + smc_free3 (auction->delta3, auction->n, auction->n, auction->k); + smc_free3 (auction->phi3, auction->n, auction->n, auction->k); + } } diff --git a/crypto.h b/crypto.h index 4c06b4a..8291bc2 100644 --- a/crypto.h +++ b/crypto.h @@ -188,6 +188,26 @@ struct BRANDT_Result *mp_priv_determine_outcome (struct BRANDT_Auction *ad, uint16_t *len); +void mp_pub_prep_outcome (struct BRANDT_Auction *ad); +unsigned char *mp_pub_compute_outcome (struct BRANDT_Auction *ad, + size_t *buflen); +int mp_pub_recv_outcome (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender); + +void mp_pub_prep_decryption (struct BRANDT_Auction *ad); +unsigned char *mp_pub_decrypt_outcome (struct BRANDT_Auction *ad, + size_t *buflen); +int mp_pub_recv_decryption (struct BRANDT_Auction *ad, + const unsigned char *buf, + size_t buflen, + uint16_t sender); + +struct BRANDT_Result *mp_pub_determine_outcome (struct BRANDT_Auction *ad, + uint16_t *len); + + /* --- Round dictionaries --- */ typedef void @@ -245,6 +265,8 @@ static const RoundPrep handler_prep[auction_last][outcome_last][msg_last] = { [outcome_public] = { [msg_init] = &smc_prep_keyshare, [msg_bid] = &smc_prep_bid, + [msg_outcome] = &mp_pub_prep_outcome, + [msg_decrypt] = &mp_pub_prep_decryption, }, }, }; @@ -285,6 +307,8 @@ static const MsgIn handler_in[auction_last][outcome_last][msg_last] = { [outcome_public] = { [msg_init] = &smc_recv_keyshare, [msg_bid] = &smc_recv_encrypted_bid, + [msg_outcome] = &mp_pub_recv_outcome, + [msg_decrypt] = &mp_pub_recv_decryption, }, }, }; @@ -326,6 +350,8 @@ static const MsgOut handler_out[auction_last][outcome_last][msg_last] = { [outcome_public] = { [msg_init] = &smc_gen_keyshare, [msg_bid] = &smc_encrypt_bid, + [msg_outcome] = &mp_pub_compute_outcome, + [msg_decrypt] = &mp_pub_decrypt_outcome, }, }, }; @@ -342,13 +368,13 @@ static const MsgOut handler_out[auction_last][outcome_last][msg_last] = { * of 0 means a private outcome, while a value of 1 means public outcome. */ static const Result handler_res[auction_last][outcome_last] = { - [auction_firstPrice] = { + [auction_firstPrice] = { [outcome_private] = &fp_priv_determine_outcome, [outcome_public] = &fp_pub_determine_outcome, }, [auction_mPlusFirstPrice] = { [outcome_private] = &mp_priv_determine_outcome, -// [outcome_public] = , + [outcome_public] = &mp_pub_determine_outcome, }, }; diff --git a/gp-scripts/mp_pub b/gp-scripts/mp_pub new file mode 100644 index 0000000..9b49c13 --- /dev/null +++ b/gp-scripts/mp_pub @@ -0,0 +1,104 @@ +\\ From: "Fully private auctions in a constant number of rounds" (2003) by Felix Brandt pages 9-10 + + +\\\\\\\\\\\\ +\\ Adapt the following values to your needs +\\\\\\\\\\\\ + +\\ auction parameter +M = 1 +\\ amount of bidders +n = 2^2 +\\ amount of possible prices +k = 2^4 +\\ randomize bids (change to something static, if you like) +bid = vector(n,i,random(k)+1) +\\bid = vector(n,i,n-i+1) \\ first bidder wins +\\bid = vector(n,i,i) \\ last bidder wins +\\bid = vector(n,i,(i+1)%2) \\ second bidder wins (with ties) + +\\ prime finite field setup (result may be ambiguous if your prime is too small, 4*n*k seems to work fine) +\\q = prime(2^12) +\\ 512bit prime: +q = 12513167897862218633350152063959653109080007724899931588313481862015596111526299656550478091592311160908219544364381660940520774223634480285451547911456579 +\\ 2048bit prime: +\\q = 31905233907400964621684499856844075173802000556075101303613351426740101897961025481077892281365444367883091980681462491724119317344478120131982416132058173572772607966572720945691237876256074322291459510766147107539260048324345382562673904236506104922357079761457605045674628331006193183908801308817507027556440703972646885207099302085383887085776295396030033300833460743425162726394704256227108175491673135830378272029374848904772902525385997099641162537271298634032011458617811670193865244028195169383991286227040469186123958053863978710424421008752927011390777187889943940479064193231486057910586526439884046593027 +\\ 3072bit prime: +\\q = 5175054779340588353586849786144680366505563673837334790820581054294754700842534366479020240016540005621125885927641963390708863183739793208880756653713659686139600715884857385144475261507869935694699816011948585170171332029002674283854825650901258017026965486602158722052719421343475066067509485302858041368266332080773331946039572497794442067057597327877030322029413318847025776818839927761556478107499002213648377029201340152459685610920194363099878398871001275336711869213616313858200583491913270052111910410231060407633125816386053759634073500319223989240814564691163285769745840521560940666058800931070258886096469889796899266014106833050284032035948051974659796051419431527095503586817863043771919051402039741075037010264761045992285666560487072740505566408086913711094879155498223636912657852688296081316652278801546924079650897913388978423388839346058027184069633227966507908979049369500450630036982661231208087459099 +g = Mod(2, q) + +\\ get generator / primitive element for G_q +\\var = 'x \\ copy pasta from internet +\\pe=ffgen(minpoly(ffprimroot(ffgen(ffinit(p,1))),var),var) \\ get primitive element +\\1/(fforder(pe) == p-1) \\ error out, if ord(pe) is wrong +\\g = Mod(eval(Str(pe))^2, p) \\ dirty hack to convert t_FFELEM to t_INT + +\\\\\\\\\\\\ +\\ PROLOG +\\\\\\\\\\\\ + +\\ private keys of agents +x = vector(n,i,random(q)) +\\ public keyshares of agents +yshares = vector(n,i,g^x[i]) +\\ shared public key +y = prod(X=1,n,yshares[X]) + +\\ first index level = owning agent id (additive share) +\\ second index level = agent id, price id +m = matrix(n,k,a,b,random(q)) + +\\ index = owning agent id, price id +r = matrix(n,k,i,j,random(q)) +\\ bid matrix +b = matrix(n,k,i,j,g^(bid[i]==j)) + +\\\\\\\\\\\\ +\\ ROUND1 +\\\\\\\\\\\\ + +\\ encrypted bids +alpha = matrix(n,k,i,j, b[i,j]*y^r[i,j]) +beta = matrix(n,k,i,j, g^r[i,j]) + +\\\\\\\\\\\\ +\\ ROUND2 +\\\\\\\\\\\\ + +\\ multiplicative shares +\\ first index level = owning agent id (multiplicative share) +\\ second index level = agent id, price id +GammaPrice = matrix(n,k,a,j, ( prod(h=1,n,prod(d=j,k,alpha[h,d]) * prod(d=j+1,k,alpha[h,d])) / g^(2*M+1) )^(m[a,j]) ) +DeltaPrice = matrix(n,k,a,j, ( prod(h=1,n,prod(d=j,k, beta[h,d]) * prod(d=j+1,k, beta[h,d])) )^(m[a,j]) ) +GammaWinner = matrix(n,k,a,j, ( GammaPrice[a,j] * prod(h=1,n,prod(d=j+1,k,alpha[h,d]^(2^(h-1)))) )) +DeltaWinner = matrix(n,k,a,j, ( DeltaPrice[a,j] * prod(h=1,n,prod(d=j+1,k, beta[h,d]^(2^(h-1)))) )) + +\\\\\\\\\\\\ +\\ ROUND3 +\\\\\\\\\\\\ + +\\ multiplicative shares (decryption) +\\ first index level = owning agent id (multiplicative share) +\\ second index level = agent id, price id +PhiPrice = matrix(n,k,a,j, prod(h=1,n,DeltaPrice[h,j])^x[a] ) +PhiWinner = matrix(n,k,a,j, prod(h=1,n,DeltaWinner[h,j])^x[a] ) + +\\\\\\\\\\\\ +\\ EPILOG +\\\\\\\\\\\\ + +\\ winner matrix +vPrice = lift(vector(k,j, prod(i=1,n,GammaPrice[i,j]) / prod(i=1,n,PhiPrice[i,j]) )) +vWinner = vector(k,j, prod(i=1,n,GammaWinner[i,j]) / prod(i=1,n,PhiWinner[i,j]) ) + +print("bids are: ", bid) + +price = -1 +for(j=1,k, if(vPrice[j]==1, price=j)) + +winners = vector(i=1,M,-1) +winp = binary(znlog(vWinner[price],g)/n) +cur = 1; +for(i=1,length(winp), if(winp[length(winp)-i+1]==1,winners[cur]=i;cur=cur+1)) +print("Winners are ", winners) +print("And the price is ", price) diff --git a/mp_pub.c b/mp_pub.c new file mode 100644 index 0000000..7c2a373 --- /dev/null +++ b/mp_pub.c @@ -0,0 +1,526 @@ +/* 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_pub.c + * @brief Implementation of the m+1st price public outcome algorithm. + * @author Markus Teich + */ + +#include "platform.h" + +#include + +#include "crypto.h" +#include "internals.h" +#include "util.h" + + +void +mp_pub_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, 2, ad->k); + brandt_assert (ad->gamma3); + + ad->delta3 = smc_init3 (ad->n, 2, 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); + } + brandt_assert (!ec_point_cmp (tmpa, tlta1[ad->k - 1])); + brandt_assert (!ec_point_cmp (tmpb, tltb1[ad->k - 1])); + + /* compute subtrahend: (2M+1)G */ + gcry_mpi_set_ui (factor, ad->m); + gcry_mpi_lshift (factor, factor, 1); + gcry_mpi_add_ui (factor, factor, 1); + gcry_mpi_ec_mul (subtr, factor, ec_gen, ec_ctx); + + /* compute gamma and delta for price determination */ + for (uint16_t j = 0; j < ad->k; j++) + { + /* compute inner gamma */ + gcry_mpi_ec_sub (tmpa, tlta1[j], subtr, ec_ctx); + + /* inner delta */ + ec_point_copy (tmpb, tltb1[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->gamma3[a][0][j], tmpa); + ec_point_copy (ad->delta3[a][0][j], tmpb); + } + } + + /* gamma and delta for winner determination: compute + * @f$\sum_{h=1}^n\sum_{d=j+1}^k2^{h-1}b_h@f and store it in every bidders gamma and + * delta, 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++) + { + /* initialize with zeroes, since we are calculating a sum */ + ec_point_copy (ad->gamma3[i][1][j], ec_zero); + ec_point_copy (ad->delta3[i][1][j], ec_zero); + } + } + gcry_mpi_set_ui (factor, 1); + for (uint16_t h = 0; h < ad->n; h++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + for (uint16_t d = j + 1; d < ad->k; d++) + { + gcry_mpi_ec_mul (tmpa, factor, ad->alpha[h][d], ec_ctx); + gcry_mpi_ec_add (ad->gamma3[0][1][j], + ad->gamma3[0][1][j], + tmpa, + ec_ctx); + gcry_mpi_ec_mul (tmpb, factor, ad->beta[h][d], ec_ctx); + gcry_mpi_ec_add (ad->delta3[0][1][j], + ad->delta3[0][1][j], + tmpb, + ec_ctx); + } + } + gcry_mpi_lshift (factor, factor, 1); + } + /* copy component to all bidders so they don't have to be recomputed */ + for (uint16_t a = 1; a < ad->n; a++) + { + for (uint16_t j = 0; j < ad->k; j++) + { + ec_point_copy (ad->gamma3[a][1][j], ad->gamma3[0][1][j]); + ec_point_copy (ad->delta3[a][1][j], ad->delta3[0][1][j]); + } + } + + 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); +} + + +/** + * mp_pub_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 * +mp_pub_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->k * /* k * (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 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)); + + /* only send the price determination gamma,delta pair, since the winner + * determination pair can and will be computed by the receiver */ + ec_point_copy (tmpa, ad->gamma3[ad->i][0][j]); + ec_point_copy (tmpb, ad->delta3[ad->i][0][j]); + + /* apply random masking for losing bidders */ + smc_zkp_2dle (ad->gamma3[ad->i][0][j], + ad->delta3[ad->i][0][j], + tmpa, + tmpb, + NULL, + proof2); + + ec_point_serialize (gamma, ad->gamma3[ad->i][0][j]); + ec_point_serialize (delta, ad->delta3[ad->i][0][j]); + + /* compute own winner determination gamma,delta pair */ + gcry_mpi_ec_add (ad->gamma3[ad->i][1][j], + ad->gamma3[ad->i][0][j], + ad->gamma3[ad->i][1][j], + ec_ctx); + gcry_mpi_ec_add (ad->delta3[ad->i][1][j], + ad->delta3[ad->i][0][j], + ad->delta3[ad->i][1][j], + ec_ctx); + + cur += sizeof (*gamma) + sizeof (*delta) + sizeof (*proof2); + } + + gcry_mpi_point_release (tmpa); + gcry_mpi_point_release (tmpb); + return ret; +} + + +int +mp_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->gamma3[sender][0][j], + ad->delta3[sender][0][j], + proof2)) + { + weprintf ("wrong zkp2 for gamma, delta received"); + goto quit; + } + ec_point_copy (ad->gamma3[sender][0][j], gamma); + ec_point_copy (ad->delta3[sender][0][j], delta); + + /* compute winner determination gamma,delta pair */ + gcry_mpi_ec_add (ad->gamma3[sender][1][j], + ad->gamma3[sender][0][j], + ad->gamma3[sender][1][j], + ec_ctx); + gcry_mpi_ec_add (ad->delta3[sender][1][j], + ad->delta3[sender][0][j], + ad->delta3[sender][1][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 +mp_pub_prep_decryption (struct BRANDT_Auction *ad) +{ + gcry_mpi_point_t tmp_price = gcry_mpi_point_new (0); + gcry_mpi_point_t tmp_winner = gcry_mpi_point_new (0); + + ad->phi3 = smc_init3 (ad->n, 2, ad->k); + brandt_assert (ad->phi3); + + for (uint16_t j = 0; j < ad->k; j++) + { + smc_sum (tmp_price, &ad->delta3[0][0][j], ad->n, 2 * ad->k); + smc_sum (tmp_winner, &ad->delta3[0][1][j], ad->n, 2 * 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][0][j], tmp_price); + ec_point_copy (ad->phi3[a][1][j], tmp_winner); + } + } + + gcry_mpi_point_release (tmp_price); + gcry_mpi_point_release (tmp_winner); +} + + +/** + * mp_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 * +mp_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) + 2 * 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); + + /* decrypt price and winner components */ + for (uint16_t comp = 0; comp < 2; comp++) + { + 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][comp][j]); + + /* decrypt outcome component and prove the correct key was used */ + smc_zkp_2dle (ad->phi3[ad->i][comp][j], + NULL, + tmp, + ec_gen, + ad->x, + proof2); + + ec_point_serialize (phi, ad->phi3[ad->i][comp][j]); + + cur += sizeof (*phi) + sizeof (*proof2); + } + } + + gcry_mpi_point_release (tmp); + return ret; +} + + +int +mp_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 != (2 * ad->k * (sizeof (struct ec_mpi) + sizeof (*proof2)))) + { + weprintf ("wrong size of received outcome decryption"); + goto quit; + } + + /* handle received price and winner components */ + for (uint16_t comp = 0; comp < 2; comp++) + { + 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][comp][j], + ec_gen, + proof2)) + { + weprintf ("wrong zkp2 for phi, y received"); + goto quit; + } + ec_point_copy (ad->phi3[sender][comp][j], phi); + cur += sizeof (struct ec_mpi) + sizeof (*proof2); + } + } + + ret = 1; +quit: + gcry_mpi_point_release (phi); + return ret; +} + + +struct BRANDT_Result * +mp_pub_determine_outcome (struct BRANDT_Auction *ad, + uint16_t *len) +{ + struct BRANDT_Result *ret; + int32_t price = -1; + uint16_t cur_winner = 0; + 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->gamma3[0][0][j], ad->n, 2 * ad->k); + smc_sum (sum_phi, &ad->phi3[0][0][j], ad->n, 2 * ad->k); + gcry_mpi_ec_sub (sum_gamma, sum_gamma, sum_phi, ec_ctx); + /* first zero component determines the price */ + if (!ec_point_cmp (sum_gamma, ec_zero)) + { + price = j; + break; + } + } + + if (-1 == price) + return NULL; + + /* extract winners point for the winning price */ + smc_sum (sum_gamma, &ad->gamma3[0][1][price], ad->n, 2 * ad->k); + smc_sum (sum_phi, &ad->phi3[0][1][price], ad->n, 2 * ad->k); + gcry_mpi_ec_sub (sum_gamma, sum_gamma, sum_phi, ec_ctx); + + dlogi = GNUNET_CRYPTO_ecc_dlog (ec_dlogctx, sum_gamma); + brandt_assert (dlogi > 0); + + /* all bidders participated with a multiplicative share */ + dlogi /= ad->n; + + price = price / ad->n; + ret = GNUNET_new_array (ad->m, struct BRANDT_Result); + + /* can only support up to bits(dlogi) bidders */ + brandt_assert (sizeof (int) * 8 > ad->n); + for (uint16_t i = 0; i < ad->n; i++) + { + /* a set bit determines a winner */ + if (dlogi & (1 << i)) + { + if (cur_winner >= ad->m) + { + weprintf ("too many winners detected"); + GNUNET_free (ret); + ret = NULL; + goto quit; + } + + ret[cur_winner].bidder = i; + ret[cur_winner].price = price; + ret[cur_winner].status = BRANDT_bidder_won; + cur_winner++; + } + } + + if (cur_winner != ad->m) + { + weprintf ("too few winners detected"); + GNUNET_free (ret); + ret = NULL; + goto quit; + } + + if (len) + *len = ad->m; +quit: + gcry_mpi_point_release (sum_gamma); + gcry_mpi_point_release (sum_phi); + return ret; +} diff --git a/test_brandt.c b/test_brandt.c index 46ec90d..d18b17a 100644 --- a/test_brandt.c +++ b/test_brandt.c @@ -54,7 +54,7 @@ static struct testcase tcase; static struct BRANDT_Result * -expected_outcome (uint16_t i) +expected_outcome (uint16_t i, uint16_t *rlen) { struct BRANDT_Result *ret = NULL; int32_t highest_bidder = -1; @@ -65,6 +65,8 @@ expected_outcome (uint16_t i) uint16_t winners = MIN (tcase.m, tcase.n); uint16_t cur_winner = 0; + *rlen = 0; + if (0 == tcase.n) return NULL; @@ -81,6 +83,7 @@ expected_outcome (uint16_t i) ret->bidder = highest_bidder; ret->price = highest_bid; ret->status = BRANDT_bidder_won; + *rlen = 1; return ret; } @@ -89,7 +92,7 @@ expected_outcome (uint16_t i) { if (tcase.outcome_public || i == tcase.n) { - ret = GNUNET_new_array (tcase.n, struct BRANDT_Result); + ret = GNUNET_new_array ((*rlen = tcase.n), struct BRANDT_Result); for (uint16_t h = 0; h < tcase.n; h++) { ret[h].bidder = h; @@ -103,6 +106,7 @@ expected_outcome (uint16_t i) ret->bidder = i; ret->price = 0; ret->status = BRANDT_bidder_won; + *rlen = 1; } return ret; } @@ -154,6 +158,7 @@ expected_outcome (uint16_t i) cur_winner++; } } + *rlen = cur_winner; return ret; } @@ -250,7 +255,16 @@ cb_result (void *auction_closure, uint16_t results_len) { uint16_t *s = (uint16_t *)auction_closure; - struct BRANDT_Result *must = expected_outcome (*s); + uint16_t mustlen = -1; + struct BRANDT_Result *must = expected_outcome (*s, &mustlen); + + if (mustlen != results_len) + { + weprintf ("expected result len is: %d", mustlen); + weprintf ("computed result len is: %d (by agent %d)", results_len, *s); + tcase.ret = 1; + goto quit; + } if (0 == results_len) { @@ -281,6 +295,7 @@ cb_result (void *auction_closure, tcase.ret = 1; } +quit: tcase.result_called[*s] = 1; if (must) GNUNET_free (must); @@ -406,17 +421,24 @@ main (int argc, char *argv[]) BRANDT_init (edc); ret |= 0 || + // zero bidders test_auction (0, 2, NULL, 0, 0) || test_auction (0, 2, NULL, 0, 1) || test_auction (0, 2, NULL, 1, 0) || test_auction (0, 2, NULL, 2, 0) || + + // too few bidders => outcome is lowest possible price test_auction (1, 2, (uint16_t[]) { 1 }, 1, 0) || test_auction (1, 2, (uint16_t[]) { 0 }, 2, 0) || test_auction (2, 2, (uint16_t[]) { 1, 0 }, 2, 0) || test_auction (2, 2, (uint16_t[]) { 1, 0 }, 1, 0) || test_auction (3, 2, (uint16_t[]) { 0, 0, 1 }, 2, 0) || + + // general checks of all four algorithms test_auction (3, 2, (uint16_t[]) { 0, 1, 1 }, 0, 0) || test_auction (3, 2, (uint16_t[]) { 0, 1, 1 }, 0, 1) || + test_auction (3, 2, (uint16_t[]) { 0, 1, 1 }, 2, 0) || + test_auction (3, 2, (uint16_t[]) { 0, 1, 1 }, 2, 1) || 0; GNUNET_CRYPTO_ecc_dlog_release (edc);