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