/ src / tests / tp-dkg.c
tp-dkg.c
  1  #include <stdio.h>
  2  #include <string.h>
  3  #include <stdlib.h>
  4  #include "utils.h"
  5  #include "toprf.h"
  6  #include "tp-dkg.h"
  7  #include "dkg.h"
  8  #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  9  #include <unistd.h>
 10  #endif
 11  
 12  #ifdef __AFL_FUZZ_INIT
 13  __AFL_FUZZ_INIT();
 14  #endif
 15  
 16  typedef struct {
 17    uint8_t index;
 18    uint8_t value[crypto_core_ristretto255_BYTES];
 19  } __attribute((packed)) TOPRF_Part;
 20  
 21  static void topart(TOPRF_Part *r, const TOPRF_Share *s) {
 22    r->index=s->index;
 23    crypto_scalarmult_ristretto255_base(r->value, s->value);
 24  }
 25  
 26  static void shuffle(uint8_t *array, const size_t n) {
 27    if (n < 2) return;
 28    srand((unsigned) time(NULL));
 29    for(unsigned i=0; i<n-1; i++) {
 30      size_t j = i + (unsigned)rand() / ((unsigned)RAND_MAX / (n - i) + 1U);
 31      uint8_t t = array[j];
 32      array[j] = array[i];
 33      array[i] = t;
 34    }
 35  }
 36  
 37  static int verify_shares(const uint8_t n, const TOPRF_Share shares[n], const uint8_t t) {
 38    uint8_t responses[t][sizeof(TOPRF_Part)];
 39    uint8_t v0[crypto_scalarmult_ristretto255_BYTES]={0};
 40  
 41    uint8_t indexes[n];
 42    for(uint8_t i=0;i<n;i++) indexes[i]=i;
 43    if(liboprf_log_file!=NULL) {
 44      fprintf(stderr, "order: ");
 45      for(int i=0;i<t;i++) fprintf(stderr, "%2d, ",indexes[i]);
 46    }
 47  
 48    for(int i=0;i<t;i++) {
 49      topart((TOPRF_Part *) responses[i], &shares[indexes[i]]);
 50    }
 51    if(toprf_thresholdmult(t, responses, v0)) return 1;
 52    dump(v0,sizeof v0, "v0\t");
 53  
 54    for(int k=0;k<t-1;k++) {
 55      uint8_t v1[crypto_scalarmult_ristretto255_BYTES]={0};
 56      shuffle(indexes,n);
 57      if(liboprf_log_file!=NULL) {
 58        fprintf(stderr, "order: ");
 59        for(int i=0;i<t;i++) fprintf(stderr, "%2d, ",indexes[i]);
 60      }
 61  
 62      for(int i=0;i<t;i++) {
 63          topart((TOPRF_Part *) responses[i], &shares[indexes[i]]);
 64      }
 65  
 66      if(toprf_thresholdmult(t, responses, v1)) return 1;
 67      dump(v1,sizeof v1, "v%d\t", k+1);
 68  
 69      if(memcmp(v0,v1,sizeof v1)!=0) {
 70          fprintf(stderr,"\e[0;31mfailed to verify shares from dkg_finish!\e[0m\n");
 71          return 1;
 72      }
 73    }
 74    return 0;
 75  }
 76  
 77  // simulate network
 78  #define NETWORK_BUF_SIZE (1024*1024*16)
 79  //static size_t _send(uint8_t *net, size_t *pkt_len, const uint8_t *msg, const size_t msg_len) {
 80  static void _send(uint8_t *net, size_t *pkt_len, const uint8_t *msg, const size_t msg_len) {
 81    if(*pkt_len+msg_len >= NETWORK_BUF_SIZE || msg_len==0 || msg == NULL) {
 82      return;// 0;
 83    }
 84    memcpy(net+*pkt_len, msg, msg_len);
 85    *pkt_len+=msg_len;
 86    //return msg_len;
 87  }
 88  //static size_t _recv(const uint8_t *net, size_t *pkt_len, uint8_t *buf, const size_t msg_len) {
 89  static void _recv(const uint8_t *net, size_t *pkt_len, uint8_t *buf, const size_t msg_len) {
 90    if(*pkt_len < msg_len || msg_len == 0) {
 91      return; // 0;
 92    }
 93    memcpy(buf, net, msg_len);
 94    *pkt_len-=msg_len;
 95    //return msg_len;
 96  }
 97  
 98  #ifdef FUZZ_DUMP
 99  #if !defined(FUZZ_PEER)
