Some small performance improvements on 32-bit architectures.
[BearSSL] / inc / bearssl_rsa.h
index 7c79d33..0a069fd 100644 (file)
@@ -28,6 +28,9 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "bearssl_hash.h"
+#include "bearssl_rand.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -277,6 +280,55 @@ typedef uint32_t (*br_rsa_pkcs1_vrfy)(const unsigned char *x, size_t xlen,
        const unsigned char *hash_oid, size_t hash_len,
        const br_rsa_public_key *pk, unsigned char *hash_out);
 
+/**
+ * \brief Type for a RSA signature verification engine (PSS).
+ *
+ * Parameters are:
+ *
+ *   - The signature itself. The provided array is NOT modified.
+ *
+ *   - The hash function which was used to hash the message.
+ *
+ *   - The hash function to use with MGF1 within the PSS padding. This
+ *     is not necessarily the same hash function as the one which was
+ *     used to hash the signed message.
+ *
+ *   - The hashed message (as an array of bytes).
+ *
+ *   - The PSS salt length (in bytes).
+ *
+ *   - The public key.
+ *
+ * **Constraints:**
+ *
+ *   - Hash message length MUST be no more than 64 bytes.
+ *
+ * Note that, contrary to PKCS#1 v1.5 signature, the hash value of the
+ * signed data cannot be extracted from the signature; it must be
+ * provided to the verification function.
+ *
+ * This function verifies that the signature length (`xlen`) matches the
+ * modulus length (this function returns 0 on mismatch). If the modulus
+ * size exceeds the maximum supported RSA size, then the function also
+ * returns 0.
+ *
+ * Returned value is 1 on success, 0 on error.
+ *
+ * Implementations of this type need not be constant-time.
+ *
+ * \param x          signature buffer.
+ * \param xlen       signature length (in bytes).
+ * \param hf_data    hash function applied on the message.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hash value of the signed message.
+ * \param salt_len   PSS salt length (in bytes).
+ * \param pk         RSA public key.
+ * \return  1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_pss_vrfy)(const unsigned char *x, size_t xlen,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1, 
+       const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
 /**
  * \brief Type for a RSA encryption engine (OAEP).
  *
@@ -383,6 +435,53 @@ typedef uint32_t (*br_rsa_pkcs1_sign)(const unsigned char *hash_oid,
        const unsigned char *hash, size_t hash_len,
        const br_rsa_private_key *sk, unsigned char *x);
 
+/**
+ * \brief Type for a RSA signature generation engine (PSS).
+ *
+ * Parameters are:
+ *
+ *   - An initialized PRNG for salt generation. If the salt length is
+ *     zero (`salt_len` parameter), then the PRNG is optional (this is
+ *     not the typical case, as the security proof of RSA/PSS is
+ *     tighter when a non-empty salt is used).
+ *
+ *   - The hash function which was used to hash the message.
+ *
+ *   - The hash function to use with MGF1 within the PSS padding. This
+ *     is not necessarily the same function as the one used to hash the
+ *     message.
+ *
+ *   - The hashed message.
+ *
+ *   - The salt length, in bytes.
+ *
+ *   - The RSA private key.
+ *
+ *   - The output buffer, that receives the signature.
+ *
+ * Returned value is 1 on success, 0 on error. Error conditions include
+ * a too small modulus for the provided hash and salt lengths, or some
+ * invalid key parameters. The signature length is exactly
+ * `(sk->n_bitlen+7)/8` bytes.
+ *
+ * This function is expected to be constant-time with regards to the
+ * private key bytes (lengths of the modulus and the individual factors
+ * may leak, though) and to the hashed data.
+ *
+ * \param rng        PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data    hash function used to hash the signed data.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hashed message.
+ * \param salt_len   salt length (in bytes).
+ * \param sk         RSA private key.
+ * \param x          output buffer for the signature value.
+ * \return  1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_pss_sign)(const br_prng_class **rng,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+       const unsigned char *hash_value, size_t salt_len,
+       const br_rsa_private_key *sk, unsigned char *x);
+
 /**
  * \brief Encoded OID for SHA-1 (in RSA PKCS#1 signatures).
  */
