/ src / oprf.h
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