frosix

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

frosix-httpd_dkg-commitment.c (11688B)


      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_commitment.c
     18  * @brief functions to handle incoming requests on /dkg-commitment
     19  * @author Joel Urech
     20  */
     21 #include "frosix-httpd_dkg.h"
     22 #include "frosix-httpd.h"
     23 #include "frosix_service.h"
     24 #include "keygen.h"
     25 #include <taler/taler_util.h>
     26 #include <gnunet/gnunet_util_lib.h>
     27 
     28 #define HASHCONTEXT "FROSIX-DKG"
     29 
     30 /**
     31  * Context for an dkg commitment operation
     32 */
     33 struct DkgCommitmentContext
     34 {
     35   /**
     36    * Our unique identifier value in the dkg process.
     37   */
     38   uint8_t provider_index;
     39 
     40   /**
     41    * Number of providers which has to collaborate in order to generate a valid signature.
     42   */
     43   uint8_t threshold;
     44 
     45   /**
     46    * Total number of providers participating in the distributed key generation process.
     47   */
     48   uint8_t num_of_participants;
     49 
     50   /**
     51    * High entropy string, which should be only used for one distributed key generation process.
     52    * The resulting commitment will be deterministically derived from this context string.
     53   */
     54   struct FROSIX_DkgContextStringP context_string;
     55 
     56   /**
     57    * Salted hash of the chosen challenge method.
     58   */
     59   struct FROSIX_ChallengeHashP auth_hash;
     60 
     61   /**
     62    * Id of the request, hash of all submitted values.
     63   */
     64   struct FROSIX_DkgRequestIdP request_id;
     65 
     66   /**
     67    *
     68   */
     69   struct FROSIX_ProviderSaltP provider_salt;
     70 
     71   /**
     72    *
     73   */
     74   struct FROSIX_SecretProviderSaltP secret_provider_salt;
     75 
     76   /**
     77    *
     78   */
     79   struct GNUNET_CRYPTO_EddsaPublicKey pub_sig_key;
     80 
     81   /**
     82    *
     83   */
     84   struct GNUNET_CRYPTO_EddsaPrivateKey priv_sig_key;
     85 
     86   /**
     87    * Our handler context
     88   */
     89   struct TM_HandlerContext *hc;
     90 
     91   /**
     92    * Uploaded JSON data, NULL if upload is not yet complete.
     93   */
     94   json_t *json;
     95 
     96   /**
     97    * Post parser context.
     98    */
     99   void *post_ctx;
    100 
    101   /**
    102    * Connection handle for closing or resuming
    103    */
    104   struct MHD_Connection *connection;
    105 
    106   /**
    107    * When should this request time out?
    108   */
    109   struct GNUNET_TIME_Absolute timeout;
    110 
    111 };
    112 
    113 
    114 /**
    115  * Return the generated dkg_commitment
    116  *
    117  * @param connection
    118  * @param dkg_comm
    119  * @return
    120 */
    121 static MHD_RESULT
    122 return_dkg_commitment (
    123   struct MHD_Connection *connection,
    124   const struct GNUNET_CRYPTO_EddsaPublicKey *pub_sig_key,
    125   const struct FROST_DkgCommitment *dkg_comm)
    126 {
    127   // Prepare commit
    128   json_t *commits;
    129   commits = json_array ();
    130   GNUNET_assert (NULL != commits);
    131 
    132   for (int i = 0; i < dkg_comm->shares_commitments_length; i++)
    133   {
    134     GNUNET_assert (0 ==
    135                    json_array_append (
    136                      commits,
    137                      GNUNET_JSON_from_data_auto (&dkg_comm->share_comm[i])));
    138   }
    139 
    140   // Return everything
    141   return TALER_MHD_REPLY_JSON_PACK (
    142     connection,
    143     MHD_HTTP_CREATED,
    144     GNUNET_JSON_pack_uint64 ("provider_index",
    145                              dkg_comm->identifier),
    146     GNUNET_JSON_pack_array_steal ("dkg_commitment",
    147                                   commits),
    148     GNUNET_JSON_pack_data_auto ("zkp_r",
    149                                 &dkg_comm->zkp.r),
    150     GNUNET_JSON_pack_data_auto ("zkp_z",
    151                                 &dkg_comm->zkp.z),
    152     GNUNET_JSON_pack_data_auto ("public_key",
    153                                 pub_sig_key));
    154 }
    155 
    156 MHD_RESULT
    157 FH_handler_dkg_commitment_post (
    158   struct MHD_Connection *connection,
    159   struct TM_HandlerContext *hc,
    160   const struct FROSIX_DkgRequestIdP *dkg_id,
    161   const struct FROSIX_ProviderSaltP *provider_salt,
    162   const struct FROSIX_SecretProviderSaltP *secret_provider_salt,
    163   const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_sig_key,
    164   const struct GNUNET_CRYPTO_EddsaPublicKey *pub_sig_key,
    165   const char *dkg_commitment_data,
    166   size_t *dkg_commitment_data_size)
    167 {
    168   enum GNUNET_GenericReturnValue res;
    169   struct DkgCommitmentContext *dc = hc->ctx;
    170   json_t *json_ppk = NULL;
    171 
    172   if (NULL == dc)
    173   {
    174     dc = GNUNET_new (struct DkgCommitmentContext);
    175     dc->connection = connection;
    176     dc->request_id = *dkg_id;
    177     dc->provider_salt = *provider_salt;
    178     dc->secret_provider_salt = *secret_provider_salt;
    179     dc->priv_sig_key = *priv_sig_key;
    180     dc->pub_sig_key = *pub_sig_key;
    181     hc->ctx = dc;
    182   }
    183 
    184   /* parse request body */
    185   if (NULL == dc->json)
    186   {
    187     res = TALER_MHD_parse_post_json (connection,
    188                                      &dc->post_ctx,
    189                                      dkg_commitment_data,
    190                                      dkg_commitment_data_size,
    191                                      &dc->json);
    192     if (GNUNET_SYSERR == res)
    193     {
    194       GNUNET_break (0);
    195       return MHD_NO;
    196     }
    197     if ((GNUNET_NO == res ||
    198          (NULL == dc->json)))
    199     {
    200       return MHD_YES;
    201     }
    202   }
    203 
    204   struct GNUNET_JSON_Specification spec[] = {
    205     GNUNET_JSON_spec_uint8 ("provider_index",
    206                             &dc->provider_index),
    207     GNUNET_JSON_spec_uint8 ("threshold",
    208                             &dc->threshold),
    209     GNUNET_JSON_spec_fixed_auto ("context_string",
    210                                  &dc->context_string),
    211     GNUNET_JSON_spec_fixed_auto ("auth_hash",
    212                                  &dc->auth_hash),
    213     GNUNET_JSON_spec_json ("providers_public_keys",
    214                            &json_ppk),
    215     GNUNET_JSON_spec_end ()
    216   };
    217 
    218   res = TALER_MHD_parse_json_data (connection,
    219                                    dc->json,
    220                                    spec);
    221   if (GNUNET_SYSERR == res)
    222   {
    223     GNUNET_break_op (0);
    224     return TALER_MHD_reply_with_error (connection,
    225                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    226                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    227                                        "Unable to parse request body");
    228   }
    229   if (GNUNET_NO == res)
    230   {
    231     GNUNET_break_op (0);
    232     return TALER_MHD_reply_with_error (connection,
    233                                        MHD_HTTP_BAD_REQUEST,
    234                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    235                                        "Unable to parse request body");
    236   }
    237 
    238   /* check number of submitted provider public keys*/
    239   if (254 < json_array_size (json_ppk))
    240   {
    241     GNUNET_JSON_parse_free (spec);
    242     GNUNET_break_op (0);
    243     return TALER_MHD_reply_with_error (connection,
    244                                        MHD_HTTP_BAD_REQUEST,
    245                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    246                                        "Too many provider public keys");
    247   }
    248 
    249   /* set number of participants */
    250   dc->num_of_participants = json_array_size (json_ppk);
    251 
    252   /* validate provider index, threshold and num_of_participants */
    253   if (GNUNET_OK != FROST_validate_dkg_params (dc->provider_index,
    254                                               dc->threshold,
    255                                               dc->num_of_participants))
    256   {
    257     GNUNET_JSON_parse_free (spec);
    258     GNUNET_break_op (0);
    259     return TALER_MHD_reply_with_error (connection,
    260                                        MHD_HTTP_BAD_REQUEST,
    261                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    262                                        "Parameters out ouf bound");
    263   }
    264 
    265   /* Check if called id is matching the send data */
    266   if (GNUNET_OK != FROSIX_dkg_validate_request_id_ (
    267         &dc->request_id,
    268         &dc->context_string,
    269         &dc->auth_hash,
    270         &dc->provider_salt,
    271         dc->provider_index,
    272         dc->num_of_participants,
    273         dc->threshold))
    274   {
    275     GNUNET_JSON_parse_free (spec);
    276     GNUNET_break_op (0);
    277     return TALER_MHD_reply_with_error (connection,
    278                                        MHD_HTTP_BAD_REQUEST,
    279                                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    280                                        "ID in URL not matching data in body");
    281   }
    282 
    283   /* parse providers public keys */
    284   struct GNUNET_CRYPTO_EddsaPublicKey
    285     providers_public_keys[dc->num_of_participants];
    286   for (unsigned int i = 0; i < dc->num_of_participants; i++)
    287   {
    288     struct GNUNET_JSON_Specification ppk_spec[] = {
    289       GNUNET_JSON_spec_fixed_auto (NULL,
    290                                    &providers_public_keys[i]),
    291       GNUNET_JSON_spec_end ()
    292     };
    293 
    294     res = TALER_MHD_parse_json_array (connection,
    295                                       json_ppk,
    296                                       ppk_spec,
    297                                       i,
    298                                       -1);
    299 
    300     if (GNUNET_SYSERR == res)
    301     {
    302       GNUNET_JSON_parse_free (spec);
    303       GNUNET_JSON_parse_free (ppk_spec);
    304       GNUNET_break (0);
    305       return MHD_NO;
    306     }
    307     if (GNUNET_NO == res)
    308     {
    309       GNUNET_JSON_parse_free (spec);
    310       GNUNET_JSON_parse_free (ppk_spec);
    311       GNUNET_break_op (0);
    312       return TALER_MHD_reply_with_error (connection,
    313                                          MHD_HTTP_BAD_REQUEST,
    314                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
    315                                          "Unable to parse request body");
    316     }
    317 
    318     GNUNET_JSON_parse_free (ppk_spec);
    319   }
    320 
    321   GNUNET_JSON_parse_free (spec);
    322 
    323   /* FIXME: check if any of the submitted public key is ours */
    324 
    325   /* derive the final context string */
    326   struct FROST_DkgContextString cs_h;
    327   if (GNUNET_YES != FROSIX_dkg_derive_context_string_ (
    328         &cs_h,
    329         dc->provider_index,
    330         dc->threshold,
    331         &dc->context_string,
    332         &dc->auth_hash,
    333         providers_public_keys,
    334         dc->num_of_participants,
    335         &dc->secret_provider_salt))
    336   {
    337     GNUNET_break (0);
    338     return TALER_MHD_reply_with_error (connection,
    339                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    340                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    341                                        "Derive context string");
    342   }
    343 
    344   /* hash public key */
    345   struct FROST_HashState h_s;
    346   struct FROST_HashCode pub_key_hash;
    347   FROST_hash_init (&h_s);
    348   FROST_hash_fixed_update (&h_s,
    349                            &dc->pub_sig_key,
    350                            sizeof (dc->pub_sig_key));
    351   FROST_hash_final (&h_s,
    352                     &pub_key_hash);
    353 
    354   /* create shares with zkp including hashed pk */
    355   struct FROST_DkgCommitment dkg_commitment;
    356 
    357   if (GNUNET_OK != FROSIX_dkg_commitment_generate_ (&dkg_commitment,
    358                                                     &cs_h,
    359                                                     &pub_key_hash,
    360                                                     dc->provider_index,
    361                                                     dc->threshold,
    362                                                     dc->num_of_participants))
    363   {
    364     GNUNET_break (0);
    365     return TALER_MHD_reply_with_error (connection,
    366                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    367                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    368                                        "Generate DKG commitment");
    369   }
    370 
    371   res = return_dkg_commitment (connection,
    372                                &dc->pub_sig_key,
    373                                &dkg_commitment);
    374 
    375   FROST_free_dkg_commitment (&dkg_commitment,
    376                              1);
    377 
    378   return res;
    379 }