@@ -474,7 +573,7 @@ uint32_t br_rsa_i32_public(unsigned char *x, size_t xlen,
        const br_rsa_public_key *pk);
 
 /**
- * \brief RSA signature verification engine "i32".
+ * \brief RSA signature verification engine "i32" (PKCS#1 v1.5 signatures).
  *
  * \see br_rsa_pkcs1_vrfy
  *
@@ -490,6 +589,24 @@ uint32_t br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen,
        const unsigned char *hash_oid, size_t hash_len,
        const br_rsa_public_key *pk, unsigned char *hash_out);
 
+/**
+ * \brief RSA signature verification engine "i32" (PSS signatures).
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x          signature buffer.
+ * \param xlen       signature length (in bytes).
+ * \param hf_data    hash function applied on the message.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hash value of the signed message.
+ * \param salt_len   PSS salt length (in bytes).
+ * \param pk         RSA public key.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i32_pss_vrfy(const unsigned char *x, size_t xlen,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1, 
+       const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
 /**
  * \brief RSA private key engine "i32".
  *
@@ -503,7 +620,7 @@ uint32_t br_rsa_i32_private(unsigned char *x,
        const br_rsa_private_key *sk);
 
 /**
- * \brief RSA signature generation engine "i32".
+ * \brief RSA signature generation engine "i32" (PKCS#1 v1.5 signatures).
  *
  * \see br_rsa_pkcs1_sign
  *
@@ -518,6 +635,25 @@ uint32_t br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid,
        const unsigned char *hash, size_t hash_len,
        const br_rsa_private_key *sk, unsigned char *x);
 
+/**
+ * \brief RSA signature generation engine "i32" (PSS signatures).
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng        PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data    hash function used to hash the signed data.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hashed message.
+ * \param salt_len   salt length (in bytes).
+ * \param sk         RSA private key.
+ * \param x          output buffer for the signature value.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i32_pss_sign(const br_prng_class **rng,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+       const unsigned char *hash_value, size_t salt_len,
+       const br_rsa_private_key *sk, unsigned char *x);
+
 /*
  * RSA "i31" engine. Similar to i32, but only 31 bits are used per 32-bit
  * word. This uses slightly more stack space (about 4% more) and code
@@ -538,7 +674,7 @@ uint32_t br_rsa_i31_public(unsigned char *x, size_t xlen,
        const br_rsa_public_key *pk);
 
 /**
- * \brief RSA signature verification engine "i31".
+ * \brief RSA signature verification engine "i31" (PKCS#1 v1.5 signatures).
  *
  * \see br_rsa_pkcs1_vrfy
  *
@@ -554,6 +690,24 @@ uint32_t br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen,
        const unsigned char *hash_oid, size_t hash_len,
        const br_rsa_public_key *pk, unsigned char *hash_out);
 
+/**
+ * \brief RSA signature verification engine "i31" (PSS signatures).
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x          signature buffer.
+ * \param xlen       signature length (in bytes).
+ * \param hf_data    hash function applied on the message.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hash value of the signed message.
+ * \param salt_len   PSS salt length (in bytes).
+ * \param pk         RSA public key.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i31_pss_vrfy(const unsigned char *x, size_t xlen,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1, 
+       const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
 /**
  * \brief RSA private key engine "i31".
  *
@@ -567,7 +721,7 @@ uint32_t br_rsa_i31_private(unsigned char *x,
        const br_rsa_private_key *sk);
 
 /**
- * \brief RSA signature generation engine "i31".
+ * \brief RSA signature generation engine "i31" (PKCS#1 v1.5 signatures).
  *
  * \see br_rsa_pkcs1_sign
  *
@@ -582,6 +736,25 @@ uint32_t br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid,
        const unsigned char *hash, size_t hash_len,
        const br_rsa_private_key *sk, unsigned char *x);
 
+/**
+ * \brief RSA signature generation engine "i31" (PSS signatures).
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng        PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data    hash function used to hash the signed data.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hashed message.
+ * \param salt_len   salt length (in bytes).
+ * \param sk         RSA private key.
+ * \param x          output buffer for the signature value.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i31_pss_sign(const br_prng_class **rng,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+       const unsigned char *hash_value, size_t salt_len,
+       const br_rsa_private_key *sk, unsigned char *x);
+
 /*
  * RSA "i62" engine. Similar to i31, but internal multiplication use
  * 64x64->128 multiplications. This is available only on architecture
@@ -606,7 +779,7 @@ uint32_t br_rsa_i62_public(unsigned char *x, size_t xlen,
        const br_rsa_public_key *pk);
 
 /**
- * \brief RSA signature verification engine "i62".
+ * \brief RSA signature verification engine "i62" (PKCS#1 v1.5 signatures).
  *
  * This function is defined only on architecture that offer a 64x64->128
  * opcode. Use `br_rsa_i62_pkcs1_vrfy_get()` to dynamically obtain a pointer
@@ -626,6 +799,28 @@ uint32_t br_rsa_i62_pkcs1_vrfy(const unsigned char *x, size_t xlen,
        const unsigned char *hash_oid, size_t hash_len,
        const br_rsa_public_key *pk, unsigned char *hash_out);
 
+/**
+ * \brief RSA signature verification engine "i62" (PSS signatures).
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_pss_vrfy_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x          signature buffer.
+ * \param xlen       signature length (in bytes).
+ * \param hf_data    hash function applied on the message.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hash value of the signed message.
+ * \param salt_len   PSS salt length (in bytes).
+ * \param pk         RSA public key.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_pss_vrfy(const unsigned char *x, size_t xlen,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1, 
+       const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
 /**
  * \brief RSA private key engine "i62".
  *
@@ -643,7 +838,7 @@ uint32_t br_rsa_i62_private(unsigned char *x,
        const br_rsa_private_key *sk);
 
 /**
- * \brief RSA signature generation engine "i62".
+ * \brief RSA signature generation engine "i62" (PKCS#1 v1.5 signatures).
  *
  * This function is defined only on architecture that offer a 64x64->128
  * opcode. Use `br_rsa_i62_pkcs1_sign_get()` to dynamically obtain a pointer
@@ -662,6 +857,29 @@ uint32_t br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid,
        const unsigned char *hash, size_t hash_len,
        const br_rsa_private_key *sk, unsigned char *x);
 
+/**
+ * \brief RSA signature generation engine "i62" (PSS signatures).
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_pss_sign_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng        PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data    hash function used to hash the signed data.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hashed message.
+ * \param salt_len   salt length (in bytes).
+ * \param sk         RSA private key.
+ * \param x          output buffer for the signature value.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_pss_sign(const br_prng_class **rng,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+       const unsigned char *hash_value, size_t salt_len,
+       const br_rsa_private_key *sk, unsigned char *x);
+
 /**
  * \brief Get the RSA "i62" implementation (public key operations),
  * if available.
@@ -671,13 +889,21 @@ uint32_t br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid,
 br_rsa_public br_rsa_i62_public_get(void);
 
 /**
- * \brief Get the RSA "i62" implementation (PKCS#1 signature verification),
+ * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature verification),
  * if available.
  *
  * \return  the implementation, or 0.
  */
 br_rsa_pkcs1_vrfy br_rsa_i62_pkcs1_vrfy_get(void);
 
