dkg-vss.c
1 #include <sodium.h> 2 #include <stdint.h> 3 #include <string.h> 4 #include "toprf.h" 5 #include "utils.h" 6 #include "dkg.h" 7 8 // nothing up my sleeve generator H, generated with: 9 // hash_to_group((uint8_t*)"DKG Generator H on ristretto255", 32, H) 10 const __attribute__((visibility("hidden"))) uint8_t H[crypto_core_ristretto255_BYTES]= { 11 0x66, 0x4e, 0x4c, 0xb5, 0x89, 0x0e, 0xb3, 0xe4, 12 0xc0, 0xd5, 0x48, 0x02, 0x74, 0x8a, 0xb2, 0x25, 13 0xf9, 0x73, 0xda, 0xe5, 0xc0, 0xef, 0xc1, 0x68, 14 0xf4, 0x4d, 0x1b, 0x60, 0x28, 0x97, 0x8f, 0x07}; 15 16 int dkg_vss_commit(const uint8_t a[crypto_core_ristretto255_SCALARBYTES], 17 const uint8_t r[crypto_core_ristretto255_SCALARBYTES], 18 uint8_t C[crypto_core_ristretto255_BYTES]) { 19 // compute commitments 20 uint8_t X[crypto_core_ristretto255_BYTES]; 21 uint8_t R[crypto_core_ristretto255_BYTES]; 22 // x = g^a_ik 23 crypto_scalarmult_ristretto255_base(X, a); 24 // r = h^b_ik 25 if(crypto_scalarmult_ristretto255(R, r, H)) return 1; 26 // C_ik = x+r 27 crypto_core_ristretto255_add(C,X,R); 28 29 return 0; 30 } 31 32 int dkg_vss_share(const uint8_t n, 33 const uint8_t threshold, 34 const uint8_t secret[crypto_core_ristretto255_SCALARBYTES], 35 uint8_t commitments[n][crypto_core_ristretto255_BYTES], 36 TOPRF_Share shares[n][2], 37 uint8_t blind[crypto_core_ristretto255_SCALARBYTES]) { 38 if(threshold==0) return 1; 39 uint8_t a[threshold][crypto_core_ristretto255_SCALARBYTES]; 40 uint8_t b[threshold][crypto_core_ristretto255_SCALARBYTES]; 41 if(secret!=NULL) memcpy(a[0],secret, crypto_core_ristretto255_SCALARBYTES); 42 for(int k=0;k<threshold;k++) { 43 #ifndef UNIT_TEST 44 if(k!=0 || secret==NULL) crypto_core_ristretto255_scalar_random(a[k]); 45 crypto_core_ristretto255_scalar_random(b[k]); 46 #else 47 if(k!=0 || secret==NULL) debian_rng_scalar(a[k]); 48 dump(a[k],crypto_core_ristretto255_SCALARBYTES,"a[%d] ", k); 49 debian_rng_scalar(b[k]); 50 dump(b[k],crypto_core_ristretto255_SCALARBYTES,"b[%d] ", k); 51 #endif 52 } 53 54 if(blind!=NULL) { 55 memcpy(blind, b[0], crypto_core_ristretto255_SCALARBYTES); 56 } 57 58 for(uint8_t j=1;j<=n;j++) { 59 //f(x) = a_0 + a_1*x + a_2*x^2 + a_3*x^3 + ⋯ + a_(t)*x^(t) 60 polynom(j, threshold, a, &shares[j-1][0]); 61 //f'(x) = b_0 + b_1*x + b_2*x^2 + b_3*x^3 + ⋯ + b_(t)*x^(t) 62 polynom(j, threshold, b, &shares[j-1][1]); 63 64 if(0!=dkg_vss_commit(shares[j-1][0].value, shares[j-1][1].value, commitments[j-1])) return 1; 65 } 66 67 return 0; 68 } 69 70 int dkg_vss_verify_commitment(const uint8_t commitment[crypto_core_ristretto255_BYTES], 71 const TOPRF_Share share[2]) { 72 uint8_t c[crypto_core_ristretto255_SCALARBYTES]; 73 if(0!=dkg_vss_commit(share[0].value, share[1].value, c)) return 1; 74 if(sodium_memcmp(c,commitment,sizeof c)!=0) return 1; 75 return 0; 76 } 77 78 int dkg_vss_finish(const uint8_t n, 79 const uint8_t qual[n], 80 const TOPRF_Share shares[n][2], 81 const uint8_t self, 82 TOPRF_Share share[2], 83 uint8_t commitment[crypto_core_ristretto255_BYTES]) { 84 memset(share[0].value, 0, crypto_core_ristretto255_SCALARBYTES); 85 memset(share[1].value, 0, crypto_core_ristretto255_SCALARBYTES); 86 for(int i=0;qual[i] && i<n;i++) { 87 // todo should we assert that there are no duplicate indexes in qual? 88 if(self!=shares[qual[i]-1][0].index) { 89 fprintf(stderr, "\x1b[0;31mbad share i=%d qual[i]=%d, index=%d\x1b[0m\n", i, qual[i], shares[qual[i]-1][0].index); 90 } 91 crypto_core_ristretto255_scalar_add(share[0].value, share[0].value, shares[qual[i]-1][0].value); 92 //dump((uint8_t*)&shares[qual[i]-1][0], sizeof(TOPRF_Share), "s[%d,%d] ", qual[i], self); 93 crypto_core_ristretto255_scalar_add(share[1].value, share[1].value, shares[qual[i]-1][1].value); 94 //dump((uint8_t*)&shares[qual[i]-1][1], sizeof(TOPRF_Share), "S[%d,%d] ", qual[i], self); 95 } 96 //dump(xi->value, crypto_core_ristretto255_SCALARBYTES, "x[%d] ", self); 97 //dump(x_i->value, crypto_core_ristretto255_SCALARBYTES, "x'[%d] ", self); 98 if(0!=dkg_vss_commit(share[0].value, share[1].value, commitment)) return 1; 99 return 0; 100 } 101 102 static void sort_shares(const int n, uint8_t arr[n], uint8_t indexes[n]) { 103 for (uint8_t c = 1 ; c <= n - 1; c++) { 104 uint8_t d = c, t, t1; 105 while(d > 0 && arr[d] < arr[d-1]) { 106 t = arr[d]; 107 t1 = indexes[d]; 108 arr[d] = arr[d-1]; 109 indexes[d] = indexes[d-1]; 110 arr[d-1] = t; 111 indexes[d-1] = t1; 112 d--; 113 } 114 } 115 } 116 117 int dkg_vss_reconstruct(const uint8_t t, 118 const uint8_t x, 119 const size_t shares_len, 120 const TOPRF_Share shares[shares_len][2], 121 const uint8_t commitments[shares_len][crypto_scalarmult_ristretto255_BYTES], 122 uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES], 123 uint8_t blind[crypto_scalarmult_ristretto255_SCALARBYTES]) { 124 if(shares_len>128) return 1; 125 uint8_t qual[t]; 126 uint8_t indexes[t]; 127 unsigned j=0; 128 for(uint8_t i=0;i<shares_len && j<t;i++) { 129 if(commitments != NULL && dkg_vss_verify_commitment(commitments[i],shares[i])!=0) continue; 130 qual[j]=shares[i][0].index; 131 indexes[j++]=i; 132 } 133 if(j<t) return 1; 134 sort_shares(t, qual, indexes); 135 136 TOPRF_Share si[t]; 137 for(unsigned i=0;i<t;i++) { 138 memcpy(&si[i], &shares[indexes[i]], TOPRF_Share_BYTES); 139 //dump((uint8_t*) &si[i], TOPRF_Share_BYTES, "s%d", i); 140 } 141 interpolate(x, t, si, result); 142 if(blind!=NULL) { 143 for(unsigned i=0;i<t;i++) { 144 memcpy(&si[i], &shares[indexes[i]][1], TOPRF_Share_BYTES); 145 //dump((uint8_t*) &si[i], TOPRF_Share_BYTES, "s%d", i); 146 } 147 interpolate(x, t, si, blind); 148 } 149 return 0; 150 }