/ src / tests / ft-mult.c
ft-mult.c
  1  #include <stdio.h>
  2  #include <string.h>
  3  #include <stdint.h>
  4  #include "../dkg-vss.h"
  5  #include "../utils.h"
  6  #include "../mpmult.h"
  7  #include "../toprf.h"
  8  
  9  static void corrupt_ci_good_ci0(const uint8_t n, const uint8_t t,
 10                                  const uint8_t peer,
 11                                  TOPRF_Share shares[][2],
 12                                  uint8_t commitments[][crypto_core_ristretto255_BYTES],
 13                                  uint8_t blind[crypto_core_ristretto255_SCALARBYTES]) {
 14    // is not detected by anything, corrupts final result
 15    uint8_t secret[crypto_core_ristretto255_SCALARBYTES]={0};
 16    secret[31]=0x10;
 17    //secret[0]=1;
 18    //crypto_core_ristretto255_scalar_random(secret);
 19    if(liboprf_log_file!=NULL) fprintf(liboprf_log_file, RED"!!! Corrupting sharing of λ_iα_iβ_i %d, C_i0 is correct though\n"NORMAL, peer);
 20    (void)dkg_vss_share(n, t, secret, commitments, shares, blind);
 21  }
 22  
 23  static void corrupt_random_ci0_ci(const uint8_t n, const uint8_t t,
 24                                    const uint8_t peer,
 25                                    TOPRF_Share shares[][2],
 26                                    uint8_t commitments[][crypto_core_ristretto255_BYTES],
 27                                    uint8_t blind[crypto_core_ristretto255_SCALARBYTES]) {
 28    // is detected by zpk, but even if we reconstruct the secret
 29    // committed by C_i0 the end result will be corrupt.
 30    uint8_t secret[crypto_core_ristretto255_SCALARBYTES];
 31    crypto_core_ristretto255_scalar_random(secret);
 32    if(liboprf_log_file!=NULL) fprintf(liboprf_log_file, RED"!!! Corrupting with totally random sharing instead of λ_iα_iβ_i %d\n"NORMAL, peer);
 33    (void)dkg_vss_share(n, t, secret, &commitments[1], shares, blind);
 34    (void)dkg_vss_commit(secret, blind, commitments[0]);
 35  }
 36  
 37  static void corrupt_ci0_good_ci(const uint8_t peer, uint8_t commitments[][crypto_core_ristretto255_BYTES]) {
 38    // is detected by both zkp and vsps, but even if ignored does not
 39    // influence the correctness of the calculation.
 40    uint8_t secret[crypto_core_ristretto255_SCALARBYTES];
 41    crypto_core_ristretto255_scalar_random(secret);
 42    if(liboprf_log_file!=NULL) fprintf(liboprf_log_file, RED"!!! Corrupting C_i0 λ_iα_iβ_i %d\n"NORMAL, peer);
 43    dkg_vss_commit(secret,secret,commitments[0]);
 44  }
 45  
 46  static void corrupt_vsps_t1(const uint8_t n, const uint8_t t, const int8_t delta,
 47                              const uint8_t peer,
 48                              const uint8_t secret[crypto_core_ristretto255_SCALARBYTES],
 49                              TOPRF_Share shares[][2],
 50                              uint8_t commitments[][crypto_core_ristretto255_BYTES],
 51                              uint8_t blind[crypto_core_ristretto255_SCALARBYTES]) {
 52    if(liboprf_log_file!=NULL) fprintf(liboprf_log_file, RED"!!! Corrupting with wrong degree of the polynom peer %d\n"NORMAL, peer);
 53    (void)dkg_vss_share(n, t+delta, secret, &commitments[1], shares, blind);
 54    (void)dkg_vss_commit(secret, blind, commitments[0]);
 55  }
 56  
 57  static void corrupt_commitment(const uint8_t peer,
 58                                 uint8_t commitments[][crypto_core_ristretto255_BYTES]) { // corrupts the 1st commitment with the 2nd
 59    if(liboprf_log_file!=NULL) fprintf(liboprf_log_file, RED"!!! Corrupting commitment of peer %d\n"NORMAL, peer);
 60    memcpy(commitments[0], commitments[1], crypto_core_ristretto255_BYTES);
 61  }
 62  
 63  
 64  static void corrupt_share(const uint8_t peer,
 65                            const uint8_t share_idx,
 66                            const uint8_t share_type,
 67                            TOPRF_Share shares[][2]) {
 68    if(liboprf_log_file!=NULL) fprintf(liboprf_log_file, RED"!!! Corrupting share of peer %d\n"NORMAL, peer);
 69    shares[share_idx][share_type].value[2]^=0xff; // flip some bits
 70  }
 71  
 72  static void corrupt_wrongshare_correct_commitment(const uint8_t peer,
 73                                                    const uint8_t share_idx,
 74                                                    TOPRF_Share shares[][2],
 75                                                    uint8_t commitments[][crypto_core_ristretto255_BYTES]) {
 76    TOPRF_Share tmp;
 77    // swap shares
 78    memcpy(&tmp, &shares[share_idx][0], sizeof tmp);
 79    memcpy(&shares[share_idx][0], &shares[share_idx][1], sizeof tmp);
 80    memcpy(&shares[share_idx][1], &tmp, sizeof tmp);
 81    if(liboprf_log_file!=NULL) fprintf(liboprf_log_file, RED"!!! Corrupting share (but correct commitment) of peer %d\n"NORMAL, peer);
 82    dkg_vss_commit(shares[share_idx][0].value,shares[share_idx][1].value,commitments[share_idx]);
 83  }
 84  
 85  static int vss_share(const uint8_t n,
 86                       const uint8_t threshold,
 87                       const uint8_t secret[crypto_core_ristretto255_SCALARBYTES],
 88                       const uint8_t blind[crypto_core_ristretto255_SCALARBYTES],
 89                       uint8_t commitments[n][crypto_core_ristretto255_BYTES],
 90                       TOPRF_Share shares[n][2]) {
 91    uint8_t a[threshold][crypto_core_ristretto255_SCALARBYTES];
 92    uint8_t b[threshold][crypto_core_ristretto255_SCALARBYTES];
 93    if(secret!=NULL) memcpy(a[0], secret, crypto_core_ristretto255_SCALARBYTES);
 94    if(blind !=NULL) memcpy(b[0], blind,  crypto_core_ristretto255_SCALARBYTES);
 95    for(int k=0;k<threshold;k++) {
 96  #ifndef UNIT_TEST
 97      if(k!=0 || secret==NULL) crypto_core_ristretto255_scalar_random(a[k]);
 98      if(k!=0 || blind==NULL)  crypto_core_ristretto255_scalar_random(b[k]);
 99  #else
100      if(k!=0 || secret==NULL) debian_rng_scalar(a[k]);
101      dump(a[k],crypto_core_ristretto255_SCALARBYTES,"a[%d] ", k);
102      if(k!=0 || blind==NULL) debian_rng_scalar(b[k]);
103      dump(b[k],crypto_core_ristretto255_SCALARBYTES,"b[%d] ", k);
104  #endif
105    }
106  
107    // compute commitments
108    //if(0!=dkg_vss_commit(a[0], b[0], commitments[0])) return 1;
109    //dump((uint8_t*) &commitments[k],crypto_core_ristretto255_BYTES, "c[%d]     ", k);
110  
111    for(uint8_t j=1;j<=n;j++) {
112      //f(x) = a_0 + a_1*x + a_2*x^2 + a_3*x^3 + ⋯ + a_(t)*x^(t)
113      polynom(j, threshold, a, &shares[j-1][0]);
114      //f'(x) = b_0 + b_1*x + b_2*x^2 + b_3*x^3 + ⋯ + b_(t)*x^(t)
115      polynom(j, threshold, b, &shares[j-1][1]);
116  
117      if(0!=dkg_vss_commit(shares[j-1][0].value, shares[j-1][1].value, commitments[j-1])) return 1;
118    }
119  
120    return 0;
121  }
122  
123  
124  int ft_mult(const uint8_t n, const uint8_t t,
125              const TOPRF_Share alpha_shares[n][2], const uint8_t A_i[n][crypto_core_ristretto255_BYTES],
126              const TOPRF_Share beta_shares[n][2], const uint8_t B_i[n][crypto_core_ristretto255_BYTES],
127              TOPRF_Share r_shares[n][2],
128              uint8_t r_commitments[n][crypto_core_ristretto255_BYTES]) {
129    fprintf(stderr, "start ft_mult\n");
130  
131    if(t<2) return 1;
132    const uint8_t dealers = (t-1)*2 + 1;
133    if(n<dealers) return 1;
134  
135    // pubic inputs, for i:=0..n
136    // 𝓐_i = 𝓗(α_i,ρ_i) = g^(α_i)*h^(ρ_i)
137    // 𝓑_i = 𝓗(β_i,σ_i) = g^(β_i)*h^(σ_i)
138    // we assume the VSPS property has been checked on the commitments
139  
140    // step 1. Each player P_i shares λ_iα_iβ_i, using VSS
141    uint8_t indexes[dealers];
142    for(unsigned i=0;i<dealers;i++) indexes[i]=i+1;
143  
144    // λ_i is row 1 of inv VDM matrix
145    uint8_t lambdas[dealers][dealers][crypto_core_ristretto255_SCALARBYTES];
146    invertedVDMmatrix(dealers, indexes, lambdas);
147  
148    TOPRF_Share ci_shares[dealers][n][2];
149    uint8_t ci_commitments[dealers][n+1][crypto_core_ristretto255_BYTES];
150    uint8_t ci_tau[dealers][crypto_core_ristretto255_SCALARBYTES];
151    for(unsigned i=0;i<dealers;i++) {
152      // c_ij = 𝑓_αβ,i(j), where 𝑓_αβ,i is a random polynomial of degree t, such that 𝑓_αβ,i(0) = λ_iα_iβ_i
153      // τ_ij = u_i(j), where u_i(j) is a random polynomial of degree t
154  
155      uint8_t lambda_ai_bi[crypto_scalarmult_ristretto255_SCALARBYTES];
156      crypto_core_ristretto255_scalar_mul(lambda_ai_bi, alpha_shares[i][0].value, beta_shares[i][0].value);
157      crypto_core_ristretto255_scalar_mul(lambda_ai_bi, lambda_ai_bi, lambdas[0][i]);
158      if(0!=dkg_vss_share(n,t,lambda_ai_bi, &ci_commitments[i][1], ci_shares[i], ci_tau[i])) return 1;
159  
160      // c_i0 for the sake of the ZK proof is g^λab * h^t
161      if(0!=dkg_vss_commit(lambda_ai_bi, ci_tau[i], ci_commitments[i][0])) return 1;
162  
163      // sanity check
164      uint8_t s[crypto_scalarmult_ristretto255_SCALARBYTES];
165      uint8_t r[crypto_scalarmult_ristretto255_SCALARBYTES];
166      if(0!=dkg_vss_reconstruct(t, 0, n, &ci_shares[i][0], &ci_commitments[i][1], s, r)) return 1;
167      if(0!=memcmp(s, lambda_ai_bi, sizeof s)) {
168        liboprf_debug=1;dump(s, sizeof s, "reconstructed");
169        dump(lambda_ai_bi, sizeof lambda_ai_bi, "expected     ");liboprf_debug=0;
170      }
171  
172      // c_i0 is correct ablambda, but the shares are of a random sharing.
173      //c_i0 is fully correct, c_i is sharing of a random value
174      //is not detected by zkp, nor ft-vsps, corrupts final result
175      if(i==0) {
176        corrupt_ci_good_ci0(n, t, i+1, ci_shares[i], &ci_commitments[i][1], ci_tau[i]);
177        if(0==toprf_mpc_vsps_check(t-1, ci_commitments[i])) continue;
178        fprintf(stderr, GREEN"vsps for corrupted peer %d failed\n"NORMAL, i+1);
179      }
180      // share with polynom of degree smaller than t - not an error at all? not detected, and completes correctly
181      //if(i==0) corrupt_vsps_t1(n, t, -4, i+1, lambda_ai_bi, ci_shares[i], ci_commitments[i], ci_tau[i]);
182  
183      // detected by ZK can be reconstructed
184      // is detected by both zkp and vsps, but even if ignored does not
185      // influence the correctness of the calculation.
186      //if(i==0) corrupt_ci0_good_ci(i+1,ci_commitments[i]);
187  
188      // shares a random value, c_i0 is calculated over random value
189      // is detected by zpk, but even if we reconstruct the secret
190      // committed by C_i0 the end result will be corrupt.
191      //if(i==0) corrupt_random_ci0_ci(n, t, i+1, ci_shares[i], ci_commitments[i], ci_tau[i]);
192  
193      // caught by vsps cannot be reconstructed, only if correctly guessed x for degree t+x
194      //if(i==0) corrupt_vsps_t1(n, t, 1, i+1, lambda_ai_bi, ci_shares[i], ci_commitments[i], ci_tau[i]);
195  
196      // caught by vsps, can be reconstructed, by excluding the
197      // corrupted share(s), which can be checked by checking if the
198      // reconstructed value is committed by C_i0
199      //if(i==3) corrupt_wrongshare_correct_commitment(i+1,3,ci_shares[i],ci_commitments[i]);
200  
201      //if(i==1) corrupt_commitment(i+1,ci_commitments[i]);
202      //if(i==2) corrupt_share(i+1,n-2,0,ci_shares[i]);
203      //if(i==2) corrupt_share(i+1,3,1,ci_shares[i]);
204  
205      uint8_t v[crypto_scalarmult_ristretto255_SCALARBYTES];
206      if(0!=dkg_vss_reconstruct(t, 0, n, ci_shares[i], &ci_commitments[i][1], v, NULL)) return 1;
207      liboprf_debug=1; dump(v, sizeof v, "[%d] λ_iα_iβ_i", i+1);liboprf_debug=0;
208      if(memcmp(v, lambda_ai_bi, sizeof v)!=0) {
209        fprintf(liboprf_log_file, RED"failed reconstruction of lambda_ai_bi for %d\n"NORMAL, i+1);
210        liboprf_debug=1;dump(lambda_ai_bi, sizeof lambda_ai_bi, "correct");liboprf_debug=0;
211      }
212  
213      // send ci_shares[j] to P_j
214      // broadcast ci_commitments
215    }
216    fprintf(stderr, "[1] calculated shares and commitments of a*b\n");
217  
218    for(unsigned i=0;i<n;i++) {
219      for(unsigned j=0;j<dealers;j++) {
220        if(dkg_vss_verify_commitment(ci_commitments[j][i+1], ci_shares[j][i])==0) continue;
221        fprintf(liboprf_log_file, RED"[%d] invalid commitment for share from %d\n"NORMAL, i+1, j+1);
222  
223        // aggregate shares/commitments
224        TOPRF_Share shares[n][2];
225        uint8_t commitments[n][crypto_core_ristretto255_BYTES];
226        unsigned k=0;
227        memcpy(shares, ci_shares[j], sizeof shares);
228        memcpy(commitments, ci_commitments[j][1], sizeof commitments);
229  
230        TOPRF_Share secret[2];
231          if(0!=dkg_vss_reconstruct(t, 0, n, &shares[0], &commitments[0], secret[0].value, secret[1].value)) continue;
232          if(dkg_vss_verify_commitment(ci_commitments[j][0],secret)!=0) continue;
233          liboprf_debug=1;dump(secret[0].value, sizeof secret[0].value, "reconstructed %d", k);liboprf_debug=0;
234          if(memcmp(secret[1].value, ci_tau[j], crypto_scalarmult_ristretto255_SCALARBYTES)!=0) {
235            fprintf(liboprf_log_file, RED"tau[%d] != reconstructed tau\n"NORMAL, i);
236            continue;
237          }
238          if(0!=vss_share(n,t,secret[0].value, ci_tau[j], commitments, shares)) return 1;
239        memcpy(&ci_shares[j], shares, sizeof shares);
240        memcpy(&ci_commitments[j][1], commitments, sizeof commitments);
241        // restart this loop
242        i=-1;
243        break;
244      }
245    }
246  
247    // step 2. P_i proves in zk that 𝓒_i0 is a commitment of the product λ_iα_iβ_i.
248    // As per Appendix F: ZK Proof for multiplication of committed values from GRR98
249    // step 2.1 all P_j generate a challenge share, and broadcast a commitment to it
250    uint8_t zk_challenge_shares[n][2][crypto_scalarmult_ristretto255_SCALARBYTES];
251    uint8_t zk_challenge_commitments[n][crypto_scalarmult_ristretto255_BYTES];
252    for(unsigned i=0;i<n;i++) {
253      crypto_core_ristretto255_scalar_random(zk_challenge_shares[i][0]);
254      crypto_core_ristretto255_scalar_random(zk_challenge_shares[i][1]);
255      if(0!=dkg_vss_commit(zk_challenge_shares[i][0], zk_challenge_shares[i][1], zk_challenge_commitments[i])) return 1;
256    }
257    // every P_j broadcasts their  zk_challenge_commitment[i]
258    fprintf(stderr, "[2.1] broadcast e_i commitment share\n");
259  
260    // step 2.2 P_i chooses d, s, x, s_1, s_2 ∈ Z_q. Sends to the verifier the messages:
261    //  M   = g^d * h^s,
262    //  M_1 = g^x * h^s_1,
263    //  M_2 = B^x * h^s_2
264    uint8_t d[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
265    uint8_t s[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
266    uint8_t x[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
267    uint8_t s_1[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
268    uint8_t s_2[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
269    uint8_t zk_commitments[dealers][3][crypto_scalarmult_ristretto255_SCALARBYTES];
270    for(unsigned i=0;i<dealers;i++) {
271      crypto_core_ristretto255_scalar_random(d[i]);
272      crypto_core_ristretto255_scalar_random(s[i]);
273      crypto_core_ristretto255_scalar_random(x[i]);
274      crypto_core_ristretto255_scalar_random(s_1[i]);
275      crypto_core_ristretto255_scalar_random(s_2[i]);
276      //  M   = g^d * h^s,
277      if(0!=dkg_vss_commit(d[i],s[i], zk_commitments[i][0])) return 1;
278      //  M_1 = g^x * h^s_1,
279      if(0!=dkg_vss_commit(x[i],s_1[i], zk_commitments[i][1])) return 1;
280      //  M_2 = B^x * h^s_2
281      uint8_t tmp[crypto_scalarmult_ristretto255_BYTES];
282      if(crypto_scalarmult_ristretto255(tmp, x[i], B_i[i])) return 1;
283      if(crypto_scalarmult_ristretto255(zk_commitments[i][2], s_2[i], H)) return 1;
284      crypto_core_ristretto255_add(zk_commitments[i][2], zk_commitments[i][2], tmp);
285    }
286    fprintf(stderr, "[2.2] broadcast M, M_1 and M_2\n");
287  
288    // step 2.3. P_j broadcasts  e_j,r_j
289    fprintf(stderr, "[2.3] broadcast e_j, r_j\n");
290  
291    // step 2.4. P_i verifies the commitment from 0. against e:
292    uint8_t y[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
293    uint8_t w[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
294    uint8_t z[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
295    uint8_t w_1[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
296    uint8_t w_2[dealers][crypto_scalarmult_ristretto255_SCALARBYTES];
297    for(unsigned i=0;i<dealers;i++) {
298      // P_i verifies commitments for e_j,r_j
299      // P_i computes e'_i:
300      //  e'_i = Σ e_j
301      //       j!=i
302      uint8_t e_i[crypto_scalarmult_ristretto255_SCALARBYTES]={0};
303      uint8_t zk_challenge_commitment[crypto_scalarmult_ristretto255_BYTES];
304      for(unsigned j=0;j<n;j++) {
305        if(j==i) continue;
306        if(0!=dkg_vss_commit(zk_challenge_shares[j][0], zk_challenge_shares[j][1], zk_challenge_commitment)) return 1;
307        if(memcmp(zk_challenge_commitment, zk_challenge_commitments[j], crypto_scalarmult_ristretto255_BYTES)!=0) return 1;
308  
309        crypto_core_ristretto255_scalar_add(e_i, e_i, zk_challenge_shares[j][0]);
310      }
311  
312      // P_i replies with the following values:
313      // y   = d + e'_iβ,
314      crypto_core_ristretto255_scalar_mul(y[i], e_i, beta_shares[i][0].value);
315      crypto_core_ristretto255_scalar_add(y[i], y[i], d[i]);
316      // w   = s + e'_iσ
317      crypto_core_ristretto255_scalar_mul(w[i], e_i, beta_shares[i][1].value);
318      crypto_core_ristretto255_scalar_add(w[i], w[i], s[i]);
319      // z   = x + e'_iα
320      crypto_core_ristretto255_scalar_mul(z[i], e_i, alpha_shares[i][0].value);
321      crypto_core_ristretto255_scalar_mul(z[i], z[i], lambdas[0][i]);
322      crypto_core_ristretto255_scalar_add(z[i], z[i], x[i]);
323      // w_1 = s_1 + e'_iρ
324      crypto_core_ristretto255_scalar_mul(w_1[i], e_i, alpha_shares[i][1].value);
325      crypto_core_ristretto255_scalar_mul(w_1[i], w_1[i], lambdas[0][i]);
326      crypto_core_ristretto255_scalar_add(w_1[i], w_1[i], s_1[i]);
327      // w_2 = s_2 + e'_i(τ - σα)
328      crypto_core_ristretto255_scalar_mul(w_2[i], beta_shares[i][1].value, alpha_shares[i][0].value);
329      crypto_core_ristretto255_scalar_mul(w_2[i], w_2[i], lambdas[0][i]);
330      crypto_core_ristretto255_scalar_sub(w_2[i], ci_tau[i], w_2[i]);
331      crypto_core_ristretto255_scalar_mul(w_2[i], e_i, w_2[i]);
332      crypto_core_ristretto255_scalar_add(w_2[i], w_2[i], s_2[i]);
333    }
334    fprintf(stderr, "[2.4] calculate proof of a*b\n");
335  
336    // step 2.5. P_j checks zk proof
337    for(unsigned j=0;j<n;j++) {
338      // for each P_i zk proof
339      for(unsigned i=0;i<dealers;i++) {
340        //  P_j computes e'_i:
341        //    e'_i = Σ e_j
342        //         j!=i
343        uint8_t e_i[crypto_scalarmult_ristretto255_SCALARBYTES]={0};
344        for(unsigned k=0;k<n;k++) {
345          if(k==i) continue;
346          crypto_core_ristretto255_scalar_add(e_i, e_i, zk_challenge_shares[k][0]);
347        }
348  
349        uint8_t v0[crypto_scalarmult_ristretto255_BYTES];
350        uint8_t v1[crypto_scalarmult_ristretto255_BYTES];
351        //   g^y * h^w   == M * B^e'_i
352        if(0!=dkg_vss_commit(y[i], w[i], v0)) return 1;
353  
354        if(crypto_scalarmult_ristretto255(v1, e_i, B_i[i])) return 1;
355        crypto_core_ristretto255_add(v1, zk_commitments[i][0], v1);
356        if(memcmp(v1, v0, crypto_scalarmult_ristretto255_BYTES)!=0) {
357          fprintf(liboprf_log_file, RED"[%d] failed ZK proof_B (g^y * h^w   == M * B^e'_i) for dealer %d\n"NORMAL, j, i+1);
358          return 1;
359        }
360  
361        //   g^z * h^w_1 == M_1 * A^e'_i
362        if(0!=dkg_vss_commit(z[i], w_1[i], v0)) return 1;
363  
364        if(crypto_scalarmult_ristretto255(v1, e_i, A_i[i])) return 1;
365        if(crypto_scalarmult_ristretto255(v1, lambdas[0][i], v1)) return 1;
366        crypto_core_ristretto255_add(v1, zk_commitments[i][1], v1);
367        if(memcmp(v1, v0, crypto_scalarmult_ristretto255_BYTES)!=0) {
368          fprintf(liboprf_log_file, RED"[%d] failed ZK proof_A (g^z * h^w_1 == M_1 * A^e'_i) for dealer %d\n"NORMAL, j, i+1);
369          return 1;
370        }
371  
372        //   B^z * h^w_2 == M_2 * C^e'_i
373        if(crypto_scalarmult_ristretto255(v0, z[i], B_i[i])) return 1;
374        // we abuse v1 as a temp storage, v1 = h^w_2
375        if(crypto_scalarmult_ristretto255(v1, w_2[i], H)) return 1;
376        crypto_core_ristretto255_add(v0, v0, v1);
377  
378        if(crypto_scalarmult_ristretto255(v1, e_i, ci_commitments[i][0])) return 1;
379        crypto_core_ristretto255_add(v1, zk_commitments[i][2], v1);
380        if(memcmp(v1, v0, crypto_scalarmult_ristretto255_BYTES)!=0) {
381          fprintf(liboprf_log_file, RED"[%d] failed ZK proof_C (B^z * h^w_2 == M_2 * C^e'_i) for dealer %d\n"NORMAL, j, i+1);
382  
383          TOPRF_Share secret[2];
384          if(0!=dkg_vss_reconstruct(t, 0, n, ci_shares[i], &ci_commitments[i][1], secret[0].value, secret[1].value)) return 1;
385          liboprf_debug=1;dump(secret[0].value, sizeof secret[0].value, "reconstructed");liboprf_debug=0;
386          if(0!=dkg_vss_commit(secret[0].value, secret[1].value, ci_commitments[i][0])) return 1;
387          i--;
388          break;
389          //return 1;
390        }
391      }
392    }
393    fprintf(stderr, "[2.5] verified proof of a*b\n");
394  
395    uint8_t C_i[n+1][crypto_scalarmult_ristretto255_BYTES];
396    for(unsigned i=0;i<n;i++) {
397      // step 3. P_i computes:
398      //      2t+1
399      //  γ_i = Σ c_ji
400      //       j=1
401      //  which is a share of γ = αβ, via random polynomial of degree t and
402      //      2t+1
403      //  τ_i = Σ τ_ji
404      //       j=1
405      memcpy(&r_shares[i][0], &ci_shares[0][i][0], TOPRF_Share_BYTES);
406      memcpy(&r_shares[i][1], &ci_shares[0][i][1], TOPRF_Share_BYTES);
407      for(unsigned j=1;j<dealers;j++) {
408        crypto_core_ristretto255_scalar_add(r_shares[i][0].value, r_shares[i][0].value, ci_shares[j][i][0].value);
409        crypto_core_ristretto255_scalar_add(r_shares[i][1].value, r_shares[i][1].value, ci_shares[j][i][1].value);
410      }
411  
412      // step 4. P_i computes and broadcasts
413      //    𝓒_i = 𝓗(γ_i, τ_i)
414      //        = g^(γ_i)*h^(τ_i)
415      //
416      //        2t+1
417      //        = Π 𝓒_ji
418      //         j=1
419      if(0!=dkg_vss_commit(r_shares[i][0].value, r_shares[i][1].value, C_i[i+1])) return 1;
420      // use this below to calculate all commitments for the other peers
421      uint8_t Cx_i[crypto_scalarmult_ristretto255_BYTES];
422      memcpy(Cx_i,ci_commitments[0][i+1], crypto_scalarmult_ristretto255_BYTES);
423      for(unsigned j=1;j<dealers;j++) {
424        crypto_core_ristretto255_add(Cx_i, Cx_i, ci_commitments[j][i+1]);
425      }
426      if(memcmp(Cx_i, C_i[i+1], sizeof Cx_i) != 0) {
427        fprintf(liboprf_log_file, RED"[%d] failed final commitment\n"NORMAL, i+1);
428      }
429    }
430    memcpy(C_i, ci_commitments[0][0], crypto_scalarmult_ristretto255_BYTES);
431    for(unsigned j=1;j<dealers;j++) {
432      crypto_core_ristretto255_add(C_i[0], C_i[0], ci_commitments[j][0]);
433    }
434  
435    fprintf(stderr, "[3&4] calculated final shares of a*b and their commitments\n");
436  
437    int fail = 0;
438    for(unsigned i=0;i<n;i++) {
439      // step 5. players run a VSPS Check on 𝓒_i, i:=1..n,
440      // if the test succeeds:
441      // Secret information of P_i: share γ_i
442      // Public information: 𝓒_i, for i:=1..n
443      // protocol terminates successfully
444  
445      if(0==toprf_mpc_vsps_check(t-1, C_i)) {
446        fprintf(liboprf_log_file, GREEN"ft-vsps checks out for C_i\n"NORMAL);
447      } else {
448        fail = 1;
449        fprintf(liboprf_log_file, RED"[%d] ft-vsps fails for C_i\n"NORMAL, i+1);
450      }
451  
452      // If the test fails STOP and run MULT from step 2.
453    }
454    if(!fail) {
455      memcpy(r_commitments, &C_i[1], n*crypto_scalarmult_ristretto255_BYTES);
456      return 0;
457    }
458  
459    fprintf(stderr, "[5] failed vsps check for C_i\n");
460  
461    // step 6. only if 5. fails, as per Mult algorithm from fig. 3. step 2
462    // Players run a VSPS Check on P_i's sharing. If a sharing fails the test
463    // then expose the secret through the VSS reconstruction.
464    for(unsigned i=0;i<n;i++) {
465      // each P_i VSPS checks P_j (i!=j) sharing
466      for(unsigned j=0;j<dealers;j++) {
467        if(j==i) continue;
468        if(0==toprf_mpc_vsps_check(t-1, ci_commitments[j])) continue;
469        fprintf(stderr, RED"[%d] vsps for peer %d failed\n"NORMAL, i+1, j+1);
470  
471        // expose the secret of P_j through vss reconstruction
472        TOPRF_Share s[2];
473        for(unsigned t1=t;t1<n;t1++) {
474          fprintf(liboprf_log_file, "trying degree t+%d\n", t1-t);
475          if(0!=dkg_vss_reconstruct(t1, 0, n, &ci_shares[j][0], &ci_commitments[j][1], s[0].value, s[1].value)) continue;
476          if(dkg_vss_verify_commitment(ci_commitments[j][0],s)!=0) continue;
477          liboprf_debug=1;dump(s[0].value, sizeof s[0].value, "reconstructed");liboprf_debug=0;
478          if(memcmp(s[1].value, ci_tau[j], crypto_scalarmult_ristretto255_SCALARBYTES)!=0) {
479            // tau[j] is only available to the cheater, so this check
480            // makes little sense, it is only a sanity test for the test
481            // itself.
482            fprintf(liboprf_log_file, RED"tau[%d] != reconstructed tau\n"NORMAL, j);
483            liboprf_debug = 1;
484            dump(s[1].value, 32, "reconstructed tau");
485            dump(ci_tau[j], 32, "originalistic tau");
486            liboprf_debug = 0;
487          }
488          if(0!=vss_share(n,t,s[0].value, ci_tau[j], &ci_commitments[j][1], ci_shares[j])) return 1;
489          break;
490        }
491      }
492    }
493    fprintf(stderr, "[6] VSPS check on P_i sharing\n");
494  
495    for(unsigned i=0;i<n;i++) { // todo possibly needs adjustment due to usage of reconstructed values.
496      // step 7. P_i computes:
497      //      2t+1
498      //  γ_i = Σ c_ji
499      //       j=1
500      //  which is a share of γ = αβ, via random polynomial of degree t and
501      //      2t+1
502      //  τ_i = Σ τ_ji
503      //       j=1
504      memcpy(&r_shares[i][0], &ci_shares[0][i][0], TOPRF_Share_BYTES);
505      memcpy(&r_shares[i][1], &ci_shares[0][i][1], TOPRF_Share_BYTES);
506      for(unsigned j=1;j<dealers;j++) {
507        crypto_core_ristretto255_scalar_add(r_shares[i][0].value, r_shares[i][0].value, ci_shares[j][i][0].value);
508        crypto_core_ristretto255_scalar_add(r_shares[i][1].value, r_shares[i][1].value, ci_shares[j][i][1].value);
509      }
510  
511      // step 8. P_i computes and broadcasts
512      //    𝓒_i = 𝓗(γ_i, τ_i)
513      //        = g^(γ_i)*h^(τ_i)
514      //
515      //        2t+1
516      //        = Π 𝓒_ji
517      //         j=1
518      if(0!=dkg_vss_commit(r_shares[i][0].value, r_shares[i][1].value, C_i[i])) return 1;
519      // use this below to calculate all commitments for the other peers
520      uint8_t Cx_i[crypto_scalarmult_ristretto255_BYTES];
521      memcpy(Cx_i,ci_commitments[0][i+1], crypto_scalarmult_ristretto255_BYTES);
522      for(unsigned j=1;j<dealers;j++) {
523        crypto_core_ristretto255_add(Cx_i, Cx_i, ci_commitments[j][i+1]);
524      }
525      if(memcmp(Cx_i, C_i[i], sizeof Cx_i) != 0) return 1;
526    }
527    fprintf(stderr, "[7&8] calculated final shares of a*b and their commitments\n");
528  
529    memcpy(r_commitments, C_i, n*crypto_scalarmult_ristretto255_BYTES);
530  
531    return 0;
532  }
533  
534  int test_interpol(void) {
535    fprintf(stderr, "testing interpol()\n");
536    liboprf_debug = 1;
537    uint8_t n=13, t=6;
538    TOPRF_Share vss_shares[n][2];
539    uint8_t commitments[n][crypto_core_ristretto255_BYTES];
540    if(dkg_vss_share(n, t, NULL, commitments, vss_shares, NULL)) return 1;
541  
542    TOPRF_Share shares[n];
543    for(unsigned i=0;i<n;i++) {
544      for(unsigned j=0,k=0;j<t;k++) {
545        if(k==i) {
546          //dump(vss_shares[i][0].value, 32, "target %d", vss_shares[i][0].index);
547          continue;
548        }
549        memcpy(&shares[j++], &vss_shares[k][0], TOPRF_Share_BYTES);
550      }
551      TOPRF_Share share;
552      share.index=i+1;
553      interpolate(i+1, t, shares, share.value);
554      if(memcmp(vss_shares[i][0].value,share.value, 32)!=0) return 1;
555      //dump(vss_shares[i][0].value, 32, "vshare %d", vss_shares[i][0].index);
556      //dump(share.value, 32, "rshare %d", i+1);
557    }
558  
559    TOPRF_Share share;
560    share.index=0;
561    interpolate(0, t, shares, share.value);
562    dump(share.value, 32, "secret   ");
563  
564    fprintf(stderr, "success: interpol()\n");
565    return 0;
566  }
567  
568  static void sort_shares(const int n, uint8_t arr[n], uint8_t indexes[n]) {
569    for (uint8_t c = 1 ; c <= n - 1; c++) {
570      uint8_t d = c, t, t1;
571      while(d > 0 && arr[d] < arr[d-1]) {
572        t = arr[d];
573        t1 = indexes[d];
574        arr[d] = arr[d-1];
575        indexes[d] = indexes[d-1];
576        arr[d-1] = t;
577        indexes[d-1] = t1;
578        d--;
579      }
580    }
581  }
582  
583  int test_sort_shares(void) {
584    //uint8_t shares[8] = { 12, 1, 8, 7, 3, 11, 10, 5 };
585    uint8_t qual[4] =       { 12, 3, 7, 5 };
586    uint8_t sorted_qual[4] = { 0, 4, 3, 7 };
587    sort_shares(4, qual, sorted_qual);
588    const uint8_t vqual[4] =        { 3, 5, 7, 12};
589    const uint8_t vsorted_qual[4] = { 4, 7, 3,  0};
590    if(memcmp(vqual, qual, 4)!=0) return 1;
591    if(memcmp(vsorted_qual, sorted_qual, 4)!=0) return 1;
592    return 0;
593  }
594  
595  int main(void) {
596    liboprf_log_file = stderr;
597    liboprf_debug = 0;
598  
599    if(test_sort_shares()!=0) return 1;
600    if(test_interpol()!=0) return 1;
601  
602    uint8_t n=13, t=6;
603    TOPRF_Share a_shares[n][2];
604    uint8_t a_commitments[n][crypto_core_ristretto255_BYTES];
605    if(dkg_vss_share(n, t, NULL, a_commitments, a_shares, NULL)) return 1;
606  
607    uint8_t a[crypto_scalarmult_ristretto255_SCALARBYTES];
608    if(0!=dkg_vss_reconstruct(t, 0, n, a_shares, a_commitments, a, NULL)) return 1;
609    liboprf_debug=1; dump(a, sizeof a, "a");liboprf_debug=0;
610  
611    // step 2. generate ρ
612    TOPRF_Share b_shares[n][2];
613    uint8_t b_commitments[n][crypto_core_ristretto255_BYTES];
614    // generate kc, the original old key, we are gonna update
615    if(dkg_vss_share(n, t, NULL, b_commitments, b_shares, NULL)) return 1;
616  
617    uint8_t b[crypto_scalarmult_ristretto255_SCALARBYTES];
618    if(0!=dkg_vss_reconstruct(t, 0, n, b_shares, b_commitments, b, NULL)) return 1;
619    liboprf_debug=1; dump(b, sizeof b, "b");liboprf_debug=0;
620  
621    if(0!=toprf_mpc_vsps_check(t-1, a_commitments)) return 1;
622    if(0!=toprf_mpc_vsps_check(t-1, b_commitments)) return 1;
623    fprintf(stderr, "[0] vsps(A_i) & vsps(B_i) ok\n");
624  
625    // 3. execute the FT-Mult protocol, to calculate FT-Mult(kc, ρ), generating sharings of r.
626    TOPRF_Share r_shares[n][2];
627    uint8_t r_commitments[n][crypto_core_ristretto255_BYTES];
628    if(0!=ft_mult(n, t, a_shares, a_commitments, b_shares, b_commitments, r_shares, r_commitments)) return 1;
629  
630    uint8_t r[crypto_scalarmult_ristretto255_SCALARBYTES];
631    if(0!=dkg_vss_reconstruct(t, 0, n, r_shares, r_commitments, r, NULL)) return 1;
632    liboprf_debug=1;dump(r, sizeof r, "r  ");liboprf_debug=0;
633  
634    uint8_t tmp[crypto_scalarmult_ristretto255_SCALARBYTES];
635    crypto_core_ristretto255_scalar_mul(tmp, a, b);
636    liboprf_debug=1;dump(tmp, sizeof tmp, "a*b");liboprf_debug=0;
637  
638    if(memcmp(tmp, r, sizeof tmp)!=0) {
639      fprintf(liboprf_log_file,RED"fail a*b != ft-mul(a,b)\n"NORMAL);
640      return 1;
641    }
642    fprintf(stderr, GREEN"everything correct!\n"NORMAL);
643    return 0;
644  }