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 }