+/**
+ * \brief Get the RSA "i62" implementation (PSS signature verification),
+ * if available.
+ *
+ * \return  the implementation, or 0.
+ */
+br_rsa_pss_vrfy br_rsa_i62_pss_vrfy_get(void);
+
 /**
  * \brief Get the RSA "i62" implementation (private key operations),
  * if available.
@@ -687,13 +913,21 @@ br_rsa_pkcs1_vrfy br_rsa_i62_pkcs1_vrfy_get(void);
 br_rsa_private br_rsa_i62_private_get(void);
 
 /**
- * \brief Get the RSA "i62" implementation (PKCS#1 signature generation),
+ * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature generation),
  * if available.
  *
  * \return  the implementation, or 0.
  */
 br_rsa_pkcs1_sign br_rsa_i62_pkcs1_sign_get(void);
 
+/**
+ * \brief Get the RSA "i62" implementation (PSS signature generation),
+ * if available.
+ *
+ * \return  the implementation, or 0.
+ */
+br_rsa_pss_sign br_rsa_i62_pss_sign_get(void);
+
 /**
  * \brief Get the RSA "i62" implementation (OAEP encryption),
  * if available.
@@ -730,7 +964,7 @@ uint32_t br_rsa_i15_public(unsigned char *x, size_t xlen,
        const br_rsa_public_key *pk);
 
 /**
- * \brief RSA signature verification engine "i15".
+ * \brief RSA signature verification engine "i15" (PKCS#1 v1.5 signatures).
  *
  * \see br_rsa_pkcs1_vrfy
  *
@@ -746,6 +980,24 @@ uint32_t br_rsa_i15_pkcs1_vrfy(const unsigned char *x, size_t xlen,
        const unsigned char *hash_oid, size_t hash_len,
        const br_rsa_public_key *pk, unsigned char *hash_out);
 
+/**
+ * \brief RSA signature verification engine "i15" (PSS signatures).
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x          signature buffer.
+ * \param xlen       signature length (in bytes).
+ * \param hf_data    hash function applied on the message.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hash value of the signed message.
+ * \param salt_len   PSS salt length (in bytes).
+ * \param pk         RSA public key.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_pss_vrfy(const unsigned char *x, size_t xlen,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1, 
+       const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
 /**
  * \brief RSA private key engine "i15".
  *
@@ -759,7 +1011,7 @@ uint32_t br_rsa_i15_private(unsigned char *x,
        const br_rsa_private_key *sk);
 
 /**
- * \brief RSA signature generation engine "i15".
+ * \brief RSA signature generation engine "i15" (PKCS#1 v1.5 signatures).
  *
  * \see br_rsa_pkcs1_sign
  *
@@ -774,6 +1026,25 @@ uint32_t br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid,
        const unsigned char *hash, size_t hash_len,
        const br_rsa_private_key *sk, unsigned char *x);
 
+/**
+ * \brief RSA signature generation engine "i15" (PSS signatures).
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng        PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data    hash function used to hash the signed data.
+ * \param hf_mgf1    hash function to use with MGF1.
+ * \param hash       hashed message.
+ * \param salt_len   salt length (in bytes).
+ * \param sk         RSA private key.
+ * \param x          output buffer for the signature value.
+ * \return  1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_pss_sign(const br_prng_class **rng,
+       const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+       const unsigned char *hash_value, size_t salt_len,
+       const br_rsa_private_key *sk, unsigned char *x);
+
 /**
  * \brief Get "default" RSA implementation (public-key operations).
  *
@@ -795,7 +1066,7 @@ br_rsa_public br_rsa_public_get_default(void);
 br_rsa_private br_rsa_private_get_default(void);
 
 /**
- * \brief Get "default" RSA implementation (PKCS#1 signature verification).
+ * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature verification).
  *
  * This returns the preferred implementation of RSA (signature verification)
  * on the current system.
@@ -805,7 +1076,17 @@ br_rsa_private br_rsa_private_get_default(void);
 br_rsa_pkcs1_vrfy br_rsa_pkcs1_vrfy_get_default(void);
 
 /**
- * \brief Get "default" RSA implementation (PKCS#1 signature generation).
+ * \brief Get "default" RSA implementation (PSS signature verification).
+ *
+ * This returns the preferred implementation of RSA (signature verification)
+ * on the current system.
+ *
+ * \return  the default implementation.
+ */
+br_rsa_pss_vrfy br_rsa_pss_vrfy_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature generation).
  *
  * This returns the preferred implementation of RSA (signature generation)
  * on the current system.
