/ src / toprf.h
toprf.h
  1  #ifndef TOPRF_H
  2  #define TOPRF_H
  3  
  4  /**
  5   * @file toprf.h
  6   * @brief API for the Threshold Oblivious Pseudorandom Function (TOPRF)
  7   *        implementation
  8   * 
  9   * SPDX-FileCopyrightText: 2023, Marsiske Stefan
 10   * SPDX-License-Identifier: LGPL-3.0-or-later
 11   *
 12   * This file defines the structures, types, and functions for implementing
 13   * a Threshold Oblivious Pseudorandom Function (TOPRF) based on the
 14   * paper section 3 of the paper:
 15   * "TOPPSS: Cost-minimal Password-Protected Secret Sharing based on
 16   * Threshold OPRF" by Stanislaw Jarecki, Aggelos Kiayias, Hugo Krawczyk,
 17   * and Jiayu Xu, 2017 (https://eprint.iacr.org/2017/363)
 18   */
 19  
 20  #include <sodium.h>
 21  #include <stdint.h>
 22  
 23  /**
 24   * @struct TOPRF_Share
 25   * @brief Share structure for TOPRF
 26   */
 27  typedef struct
 28  {
 29    uint8_t index;
 30    uint8_t value[crypto_core_ristretto255_SCALARBYTES];
 31  } __attribute((packed)) TOPRF_Share;
 32  
 33  #define TOPRF_Share_BYTES (sizeof(TOPRF_Share))
 34  #define TOPRF_Part_BYTES (crypto_core_ristretto255_BYTES + 1UL)
 35  
 36  /**
 37   * @brief Interpolates a polynomial of degree `t` at an arbitrary point
 38   *        `x: y = f(x)`
 39   *
 40   * Uses Lagrange interpolation to reconstruct the polynomial value at `x`,
 41   * given `t` shares (evaluations) of the polynomial.
 42   *
 43   * @param[in] x The value at which the polynomial is evaluated
 44   * @param[in] t The degree of the polynomial
 45   * @param[in] shares Evaluated points on the polynomial.
 46   * @param[out] y Output buffer to store the computed result, `f(x)`
 47   */
 48  void interpolate(const uint8_t x, const uint8_t t, const TOPRF_Share shares[t], uint8_t y[crypto_scalarmult_ristretto255_SCALARBYTES]);
 49  
 50  /**
 51   * @brief Computes the Lagrange coefficient for `f(x)`
 52   *
 53   * This function calculates a Lagrange coefficient for `f(x)`
 54   * based on the index and the indices of the other contributing peers
 55   *
 56   * @param[in] index The index of the peer for which the Lagrange coefficient
 57   *            is being calculated
 58   * @param[in] x The evaluation point for the polynomial
 59   * @param[in] degree Total number of shares participating (number of peers)
 60   * @param[in] peers Array of indices of all participating peers that
 61   *            contribute to the reconstruction
 62   * @param[out] result Output buffer to store the computed Lagrange
 63   *             coefficient
 64   */
 65  
 66  void lcoeff(const uint8_t index, const uint8_t x, const size_t degree, const uint8_t peers[degree], uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES]);
 67  
 68  /**
 69   * @brief Computes the Lagrange coefficient for `f(0)
 70   *
 71   * This function calculates a lagrange coefficient for `f(0)` based on
 72   * the index and the indices of the other contributing peers
 73   *
 74   * @param[in] index The index of the peer for which the Lagrange coefficient
 75   *            is being calculated
 76   * @param[in] peers_len Total number of shares in the peers
 77   * @param[in] peers Shares that contribute to the reconstruction
 78   * @param[out] result Output buffer to store the computed Lagrange
 79   *             coefficient
 80   */
 81  void coeff(const uint8_t index, const size_t peers_len, const uint8_t peers[peers_len], uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES]);
 82  
 83  /**
 84   * @brief Splits a secret into `n` shares using Shamir's secret sharing over
 85   *        the curve Ristretto255
 86   *
 87   * The secret is shared in a (threshold, n) scheme: any threshold number
 88   * of shares can reconstruct the secret, but fewer reveal nothing.
 89   * This function wraps `lcoeff()`, allowing to recover the shared
 90   * secret without providing `x=0` as a parameter. This is mostly for
 91   * backward compatibility.
 92   *
 93   * @param[in] secret The scalar value to be secretly shared
 94   * @param[in] n The number of shares created
 95   * @param[in] threshold Minimum number of shares required to reconstruct
 96   *            the secret
 97   * @param[out] shares Output buffer receiving `n` generated shares
 98   *
 99   * @return 0 on success, non-zero on failure
100   */
101  void toprf_create_shares(const uint8_t secret[crypto_core_ristretto255_SCALARBYTES],
102                           const uint8_t n,
103                           const uint8_t threshold,
104                           uint8_t shares[n][TOPRF_Share_BYTES]);
105  
106  /**
107   * @brief Combines shares in the exponent using Lagrange interpolation over
108   *        the curve Ristretto255
109   *
110   * This function combines a threshold number of shares to recover the secret
111   * in the exponent. It uses Lagrange interpolation over the curve
112   * Ristretto255.
113   * The peers are unaware of whether they participate in threshold or
114   * standalone mode. Their computation remains the same in both cases.
115   *
116   * @param[in] response_len Number of elements in the `responses` array
117   * @param[in] responses Array of shares to be combined
118   * @param[out] result  Output buffer receiving the reconstructed secret
119   *
120   * @return 0 on success, non-zero on error
121   */
122  int toprf_thresholdmult(const size_t response_len,
123                          const uint8_t responses[response_len][TOPRF_Part_BYTES],
124                          uint8_t result[crypto_scalarmult_ristretto255_BYTES]);
125  
126  /**
127   * @brief Efficiently evaluates a blinded input using the private key
128   *        in a threshold setting
129   *
130   * This function is the efficient threshold version of `oprf_Evaluate()`
131   * defined in oprf.h.
132   * It needs to know in advance the indices of all shares that will be
133   * combined later in the `toprf_thresholdcombine()` function. This
134   * precomputation reduces the total costs and distributes them to the peers
135   *
136   * @param[in] k The server's secret key share. For OPAQUE, this is kU, the
137   *            user's OPRF private key
138   * @param[in] blinded Serialized OPRF group element, an output of
139   *            `oprf_Blind()`. For OPAQUE, this is the blinded user's
140   *             password, pwdU
141   * @param[in] self The index of the current peer
142   * @param[in] indexes Array of indices of all peers contributing to this
143   *            OPRF evaluation
144   * @param[in] index_len Number of participating peers (Length of `indexes`)
145   * @param[out] Z Serialized OPRF group element, used as input to
146   *            `oprf_Unblind()`
147   *
148   * @return 0 on success, non-zero on error
149   */
150  int toprf_Evaluate(const uint8_t k[TOPRF_Share_BYTES],
151                     const uint8_t blinded[crypto_core_ristretto255_BYTES],
152                     const uint8_t self, const uint8_t *indexes, const uint16_t index_len,
153                     uint8_t Z[TOPRF_Part_BYTES]);
154  
155  /**
156   * @brief Combines the partial results to reconstruct the final OPRF output
157   *
158   * This function is combines the results of the `toprf_Evaluate()` to recover
159   * the shared secret in the exponent.
160  
161   * @param[in] response_len Number of elements in the `responses` array
162   * @param[in] responses Array of shares to be combined
163   * @param[out] result  Output buffer receiving the reconstructed secret
164   *
165   * @return 0 on success, non-zero on error
166   */
167  int toprf_thresholdcombine(const size_t response_len,
168                             const uint8_t _responses[response_len][TOPRF_Part_BYTES],
169                             uint8_t result[crypto_scalarmult_ristretto255_BYTES]);
170  
171  typedef int (*toprf_evalcb)(void *ctx,
172                              const uint8_t k[crypto_core_ristretto255_SCALARBYTES],
173                              const uint8_t alpha[crypto_core_ristretto255_BYTES],
174                              uint8_t beta[crypto_core_ristretto255_BYTES]);
175  
176  typedef int (*toprf_keygencb)(void *ctx, uint8_t k[crypto_core_ristretto255_SCALARBYTES]);
177  
178  /**
179   * @brief Implements the 3HashTDH protocol
180   *
181   * This function implements the 3HashTDH protocol from the paper:
182   * "Threshold PAKE with Security against Compromise of All Servers"
183   * (https://eprint.iacr.org/2024/1455) by Gu, Jarecki, Kedzior,
184   * Nazarian, Xu.
185   *
186   * Use this function to implement a threshold OPRF.
187   *
188   * @param[in] k A share of the secret key
189   * @param[in] z A random zero-sharing of the secret key. This is a share of
190   *            a random `t`-degree polynomial that evaluates to zero, where t
191   *            is the threshold
192   * @param[in] alpha The blinded element from the client
193   * @param[in] ssid_S A session-specific identifier that all participants in
194   *            the threshold evaluation must agree on (it must be the same
195   *            for all participants)
196   * @param[in] ssid_S_len Length of the `ssid_S` identifier
197   * @param[out] beta Output buffer containing the result of evaluation, to
198   *             be returned to the client
199   *
200   * @return 0 on success, non-zero on error
201   */
202  int toprf_3hashtdh(const uint8_t k[TOPRF_Share_BYTES],
203                     const uint8_t z[TOPRF_Share_BYTES],
204                     const uint8_t alpha[crypto_core_ristretto255_BYTES],
205                     const uint8_t *ssid_S, const uint16_t ssid_S_len,
206                     uint8_t beta[TOPRF_Part_BYTES]);
207  
208  #endif // TOPRF_H