frosix

Multiparty signature service (experimental)
Log | Files | Refs | README | LICENSE

frosix-httpd_dkg-key.c (24129B)


      1 /*
      2   This file is part of Frosix
      3   Copyright (C) 2022, 2023 Joel Urech
      4 
      5   Frosix is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Frosix is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Frosix; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file backend/frosix-httpd_dkg-key.c
     18  * @brief functions to handle incoming requests on /dkg-key
     19  * @author Joel Urech
     20  */
     21 #include "frosix-httpd_dkg.h"
     22 #include "frosix-httpd.h"
     23 #include "frosix_database_plugin.h"
     24 #include "frosix_service.h"
     25 #include "keygen.h"
     26 #include <taler/taler_util.h>
     27 #include <gnunet/gnunet_util_lib.h>
     28 #include <gnunet/gnunet_db_lib.h>
     29 
     30 
     31 struct DkgKeyContext
     32 {
     33   /**
     34    *
     35   */
     36   uint8_t provider_index;
     37 
     38   /**
     39    *
     40   */
     41   uint8_t threshold;
     42 
     43   /**
     44    *
     45   */
     46   uint8_t num_of_participants;
     47 
     48   /**
     49    *
     50   */
     51   struct FROSIX_DkgContextStringP context_string;
     52 
     53   /**
     54    *
     55   */
     56   struct FROSIX_ChallengeHashP auth_hash;
     57 
     58   /**
     59    *
     60   */
     61   struct FROSIX_EncryptionKey pre_enc_key;
     62 
     63   /**
     64    *
     65   */
     66   uint8_t expiration;
     67 
     68 
     69   /**
     70    *
     71   */
     72   struct FROSIX_DkgRequestIdP request_id;
     73 
     74   /**
     75    *
     76   */
     77   struct FROSIX_ProviderSaltP provider_salt;
     78 
     79   /**
     80    *
     81   */
     82   struct FROSIX_SecretProviderSaltP secret_provider_salt;
     83 
     84   /**
     85    *
     86   */
     87   struct GNUNET_CRYPTO_EddsaPrivateKey priv_sig_key;
     88 
     89   /**
     90    *
     91   */
     92   struct FROST_DkgShare *dkg_shares;
     93 
     94   /**
     95    * Our handler context
     96   */
     97   struct TM_HandlerContext *hc;
     98 
     99   /**
    100    * Uploaded JSON data, NULL if upload is not yet complete.
    101   */
    102   json_t *json;
    103 
    104   /**
    105    * Post parser context.
    106    */
    107   void *post_ctx;
    108 
    109   /**
    110    * Connection handle for closing or resuming
    111    */
    112   struct MHD_Connection *connection;
    113 
    114   /**
    115    * When should this request time out?
    116   */
    117   struct GNUNET_TIME_Absolute timeout;
    118 };
    119 
    120 
    121 static enum GNUNET_GenericReturnValue
    122 derive_encryption_key (
    123   struct FROSIX_EncryptionKey *enc_key,
    124   const struct FROSIX_EncryptionKey *pre_enc_key,
    125   const struct FROST_PublicKey *pk,
    126   const struct FROSIX_ProviderSaltP *provider_salt,
    127   uint8_t provider_index)
    128 {
    129   return GNUNET_CRYPTO_kdf (enc_key,
    130                             sizeof (*enc_key),
    131                             "FROSIX-KEY",
    132                             strlen ("FROSIX-KEY"),
    133                             pre_enc_key,
    134                             sizeof (*pre_enc_key),
    135                             pk,
    136                             sizeof (*pk),
    137                             provider_salt,
    138                             sizeof (*provider_salt),
    139                             &provider_index,
    140                             sizeof (provider_index),
    141                             NULL,
    142                             0);
    143 }
    144 
    145 static void
    146 generate_key_pair (struct FROST_KeyPair *key_pair,
    147                    struct FROST_DkgShare other_shares[],
    148                    const struct FROST_DkgShare my_shares[],
    149                    const struct FROST_DkgCommitment dkg_commitments[],
    150                    uint8_t my_index,
    151                    uint8_t threshold,
    152                    uint8_t num_of_participants)
    153 {
    154   memcpy (&other_shares[my_index - 1].share,
    155           &my_shares[my_index - 1].share,
    156           sizeof (my_shares[my_index - 1].share));
    157 
    158   FROST_keygen_finalize (key_pair,
    159                          my_index,
    160                          other_shares,
    161                          dkg_commitments,
    162                          num_of_participants);
    163 }
    164 
    165 static MHD_RESULT
    166 store_key_data (struct DkgKeyContext *dc,
    167                 struct FROST_HashCode *enc_key_hash,
    168                 struct FROSIX_EncryptionKey *enc_key,
    169                 struct FROST_KeyPair *key_pair)
    170 {
    171   /* Copy key data together */
    172   struct FROSIX_KeyDataRaw raw_data;
    173   memcpy (&raw_data.bytes[0],
    174           &key_pair->my_sk,
    175           sizeof (key_pair->my_sk));
    176 
    177   memcpy (&raw_data.bytes[sizeof key_pair->my_sk],
    178           &key_pair->group_pk,
    179           sizeof (key_pair->group_pk));
    180 
    181   /* Generate nonce */
    182   struct FROSIX_EncryptionNonceP nonce;
    183   FROSIX_secretbox_nonce_randombytes (&nonce);
    184 
    185   /* Encrypt key data */
    186   struct FROSIX_KeyDataEncrypted ciphertext;
    187   FROSIX_secretbox_keydata (&ciphertext,
    188                             &raw_data,
    189                             &nonce,
    190                             enc_key);
    191 
    192   /* store key data */
    193   enum GNUNET_DB_QueryStatus qs;
    194   qs = db->store_key (db->cls,
    195                       enc_key_hash,
    196                       &nonce,
    197                       &ciphertext,
    198                       &dc->auth_hash,
    199                       dc->expiration,
    200                       dc->provider_index);
    201   switch (qs)
    202   {
    203   case GNUNET_DB_STATUS_HARD_ERROR:
    204   case GNUNET_DB_STATUS_SOFT_ERROR:
    205   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    206     GNUNET_break (0);
    207     return TALER_MHD_reply_with_error (dc->connection,
    208                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    209                                        TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
    210                                        "store key");
    211   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    212     break;
    213   }
    214   return MHD_HTTP_OK;
    215 }
    216 
    217 
    218 MHD_RESULT
    219 FH_handler_dkg_key_post (
    220   struct MHD_Connection *connection,
    221   struct TM_HandlerContext *hc,
    222   const struct FROSIX_DkgRequestIdP *dkg_id,
    223   const struct FROSIX_ProviderSaltP *provider_salt,
    224   const struct FROSIX_SecretProviderSaltP *secret_provider_salt,
    225   const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_sig_key,
    226   const char *dkg_key_data,
    227   size_t *dkg_key_data_size)
    228 {
    229   enum GNUNET_GenericReturnValue res;
    230   struct DkgKeyContext *dc = hc->ctx;
    231   json_t *json_ppk = NULL;
    232   json_t *shares = NULL;
    233   size_t share_n_comm_length;
    234 
    235   if (NULL == dc)
    236   {
    237     dc = GNUNET_new (struct DkgKeyContext);
    238     dc->connection = connection;
    239     dc->request_id = *dkg_id;
    240     dc->provider_salt = *provider_salt;
    241     dc->secret_provider_salt = *secret_provider_salt;
    242     dc->priv_sig_key = *priv_sig_key;
    243     hc->ctx = dc;
    244   }
    245 
    246   /* parse request body */
    247   if (NULL == dc->json)
    248   {
    249     res = TALER_MHD_parse_post_json (dc->connection,
    250                                      &dc->post_ctx,
    251                                      dkg_key_data,
    252                                      dkg_key_data_size,
    253                                      &dc->json);
    254     if (GNUNET_SYSERR == res)
    255     {
    256       GNUNET_break (0);
    257       return MHD_NO;
    258     }
    259     if ((GNUNET_NO == res ||
    260          (NULL == dc->json)))
    261     {
    262       return MHD_YES;
    263     }
    264   }
    265 
    266   struct GNUNET_JSON_Specification spec[] = {
    267     GNUNET_JSON_spec_uint8 ("provider_index",
    268                             &dc->provider_index),
    269     GNUNET_JSON_spec_uint8 ("threshold",
    270                             &dc->threshold),
    271     GNUNET_JSON_spec_fixed_auto ("context_string",
    272                                  &dc->context_string),
    273     GNUNET_JSON_spec_fixed_auto ("auth_hash",
    274                                  &dc->auth_hash),
    275     GNUNET_JSON_spec_json ("providers_public_keys",
    276                            &json_ppk),
    277     GNUNET_JSON_spec_fixed_auto ("pre_encryption_key",
    278                                  &dc->pre_enc_key),
    279     GNUNET_JSON_spec_json ("secret_shares",
    280                            &shares),
    281     GNUNET_JSON_spec_uint8 ("expiration",
    282                             &dc->expiration),
    283     GNUNET_JSON_spec_end ()
    284   };
    285 
    286   res = TALER_MHD_parse_json_data (connection,
    287                                    dc->json,
    288                                    spec);
    289 
    290   if (GNUNET_SYSERR == res)
    291   {
    292     GNUNET_JSON_parse_free (spec);
    293     GNUNET_break (0);
    294     return MHD_NO;
    295   }
    296   if (GNUNET_NO == res)
    297   {
    298     GNUNET_JSON_parse_free (spec);
    299     GNUNET_break_op (0);
    300     return TALER_MHD_reply_with_error (connection,
    301                                        MHD_HTTP_BAD_REQUEST,
    302                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    303                                        "Unable to parse request body");
    304   }
    305 
    306   /* check number of submitted provider public keys*/
    307   if (254 < json_array_size (json_ppk))
    308   {
    309     GNUNET_JSON_parse_free (spec);
    310     GNUNET_break_op (0);
    311     return TALER_MHD_reply_with_error (connection,
    312                                        MHD_HTTP_BAD_REQUEST,
    313                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    314                                        "Too many provider public keys");
    315   }
    316 
    317   /* set number of participants */
    318   dc->num_of_participants = json_array_size (json_ppk);
    319 
    320   /* validate provider_index, threshold and num_of_participants */
    321   if (GNUNET_OK != FROST_validate_dkg_params (dc->provider_index,
    322                                               dc->threshold,
    323                                               dc->num_of_participants))
    324   {
    325     GNUNET_JSON_parse_free (spec);
    326     GNUNET_break_op (0);
    327     return TALER_MHD_reply_with_error (connection,
    328                                        MHD_HTTP_BAD_REQUEST,
    329                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    330                                        "Protocol parameters out of bound");
    331   }
    332 
    333   /* Check if called id is matching the send data */
    334   if (GNUNET_OK != FROSIX_dkg_validate_request_id_ (&dc->request_id,
    335                                                     &dc->context_string,
    336                                                     &dc->auth_hash,
    337                                                     &dc->provider_salt,
    338                                                     dc->provider_index,
    339                                                     dc->num_of_participants,
    340                                                     dc->threshold))
    341   {
    342     GNUNET_JSON_parse_free (spec);
    343     GNUNET_break_op (0);
    344     return TALER_MHD_reply_with_error (connection,
    345                                        MHD_HTTP_BAD_REQUEST,
    346                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    347                                        "Unable to validate request ID");
    348   }
    349 
    350   /* parse provider public keys */
    351   struct GNUNET_CRYPTO_EddsaPublicKey
    352     providers_public_keys[dc->num_of_participants];
    353   for (unsigned int i = 0; i < dc->num_of_participants; i++)
    354   {
    355     struct GNUNET_JSON_Specification ppk_spec[] = {
    356       GNUNET_JSON_spec_fixed_auto (NULL,
    357                                    &providers_public_keys[i]),
    358       GNUNET_JSON_spec_end ()
    359     };
    360 
    361     res = TALER_MHD_parse_json_array (connection,
    362                                       json_ppk,
    363                                       ppk_spec,
    364                                       i,
    365                                       -1);
    366 
    367     if (GNUNET_SYSERR == res)
    368     {
    369       GNUNET_JSON_parse_free (spec);
    370       GNUNET_JSON_parse_free (ppk_spec);
    371       GNUNET_break (0);
    372       return MHD_NO;
    373     }
    374     if (GNUNET_NO == res)
    375     {
    376       GNUNET_JSON_parse_free (spec);
    377       GNUNET_JSON_parse_free (ppk_spec);
    378       GNUNET_break_op (0);
    379       return TALER_MHD_reply_with_error (connection,
    380                                          MHD_HTTP_BAD_REQUEST,
    381                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
    382                                          "Unable to parse request body");
    383     }
    384 
    385     GNUNET_JSON_parse_free (ppk_spec);
    386   }
    387 
    388   /* check if there are 'num_of_participants - 1' shares */
    389   if (dc->num_of_participants - 1 != json_array_size (shares))
    390   {
    391     GNUNET_break_op (0);
    392     GNUNET_JSON_parse_free (spec);
    393 
    394     return TALER_MHD_reply_with_error (connection,
    395                                        MHD_HTTP_BAD_REQUEST,
    396                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    397                                        "Number of shares not matching");
    398   }
    399 
    400   share_n_comm_length = dc->num_of_participants - 1;
    401 
    402   /* initialize shares and commitments */
    403   struct FROST_DkgShare dkg_shares[dc->num_of_participants];
    404   struct FROST_DkgCommitment dkg_commitments[dc->num_of_participants];
    405 
    406   {
    407     /* parse all shares */
    408     struct FROSIX_EncryptedShareP enc_shares[share_n_comm_length];
    409     struct GNUNET_CRYPTO_EcdhePublicKey pub_enc_keys[share_n_comm_length];
    410 
    411     unsigned int pi_counter = 0;
    412     for (int i = 0; i < share_n_comm_length; i++)
    413     {
    414       if (dc->provider_index - 1 == pi_counter)
    415         pi_counter++;
    416 
    417       struct GNUNET_JSON_Specification share_spec[] = {
    418         GNUNET_JSON_spec_uint8 ("provider_index",
    419                                 &dkg_shares[pi_counter].identifier),
    420         GNUNET_JSON_spec_fixed_auto ("secret_share",
    421                                      &enc_shares[i]),
    422         GNUNET_JSON_spec_fixed_auto ("ephemeral_key",
    423                                      &pub_enc_keys[i]),
    424         GNUNET_JSON_spec_end ()
    425       };
    426 
    427       res = TALER_MHD_parse_json_array (connection,
    428                                         shares,
    429                                         share_spec,
    430                                         i,
    431                                         -1);
    432 
    433       if (GNUNET_SYSERR == res)
    434       {
    435         GNUNET_JSON_parse_free (spec);
    436         GNUNET_JSON_parse_free (share_spec);
    437         GNUNET_break (0);
    438         return MHD_NO;
    439       }
    440       if (GNUNET_NO == res)
    441       {
    442         GNUNET_JSON_parse_free (spec);
    443         GNUNET_JSON_parse_free (share_spec);
    444         GNUNET_break_op (0);
    445         return TALER_MHD_reply_with_error (connection,
    446                                            MHD_HTTP_BAD_REQUEST,
    447                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    448                                            "Unable to parse request body");
    449       }
    450 
    451       /* free json spec */
    452       GNUNET_JSON_parse_free (share_spec);
    453 
    454       pi_counter++;
    455     }
    456 
    457     /* free json spec */
    458     GNUNET_JSON_parse_free (spec);
    459 
    460     /* get commitments from db */
    461     {
    462       struct FROSIX_DkgCommitmentsRaw commits;
    463       commits.length = (sizeof (dc->provider_index)
    464                         + (sizeof (struct FROST_Point)
    465                            * dc->threshold))
    466                        * (share_n_comm_length);
    467 
    468       enum GNUNET_DB_QueryStatus qs;
    469       qs = db->get_dkg_commitment (db->cls,
    470                                    &dc->request_id,
    471                                    &commits);
    472 
    473       switch (qs)
    474       {
    475       case GNUNET_DB_STATUS_HARD_ERROR:
    476       case GNUNET_DB_STATUS_SOFT_ERROR:
    477       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    478         GNUNET_break (0);
    479         return TALER_MHD_reply_with_error (connection,
    480                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    481                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    482                                            "get_dkg_commitments");
    483       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    484         break;
    485       }
    486 
    487       // FIXME: check how many bytes we got from the db
    488 
    489       /* parse result to struct */
    490       for (int i = 0; i < dc->num_of_participants; i++)
    491       {
    492         if (GNUNET_OK != FROST_initialize_dkg_commitment (&dkg_commitments[i],
    493                                                           dc->provider_index,
    494                                                           dc->threshold))
    495         {
    496           FROST_free_dkg_commitment (dkg_commitments,
    497                                      dc->num_of_participants);
    498           GNUNET_break (0);
    499           return TALER_MHD_reply_with_error (connection,
    500                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    501                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
    502                                              "Initialize DKG commitment");
    503         }
    504       }
    505 
    506       unsigned int offset = 0;
    507       unsigned int comm_counter = 0;
    508       for (uint8_t i = 0; i < share_n_comm_length; i++)
    509       {
    510         if (dc->provider_index - 1 == comm_counter)
    511           comm_counter++;
    512 
    513         memcpy (&dkg_commitments[comm_counter].identifier,
    514                 (char *) commits.ptr_commits + offset,
    515                 1);
    516         offset += 1;
    517 
    518         for (int j = 0; j < dc->threshold; j++)
    519         {
    520           memcpy (&dkg_commitments[comm_counter].share_comm[j].sc.xcoord,
    521                   (char *) commits.ptr_commits + offset,
    522                   sizeof (struct FROST_Point));
    523           offset += sizeof (struct FROST_Point);
    524         }
    525 
    526         dkg_commitments[comm_counter].shares_commitments_length = dc->threshold;
    527 
    528         comm_counter++;
    529       }
    530     }
    531 
    532 
    533     /* check if shares are valid */
    534     unsigned int share_counter = 0;
    535     for (int i = 0; i < share_n_comm_length; i++)
    536     {
    537       if (dc->provider_index - 1 == i)
    538         share_counter++;
    539 
    540       /* get key material */
    541       struct GNUNET_HashCode key_material;
    542       if (GNUNET_OK != GNUNET_CRYPTO_eddsa_ecdh (&dc->priv_sig_key,
    543                                                  &pub_enc_keys[i],
    544                                                  &key_material))
    545       {
    546         GNUNET_break_op (0);
    547         FROST_free_dkg_commitment (dkg_commitments,
    548                                    dc->num_of_participants);
    549         return TALER_MHD_reply_with_error (connection,
    550                                            MHD_HTTP_BAD_REQUEST,
    551                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    552                                            "Unable to compute encryption key");
    553       }
    554 
    555       /* derive key */
    556       struct GNUNET_CRYPTO_SymmetricSessionKey sym_key;
    557       struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
    558       GNUNET_CRYPTO_hash_to_aes_key (&key_material,
    559                                      &sym_key,
    560                                      &iv);
    561 
    562       /* decrypt share */
    563       ssize_t len = GNUNET_CRYPTO_symmetric_decrypt (&enc_shares[i],
    564                                                      sizeof (enc_shares[i]),
    565                                                      &sym_key,
    566                                                      &iv,
    567                                                      &dkg_shares[share_counter].
    568                                                      share);
    569 
    570       if ( -1 == len || sizeof (dkg_shares[share_counter].share) != len)
    571       {
    572         GNUNET_break_op (0);
    573         FROST_free_dkg_commitment (dkg_commitments,
    574                                    dc->num_of_participants);
    575         return TALER_MHD_reply_with_error (connection,
    576                                            MHD_HTTP_BAD_REQUEST,
    577                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    578                                            "Unable to decrypt encrypted share");
    579       }
    580 
    581       if (GNUNET_OK != FROST_keygen_validate_share (
    582             &dkg_commitments[share_counter],
    583             &dkg_shares[share_counter],
    584             dc->provider_index))
    585       {
    586         GNUNET_break_op (0);
    587         FROST_free_dkg_commitment (dkg_commitments,
    588                                    dc->num_of_participants);
    589         return TALER_MHD_reply_with_error (connection,
    590                                            MHD_HTTP_BAD_REQUEST,
    591                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    592                                            "Unable to validate share");
    593       }
    594       share_counter++;
    595     }
    596   }
    597 
    598   /* derive the final context string */
    599   struct FROST_DkgContextString cs_h;
    600   if (GNUNET_YES != FROSIX_dkg_derive_context_string_ (
    601         &cs_h,
    602         dc->provider_index,
    603         dc->threshold,
    604         &dc->context_string,
    605         &dc->auth_hash,
    606         providers_public_keys,
    607         dc->num_of_participants,
    608         &dc->secret_provider_salt))
    609   {
    610     GNUNET_break (0);
    611     return TALER_MHD_reply_with_error (connection,
    612                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    613                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    614                                        "Derive context string");
    615   }
    616 
    617   /* calculate own commitment and share */
    618   if (GNUNET_OK != FROSIX_dkg_commitment_generate_ (
    619         &dkg_commitments[dc->provider_index - 1],
    620         &cs_h,
    621         NULL,
    622         dc->provider_index,
    623         dc->threshold,
    624         dc->num_of_participants))
    625   {
    626     FROST_free_dkg_commitment (dkg_commitments,
    627                                dc->num_of_participants);
    628     GNUNET_break (0);
    629     return TALER_MHD_reply_with_error (connection,
    630                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    631                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    632                                        "Generate DKG commitment");
    633   }
    634 
    635   struct FROST_DkgShare my_shares[dc->num_of_participants];
    636   if (GNUNET_OK != FROSIX_dkg_shares_generate_ (
    637         my_shares,
    638         &cs_h,
    639         NULL,
    640         dc->provider_index,
    641         dc->threshold,
    642         dc->num_of_participants))
    643   {
    644     FROST_free_dkg_commitment (dkg_commitments,
    645                                dc->num_of_participants);
    646     GNUNET_break (0);
    647     return TALER_MHD_reply_with_error (connection,
    648                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    649                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    650                                        "Generate DKG shares");
    651   }
    652 
    653   /* calculate key share */
    654   struct FROST_KeyPair key_pair;
    655   generate_key_pair (&key_pair,
    656                      dkg_shares,
    657                      my_shares,
    658                      dkg_commitments,
    659                      dc->provider_index,
    660                      dc->threshold,
    661                      dc->num_of_participants);
    662 
    663   /* free initialized memory */
    664   FROST_free_dkg_commitment (dkg_commitments,
    665                              dc->num_of_participants);
    666 
    667   /* Derive symmetric key */
    668   struct FROSIX_EncryptionKey encryption_key;
    669   if (GNUNET_OK != derive_encryption_key (&encryption_key,
    670                                           &dc->pre_enc_key,
    671                                           &key_pair.group_pk,
    672                                           &dc->provider_salt,
    673                                           dc->provider_index))
    674   {
    675     GNUNET_break (0);
    676     return TALER_MHD_reply_with_error (connection,
    677                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    678                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    679                                        "Derive encryption key");
    680   }
    681 
    682   /* check if key is already stored */
    683   /* hash encryption key */
    684   struct FROST_HashCode enc_key_hash;
    685   FROSIX_hash_encryption_key (&enc_key_hash,
    686                               &encryption_key);
    687 
    688   enum GNUNET_DB_QueryStatus qs;
    689   qs = db->lookup_key (db->cls,
    690                        &enc_key_hash);
    691 
    692   switch (qs)
    693   {
    694   case GNUNET_DB_STATUS_HARD_ERROR:
    695   case GNUNET_DB_STATUS_SOFT_ERROR:
    696     GNUNET_break (0);
    697     return TALER_MHD_reply_with_error (connection,
    698                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    699                                        TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
    700                                        "lookup key");
    701   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    702     /* store key data */
    703     MHD_RESULT mhd_res;
    704     mhd_res = store_key_data (dc,
    705                               &enc_key_hash,
    706                               &encryption_key,
    707                               &key_pair);
    708     if (MHD_HTTP_OK != mhd_res)
    709     {
    710       return mhd_res;
    711     }
    712     break;
    713   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    714     // key is already stored - go ahead
    715     break;
    716   }
    717 
    718   // Sign data
    719   struct FROSIX_DkgKeySignaturePS ks = {
    720     .purpose.purpose = htonl (104),
    721     .purpose.size = htonl (sizeof (ks)),
    722     .public_key = key_pair.group_pk,
    723     .auth_hash = dc->auth_hash,
    724   };
    725 
    726   struct GNUNET_CRYPTO_EddsaSignature sig;
    727   GNUNET_CRYPTO_eddsa_sign (priv_sig_key,
    728                             &ks,
    729                             &sig);
    730 
    731   return TALER_MHD_REPLY_JSON_PACK (
    732     connection,
    733     MHD_HTTP_OK,
    734     GNUNET_JSON_pack_data_auto ("public_key",
    735                                 &key_pair.group_pk),
    736     GNUNET_JSON_pack_data_auto ("signature",
    737                                 &sig));
    738 }