@@ -814,6 +1095,16 @@ br_rsa_pkcs1_vrfy br_rsa_pkcs1_vrfy_get_default(void);
  */
 br_rsa_pkcs1_sign br_rsa_pkcs1_sign_get_default(void);
 
+/**
+ * \brief Get "default" RSA implementation (PSS signature generation).
+ *
+ * This returns the preferred implementation of RSA (signature generation)
+ * on the current system.
+ *
+ * \return  the default implementation.
+ */
+br_rsa_pss_sign br_rsa_pss_sign_get_default(void);
+
 /**
  * \brief Get "default" RSA implementation (OAEP encryption).
  *
@@ -1068,7 +1359,7 @@ uint32_t br_rsa_i62_oaep_decrypt(
  * Similarly, the public key elements are written in `kbuf_pub`, with
  * pointers and lengths set in `pk`.
  *
- * If `sk` is `NULL`, then `kbuf_pub` may be `NULL`, and only the
+ * If `pk` is `NULL`, then `kbuf_pub` may be `NULL`, and only the
  * private key is set.
  *
  * If `pubexp` is not zero, then its value will be used as public
@@ -1098,8 +1389,8 @@ uint32_t br_rsa_i62_oaep_decrypt(
  */
 typedef uint32_t (*br_rsa_keygen)(
        const br_prng_class **rng_ctx,
-       br_rsa_private_key *sk, unsigned char *kbuf_priv,
-       br_rsa_public_key *pk, unsigned char *kbuf_pub,
+       br_rsa_private_key *sk, void *kbuf_priv,
+       br_rsa_public_key *pk, void *kbuf_pub,
        unsigned size, uint32_t pubexp);
 
 /**
@@ -1118,8 +1409,8 @@ typedef uint32_t (*br_rsa_keygen)(
  */
 uint32_t br_rsa_i15_keygen(
        const br_prng_class **rng_ctx,
-       br_rsa_private_key *sk, unsigned char *kbuf_priv,
-       br_rsa_public_key *pk, unsigned char *kbuf_pub,
+       br_rsa_private_key *sk, void *kbuf_priv,
+       br_rsa_public_key *pk, void *kbuf_pub,
        unsigned size, uint32_t pubexp);
 
 /**
@@ -1138,8 +1429,8 @@ uint32_t br_rsa_i15_keygen(
  */
 uint32_t br_rsa_i31_keygen(
        const br_prng_class **rng_ctx,
-       br_rsa_private_key *sk, unsigned char *kbuf_priv,
-       br_rsa_public_key *pk, unsigned char *kbuf_pub,
+       br_rsa_private_key *sk, void *kbuf_priv,
+       br_rsa_public_key *pk, void *kbuf_pub,
        unsigned size, uint32_t pubexp);
 
 /**
@@ -1162,8 +1453,8 @@ uint32_t br_rsa_i31_keygen(
  */
 uint32_t br_rsa_i62_keygen(
        const br_prng_class **rng_ctx,
-       br_rsa_private_key *sk, unsigned char *kbuf_priv,
-       br_rsa_public_key *pk, unsigned char *kbuf_pub,
+       br_rsa_private_key *sk, void *kbuf_priv,
+       br_rsa_public_key *pk, void *kbuf_pub,
        unsigned size, uint32_t pubexp);
 
 /**
@@ -1184,6 +1475,179 @@ br_rsa_keygen br_rsa_i62_keygen_get(void);
  */
 br_rsa_keygen br_rsa_keygen_get_default(void);
 
