869 lines
23 KiB
C
869 lines
23 KiB
C
/* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* @file test_brandt.c
|
|
* @brief testing API functions.
|
|
* @author Markus Teich
|
|
*/
|
|
|
|
#include "platform.h"
|
|
|
|
#include <gnunet/gnunet_util_lib.h>
|
|
#include <gnunet/gnunet_json_lib.h>
|
|
#include <jansson.h>
|
|
|
|
#include "brandt.h"
|
|
#include "crypto.h"
|
|
#include "util.h"
|
|
|
|
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
|
|
|
struct msg
|
|
{
|
|
uint16_t sender;
|
|
uint16_t receiver;
|
|
void *buf;
|
|
size_t buf_len;
|
|
};
|
|
|
|
struct testcase
|
|
{
|
|
uint16_t n;
|
|
uint16_t k;
|
|
uint16_t *bids;
|
|
uint16_t m;
|
|
uint16_t outcome_public;
|
|
uint16_t ret;
|
|
struct BRANDT_Auction **ad;
|
|
uint16_t *id;
|
|
uint16_t *result_called;
|
|
|
|
/* key material for signatures */
|
|
struct GNUNET_CRYPTO_EddsaPrivateKey *prv;
|
|
struct GNUNET_CRYPTO_EddsaPublicKey *pub;
|
|
|
|
struct msg **tr; /* transcript of the messages */
|
|
size_t tr_idx;
|
|
struct BRANDT_Auction *rad; /* auction for replay */
|
|
struct BRANDT_Result *res; /* result for transcript */
|
|
size_t res_len;
|
|
};
|
|
|
|
|
|
static struct testcase tcase;
|
|
static struct GNUNET_CRYPTO_EccDlogContext *edc;
|
|
|
|
static struct BRANDT_Result *
|
|
expected_outcome (uint16_t i, uint16_t *rlen)
|
|
{
|
|
struct BRANDT_Result *ret = NULL;
|
|
int32_t highest_bidder = -1;
|
|
int32_t highest_bid = -1;
|
|
int32_t mpf_highest_bidder;
|
|
int32_t mpf_highest_bid = -1;
|
|
int32_t prev_mpf_highest_bidder = -1;
|
|
uint16_t winners = MIN (tcase.m, tcase.n);
|
|
uint16_t cur_winner = 0;
|
|
|
|
*rlen = 0;
|
|
|
|
if (0 == tcase.n)
|
|
return NULL;
|
|
|
|
if (0 == tcase.m)
|
|
{
|
|
for (uint16_t h = 0; h < tcase.n; h++)
|
|
if (tcase.bids[h] > highest_bid)
|
|
highest_bid = tcase.bids[highest_bidder = h];
|
|
|
|
if (!tcase.outcome_public && !(i == highest_bidder || i == tcase.n))
|
|
return NULL;
|
|
|
|
ret = GNUNET_new (struct BRANDT_Result);
|
|
ret->bidder = highest_bidder;
|
|
ret->price = highest_bid;
|
|
ret->status = BRANDT_bidder_won;
|
|
*rlen = 1;
|
|
return ret;
|
|
}
|
|
|
|
/* fewer bidders than needed -> everyone wins with lowest price */
|
|
if (tcase.n <= tcase.m)
|
|
{
|
|
if (tcase.outcome_public || i == tcase.n)
|
|
{
|
|
ret = GNUNET_new_array ((*rlen = tcase.n), struct BRANDT_Result);
|
|
for (uint16_t h = 0; h < tcase.n; h++)
|
|
{
|
|
ret[h].bidder = h;
|
|
ret[h].price = 0;
|
|
ret[h].status = BRANDT_bidder_won;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = GNUNET_new (struct BRANDT_Result);
|
|
ret->bidder = i;
|
|
ret->price = 0;
|
|
ret->status = BRANDT_bidder_won;
|
|
*rlen = 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* find M+1st highest bidder to determine selling price */
|
|
for (uint16_t h = 0; h < tcase.n; h++)
|
|
if (tcase.bids[h] > mpf_highest_bid)
|
|
mpf_highest_bid = tcase.bids[prev_mpf_highest_bidder = h];
|
|
for (uint16_t m = 0; m < MIN (tcase.m, tcase.n - 1); m++)
|
|
{
|
|
mpf_highest_bidder = -1;
|
|
mpf_highest_bid = -1;
|
|
for (uint16_t h = 0; h < tcase.n; h++)
|
|
{
|
|
if (tcase.bids[h] > mpf_highest_bid &&
|
|
(tcase.bids[h] < tcase.bids[prev_mpf_highest_bidder] ||
|
|
(tcase.bids[h] == tcase.bids[prev_mpf_highest_bidder] &&
|
|
h > prev_mpf_highest_bidder)))
|
|
{
|
|
mpf_highest_bid = tcase.bids[mpf_highest_bidder = h];
|
|
}
|
|
}
|
|
prev_mpf_highest_bidder = mpf_highest_bidder;
|
|
}
|
|
|
|
/* for simplicity always locate the big block if we need to report at
|
|
* least one winner. with private outcome for losing bidders or winners
|
|
* only none or one element will be used respectively. */
|
|
if (tcase.outcome_public || i == tcase.n ||
|
|
tcase.bids[i] > mpf_highest_bid ||
|
|
(tcase.bids[i] == mpf_highest_bid && i < mpf_highest_bidder))
|
|
ret = GNUNET_new_array (winners, struct BRANDT_Result);
|
|
|
|
/* report winners */
|
|
for (uint16_t h = 0; h < tcase.n; h++)
|
|
{
|
|
if (((tcase.bids[h] == mpf_highest_bid && h < mpf_highest_bidder) ||
|
|
tcase.bids[h] > mpf_highest_bid) && /* h is a winner */
|
|
(tcase.outcome_public || i == h || i == tcase.n)) /* needs report */
|
|
{
|
|
if (cur_winner >= winners)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "got too many winners\n");
|
|
_exit (1);
|
|
}
|
|
ret[cur_winner].bidder = h;
|
|
ret[cur_winner].price = mpf_highest_bid;
|
|
ret[cur_winner].status = BRANDT_bidder_won;
|
|
cur_winner++;
|
|
}
|
|
}
|
|
*rlen = cur_winner;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void
|
|
bidder_start (void *arg)
|
|
{
|
|
uint16_t i = *(uint16_t *) arg;
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "starting bidder %d\n", i);
|
|
BRANDT_bidder_start (tcase.ad[i], i, tcase.n);
|
|
}
|
|
|
|
|
|
static void
|
|
transfer_message (void *arg)
|
|
{
|
|
struct msg *m = (struct msg *) arg;
|
|
struct msg_head *h = (struct msg_head *) m->buf;
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "xfer msg %d %p from %d to %d\n",
|
|
ntohl (h->msg_type), arg, m->sender, m->receiver);
|
|
|
|
/** keep a transcript as the seller **/
|
|
if (tcase.n == m->receiver)
|
|
{
|
|
struct msg *m2 = GNUNET_new (struct msg);
|
|
|
|
m2->sender = m->sender;
|
|
m2->buf_len = m->buf_len;
|
|
m2->buf = GNUNET_malloc (m->buf_len);
|
|
GNUNET_memcpy (m2->buf, m->buf, m->buf_len);
|
|
tcase.tr[tcase.tr_idx++] = m2;
|
|
}
|
|
|
|
BRANDT_got_message (tcase.ad[m->receiver], m->sender, m->buf, m->buf_len);
|
|
|
|
GNUNET_free (m->buf);
|
|
GNUNET_free (m);
|
|
}
|
|
|
|
|
|
static uint16_t
|
|
cb_start (void *auction_closure)
|
|
{
|
|
uint16_t *s = (uint16_t *) auction_closure;
|
|
|
|
if (tcase.n != *s)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
"start callback called from bidder\n");
|
|
_exit (1);
|
|
}
|
|
|
|
for (uint16_t i = 0; i < tcase.n; i++)
|
|
GNUNET_SCHEDULER_add_now (&bidder_start, &tcase.id[i]);
|
|
|
|
return tcase.n;
|
|
}
|
|
|
|
|
|
static int
|
|
cb_broadcast (void *auction_closure,
|
|
const void *msg,
|
|
size_t msg_len)
|
|
{
|
|
uint16_t *s = (uint16_t *) auction_closure;
|
|
struct msg *m;
|
|
|
|
for (uint16_t i = 0; i <= tcase.n; i++)
|
|
{
|
|
if (i == *s)
|
|
continue;
|
|
m = GNUNET_new (struct msg);
|
|
m->sender = *s;
|
|
m->receiver = i;
|
|
m->buf = GNUNET_new_array (msg_len, unsigned char);
|
|
memcpy (m->buf, msg, msg_len);
|
|
m->buf_len = msg_len;
|
|
GNUNET_SCHEDULER_add_now (&transfer_message, m);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
cb_unicast (void *auction_closure,
|
|
const void *msg,
|
|
size_t msg_len)
|
|
{
|
|
uint16_t *s = (uint16_t *) auction_closure;
|
|
struct msg *m;
|
|
|
|
m = GNUNET_new (struct msg);
|
|
m->sender = *s;
|
|
m->receiver = tcase.n; /* == seller */
|
|
m->buf = GNUNET_new_array (msg_len, unsigned char);
|
|
memcpy (m->buf, msg, msg_len);
|
|
m->buf_len = msg_len;
|
|
GNUNET_SCHEDULER_add_now (&transfer_message, m);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
cb_result (void *auction_closure,
|
|
struct BRANDT_Result results[],
|
|
uint16_t results_len)
|
|
{
|
|
uint16_t *s = (uint16_t *) auction_closure;
|
|
uint16_t mustlen = -1;
|
|
struct BRANDT_Result *must = expected_outcome (*s, &mustlen);
|
|
|
|
if (mustlen != results_len)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"expected result len is: %d\n",
|
|
mustlen);
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"computed result len is: %d (by agent %d)\n",
|
|
results_len,
|
|
*s);
|
|
tcase.ret = 1;
|
|
goto quit;
|
|
}
|
|
|
|
if (0 == results_len && NULL != must)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"expected result is: %p\n",
|
|
(void *) must);
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"computed result is: (nil) (by agent %d)\n",
|
|
*s);
|
|
|
|
tcase.ret = 1;
|
|
}
|
|
|
|
for (uint16_t i = 0; i < results_len; i++)
|
|
{
|
|
GNUNET_log (
|
|
GNUNET_ERROR_TYPE_INFO,
|
|
"[%s] expected result is: bidder %d got status %d with price %d\n",
|
|
tcase.n == *s ? "seller" : "bidder",
|
|
must[i].bidder,
|
|
must[i].status,
|
|
must[i].price);
|
|
GNUNET_log (
|
|
GNUNET_ERROR_TYPE_INFO,
|
|
"[%s] computed result is: bidder %d got status %d with price %d (by agent %d)\n",
|
|
tcase.n == *s ? "seller" : "bidder",
|
|
results[i].bidder,
|
|
results[i].status,
|
|
results[i].price,
|
|
*s);
|
|
|
|
if (NULL == must ||
|
|
must[i].bidder != results[i].bidder ||
|
|
must[i].status != results[i].status ||
|
|
must[i].price != results[i].price)
|
|
tcase.ret = 1;
|
|
}
|
|
|
|
if (*s == tcase.n)
|
|
{
|
|
/* save the results of the seller */
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
"Saving results, len %d\n",
|
|
results_len);
|
|
tcase.res = results;
|
|
tcase.res_len = results_len;
|
|
}
|
|
|
|
|
|
quit:
|
|
tcase.result_called[*s] = 1;
|
|
if (must)
|
|
GNUNET_free (must);
|
|
}
|
|
|
|
|
|
static void
|
|
run_auction (void *arg)
|
|
{
|
|
void *desc;
|
|
size_t desc_len;
|
|
|
|
tcase.ad[tcase.n] = BRANDT_new (&cb_result,
|
|
&cb_broadcast,
|
|
&cb_start,
|
|
&tcase.id[tcase.n],
|
|
&desc,
|
|
&desc_len,
|
|
GNUNET_TIME_absolute_get (),
|
|
GNUNET_TIME_UNIT_MINUTES,
|
|
tcase.k, /* number of prizes */
|
|
tcase.m, /* m */
|
|
tcase.outcome_public, /* outcome public */
|
|
tcase.outcome_public ? edc : NULL);
|
|
if (!tcase.ad[tcase.n])
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "BRANDT_new() failed.\n");
|
|
_exit (1);
|
|
}
|
|
|
|
for (uint16_t i = 0; i < tcase.n; i++)
|
|
{
|
|
tcase.ad[i] = BRANDT_join (&cb_result,
|
|
&cb_broadcast,
|
|
&cb_unicast,
|
|
&tcase.id[i],
|
|
desc,
|
|
desc_len,
|
|
tcase.bids[i], /* bid */
|
|
tcase.outcome_public ? edc : NULL);
|
|
if (!tcase.ad[i])
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "BRANDT_join() failed.\n");
|
|
tcase.ret = 1;
|
|
return;
|
|
}
|
|
|
|
if (tcase.ad[tcase.n]->k != tcase.ad[i]->k ||
|
|
tcase.ad[tcase.n]->m != tcase.ad[i]->m ||
|
|
tcase.ad[tcase.n]->outcome_public != tcase.ad[i]->outcome_public ||
|
|
tcase.ad[tcase.n]->time_start.abs_value_us
|
|
!= tcase.ad[i]->time_start.abs_value_us ||
|
|
tcase.ad[tcase.n]->time_round.rel_value_us
|
|
!= tcase.ad[i]->time_round.rel_value_us ||
|
|
!tcase.ad[tcase.n]->seller_mode || /* todo: split out */
|
|
tcase.ad[i]->seller_mode)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
"error/mismatch in basic auction data\n");
|
|
tcase.ret = 1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
tr_result (void *auction_closure,
|
|
struct BRANDT_Result results[],
|
|
uint16_t results_len)
|
|
{
|
|
uint16_t *s = (uint16_t *) auction_closure;
|
|
uint16_t mustlen = -1;
|
|
struct BRANDT_Result *must = expected_outcome (*s, &mustlen);
|
|
|
|
if (mustlen != results_len)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"expected result len is: %d\n",
|
|
mustlen);
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"computed result len is: %d (by seller)\n",
|
|
results_len);
|
|
tcase.ret = 1;
|
|
goto quit;
|
|
}
|
|
|
|
if (0 == results_len && NULL != must)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"expected result is: %p\n",
|
|
(void *) must);
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
"computed result is: (nil) (by seller)\n");
|
|
|
|
tcase.ret = 1;
|
|
}
|
|
|
|
for (uint16_t i = 0; i < results_len; i++)
|
|
{
|
|
GNUNET_log (
|
|
GNUNET_ERROR_TYPE_INFO,
|
|
"REPLAY [seller] expected result is: bidder %d got status %d with price %d\n",
|
|
must[i].bidder,
|
|
must[i].status,
|
|
must[i].price);
|
|
GNUNET_log (
|
|
GNUNET_ERROR_TYPE_INFO,
|
|
"REPLAY [seller] computed result is: bidder %d got status %d with price %d\n",
|
|
results[i].bidder,
|
|
results[i].status,
|
|
results[i].price);
|
|
|
|
if (NULL == must ||
|
|
must[i].bidder != results[i].bidder ||
|
|
must[i].status != results[i].status ||
|
|
must[i].price != results[i].price)
|
|
tcase.ret = 1;
|
|
}
|
|
|
|
quit:
|
|
tcase.result_called[*s] = 1;
|
|
if (must)
|
|
GNUNET_free (must);
|
|
}
|
|
|
|
|
|
static uint16_t
|
|
tr_start (void *auction_closure)
|
|
{
|
|
void
|
|
resend (void *x)
|
|
{
|
|
size_t i = (size_t) x;
|
|
struct msg *m = tcase.tr[i];
|
|
if (NULL == m)
|
|
{
|
|
dprintf (2, "REPLAY skipping empty msg no. %ld\n", i);
|
|
return;
|
|
}
|
|
dprintf (2, "REPLAY sent msg no. %ld\n", i);
|
|
BRANDT_got_message (tcase.rad, m->sender, m->buf, m->buf_len);
|
|
}
|
|
|
|
|
|
dprintf (2, "REPLAY start replay auction\n");
|
|
for (size_t i = 0; i < 4 * tcase.n; i++)
|
|
GNUNET_SCHEDULER_add_now (&resend, (void *) i);
|
|
|
|
return tcase.n;
|
|
}
|
|
|
|
|
|
struct some_sig
|
|
{
|
|
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
|
struct GNUNET_HashCode hc GNUNET_PACKED;
|
|
};
|
|
|
|
static void
|
|
print_transcript (uint32_t highestprice)
|
|
{
|
|
struct BRANDT_Auction *ad = tcase.ad[tcase.n];
|
|
json_t *root;
|
|
json_t *auction;
|
|
json_t *prices;
|
|
json_t *bidders;
|
|
json_t *sigs;
|
|
json_t *transcript;
|
|
json_t *winners;
|
|
struct GNUNET_HashCode hc;
|
|
struct some_sig p = { .purpose.size = htonl (sizeof(struct some_sig)) };
|
|
char price[256];
|
|
|
|
prices = json_array ();
|
|
GNUNET_assert (prices);
|
|
|
|
for (size_t p = 0; p < tcase.k; p++)
|
|
{
|
|
sprintf (price, "EUR:%d", highestprice--);
|
|
GNUNET_assert (
|
|
-1 != json_array_append_new (
|
|
prices,
|
|
json_string (price)));
|
|
}
|
|
|
|
auction = json_pack ("{s:{s:o}, s:{s:o}, s:i, s:b, s:o, s:s, s:s}",
|
|
"time_start", "t_s", json_integer (
|
|
ad->time_start.abs_value_us / 1000LL),
|
|
"time_round", "d_us", json_integer (
|
|
ad->time_round.rel_value_us),
|
|
"type", ad->m,
|
|
"is_public", ad->outcome_public == 0 ? json_false () : json_true (),
|
|
"prices", prices,
|
|
"payto_uri", "payto://some/iban",
|
|
"pubkey", GNUNET_CRYPTO_eddsa_public_key_to_string (
|
|
&tcase.pub[tcase.n]));
|
|
GNUNET_assert (auction);
|
|
|
|
bidders = json_array ();
|
|
GNUNET_assert (bidders);
|
|
|
|
for (size_t b = 0; b < tcase.n; b++)
|
|
{
|
|
char *ps = GNUNET_CRYPTO_eddsa_public_key_to_string (&tcase.pub[b]);
|
|
GNUNET_assert (-1 !=
|
|
json_array_append_new (bidders,
|
|
json_string (ps)));
|
|
}
|
|
|
|
// Add signatures form each bidder for the auction.
|
|
sigs = json_array ();
|
|
GNUNET_assert (sigs);
|
|
{
|
|
char *auc_js = json_dumps (auction, JSON_COMPACT);
|
|
GNUNET_CRYPTO_hash (auc_js,
|
|
strlen (auc_js),
|
|
&hc);
|
|
|
|
p.purpose.purpose = htonl (23);
|
|
p.hc = hc;
|
|
|
|
for (size_t b = 0; b < tcase.n; b++)
|
|
{
|
|
struct GNUNET_CRYPTO_EddsaSignature sig;
|
|
GNUNET_CRYPTO_eddsa_sign (&tcase.prv[b],
|
|
&p,
|
|
&sig);
|
|
GNUNET_assert (-1 !=
|
|
json_array_append_new (
|
|
sigs,
|
|
GNUNET_JSON_from_data_auto (&sig)));
|
|
}
|
|
}
|
|
|
|
transcript = json_array ();
|
|
GNUNET_assert (transcript);
|
|
|
|
for (size_t i = 0; i < 4 * tcase.n; i++)
|
|
{
|
|
json_t *entry;
|
|
struct msg *msg = tcase.tr[i];
|
|
struct GNUNET_CRYPTO_EddsaSignature sig;
|
|
|
|
if (NULL == msg)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
"skipping NULL msg[%ld]\n", i);
|
|
continue;
|
|
}
|
|
|
|
GNUNET_assert (msg);
|
|
|
|
GNUNET_CRYPTO_hash (msg->buf, msg->buf_len, &hc);
|
|
|
|
p.purpose.purpose = htonl (42);
|
|
p.hc = hc;
|
|
|
|
GNUNET_CRYPTO_eddsa_sign (
|
|
&tcase.prv[msg->sender],
|
|
&p,
|
|
&sig);
|
|
|
|
|
|
entry = json_pack ("{s:i, s:o, s:o}",
|
|
"bidder", msg->sender,
|
|
"msg", GNUNET_JSON_from_data (msg->buf, msg->buf_len),
|
|
"sig", GNUNET_JSON_from_data_auto (&sig));
|
|
|
|
GNUNET_assert (entry);
|
|
GNUNET_assert (-1 !=
|
|
json_array_append_new (transcript,
|
|
entry));
|
|
|
|
}
|
|
|
|
winners = json_array ();
|
|
GNUNET_assert (winners);
|
|
|
|
// add the winner(s)
|
|
{
|
|
for (uint16_t i = 0; i < tcase.res_len; i++)
|
|
{
|
|
json_t *res = json_pack ("{s:i, s:i, s:o*}",
|
|
"bidder",
|
|
tcase.res[i].bidder,
|
|
"price_idx",
|
|
tcase.res[i].price,
|
|
"price",
|
|
json_array_get (prices, tcase.res[i].price));
|
|
GNUNET_assert (res);
|
|
GNUNET_assert (-1 !=
|
|
json_array_append_new (winners, res));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
root = json_pack ("{s:o, s:o, s:o, s:o, s:o}",
|
|
"auction", auction,
|
|
"bidders", bidders,
|
|
"signatures", sigs,
|
|
"transcript", transcript,
|
|
"winners", winners);
|
|
|
|
GNUNET_assert (root);
|
|
|
|
// Add signature of seller to H(auction, bidders, signatures, transcript, result)
|
|
{
|
|
struct GNUNET_CRYPTO_EddsaSignature sig;
|
|
char *root_js = json_dumps (root, JSON_COMPACT | JSON_SORT_KEYS);
|
|
|
|
GNUNET_CRYPTO_hash (root_js,
|
|
strlen (root_js),
|
|
&hc);
|
|
|
|
p.purpose.purpose = htonl (815);
|
|
p.hc = hc;
|
|
|
|
GNUNET_CRYPTO_eddsa_sign (&tcase.prv[tcase.n],
|
|
&p,
|
|
&sig);
|
|
GNUNET_assert (-1 !=
|
|
json_object_set_new (
|
|
root,
|
|
"sig",
|
|
GNUNET_JSON_from_data_auto (&sig)));
|
|
|
|
free (root_js);
|
|
}
|
|
|
|
// After signing the transcript, add private key material, too, so it
|
|
// can be used in integration tests.
|
|
{
|
|
json_t *keys = json_array ();
|
|
GNUNET_assert (keys);
|
|
|
|
for (size_t b = 0; b <= /* = is important */ tcase.n; b++)
|
|
{
|
|
char *ps = GNUNET_CRYPTO_eddsa_private_key_to_string (&tcase.prv[b]);
|
|
GNUNET_assert (-1 !=
|
|
json_array_append_new (keys,
|
|
json_string (ps)));
|
|
}
|
|
|
|
json_object_set_new (
|
|
root,
|
|
"NOTSIGNED_keys",
|
|
keys);
|
|
}
|
|
|
|
printf ("\n%s\n", json_dumps (root, JSON_INDENT (2)));
|
|
json_decref (root);
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
replay_transcript (void *arg)
|
|
{
|
|
void *desc;
|
|
size_t desc_len;
|
|
static struct GNUNET_CRYPTO_EccDlogContext *redc;
|
|
|
|
print_transcript (96);
|
|
redc = GNUNET_CRYPTO_ecc_dlog_prepare (1024, 16);
|
|
|
|
dprintf (2,"REPLAY, calling BRANDT_new...\n");
|
|
tcase.rad = BRANDT_new (&tr_result,
|
|
NULL,
|
|
&tr_start,
|
|
&tcase.id[tcase.n],
|
|
&desc,
|
|
&desc_len,
|
|
tcase.ad[tcase.n]->time_start,
|
|
tcase.ad[tcase.n]->time_round,
|
|
tcase.k, /* number of prizes */
|
|
tcase.m, /* m */
|
|
tcase.outcome_public, /* outcome public */
|
|
tcase.outcome_public ? redc : NULL);
|
|
if (!tcase.rad)
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "REPLAY BRANDT_new() failed.\n");
|
|
_exit (1);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Test a specific auction setup.
|
|
*
|
|
* @param[in] n number of bidders.
|
|
* @param[in] k number of different prices.
|
|
* @param[in] bids The bid array. Must contain exactly @a n elements each less
|
|
* than @a k.
|
|
* @param[in] m If 0 it's a first price auction, else an M+1st price auction
|
|
* specifying the M.
|
|
* @param[in] outcome_public 1 means public outcome, 0 means private outcome.
|
|
* @return 0 on success, 1 on failure
|
|
*/
|
|
static int
|
|
test_auction (uint16_t n,
|
|
uint16_t k,
|
|
uint16_t *bids,
|
|
uint16_t m,
|
|
uint16_t outcome_public)
|
|
{
|
|
tcase.n = n;
|
|
tcase.k = k;
|
|
tcase.bids = bids;
|
|
tcase.m = m;
|
|
tcase.outcome_public = outcome_public;
|
|
tcase.ret = 0;
|
|
tcase.res = NULL;
|
|
tcase.res_len = 0;
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
"######################################\n");
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
"testing %s auction with m = %d and %s outcome\n",
|
|
tcase.m > 0 ? "M+1ST PRICE" : "FIRST PRICE",
|
|
tcase.m,
|
|
tcase.outcome_public ? "PUBLIC" : "PRIVATE");
|
|
/** \todo: output bids */
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
"######################################\n");
|
|
tcase.ad = GNUNET_new_array (tcase.n + 1, struct BRANDT_Auction *);
|
|
tcase.id = GNUNET_new_array (tcase.n + 1, uint16_t);
|
|
tcase.prv = GNUNET_new_array (tcase.n + 1, struct
|
|
GNUNET_CRYPTO_EddsaPrivateKey);
|
|
tcase.pub = GNUNET_new_array (tcase.n + 1, struct
|
|
GNUNET_CRYPTO_EddsaPublicKey);
|
|
for (uint16_t i = 0; i <= tcase.n; i++)
|
|
{
|
|
tcase.id[i] = i;
|
|
GNUNET_CRYPTO_eddsa_key_create (&tcase.prv[i]);
|
|
GNUNET_CRYPTO_eddsa_key_get_public (&tcase.prv[i], &tcase.pub[i]);
|
|
}
|
|
tcase.result_called = GNUNET_new_array (tcase.n + 1, uint16_t);
|
|
tcase.tr = GNUNET_new_array (4 * tcase.n, struct msg *); /* transcript, one message per bidder per round */
|
|
|
|
|
|
GNUNET_SCHEDULER_run (&run_auction, NULL);
|
|
|
|
for (uint16_t i = 0; i <= tcase.n; i++)
|
|
{
|
|
BRANDT_destroy (tcase.ad[i]);
|
|
if (!tcase.result_called[i])
|
|
{
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
"result callback not called for bidder %d\n",
|
|
i);
|
|
tcase.ret = 1;
|
|
}
|
|
}
|
|
|
|
GNUNET_SCHEDULER_run (&replay_transcript, NULL);
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
"DONE testing auction\n");
|
|
|
|
|
|
tcase.tr_idx = 0;
|
|
GNUNET_free (tcase.tr);
|
|
GNUNET_free (tcase.ad);
|
|
GNUNET_free (tcase.id);
|
|
GNUNET_free (tcase.result_called);
|
|
GNUNET_free (tcase.prv);
|
|
GNUNET_free (tcase.pub);
|
|
|
|
return tcase.ret;
|
|
}
|
|
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
if (GNUNET_OK != GNUNET_log_setup ("test_brandt", "INFO", NULL))
|
|
return 1;
|
|
|
|
edc = GNUNET_CRYPTO_ecc_dlog_prepare (1024, 16);
|
|
BRANDT_init ();
|
|
|
|
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, 5, (uint16_t[]) { 4, 3, 1 }, 0, 1) ||
|
|
// test_auction (3, 5, (uint16_t[]) { 1, 2, 3 }, 0, 1) ||
|
|
test_auction (3, 5, (uint16_t[]) { 1, 2, 3 }, 0, 1) ||
|
|
test_auction (5, 6, (uint16_t[]) {5,4,2,1,0,3}, 1, 1) ||
|
|
// test_auction (5, 6, (uint16_t[]) {5,4,2,1,0,3}, 1, 0) ||
|
|
test_auction (10, 3, (uint16_t[]) {1,2,0,1,1,0,1,0,1,0}, 0, 1) ||
|
|
test_auction (10, 6, (uint16_t[]) {3,4,5,2,1,0,1,2,3,4}, 2, 1) ||
|
|
// test_auction (10, 3, (uint16_t[]) {1,2,0,1,1,0,1,0,1,0}, 1, 0) ||
|
|
0;
|
|
|
|
GNUNET_CRYPTO_ecc_dlog_release (edc);
|
|
return ret;
|
|
}
|