oprf.h
1 #ifndef oprf_h 2 #define oprf_h 3 4 /** 5 * @file oprf.h 6 * @brief API for Oblivious Pseudorandom Function (OPRF) implementation 7 * 8 * SPDX-FileCopyrightText: 2025, Marsiske Stefan 9 * SPDX-License-Identifier: LGPL-3.0-or-later 10 * 11 * This file provides the API for Oblivious Pseudorandom Functions (OPRFs) 12 * using the Ristretto255 group. It includes functions for key generation, 13 * blinding inputs, evaluating OPRFs, and unblinding results. 14 * 15 * This implementation is based on RFC 9497: Oblivious Pseudorandom 16 * Functions (OPRFs) Using Prime-Order Groups 17 * (https://www.rfc-editor.org/rfc/rfc9497.html). 18 * 19 * 20 * This implementation also uses hashing techniques as defined in 21 * RFC 9380: Hashing to Elliptic Curves 22 * (https://www.rfc-editor.org/rfc/rfc9380). 23 * 24 */ 25 26 #include <stdint.h> 27 #include <sodium.h> 28 #include "toprf.h" 29 30 #define OPRF_BYTES 64 31 32 /** 33 * @brief Generates an OPRF private key 34 * 35 * This is almost the `KeyGen` OPRF function defined in RFC 9497. 36 * Since this library does not implement Verfiable OPRF (VOPRF) 37 * functionality, no public key is needed, so steps related to that 38 * are omitted. 39 * 40 * @param[out] kU The per-user OPRF private key 41 */ 42 43 void oprf_KeyGen(uint8_t kU[crypto_core_ristretto255_SCALARBYTES]); 44 45 /** 46 * @brief Computes the final OPRF output 47 * 48 * Implements the `Finalize` OPRF function defined in RFC 9497. 49 * It hashes the input and the OPRF evaluation to produce the 50 * final output for the client. 51 * 52 * @param[in] x A value used to compute OPRF (the same value that 53 * was used as input to be blinded) 54 * @param[in] x_len Length of input x in bytes. 55 * @param[in] N Evaluated group element (output from `oprf_Unblind()`) 56 * @param[out] rwdU Output buffer for the OPRF result 57 */ 58 int oprf_Finalize(const uint8_t *x, const uint16_t x_len, 59 const uint8_t N[crypto_core_ristretto255_BYTES], 60 uint8_t rwdU[OPRF_BYTES]); 61 62 /** 63 * @brief Blinds an input value for OPRF evaluation 64 * 65 * Implements the `Blind` OPRF function defined in RFC 9497. 66 * This function converts the input into an OPRF group element and 67 * randomizes it with a scalar value `r`. Both the scalar and blinded 68 * element are returned. 69 * 70 * @param[in] x Input value to blind. E.g., the user's password in 71 * OPAQUE (pwdU) 72 * @param[in] x_len Length of the input value in bytes 73 * @param[out] r Random scalar used to blind the input 74 * @param[out] alpha Serialized OPRF group element, the blinded version 75 * of `x`, used as input to `oprf_Evaluate()` 76 * 77 * @return 0 on success, non-zero on error 78 */ 79 int oprf_Blind(const uint8_t *x, const uint16_t x_len, 80 uint8_t r[crypto_core_ristretto255_SCALARBYTES], 81 uint8_t alpha[crypto_core_ristretto255_BYTES]); 82 83 /** 84 * @brief Evaluates a blinded input using the OPRF private key 85 * 86 * Implements the `Evaluate` OPRF function defined in RFC 9497. 87 * This function is run by the server. It uses the server's private 88 * key `k` to evaluate the client's blinded input, producing a group 89 * element `beta` that the client can later unblind. 90 * 91 * @param[in] k OPRF private key E.g., the user's private key in OPAQUE 92 * (kU) 93 * @param[in] alpha Serialized OPRF group element, an output of 94 * `oprf_Blind()`. For OPAQUE, this is the blinded user's 95 * password, pwdU 96 * @param[out] beta Serialized OPRF group element, used as input to 97 * `oprf_Unblind()` 98 * 99 * @return 0 on success, non-zero on error 100 */ 101 int oprf_Evaluate(const uint8_t k[crypto_core_ristretto255_SCALARBYTES], 102 const uint8_t alpha[crypto_core_ristretto255_BYTES], 103 uint8_t beta[crypto_core_ristretto255_BYTES]); 104 105 /** 106 * @brief Unblinds an evaluated OPRF element 107 * 108 * Implements the `Unblind` OPRF function defined in RFC 9497. 109 * This function removes the random scalar `r` from the evaluated 110 * element `beta`, producing the unblinded output `N`. 111 * 112 * @param[in] r Scalar used to blind the input originally 113 * @param[in] beta OPRF evaluation result from the server, an output of 114 * `oprf_Evaluate()` 115 * @param[out] N Serialized OPRF group element with random scalar `r` 116 * remove, used as input to `oprf_Finalize()`. 117 * 118 * @return 0 on success, non-zero on error 119 */ 120 int oprf_Unblind(const uint8_t r[crypto_core_ristretto255_SCALARBYTES], 121 const uint8_t beta[crypto_core_ristretto255_BYTES], 122 uint8_t N[crypto_core_ristretto255_BYTES]); 123 124 /** 125 * @brief Hashes an input message to a point on the Ristretto255 curve 126 * 127 * Implements the `hash-to-curve` function defined in RFC 9380. 128 * This function is needed for the OPRF implementation. 129 * 130 * @param[in] msg Input message to hash to a Ristretto255 point 131 * @param[in] msg_len Length of the input message in bytes 132 * @param[out] p The resulting Ristretto255 point 133 * 134 * @return 0 on success, non-zero on error 135 */ 136 int voprf_hash_to_group(const uint8_t *msg, const uint16_t msg_len, uint8_t p[crypto_core_ristretto255_BYTES]); 137 138 /** 139 * @brief Expands an input message to a uniformly random byte string 140 * using a cryptographic hash function 141 * 142 * Implements `expand_message_xmd` as defined in RFC 9380. 143 * 144 * @param[in] msg The input message to expand 145 * @param[in] msg_len The length of the input message in bytes 146 * @param[in] dst Domain separation tag (DST) 147 * @param[in] dst_len The length of the DST 148 * @param[in] len_in_bytes Desired number of output bytes 149 * @param[out] uniform_bytes Output buffer of length `len_in_bytes` to 150 * receive the high entropy result 151 * 152 * @return 0 on success, non-zero on error 153 */ 154 int oprf_expand_message_xmd(const uint8_t *msg, const uint16_t msg_len, const uint8_t *dst, const uint8_t dst_len, const uint8_t len_in_bytes, uint8_t *uniform_bytes); 155 156 #ifdef __EMSCRIPTEN__ 157 /** 158 * if compiling to webassembly, there is no sodium_m(un)?lock and thus we suppress that with the following 159 */ 160 161 // Per 162 // https://emscripten.org/docs/compiling/Building-Projects.html#detecting-emscripten-in-preprocessor, 163 // "The preprocessor define __EMSCRIPTEN__ is always defined when compiling 164 // programs with Emscripten". For why we are replacing sodium_m(un)?lock, see 165 // common.c for more details. 166 #define sodium_mlock(a,l) (0) 167 #define sodium_munlock(a,l) (0) 168 #endif //__EMSCRIPTEN__ 169 170 171 #endif