frosix

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

frost_high.h (11192B)


      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 include/frost_high.h
     18  * @brief frosix high level api to create a signature share
     19  * @author Joel Urech
     20 */
     21 #ifndef FROST_HIGH_H
     22 #define FROST_HIGH_H
     23 
     24 #include "frost_low.h"
     25 #include <gnunet/gnunet_util_lib.h>
     26 
     27 /**
     28  * Representation of the PUBLIC KEY
     29  */
     30 struct FROST_PublicKey
     31 {
     32   /**
     33    * Our public key is an element on the elliptic curve.
     34    */
     35   struct FROST_Point pk;
     36 };
     37 
     38 /**
     39  * Representation of the KEY MATERIAL every participant needs in order to
     40  * create a partial signature.
     41  * Gets generated in a key generation process.
     42  */
     43 struct FROST_KeyPair
     44 {
     45   /**
     46    * Unique identifier of the participant, must be greater than 0 and less
     47    * than 255.
     48   */
     49   uint8_t identifier;
     50   /**
     51    * The secret key of the participant, a scalar in the range of the elliptic
     52    * curve.
     53   */
     54   struct FROST_Scalar my_sk;
     55   /**
     56    * Public key matching the secret key above, as an element on the elliptic
     57    * curve.
     58   */
     59   struct FROST_Point my_pk;
     60   /**
     61    * Public key to identify the group and to verify the final signatures.
     62   */
     63   struct FROST_PublicKey group_pk;
     64 };
     65 
     66 /**
     67  * Representation of a HASH over an arbitrary long message.
     68  */
     69 struct FROST_MessageHash
     70 {
     71   /**
     72    * The hash of our message.
     73    */
     74   struct FROST_HashCode hash;
     75 };
     76 
     77 /**
     78  * Representation of a NONCE generated by each participant in 'Round 1'.
     79  */
     80 struct FROST_Nonce
     81 {
     82   /**
     83    * Secret hiding or blinding value, a random scalar in the range of the elliptic
     84    * curve.
     85    */
     86   struct FROST_Scalar hiding_nonce;
     87   /**
     88    * Secret binding value, a random scalar in the range of the elliptic curve.
     89    */
     90   struct FROST_Scalar binding_nonce;
     91 };
     92 
     93 /**
     94  * Representation of a COMMITMENT generated by each participant in 'Round 1'.
     95  */
     96 struct FROST_Commitment
     97 {
     98   /**
     99    * ID of the participant issuing the commitment.
    100    */
    101   uint8_t identifier;
    102   /**
    103    * Public hiding or blinding value, an element on the elliptic curve.
    104    */
    105   struct FROST_Point hiding_commitment;
    106   /**
    107    * Public binding value, an element on the elliptic curve.
    108    */
    109   struct FROST_Point binding_commitment;
    110 };
    111 
    112 /**
    113  * Representation of a PARTIAL SIGNATURE.
    114  */
    115 struct FROST_SignatureShare
    116 {
    117   /**
    118    * Not sure if needed...
    119    */
    120   uint8_t identifier;
    121   /**
    122    * The resulting signature share, a scalar in the range of the elliptic
    123    * curve.
    124    */
    125   struct FROST_Scalar sig_share;
    126   /**
    127    * The partial public key for convenience only.
    128    * Otherwise the 'SA' has to compute each partial public key to verify the
    129    * partial signature.
    130    */
    131   struct FROST_Point pk_i;
    132 };
    133 
    134 
    135 /**
    136  * Representation of a Schnorr SIGNATURE
    137  */
    138 struct FROST_Signature
    139 {
    140   /**
    141    * The 'R' value aka group commitment, as an element on the elliptic curve.
    142    */
    143   struct FROST_Point r;
    144   /**
    145    * The aggregation of all partial signatures, a scalar in the range of the
    146    * elliptic curve.
    147    * This is the 's' value in a EdDSA signature scheme.
    148    */
    149   struct FROST_Scalar z;
    150 };
    151 
    152 
    153 /**
    154  * High entropy value to seed the nonce generation function.
    155  * If this value gets reused, an attack on the private key is possible!
    156 */
    157 struct FROST_CommitmentSeed
    158 {
    159   /**
    160    * The seed is instantiated as a random scalar value from the group.
    161   */
    162   struct FROST_Scalar scal;
    163 };
    164 
    165 /**
    166  * Initializes the underlying libsodium library.Always call this function
    167  * first, before using libfrost!
    168  *
    169  * @result Returns 0 on success, -1 on failure and 1 if the library had already
    170  * been initialized.
    171 */
    172 int
    173 FROST_init (void);
    174 
    175 /**
    176  * @brief Before a user can start a signing process, he has to convert a message,
    177  * an arbitrary amount of data, into a hash value that we can use.
    178  *
    179  * @param[out] message_hash The resulting hash
    180  * @param[in] msg The real message, a pointer to an abritrary long datablock
    181  * @param msg_len Nmber of bytes, the length, of the given datablock
    182  */
    183 void
    184 FROST_message_to_hash (struct FROST_MessageHash *message_hash,
    185                        const void *msg,
    186                        size_t msg_len);
    187 
    188 
    189 /**
    190  * Generates a high entropy and unpredictable random value
    191  * in the range of [0..L[.  * L is the order of the ristretto255 group.
    192  * Take care if application runs as a VM, can produce same output if
    193  * snapshotted and restored!
    194  *
    195  * @param[out] seed The returning random and therefore unpredictable bytes.
    196 */
    197 void
    198 FROST_get_random_seed (struct FROST_CommitmentSeed *seed);
    199 
    200 /**
    201  * @brief The Signature Aggregator 'SA' (normally the user) chooses 't' (t = threshold) random participants
    202  * out of all available participants and asks them to send him a commitment.
    203  * This function generates a secret nonce- and a public commitment value.
    204  *
    205  * @param[out] nonce The resulting secret nonce, which we will use in 'Round 2'
    206  * @param[out] commitment The resulting public commitment, which we send back to the 'SA'
    207  * @param[in] message_hash Hash of the message to sign. Is part of the commitment
    208  * @param[in] seed A high entropy random seed to generate the commitment from.
    209  * DO NOT USE TWICE!
    210  */
    211 void
    212 FROST_generate_nonce_and_commitment (struct FROST_Nonce *nonce,
    213                                      struct FROST_Commitment *commitment,
    214                                      const struct
    215                                      FROST_MessageHash *message_hash,
    216                                      const struct FROST_CommitmentSeed *seed);
    217 
    218 /**
    219  * @brief The 'SA' constructs a sorted list out of all commitments and send this commitment list together with the message hash to each chosen participant.
    220  * Every participant has to verify for each of the received commitments if they are actually two valid encoded points on the curve.
    221  * If the validation fails, abort the signature process and return to the 'SA' which of the commitment has failed.
    222  *
    223  * @param[in] commitment A single commitment to validate
    224  * @return GNUNET_OK if everything is ok, otherwise GNUNET_NO. Abort the signing process in case its not 1!
    225  */
    226 enum GNUNET_GenericReturnValue
    227 FROST_validate_commitment (
    228   const struct FROST_Commitment *commitment);
    229 
    230 
    231 /**
    232  * @brief If the validation has not failed, compute a signature share for the given message hash.
    233  *
    234  * Secret key share of participant: \f$s_i\f$
    235  * Nonce of participant: \f$(d_i, e_i)\f$
    236  * Lagrange coefficient of participant: \f$\lambda_i\f$
    237  * Compute binding value of each participant:
    238  * \f$p_i = H(i || m || B)\f$
    239  * Compute group commitment:
    240  * \f$R_i = D_i(E_i)^{p_i}\f$
    241  * \f$R = \prod R_i\f$
    242  * Compute challenge:
    243  * \f$c = H(R || pk || m)\f$
    244  * Compute signature share:
    245  * \f$z_i = d_i + (e_i \cdot p_i)\lambda_is_ic\f$
    246  *
    247  * @param[out] signature_share The resulting signature share. We have to return this data back to the 'SA' (\f$(z_i,pk_i)\f$)
    248  * @param[in] message_hash Our message we want to sign (\f$m\f$)
    249  * @param[in] commitments List of all commitments, the order of the elements is crucial! (\f$B\f$)
    250  * @param commitments_len Number of commitments, usually corresponds to the number of participants
    251  * @param my_key_pair Our key material, which was generated by a preliminary key generation process
    252  * @param my_nonce Our secret random value, matching our commitment that we sent previously to the 'SA'
    253  * @return #GNUNET_OK
    254  *         #GNUNET_NO
    255  */
    256 enum GNUNET_GenericReturnValue
    257 FROST_sign_message_hash (struct FROST_SignatureShare *signature_share,
    258                          const struct FROST_MessageHash *message_hash,
    259                          const struct FROST_Commitment commitments[],
    260                          size_t commitments_len,
    261                          const struct FROST_KeyPair *my_key_pair,
    262                          const struct FROST_Nonce *my_nonce);
    263 
    264 /**
    265  * @brief Gives the 'SA' the possibility to verify each received signature share
    266  * against the commitment from round 1.
    267  *
    268  * Compute binding value of each participant:
    269  * \f$p_i = H(i || m || B)\f$
    270  * Compute group commitment:
    271  * \f$R_i = D_i(E_i)^{p_i}\f$
    272  * \f$R = \prod R_i\f$
    273  * Compute challenge:
    274  * \f$c = H(R || pk || m)\f$
    275  * Lagrange coefficient of participant: \f$\lambda_i\f$
    276  * Verify signature share:
    277  * \f$g^{z_i} = R_ipk^{c\lambda_i}\f$ ?
    278  *
    279  * @param[in] commitment_i The commitment that the participant 'i' has previously sent (\f$(D_i, E_i)\f$)
    280  * @param[in] signature_share_i The partial signature of the participant 'i' to be verified (\f$z_i\f$)
    281  * @param[in] commitments List of all commitments. The order of the elements is crucial! (\f$B\f$)
    282  * @param commitments_len Number of commitments, usually corresponds to the number of participants
    283  * @param[in] public_key Group public key is needed to compute the group challenge (\f$pk\f$)
    284  * @param[in] message_hash The hashed message (\f$m\f$)
    285  * @return GNUNET_OK or GNUNET_NO. Abort the signing process in case its not GNUNET_OK!
    286  */
    287 enum GNUNET_GenericReturnValue
    288 FROST_verify_signature_share (const struct FROST_Commitment *commitment_i,
    289                               const struct FROST_SignatureShare
    290                               *signature_share_i,
    291                               const struct FROST_Commitment commitments[],
    292                               uint8_t commitments_len,
    293                               const struct FROST_PublicKey *public_key,
    294                               const struct FROST_MessageHash *message_hash);
    295 
    296 /**
    297  * @brief Aggregates the signature shares from all participants, computes the group commitment aka 'R' value
    298  * and returns the final signature over the given message.
    299  * Sum all singature shares:
    300  * \f$z = \sum z_i\f$
    301  * Compute binding value of each participant:
    302  * \f$p_i = H(i || m || B)\f$
    303  * Compute group commitment:
    304  * \f$R_i = D_i(E_i)^{p_i}\f$
    305  * \f$R = \prod R_i\f$
    306  * Resulting signature:
    307  * \f$sig = (R, z)\f$
    308  *
    309  * @param[out] signature The resulting signature of the given message (\f$sig = (R, z)\f$)
    310  * @param[in] commitments List of all commitments. The order of the elements is crucial! (\f$B\f$)
    311  * @param[in] signature_shares List of all partial signatures. The sorting doesn't matter (\f$z_i\f$)
    312  * @param commitments_and_sig_shares_len Should correspond to the number of participants
    313  * @param[in] message_hash The hashed message as an element on the elliptic curve (\f$m\f$)
    314  */
    315 void
    316 FROST_compose_signature (struct FROST_Signature *signature,
    317                          const struct FROST_Commitment commitments[],
    318                          const struct FROST_SignatureShare
    319                          signature_shares[],
    320                          uint8_t commitments_and_sig_shares_len,
    321                          const struct FROST_MessageHash *message_hash);
    322 
    323 #endif