100  static void fuzz_dump(const uint8_t step, TP_DKG_TPState *ctx, const uint8_t *buf_in, const size_t buf_in_size, const char **argv, const int argc) {
101  #else
102  static void fuzz_dump(const uint8_t step, TP_DKG_PeerState *ctx, const uint8_t *buf_in, const size_t buf_in_size, const char **argv, const int argc) {
103  #endif //!defined(FUZZ_PEER)
104    if(argc<5) {
105      fprintf(stderr, "error incorrect number of params, run as: %% %s <n> <t> <step> <output-file>\n", argv[0]);
106      exit(1);
107    }
108    if(ctx->step==step) {
109      FILE *tc = fopen(argv[4], "wb");
110      fwrite(buf_in, 1, buf_in_size, tc);
111      fclose(tc);
112      exit(0);
113    }
114  }
115  #endif
116  
117  #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
118  #if !defined(FUZZ_PEER)
119  static int fuzz_loop(const uint8_t step, TP_DKG_TPState *tp, TP_DKG_PeerState *peers, uint8_t network_buf[][NETWORK_BUF_SIZE],size_t pkt_len[]) {
120    if(tp->step!=step) return 0;
121  
122    TP_DKG_TPState checkpoint;
123    memcpy(&checkpoint, tp, sizeof(checkpoint));
124    TP_DKG_PeerState pcheckpoints[tp->n];
125    memcpy(&pcheckpoints, peers, sizeof(pcheckpoints));
126  
127  #ifdef __AFL_HAVE_MANUAL_CONTROL
128    __AFL_INIT();
129  #endif
130    unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;  // must be after __AFL_INIT
131                                               // and before __AFL_LOOP!
132  
133    while (__AFL_LOOP(10000)) {
134  
135      int len = __AFL_FUZZ_TESTCASE_LEN;  // don't use the macro directly in a call!
136      if (len < sizeof(DKG_Message)) continue;  // check for a required/useful minimum input length
137  
138      // doing vla - but avoiding 0 sized ones is ugly
139      const size_t tp_out_size = tpdkg_tp_output_size(tp);
140      uint8_t tp_out_buf[tp_out_size==0?1:tp_out_size], *tp_out;
141      if(tp_out_size==0) tp_out = NULL;
142      else tp_out = tp_out_buf;
143  
144      /* Setup function call, e.g. struct target *tmp = libtarget_init() */
145      /* Call function to be fuzzed, e.g.: */
146      int ret = tpdkg_tp_next(tp, buf, len, tp_out, tp_out_size);
147      if(0!=ret) {
148        // clean up peers
149        for(uint8_t i=0;i<tp->n;i++) tpdkg_peer_free(&peers[i]);
150        if(tp->cheater_len > 0) return 125;
151        return ret;
152      }
153  
154      while(tpdkg_tp_not_done(tp)) {
155        for(uint8_t i=0;i<tp->n;i++) {
156          const uint8_t *msg;
157          size_t len;
158          if(0!=tpdkg_tp_peer_msg(tp, tp_out, tp_out_size, i, &msg, &len)) {
159            return 1;
160          }
161          _send(network_buf[i+1], &pkt_len[i+1], msg, len);
162        }
163  
164        while(pkt_len[0]==0 && tpdkg_peer_not_done(&peers[1])) {
165          for(uint8_t i=0;i<tp->n;i++) {
166            // 0sized vla meh
167            const size_t peer_out_size = tpdkg_peer_output_size(&peers[i]);
168            uint8_t peers_out_buf[peer_out_size==0?1:peer_out_size], *peers_out;
169            if(peer_out_size==0) peers_out = NULL;
170            else peers_out = peers_out_buf;
171  
172            // 0sized vla meh for the last time..
173            const size_t peer_in_size = tpdkg_peer_input_size(&peers[i]);
174            uint8_t peer_in_buf[peer_in_size==0?1:peer_in_size], *peer_in;
175            if(peer_in_size==0) peer_in = NULL;
176            else peer_in = peer_in_buf;
177  
178            _recv(network_buf[i+1], &pkt_len[i+1], peer_in, peer_in_size);
179            ret = tpdkg_peer_next(&peers[i],
180                                  peer_in, peer_in_size,
181                                  peers_out, peer_out_size);
182  
183            if(0!=ret) {
184              // clean up peers
185              for(uint8_t i=0;i<tp->n;i++) tpdkg_peer_free(&peers[i]);
186              return ret;
187            }
188  
189            _send(network_buf[0], &pkt_len[0], peers_out, peer_out_size);
190          }
191        }
192  
193        // doing vla - but avoiding 0 sized ones is ugly
194        const size_t tp_out_size = tpdkg_tp_output_size(tp);
195        uint8_t tp_out_buf[tp_out_size==0?1:tp_out_size], *tp_out;
196        if(tp_out_size==0) tp_out = NULL;
197        else tp_out = tp_out_buf;
198  
199        // avoiding zero-sized vla is still ugly
200        const size_t tp_in_size = tpdkg_tp_input_size(tp);
201        uint8_t tp_in_buf[tp_in_size==0?1:tp_in_size], *tp_in;
202        if(tp_in_size==0) tp_in = NULL;
203        else tp_in = tp_in_buf;
204  
205        _recv(network_buf[0], &pkt_len[0], tp_in, tp_in_size);
206  
207        ret = tpdkg_tp_next(tp, tp_in, tp_in_size, tp_out, tp_out_size);
208        if(0!=ret) {
209          // clean up peers
210          for(uint8_t i=0;i<tp->n;i++) tpdkg_peer_free(&peers[i]);
211          if(tp->cheater_len > 0) return 55;
212          return ret;
213        }
214      }
215  
216      /* Reset state. e.g. libtarget_free(tmp) */
217      memcpy(tp, &checkpoint, sizeof(TP_DKG_TPState));
218      memcpy(peers, &pcheckpoints, sizeof(pcheckpoints));
219    }
220    return 0;
221  }
222  #else // !defined(FUZZ_PEER)
223  static int fuzz_loop(const uint8_t step, TP_DKG_TPState *tp, TP_DKG_PeerState *peers, uint8_t network_buf[][NETWORK_BUF_SIZE],size_t pkt_len[]) {
224    if(peers[0].step!=step) return 0;
225  
226    TP_DKG_TPState checkpoint;
227    memcpy(&checkpoint, tp, sizeof(checkpoint));
228    TP_DKG_PeerState pcheckpoints[tp->n];
229    memcpy(&pcheckpoints, peers, sizeof(pcheckpoints));
230  
231  #ifdef __AFL_HAVE_MANUAL_CONTROL
232    __AFL_INIT();
233  #endif
234    unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;  // must be after __AFL_INIT
235                                               // and before __AFL_LOOP!
236  
237    int ret;
238    while (__AFL_LOOP(10000)) {
239  
240      int len = __AFL_FUZZ_TESTCASE_LEN;  // don't use the macro directly in a call!
241      if (len < sizeof(DKG_Message)) continue;  // check for a required/useful minimum input length
242  
243      // doing vla - but avoiding 0 sized ones is ugly
244      const size_t peer_out_size = tpdkg_peer_output_size(&peers[0]);
245      uint8_t peer_out_buf[peer_out_size==0?1:peer_out_size], *peer_out;
246      if(peer_out_size==0) peer_out = NULL;
247      else peer_out = peer_out_buf;
248  
249      ret = tpdkg_peer_next(&peers[0], buf, len, peer_out, peer_out_size);
250      if(ret!=0) {
251        //for(uint8_t i=0;i<tp->n;i++) tpdkg_peer_free(&peers[i]);
252        return ret;
253      }
254      _send(network_buf[0], &pkt_len[0], peer_out, peer_out_size);
255  
256      for(uint8_t i=1;i<tp->n;i++) {
257        // 0sized vla meh
258        const size_t peer_out_size = tpdkg_peer_output_size(&peers[i]);
259        uint8_t peers_out_buf[peer_out_size==0?1:peer_out_size], *peers_out;
260        if(peer_out_size==0) peers_out = NULL;
261        else peers_out = peers_out_buf;
262  
263        // 0sized vla meh for the last time..
264        const size_t peer_in_size = tpdkg_peer_input_size(&peers[i]);
265        uint8_t peer_in_buf[peer_in_size==0?1:peer_in_size], *peer_in;
266        if(peer_in_size==0) peer_in = NULL;
267        else peer_in = peer_in_buf;
268  
269        _recv(network_buf[i+1], &pkt_len[i+1], peer_in, peer_in_size);
270        ret = tpdkg_peer_next(&peers[i],
271                              peer_in, peer_in_size,
272                              peers_out, peer_out_size);
273  
274        if(0!=ret) {
275          // clean up peers
276          //for(uint8_t i=0;i<tp->n;i++) tpdkg_peer_free(&peers[i]);
277          return ret;
278        }
279        _send(network_buf[0], &pkt_len[0], peers_out, peer_out_size);
280      }
281  
282      while(tpdkg_tp_not_done(tp)) {
283        while(pkt_len[0]==0 && tpdkg_peer_not_done(&peers[1])) {
284          for(uint8_t i=0;i<tp->n;i++) {
285            // 0sized vla meh
286            const size_t peer_out_size = tpdkg_peer_output_size(&peers[i]);
287            uint8_t peers_out_buf[peer_out_size==0?1:peer_out_size], *peers_out;
288            if(peer_out_size==0) peers_out = NULL;
289            else peers_out = peers_out_buf;
290  
291            // 0sized vla meh for the last time..
292            const size_t peer_in_size = tpdkg_peer_input_size(&peers[i]);
293            uint8_t peer_in_buf[peer_in_size==0?1:peer_in_size], *peer_in;
294            if(peer_in_size==0) peer_in = NULL;
295            else peer_in = peer_in_buf;
296  
297            _recv(network_buf[i+1], &pkt_len[i+1], peer_in, peer_in_size);
298            ret = tpdkg_peer_next(&peers[i],
299                                  peer_in, peer_in_size,
300                                  peers_out, peer_out_size);
301  
302            if(0!=ret) {
303              // clean up peers
304              //for(uint8_t i=0;i<tp->n;i++) tpdkg_peer_free(&peers[i]);
305              return ret;
306            }
307  
308            _send(network_buf[0], &pkt_len[0], peers_out, peer_out_size);
309          }
310        }
311  
312        // doing vla - but avoiding 0 sized ones is ugly
313        const size_t tp_out_size = tpdkg_tp_output_size(tp);
314        uint8_t tp_out_buf[tp_out_size==0?1:tp_out_size], *tp_out;
315        if(tp_out_size==0) tp_out = NULL;
316        else tp_out = tp_out_buf;
317  
318        // avoiding zero-sized vla is still ugly
319        const size_t tp_in_size = tpdkg_tp_input_size(tp);
320        uint8_t tp_in_buf[tp_in_size==0?1:tp_in_size], *tp_in;
321        if(tp_in_size==0) tp_in = NULL;
322        else tp_in = tp_in_buf;
323  
324        _recv(network_buf[0], &pkt_len[0], tp_in, tp_in_size);
325  
326        ret = tpdkg_tp_next(tp, tp_in, tp_in_size, tp_out, tp_out_size);
327        if(0!=ret) {
328          // clean up peers
329          for(uint8_t i=0;i<tp->n;i++) tpdkg_peer_free(&peers[i]);
330          if(tp->cheater_len > 0) return 55;
331          return ret;
332        }
333  
334        for(uint8_t i=0;i<tp->n;i++) {
335          const uint8_t *msg;
336          size_t len;
337          if(0!=tpdkg_tp_peer_msg(tp, tp_out, tp_out_size, i, &msg, &len)) {
338            return 1;
339          }
340          _send(network_buf[i+1], &pkt_len[i+1], msg, len);
341        }
342      }
343  
344      /* Reset state. e.g. libtarget_free(tmp) */
345      memcpy(tp, &checkpoint, sizeof(TP_DKG_TPState));
346      memcpy(peers, &pcheckpoints, sizeof(pcheckpoints));
347    }
348    return 0;
349  }
350  #endif
351  #endif
352  
353  int main(const int argc, const char **argv) {
354    int ret;
355    // enable logging
356    liboprf_log_file = stderr;
357    liboprf_debug = 1;
358  
359    if(argc<3) {
360  #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(FUZZ_DUMP)
361      fprintf(stderr, "error incorrect numbers of parameters, run as: %% %s <n> <t> [<step> [<path>]]\n", argv[0]);
362  #else
363      fprintf(stderr, "error incorrect numbers of parameters, run as: %% %s <n> <t>\n", argv[0]);
364  #endif // defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(FUZZ_DUMP)
365      exit(1);
366    }
367    uint8_t n=(uint8_t)atoi(argv[1]),t=(uint8_t)atoi(argv[2]);
368  #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(FUZZ_DUMP)
369    uint8_t step=atoi(argv[3]);
370  #ifdef FUZZ_PEER
371    if(step<1 || step > 9 || step==7 || step==8) {
372  #else
373    if(step<1 || step > 9) {
374  #endif
375      fprintf(stderr, "error incorrect value for step must be 1-9 (but not 7 or 8), run as: %% %s <1-7> <output-file>\n", argv[0]);
376      exit(1);
377    }
378  #endif
379  
380    // mock long-term peer keys
381    // all known by TP
382    uint8_t peer_lt_pks[n][crypto_sign_PUBLICKEYBYTES];
383    // only known by corresponding peer
384    uint8_t peer_lt_sks[n][crypto_sign_SECRETKEYBYTES];
385    for(uint8_t i=0;i<n;i++) {
386        crypto_sign_keypair(peer_lt_pks[i], peer_lt_sks[i]);
387    }
388  
389    TP_DKG_TPState tp;
390    uint8_t msg0[tpdkg_msg0_SIZE];
391    ret = tpdkg_start_tp(&tp, dkg_freshness_TIMEOUT, n, t, "proto test", 10, sizeof msg0, (DKG_Message*) msg0);
392    if(0!=ret) return ret;
393  
394    fprintf(stderr, "allocating memory for TP\n");
395    // set bufs
396    // we need to store these outside of the ctx, since they are
397    // variable size, and the struct can only handle one variable size
398    // entry...
399    uint8_t tp_peers_sig_pks[n][crypto_sign_PUBLICKEYBYTES];
400    memset(tp_peers_sig_pks,0,sizeof(tp_peers_sig_pks));
401    // tp needs to store the commitments
402    uint8_t tp_commitments[n*t][crypto_core_ristretto255_BYTES];
403    memset(tp_commitments,0,sizeof(tp_commitments));
404    // tp needs to store the complaints, with max n==128 this takes max 16KB of ram.
405    uint16_t tp_complaints[n*n];
406    memset(tp_complaints,0,sizeof(tp_complaints));
407    uint8_t noisy_shares[n*n][tpdkg_msg8_SIZE];
408    memset(noisy_shares,0,sizeof(noisy_shares));
409    TP_DKG_Cheater cheaters[t*t - 1];
410    memset(cheaters,0,sizeof(cheaters));
411    uint64_t last_ts[n];
412    tpdkg_tp_set_bufs(&tp, &tp_commitments, &tp_complaints, &noisy_shares, &cheaters, sizeof(cheaters) / sizeof(TP_DKG_Cheater), &tp_peers_sig_pks, &peer_lt_pks, last_ts);
413  
414    // only tp_out can survive for the peers in local scope of the "main protocol loop"
415    // and thus we simulate a network with this buffer
416  
417    TP_DKG_PeerState peers[n];
418    for(uint8_t i=0;i<n;i++) {
419      ret = tpdkg_start_peer(&peers[i], dkg_freshness_TIMEOUT, peer_lt_sks[i], (DKG_Message*) msg0);
420      if(0!=ret) return ret;
421    }
422  
423    fprintf(stderr, "allocating memory for peers ..");
424    // now that the peer(s) know the value of N, we can allocate buffers
425    // to hold all the sig&noise keys, noise sessions, temp shares, commitments
426    uint8_t peers_sig_pks[peers[1].n][crypto_sign_PUBLICKEYBYTES];
427    memset(peers_sig_pks, 0, sizeof(peers_sig_pks));
428    uint8_t peers_noise_pks[peers[1].n][crypto_scalarmult_BYTES];
429    Noise_XK_session_t *noise_outs[n][n];
430    memset(noise_outs, 0, sizeof noise_outs);
431    Noise_XK_session_t *noise_ins[n][n];
432    memset(noise_ins, 0, sizeof noise_ins);
433    TOPRF_Share ishares[peers[1].n][peers[1].n];
434    memset(ishares, 0, sizeof ishares);
435    TOPRF_Share xshares[peers[1].n][peers[1].n];
436    memset(xshares, 0, sizeof xshares);
437    uint8_t commitments[peers[1].n][peers[1].n *peers[1].t][crypto_core_ristretto255_BYTES];
438    memset(commitments, 0, sizeof commitments);
439    uint16_t peer_complaints[peers[1].n][peers[1].n*peers[1].n];
440    memset(peer_complaints, 0, sizeof peer_complaints);
441    uint8_t peer_my_complaints[peers[1].n][peers[1].n];
442    memset(peer_my_complaints, 0, sizeof peer_my_complaints);
443    uint64_t peer_last_ts[n][n];
444    memset(peer_last_ts, 0, sizeof peer_last_ts);
445    fprintf(stderr, "done\n");
446  
447    for(uint8_t i=0;i<n;i++) {
448      // in a real deployment peers do not share the same pks buffers
449      tpdkg_peer_set_bufs(&peers[i], &peers_sig_pks, &peers_noise_pks,
450                          &noise_outs[i], &noise_ins[i],
451                          &ishares[i], &xshares[i],
452                          &commitments[i],
453                          peer_complaints[i], peer_my_complaints[i],
454                          peer_last_ts[i]);
455    }
456  
457  
458    // simulate network.
459    uint8_t network_buf[n+1][NETWORK_BUF_SIZE];
460    size_t pkt_len[n+1];
461    memset(pkt_len,0,sizeof pkt_len);
462  
463    // this is the mainloop - normally only one tp or one peer, but here
464    // for demo purposes mixed.
465    // end condition for peers is tpdkg_peer_not_done(&peer)
466    while(tpdkg_tp_not_done(&tp)) {
467  
468      // doing vla - but avoiding 0 sized ones is ugly
469      const size_t tp_out_size = tpdkg_tp_output_size(&tp);
470      uint8_t tp_out_buf[tp_out_size==0?1:tp_out_size], *tp_out;
471      if(tp_out_size==0) tp_out = NULL;
472      else tp_out = tp_out_buf;
473  
474      // avoiding zero-sized vla is still ugly
475      const size_t tp_in_size = tpdkg_tp_input_size(&tp);
476      uint8_t tp_in_buf[tp_in_size==0?1:tp_in_size], *tp_in;
477      if(tp_in_size==0) tp_in = NULL;
478      else tp_in = tp_in_buf;
479  
480      _recv(network_buf[0], &pkt_len[0], tp_in, tp_in_size);
481  
482  #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZ_PEER)
483      ret = fuzz_loop(step, &tp, peers, network_buf, pkt_len);
484      if(0!=ret) return ret;
485  #endif
486  #if defined(FUZZ_DUMP) && !defined(FUZZ_PEER)
487      fuzz_dump(step, &tp, tp_in, tp_in_size, argv, argc);
488  #endif
489  
490      ret = tpdkg_tp_next(&tp, tp_in, tp_in_size, tp_out, tp_out_size);
491      if(0!=ret) {
492        // clean up peers
493        for(uint8_t i=0;i<n;i++) tpdkg_peer_free(&peers[i]);
494        if(tp.cheater_len > 0) break;
495        return ret;
496      }
497  
498      for(uint8_t i=0;i<tp.n;i++) {
499        const uint8_t *msg;
500        size_t len;
501        if(0!=tpdkg_tp_peer_msg(&tp, tp_out, tp_out_size, i, &msg, &len)) {
502          return 1;
503        }
504        _send(network_buf[i+1], &pkt_len[i+1], msg, len);
505      }
506  
507      while(pkt_len[0]==0 && tpdkg_peer_not_done(&peers[1])) {
508        for(uint8_t i=0;i<n;i++) {
509          // 0sized vla meh
510          const size_t peer_out_size = tpdkg_peer_output_size(&peers[i]);
511          uint8_t peers_out_buf[peer_out_size==0?1:peer_out_size], *peers_out;
512          if(peer_out_size==0) peers_out = NULL;
513          else peers_out = peers_out_buf;
514  
515          // 0sized vla meh for the last time..
516          const size_t peer_in_size = tpdkg_peer_input_size(&peers[i]);
517          uint8_t peer_in_buf[peer_in_size==0?1:peer_in_size], *peer_in;
518          if(peer_in_size==0) peer_in = NULL;
519          else peer_in = peer_in_buf;
520  
521          _recv(network_buf[i+1], &pkt_len[i+1], peer_in, peer_in_size);
522  
523  #if defined(FUZZ_DUMP) && defined(FUZZ_PEER)
524          if(i==0) fuzz_dump(step, &peers[i], peer_in, peer_in_size, argv, argc);
525  #endif
526  #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZ_PEER)
527          ret = fuzz_loop(step, &tp, peers, network_buf, pkt_len);
528          if(0!=ret) return ret;
529  #endif
530          ret = tpdkg_peer_next(&peers[i],
531                                peer_in, peer_in_size,
532                                peers_out, peer_out_size);
533  
534          if(0!=ret) {
535            // clean up peers
536            for(uint8_t i=0;i<n;i++) tpdkg_peer_free(&peers[i]);
537            return ret;
538          }
539  
540          _send(network_buf[0], &pkt_len[0], peers_out, peer_out_size);
541        }
542      }
543    }
544  
545    // we are done. let's check the shares...
546    TOPRF_Share shares[n];
547    if(tp.cheater_len == 0) {
548      for(uint8_t i=0;i<n;i++) {
549        memcpy(&shares[i], (uint8_t*) &peers[i].share, sizeof(TOPRF_Share));
550        dump((uint8_t*) &shares[i], sizeof(TOPRF_Share), "share[%d]", i+1);
551      }
552  
553      if(0!=verify_shares(n, shares, t)) {
554          fprintf(stderr, "verify_shares failed\n");
555          return 1;
556      }
557    } else {
558      int total_cheaters=0;
559      uint8_t tmp[n+1];
560      memset(tmp,0,n+1);
561      for(int i=0;i<tp.cheater_len;i++) {
562        char err[dkg_max_err_SIZE];
563        uint8_t p = tpdkg_cheater_msg(&(*tp.cheaters)[i], err, sizeof(err));
564        fprintf(stderr,"\e[0;31m%s\e[0m\n", err);
565        if(p > n) return 1;
566        if(tmp[p]==0) total_cheaters++;
567        tmp[p]++;
568      }
569      fprintf(stderr, "\e[0;31m:/ dkg failed, total cheaters %d, list of cheaters:", total_cheaters);
570      for(int i=1;i<=n;i++) {
571        if(tmp[i]==0) continue;
572        fprintf(stderr," %d(%d)", i, tmp[i]);
573      }
574      fprintf(stderr, "\e[0m\n");
575      return 1;
576    }
577  
578    // clean up peers
579    for(uint8_t i=0;i<n;i++) tpdkg_peer_free(&peers[i]);
580  
581    fprintf(stderr, "\e[0;32meverything correct!\e[0m\n");
582    return 0;
583  }