/ src / dkg-vss.c
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  }