+/**
+ * \brief Type for a modulus computing function.
+ *
+ * Such a function computes the public modulus from the private key. The
+ * encoded modulus (unsigned big-endian) is written on `n`, and the size
+ * (in bytes) is returned. If `n` is `NULL`, then the size is returned but
+ * the modulus itself is not computed.
+ *
+ * If the key size exceeds an internal limit, 0 is returned.
+ *
+ * \param n    destination buffer (or `NULL`).
+ * \param sk   RSA private key.
+ * \return  the modulus length (in bytes), or 0.
+ */
+typedef size_t (*br_rsa_compute_modulus)(void *n, const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA modulus ("i15" engine).
+ *
+ * \see br_rsa_compute_modulus
+ *
+ * \param n    destination buffer (or `NULL`).
+ * \param sk   RSA private key.
+ * \return  the modulus length (in bytes), or 0.
+ */
+size_t br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA modulus ("i31" engine).
+ *
+ * \see br_rsa_compute_modulus
+ *
+ * \param n    destination buffer (or `NULL`).
+ * \param sk   RSA private key.
+ * \return  the modulus length (in bytes), or 0.
+ */
+size_t br_rsa_i31_compute_modulus(void *n, const br_rsa_private_key *sk);
+
+/**
+ * \brief Get "default" RSA implementation (recompute modulus).
+ *
+ * This returns the preferred implementation of RSA (recompute modulus)
+ * on the current system.
+ *
+ * \return  the default implementation.
+ */
+br_rsa_compute_modulus br_rsa_compute_modulus_get_default(void);
+
+/**
+ * \brief Type for a public exponent computing function.
+ *
+ * Such a function recomputes the public exponent from the private key.
+ * 0 is returned if any of the following occurs:
+ *
+ *   - Either `p` or `q` is not equal to 3 modulo 4.
+ *
+ *   - The public exponent does not fit on 32 bits.
+ *
+ *   - An internal limit is exceeded.
+ *
+ *   - The private key is invalid in some way.
+ *
+ * For all private keys produced by the key generator functions
+ * (`br_rsa_keygen` type), this function succeeds and returns the true
+ * public exponent. The public exponent is always an odd integer greater
+ * than 1.
+ *
+ * \return  the public exponent, or 0.
+ */
+typedef uint32_t (*br_rsa_compute_pubexp)(const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA public exponent ("i15" engine).
+ *
+ * \see br_rsa_compute_pubexp
+ *
+ * \return  the public exponent, or 0.
+ */
+uint32_t br_rsa_i15_compute_pubexp(const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA public exponent ("i31" engine).
+ *
+ * \see br_rsa_compute_pubexp
+ *
+ * \return  the public exponent, or 0.
+ */
+uint32_t br_rsa_i31_compute_pubexp(const br_rsa_private_key *sk);
+
+/**
+ * \brief Get "default" RSA implementation (recompute public exponent).
+ *
+ * This returns the preferred implementation of RSA (recompute public
+ * exponent) on the current system.
+ *
+ * \return  the default implementation.
+ */
+br_rsa_compute_pubexp br_rsa_compute_pubexp_get_default(void);
+
+/**
+ * \brief Type for a private exponent computing function.
+ *
+ * An RSA private key (`br_rsa_private_key`) contains two reduced
+ * private exponents, which are sufficient to perform private key
+ * operations. However, standard encoding formats for RSA private keys
+ * require also a copy of the complete private exponent (non-reduced),
+ * which this function recomputes.
+ *
+ * This function suceeds if all the following conditions hold:
+ *
+ *   - Both private factors `p` and `q` are equal to 3 modulo 4.
+ *
+ *   - The provided public exponent `pubexp` is correct, and, in particular,
+ *     is odd, relatively prime to `p-1` and `q-1`, and greater than 1.
+ *
+ *   - No internal storage limit is exceeded.
+ *
+ * For all private keys produced by the key generator functions
+ * (`br_rsa_keygen` type), this function succeeds. Note that the API
+ * restricts the public exponent to a maximum size of 32 bits.
+ *
+ * The encoded private exponent is written in `d` (unsigned big-endian
+ * convention), and the length (in bytes) is returned. If `d` is `NULL`,
+ * then the exponent is not written anywhere, but the length is still
+ * returned. On error, 0 is returned.
+ *
+ * Not all error conditions are detected when `d` is `NULL`; therefore, the
+ * returned value shall be checked also when actually producing the value.
+ *
+ * \param d        destination buffer (or `NULL`).
+ * \param sk       RSA private key.
+ * \param pubexp   the public exponent.
+ * \return  the private exponent length (in bytes), or 0.
+ */
+typedef size_t (*br_rsa_compute_privexp)(void *d,
+       const br_rsa_private_key *sk, uint32_t pubexp);
+
+/**
+ * \brief Recompute RSA private exponent ("i15" engine).
+ *
+ * \see br_rsa_compute_privexp
+ *
+ * \param d        destination buffer (or `NULL`).
+ * \param sk       RSA private key.
+ * \param pubexp   the public exponent.
+ * \return  the private exponent length (in bytes), or 0.
+ */
+size_t br_rsa_i15_compute_privexp(void *d,
+       const br_rsa_private_key *sk, uint32_t pubexp);
+
+/**
+ * \brief Recompute RSA private exponent ("i31" engine).
+ *
+ * \see br_rsa_compute_privexp
+ *
+ * \param d        destination buffer (or `NULL`).
+ * \param sk       RSA private key.
+ * \param pubexp   the public exponent.
+ * \return  the private exponent length (in bytes), or 0.
+ */
+size_t br_rsa_i31_compute_privexp(void *d,
+       const br_rsa_private_key *sk, uint32_t pubexp);
+
+/**
+ * \brief Get "default" RSA implementation (recompute private exponent).
+ *
+ * This returns the preferred implementation of RSA (recompute private
+ * exponent) on the current system.
+ *
+ * \return  the default implementation.
+ */
+br_rsa_compute_privexp br_rsa_compute_privexp_get_default(void);
+
 #ifdef __cplusplus
 }
 #endif