blob: 7909f5c3f0ea036816397f9103f0e569998d35f5 [file] [edit]
/*
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef OPENSSL_FN_H
#define OPENSSL_FN_H
#pragma once
#include <stddef.h>
#include <openssl/opensslconf.h>
#include <openssl/bn_limbs.h>
#include <openssl/types.h>
#include "crypto/types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* @type OSSL_FN_ULONG is the type for the OSSL_FN limb. It's made to be
* compatible with BN_ULONG (quite literally).
*
* @def OSSL_FN_BYTES is defined with the size of OSSL_FN_ULONG, measured in
* bytes. This is mainly useful where 'sizeof(OSSL_FN_ULONG)' isn't suitable,
* such as the C pre-processor.
*/
#ifdef BN_BYTES
typedef BN_ULONG OSSL_FN_ULONG;
#define OSSL_FN_BYTES BN_BYTES
#endif
#ifndef OSSL_FN_BYTES
#error "OpenSSL doesn't support large numbers on this platform"
#endif
/*
* For practical reasons, we allow allocating OSSL_FNs in terms of limbs (what
* the BIGNUM library calls "words"), bytes and bits. The number of bytes and
* bits are rounded up to the number of limbs that can fit them.
*/
/**
* Allocate an OSSL_FN in memory.
*
* @param[in] size The number of limbs for the number itself.
* There's an additional few bytes allocated for bookkeeping.
* @returns an OSSL_FN instance.
* @retval NULL on error.
*/
OSSL_FN *OSSL_FN_new_limbs(size_t size);
/**
* Allocate an OSSL_FN in secure memory.
*
* @param[in] size The number of limbs for the number itself.
* There's an additional few bytes allocated for bookkeeping.
* @returns an OSSL_FN instance.
* @retval NULL on error.
*/
OSSL_FN *OSSL_FN_secure_new_limbs(size_t size);
/**
* Allocate an OSSL_FN in memory.
*
* @param[in] size The number of bytes for the number itself.
* There's an additional few bytes allocated for bookkeeping.
* @returns an OSSL_FN instance.
* @retval NULL on error.
*/
OSSL_FN *OSSL_FN_new_bytes(size_t size);
/**
* Allocate an OSSL_FN in secure memory.
*
* @param[in] size The number of bytes for the number itself.
* There's an additional few bytes allocated for bookkeeping.
* @returns an OSSL_FN instance.
* @retval NULL on error.
*/
OSSL_FN *OSSL_FN_secure_new_bytes(size_t size);
/**
* Allocate an OSSL_FN in memory.
*
* @param[in] size The number of bits for the number itself.
* There's an additional few bytes allocated for bookkeeping.
* @returns an OSSL_FN instance.
* @retval NULL on error.
*/
OSSL_FN *OSSL_FN_new_bits(size_t size);
/**
* Allocate an OSSL_FN in secure memory.
*
* @param[in] size The number of bits for the number itself.
* There's an additional few bytes allocated for bookkeeping.
* @returns an OSSL_FN instance.
* @retval NULL on error.
*/
OSSL_FN *OSSL_FN_secure_new_bits(size_t size);
/**
* Free an OSSL_FN instance if it was dynamically allocated.
* Free it securely if it was allocated securely.
*
* @param[in] f The OSSL_FN instance to be freed.
*/
void OSSL_FN_free(OSSL_FN *f);
/**
* Cleanse and free an OSSL_FN instance if it was dynamically allocated.
* Cleanse and free it securely if it was allocated securely.
* Merely cleanse it if it was not dynamically allocated.
*
* @param[in] f The OSSL_FN instance to be freed.
*/
void OSSL_FN_clear_free(OSSL_FN *f);
/**
* Cleanse the data of an OSSL_FN instance, effectively making it zero.
*
* @param[in] f The OSSL_FN instance to be cleared.
*/
void OSSL_FN_clear(OSSL_FN *f);
/**
* Set an OSSL_FN to a single-limb word value.
*
* @param[out] a The destination OSSL_FN
* @param[in] w The OSSL_FN_ULONG word
* @returns 1 on success, 0 on error
*
* @note Sets a->d[0] to @p w and zeroes the remaining limbs, so the full
* dsize array reflects the value @p w. If a->dsize is 0 there is no
* limb to write and the call fails with
* OSSL_FN_R_RESULT_ARG_TOO_SMALL (OSSL_FN is fixed-size, so the
* destination cannot be grown). The operation is constant-time with
* respect to @p w's value; the only branch is on the operand's public
* width (dsize).
*/
int OSSL_FN_set_word(OSSL_FN *a, OSSL_FN_ULONG w);
/**
* Set an OSSL_FN to one.
*
* @param[out] a The destination OSSL_FN
* @returns 1 on success, 0 on error
*
* @note Equivalent to OSSL_FN_set_word(a, 1), provided as a named function
* for readability at call sites. Leak profile as for
* OSSL_FN_set_word().
*/
int OSSL_FN_one(OSSL_FN *a);
/**
* Set an OSSL_FN to zero.
*
* @param[out] a The destination OSSL_FN
* @returns 1 on success, 0 on error
*
* @note This is a plain value assignment, not a secure wipe; use
* OSSL_FN_clear() when the limbs may hold secret data and must be wiped
* irreversibly. Equivalent to OSSL_FN_set_word(a, 0). Leak profile as
* for OSSL_FN_set_word().
*/
int OSSL_FN_zero(OSSL_FN *a);
/**
* Copy the contents of one OSSL_FN instance to another.
*
* @param[out] a The destination OSSL_FN
* @param[in] b The source OSSL_FN
* @returns The destination on success, NULL on error.
*
* @note The destination must be at least as large as the source.
* Any limbs beyond the source size are zeroed.
*/
OSSL_FN *OSSL_FN_copy(OSSL_FN *a, const OSSL_FN *b);
/**
* Copy the contents of one OSSL_FN instance to another,
* normally the shorter one, truncating the high bytes.
*
* @param[out] a The destination OSSL_FN
* @param[in] b The source OSSL_FN
* @returns the destination.
*/
OSSL_FN *OSSL_FN_copy_truncate(OSSL_FN *a, const OSSL_FN *b);
/**
* Calculate the arena payload size for an OSSL_FN_CTX.
*
* @param[in] max_n_frames Maximum number of simultaneously active frames.
* This indicates the expected depth of call stack
* that the resulting OSSL_FN_CTX will be used in.
* Must be at least 1.
* @param[in] max_n_numbers Maximum number of simultaneously active OSSL_FN.
* Must be 0 if and only if @p max_n_limbs is 0.
* @param[in] max_n_limbs Maximum number of simultaneously active OSSL_FN
* limbs. Must be 0 if and only if
* @p max_n_numbers is 0.
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid argument.
*
* The returned size is the value to pass to OSSL_FN_CTX_new_size() or
* OSSL_FN_CTX_secure_new_size(). It does not include sizeof(OSSL_FN_CTX).
*/
size_t OSSL_FN_CTX_size(size_t max_n_frames, size_t max_n_numbers,
size_t max_n_limbs);
/**
* Allocate a new OSSL_FN_CTX, given a set of input numbers.
*
* @param[in] libctx OpenSSL library context (currently unused)
* @param[in] max_n_frames Maximum number of simultaneously active frames.
* This indicates the expected depth of call stack
* that the resulting OSSL_FN_CTX will be used in.
* @param[in] max_n_numbers Maximum number of simultaneously active OSSL_FN.
* @param[in] max_n_limbs Maximum number of simultaneously active OSSL_FN
* limbs.
* @returns An allocated OSSL_FN_CTX, or NULL on error.
*/
OSSL_FN_CTX *OSSL_FN_CTX_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
size_t max_n_numbers, size_t max_n_limbs);
/**
* Allocate a new OSSL_FN_CTX with a given arena payload size.
*
* @param[in] libctx OpenSSL library context (currently unused)
* @param[in] size Arena payload size in bytes, typically from
* OSSL_FN_CTX_size(). A size of 0 is the error
* return of OSSL_FN_CTX_size() and is treated as
* an error here too.
* @returns An allocated OSSL_FN_CTX, or NULL on error.
*/
OSSL_FN_CTX *OSSL_FN_CTX_new_size(OSSL_LIB_CTX *libctx, size_t size);
/**
* Allocate a new OSSL_FN_CTX in secure memory, given a set of input numbers.
* Other than allocating in secure memory, this function does exactly the same
* thing as OSSL_FN_CTX_new().
*/
OSSL_FN_CTX *OSSL_FN_CTX_secure_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
size_t max_n_numbers, size_t max_n_limbs);
/**
* Allocate a new OSSL_FN_CTX in secure memory with a given arena payload size.
*
* @param[in] libctx OpenSSL library context (currently unused)
* @param[in] size Arena payload size in bytes, typically from
* OSSL_FN_CTX_size(). A size of 0 is treated as
* an error, as in OSSL_FN_CTX_new_size().
* @returns An allocated OSSL_FN_CTX, or NULL on error.
*/
OSSL_FN_CTX *OSSL_FN_CTX_secure_new_size(OSSL_LIB_CTX *libctx, size_t size);
/**
* Report the peak number of frames, numbers, and limbs that were
* simultaneously active during the lifetime of the OSSL_FN_CTX.
* This can be used to determine suitable arena parameters for a
* given workload.
*
* @param[in] ctx The OSSL_FN_CTX to query. This may be NULL.
* @param[out] peak_n_frames Peak number of simultaneously active frames
* @param[out] peak_n_numbers Peak number of simultaneously active OSSL_FNs
* @param[out] peak_n_limbs Peak total limbs across all active OSSL_FNs
*
* Any of the out parameters may be NULL. If ctx is NULL, all out
* parameters that are non-NULL are set to 0.
*/
void OSSL_FN_CTX_peak_usage(const OSSL_FN_CTX *ctx, size_t *peak_n_frames,
size_t *peak_n_numbers, size_t *peak_n_limbs);
/**
* Free an OSSL_FN_CTX.
*
* @param[in] ctx The OSSL_FN_CTX to be freed. This may be NULL.
*/
void OSSL_FN_CTX_free(OSSL_FN_CTX *ctx);
/**
* Start a new OSSL_FN_CTX frame. This *must* be called by any function
* that wants to get a temporary OSSL_FN from the OSSL_FN_CTX. The function
* call this must also clean up with a OSSL_FN_CTX_end() call.
*
* @param[in] ctx The OSSL_FN_CTX to start the frame in.
* @returns Ownership token of the started frame, NULL on error.
* This token must be passed to OSSL_FN_CTX_end().
*/
const void *OSSL_FN_CTX_start(OSSL_FN_CTX *ctx);
/**
* End the last OSSL_FN_CTX frame, resetting back to the previous
* frame. If a function called OSSL_FN_CTX_start(), it *must* call
* this function before returning.
*
* @param[in] ctx The OSSL_FN_CTX to start the frame in.
* @param[in] token Ownership token returned by OSSL_FN_CTX_start().
* @returns 1 on success, 0 on error.
*
* @note The token parameter is validated but not used for choosing a
* frame; only the most recent frame can be ended. Passing an incorrect
* token indicates a programming error and the function will fail.
* If NULL is passed, nothing will be done but the function will return 1.
*/
int OSSL_FN_CTX_end(OSSL_FN_CTX *ctx, const void *token);
/**
* Get a suitably sized OSSL_FN from an OSSL_FN_CTX.
*
* @param[in] ctx The OSSL_FN_CTX
* @param[in] limbs The desired size of the resulting OSSL_FN,
* in number of limbs.
* @returns an OSSL_FN pointer on success, NULL on error.
*/
OSSL_FN *OSSL_FN_CTX_get_limbs(OSSL_FN_CTX *ctx, size_t limbs);
/**
* Get a suitably sized OSSL_FN from an OSSL_FN_CTX.
*
* @param[in] ctx The OSSL_FN_CTX
* @param[in] limbs The desired size of the resulting OSSL_FN,
* in number of bytes.
* @returns an OSSL_FN pointer on success, NULL on error.
*/
OSSL_FN *OSSL_FN_CTX_get_bytes(OSSL_FN_CTX *ctx, size_t bytes);
/**
* Get a suitably sized OSSL_FN from an OSSL_FN_CTX.
*
* @param[in] ctx The OSSL_FN_CTX
* @param[in] limbs The desired size of the resulting OSSL_FN,
* in number of bits.
* @returns an OSSL_FN pointer on success, NULL on error.
*/
OSSL_FN *OSSL_FN_CTX_get_bits(OSSL_FN_CTX *ctx, size_t bits);
/*
* Arithmetic functions treat the OSSL_FN 'd' array as a large 2's complement
* unsigned integer, least significant limb first. All carrys or borrows are
* extended in the result and otherwise ignored. This makes OSSL_FN functions
* act just like operations on C unsigned integer types, but at a larger scale.
*/
/**
* Return the number of significant bits in an OSSL_FN number.
*
* @param[in] a The operand
* @returns The number of significant bits, or zero if a is zero
*/
size_t OSSL_FN_num_bits(const OSSL_FN *a);
/**
* Compare two OSSL_FN numbers as unsigned integers.
*
* @param[in] a The first operand
* @param[in] b The second operand
* @returns 1 if a > b, -1 if a < b, 0 if a == b
*/
int OSSL_FN_cmp(const OSSL_FN *a, const OSSL_FN *b);
/**
* Test whether bit @p n is set in @p a.
*
* @param[in] a The operand
* @param[in] n The bit index (0 = least significant)
* @returns 1 if bit @p n of @p a is set, 0 otherwise.
*
* @note An out-of-range index (n < 0 or n >= the operand's width in bits)
* reads as 0. The only control flow branches on the operand's public
* width (its dsize), not on limb values; the returned value is the bit
* itself, which is the information the caller asked for.
*/
int OSSL_FN_is_bit_set(const OSSL_FN *a, int n);
/**
* Test whether the unsigned value of @p a equals the single-limb word @p w.
*
* @param[in] a The operand
* @param[in] w The OSSL_FN_ULONG word to compare against
* @returns 1 if the unsigned value of @p a equals @p w, 0 otherwise
*
* @note Control flow branches only on the operand's public width (its dsize),
* not on limb values; the returned value is the equality test the caller
* asked for.
*/
int OSSL_FN_is_word(const OSSL_FN *a, OSSL_FN_ULONG w);
/**
* Test whether @p a is zero.
*
* @param[in] a The operand
* @returns 1 if @p a is zero, 0 otherwise
*
* @note Equivalent to OSSL_FN_is_word(a, 0), provided as a named predicate for
* readability at call sites. Leak profile as for OSSL_FN_is_word():
* branches only on the operand's public width (its dsize).
*/
int OSSL_FN_is_zero(const OSSL_FN *a);
/**
* Test whether @p a is one.
*
* @param[in] a The operand
* @returns 1 if @p a is one, 0 otherwise
*
* @note Equivalent to OSSL_FN_is_word(a, 1), provided as a named predicate for
* readability at call sites. Leak profile as for OSSL_FN_is_word():
* branches only on the operand's public width (its dsize).
*/
int OSSL_FN_is_one(const OSSL_FN *a);
/**
* Test whether @p a is odd.
*
* @param[in] a The operand
* @returns the least significant bit of @p a (1 if odd, 0 if even)
*
* @note The only control flow branches on the operand's public width (its
* dsize), not on limb values; the returned value is the bit itself,
* which is the information the caller asked for.
*/
int OSSL_FN_is_odd(const OSSL_FN *a);
/*-
* Top/bottom selectors for OSSL_FN_rand() / OSSL_FN_priv_rand(). These are
* caller-chosen public parameters (not secrets); OSSL_FN_rand() branches on
* them to shape the top and bottom bits of the result. Each TOP_* value is
* the number of high bits to force to 1 (0 = unconstrained, 1, 2), matching
* the BOTTOM_* numbering (0 = unconstrained, 1 = force the low bit).
*/
#define OSSL_FN_RAND_TOP_ANY 0
#define OSSL_FN_RAND_TOP_ONE 1
#define OSSL_FN_RAND_TOP_TWO 2
#define OSSL_FN_RAND_BOTTOM_ANY 0
#define OSSL_FN_RAND_BOTTOM_ODD 1
/**
* Fill @p rnd with @p bits random bits.
*
* @param[out] rnd The OSSL_FN for the result
* @param[in] bits The number of random bits to generate
* @param[in] top Top-bit selector (OSSL_FN_RAND_TOP_*)
* @param[in] bottom Bottom-bit selector (OSSL_FN_RAND_BOTTOM_*)
* @param[in] strength The private strength of the generated bytes
* @param[in] libctx The OpenSSL library context (for the DRBG)
* @returns 1 on success, 0 on error
*
* Draws from the public DRBG pool via RAND_bytes_ex(). The library context
* is taken directly as @p libctx. The random bytes are drawn straight into
* rnd->d (no intermediate buffer) and the top/bottom/mask constraints are
* applied as limb value operations; a @p rnd too small for @p bits is
* reported as OSSL_FN_R_RESULT_ARG_TOO_SMALL rather than grown. Leak
* profile as for OSSL_FN_priv_rand().
*/
int OSSL_FN_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
size_t strength, OSSL_LIB_CTX *libctx);
/**
* Fill @p rnd with @p bits random bits from the private DRBG pool.
*
* @param[out] rnd The OSSL_FN for the result
* @param[in] bits The number of random bits to generate
* @param[in] top Top-bit selector (OSSL_FN_RAND_TOP_*)
* @param[in] bottom Bottom-bit selector (OSSL_FN_RAND_BOTTOM_*)
* @param[in] strength The private strength of the generated bytes
* @param[in] libctx The OpenSSL library context (for the DRBG)
* @returns 1 on success, 0 on error
*
* Draws from the private (non-forward-linkable) DRBG pool via
* RAND_priv_bytes_ex(). This is the private counterpart of OSSL_FN_rand();
* the public/private pool selection is exposed as separate functions rather
* than a flag argument. Control flow branches only on @p bits, @p top,
* @p bottom (all caller-chosen, public) and on the byte-draw return value,
* never on the random bytes themselves; the returned value is the random
* number the caller asked for.
*
* @note See ossl_fn_rand() in crypto/fn/fn_rand.c for the byte-to-limb
* shaping mechanics.
*/
int OSSL_FN_priv_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
size_t strength, OSSL_LIB_CTX *libctx);
/**
* Generate 0 <= r < range.
*
* @param[out] r The OSSL_FN for the result
* @param[in] range The exclusive upper bound (must be non-zero)
* @param[in] strength The private strength of the generated bytes
* @param[in] libctx The OpenSSL library context (for the DRBG)
* @returns 1 on success, 0 on error
*
* Draws from the public DRBG pool. OSSL_FN is unsigned, so no sign
* rejection is performed. The loop iteration count leaks the magnitude of
* @p range via OSSL_FN_num_bits() and the rejection probability.
*
* The destination @p r must be sized to hold at least
* OSSL_FN_num_bits(@p range) bits. Sizing @p r to hold one extra bit
* (OSSL_FN_num_bits(@p range) + 1) additionally enables the optimized
* "range = 100..._2" path, which draws n + 1 bits; an exactly-sized @p r
* (room for exactly OSSL_FN_num_bits(@p range) bits) uses standard n-bit
* rejection sampling instead. An @p r too small for
* OSSL_FN_num_bits(@p range) bits fails with OSSL_FN_R_RESULT_ARG_TOO_SMALL.
*/
int OSSL_FN_rand_range(OSSL_FN *r, const OSSL_FN *range, size_t strength,
OSSL_LIB_CTX *libctx);
/**
* Generate 0 <= r < range from the private DRBG pool.
*
* @param[out] r The OSSL_FN for the result
* @param[in] range The exclusive upper bound (must be non-zero)
* @param[in] strength The private strength of the generated bytes
* @param[in] libctx The OpenSSL library context (for the DRBG)
* @returns 1 on success, 0 on error
*
* Draws from the private DRBG pool. Leak profile and destination sizing
* as for OSSL_FN_rand_range().
*/
int OSSL_FN_priv_rand_range(OSSL_FN *r, const OSSL_FN *range,
size_t strength, OSSL_LIB_CTX *libctx);
/**
* Shift an OSSL_FN number left by n bits. Truncates the result to fit in r.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] n The number of bits to shift
* @returns 1 on success, 0 on error
*/
int OSSL_FN_lshift(OSSL_FN *r, const OSSL_FN *a, int n);
/**
* Shift an OSSL_FN number left by one bit. Truncates the result to fit in r.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @returns 1 on success, 0 on error
*/
int OSSL_FN_lshift1(OSSL_FN *r, const OSSL_FN *a);
/**
* Shift an OSSL_FN number right by n bits. Truncates the result to fit in r.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] n The number of bits to shift
* @returns 1 on success, 0 on error
*/
int OSSL_FN_rshift(OSSL_FN *r, const OSSL_FN *a, int n);
/**
* Shift an OSSL_FN number right by one bit. Truncates the result to fit in r.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @returns 1 on success, 0 on error
*/
int OSSL_FN_rshift1(OSSL_FN *r, const OSSL_FN *a);
/**
* Calculate the greatest common divisor of two OSSL_FN numbers. Truncates
* the result to fit in r.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for four temporary OSSL_FNs, max(a->dsize, b->dsize) + 1 limbs
* each, plus one frame.
*/
int OSSL_FN_gcd(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_gcd() needs.
*
* @param[in] a The first operand
* @param[in] b The second operand
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_gcd().
*/
size_t OSSL_FN_gcd_ctx_size(const OSSL_FN *a, const OSSL_FN *b);
/**
* Add two OSSL_FN numbers.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @returns 1 on success, 0 on error
*/
int OSSL_FN_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b);
/**
* Add an OSSL_FN_ULONG word to an OSSL_FN numbers.
*
* @param[in,out] a The OSSL_FN to add the word to
* @param[in] w The OSSL_FN_ULONG word
* @returns 1 on success, 0 on error
*/
int OSSL_FN_add_word(OSSL_FN *a, OSSL_FN_ULONG w);
/**
* Subtract two OSSL_FN numbers.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @returns 1 on success, 0 on error
*/
int OSSL_FN_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b);
/**
* Subtract an OSSL_FN_ULONG word from an OSSL_FN numbers.
*
* @param[in,out] a The OSSL_FN to subtract the word from
* @param[in] w The OSSL_FN_ULONG word
* @returns 1 on success, 0 on error
*/
int OSSL_FN_sub_word(OSSL_FN *a, OSSL_FN_ULONG w);
/**
* Multiply two OSSL_FN numbers. Truncates the result to fit in r.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for one temporary OSSL_FN with res->dsize limbs, plus one frame
* (currently 32 bytes).
*/
int OSSL_FN_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mul() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mul().
*/
size_t OSSL_FN_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *b);
/**
* Divide two OSSL_FN numbers. Truncates the result to fit in q and r.
*
* @param[out] q The OSSL_FN for the quotient
* @param[out] r The OSSL_FN for the remainder
* @param[in] n The first operand (numerator)
* @param[in] d The second operand (denominator)
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for 1 frame, 4 numbers, and 4 * max(n->dsize, d->dsize) + 2 limbs.
* Note that this provides an upper bound. Actual use of the arena may be
* smaller - see OSSL_FN_div_ctx_size() for an exact, conditional value.
*/
int OSSL_FN_div(OSSL_FN *q, OSSL_FN *r, const OSSL_FN *n, const OSSL_FN *d,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_div() needs.
*
* @param[in] q The OSSL_FN for the quotient, or NULL when
* only the remainder is of interest.
* @param[in] r The OSSL_FN for the remainder
* @param[in] n The first operand (numerator)
* @param[in] d The second operand (denominator)
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_div().
* When q is NULL, the size is computed for the modulo case, i.e. as if
* only the remainder is produced.
*/
size_t OSSL_FN_div_ctx_size(const OSSL_FN *q, const OSSL_FN *r,
const OSSL_FN *n, const OSSL_FN *d);
/**
* Add two OSSL_FN numbers modulo m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for one temporary OSSL_FN with max(a->dsize, b->dsize) + 1
* limbs, plus the requirements of OSSL_FN_mod(), plus one frame
* (currently 32 bytes).
*/
int OSSL_FN_mod_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
const OSSL_FN *m, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_add() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_add().
*/
size_t OSSL_FN_mod_add_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *b, const OSSL_FN *m);
/**
* Add two OSSL_FN numbers modulo m. This is a quick variant that may be
* used if both a and b are less than m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @returns 1 on success, 0 on error
*/
int OSSL_FN_mod_add_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
const OSSL_FN *m);
/**
* Subtract two OSSL_FN numbers modulo m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for two temporary OSSL_FNs with m->dsize limbs each, plus an
* additional temporary OSSL_FN with m->dsize limbs if r == m, plus the
* requirements of OSSL_FN_mod(), plus one frame (currently 32 bytes).
*/
int OSSL_FN_mod_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
const OSSL_FN *m, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_sub() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_sub().
*/
size_t OSSL_FN_mod_sub_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *b, const OSSL_FN *m);
/**
* Subtract two OSSL_FN numbers modulo m. This is a quick variant that may
* be used if a is less than m and b is of the same bit width as m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @returns 1 on success, 0 on error
*/
int OSSL_FN_mod_sub_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
const OSSL_FN *m);
/**
* Multiply two OSSL_FN numbers modulo m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for one temporary OSSL_FN with a->dsize + b->dsize limbs
* (or 2 * a->dsize limbs if a == b), plus the largest of the
* requirements of OSSL_FN_mul(), OSSL_FN_sqr(), and OSSL_FN_mod(),
* plus one frame (currently 32 bytes).
*/
int OSSL_FN_mod_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
const OSSL_FN *m, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_mul() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_mul().
*/
size_t OSSL_FN_mod_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *b, const OSSL_FN *m);
/**
* Square an OSSL_FN number modulo m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] m The modulus
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for one temporary OSSL_FN with 2 * a->dsize limbs, plus the
* larger of the requirements of OSSL_FN_sqr() and OSSL_FN_mod(),
* plus one frame (currently 32 bytes).
*/
int OSSL_FN_mod_sqr(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_sqr() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_sqr().
*/
size_t OSSL_FN_mod_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *m);
/**
* Left shift an OSSL_FN number by 1 bit, modulo m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] m The modulus
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for one temporary OSSL_FN with m->dsize + 1 limbs, plus the
* requirements of OSSL_FN_mod(), plus one frame (currently 32 bytes).
*/
int OSSL_FN_mod_lshift1(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_lshift1() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by
* OSSL_FN_mod_lshift1().
*/
size_t OSSL_FN_mod_lshift1_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *m);
/**
* Left shift an OSSL_FN number by 1 bit, modulo m. This is a quick
* variant that may be used if a is less than m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] m The modulus
* @returns 1 on success, 0 on error
*/
int OSSL_FN_mod_lshift1_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m);
/**
* Left shift an OSSL_FN number by n bits, modulo m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] n The number of bits to shift
* @param[in] m The modulus
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for one temporary OSSL_FN with m->dsize limbs, plus the
* requirements of OSSL_FN_mod(), plus one frame (currently 32 bytes).
*/
int OSSL_FN_mod_lshift(OSSL_FN *r, const OSSL_FN *a, int n, const OSSL_FN *m,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_lshift() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] n The number of bits to shift
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_lshift().
*/
size_t OSSL_FN_mod_lshift_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
int n, const OSSL_FN *m);
/**
* Left shift an OSSL_FN number by n bits, modulo m. This is a quick
* variant that may be used if a is less than m.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] n The number of bits to shift
* @param[in] m The modulus
* @returns 1 on success, 0 on error
*/
int OSSL_FN_mod_lshift_quick(OSSL_FN *r, const OSSL_FN *a, int n,
const OSSL_FN *m);
/**
* Calculate modulo of two OSSL_FN numbers. Truncates the result to fit in r.
*
* @param[out] r The OSSL_FN for the remainder
* @param[in] n The first operand (numerator)
* @param[in] d The second operand (denominator)
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function has the same requirements on ctx as OSSL_FN_div().
* It is equivalent to OSSL_FN_div(NULL, r, n, d, ctx).
*/
static inline int OSSL_FN_mod(OSSL_FN *r, const OSSL_FN *n, const OSSL_FN *d,
OSSL_FN_CTX *ctx)
{
return OSSL_FN_div(NULL, r, n, d, ctx);
}
/**
* Calculate the arena payload size that OSSL_FN_mod() needs.
*
* @param[in] r The OSSL_FN for the remainder
* @param[in] n The numerator
* @param[in] d The denominator
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod().
* This is a thin wrapper around OSSL_FN_div_ctx_size() with a NULL
* quotient, since OSSL_FN_mod() is itself a wrapper around OSSL_FN_div().
*/
static inline size_t OSSL_FN_mod_ctx_size(const OSSL_FN *r,
const OSSL_FN *n, const OSSL_FN *d)
{
return OSSL_FN_div_ctx_size(NULL, r, n, d);
}
/**
* Calculate the modular multiplicative inverse of |a| modulo |n|, i.e. a
* value |r| such that r * a == 1 (mod n), with 0 <= r < n.
*
* The call fails with OSSL_FN_R_NO_INVERSE when |a| and |n| are not
* coprime, or when |n| is degenerate (0 or 1): modulo 0 the relation
* r * a == 1 is never satisfiable, and modulo 1 the multiplicative
* identity is not representable as a residue in [0, n).
*
* @param[out] r The OSSL_FN for the result. Truncates high
* limbs if too small, zero-pads if too large.
* @param[in] a The operand.
* @param[in] n The modulus. Must be greater than 1.
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error.
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for six temporary OSSL_FNs with max(a->dsize, n->dsize) limbs
* each, plus the requirements of OSSL_FN_div() (the loop-body division
* and the initial/final reductions), plus one frame (currently 32 bytes).
*/
int OSSL_FN_mod_inverse(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *n,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_inverse() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] n The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_inverse().
*/
size_t OSSL_FN_mod_inverse_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *n);
/**
* Calculate a^p mod m (modular exponentiation) with a sliding-window
* algorithm. Odd moduli use the Montgomery sliding-window path; even
* moduli fall through to the simple sliding-window path. See the
* implementation in crypto/fn/fn_exp.c for the constant-time profile and
* the dispatcher scaffold (even-modulus reciprocal remaindering is not
* wired in yet).
*
* @param[out] r The OSSL_FN for the result. As for all OSSL_FN
* operations, the destination width is the
* caller's choice: if smaller than the modulus,
* the result is truncated; if larger, it is
* zero-padded. |r| must not alias |m|.
* @param[in] a The base.
* @param[in] p The exponent.
* @param[in] m The modulus. Must be non-zero.
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error.
*
* @note This path is currently not constant-time per se; do not use it for
* secret exponents. See the implementation in crypto/fn/fn_exp.c.
*
* @note This function currently requires that the OSSL_FN_CTX is sized per
* OSSL_FN_mod_exp_ctx_size().
*/
int OSSL_FN_mod_exp(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *p,
const OSSL_FN *m, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_exp() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The base
* @param[in] p The exponent
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_exp().
* It covers both the Montgomery (odd modulus) and simple (even modulus)
* sliding-window paths, sizing the arena for whichever path the modulus
* selects; see fn_exp.c.
*/
size_t OSSL_FN_mod_exp_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *p, const OSSL_FN *m);
/**
* Calculate a^p mod m with the simple sliding-window algorithm.
* This is the entry point that OSSL_FN_mod_exp() dispatches to for even
* moduli.
*
* @param[out] r The OSSL_FN for the result. Destination width
* is the caller's choice: if smaller than the
* modulus, the result is truncated; if larger,
* zero-padded. |r| must not alias |m|.
* @param[in] a The base.
* @param[in] p The exponent.
* @param[in] m The modulus. Must be non-zero.
* @param[in] ctx A context to get temporary OSSL_FN instances
* from, sized per OSSL_FN_mod_exp_simple_ctx_size().
* @returns 1 on success, 0 on error.
*
* @note This path is not constant-time per se; do not use it for secret
* exponents. See the implementation in crypto/fn/fn_exp.c.
*/
int OSSL_FN_mod_exp_simple(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *p,
const OSSL_FN *m, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_exp_simple() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The base
* @param[in] p The exponent
* @param[in] m The modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by
* OSSL_FN_mod_exp_simple().
*/
size_t OSSL_FN_mod_exp_simple_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *p, const OSSL_FN *m);
/**
* Calculate a^p mod m with the Montgomery sliding-window algorithm.
* This is the Montgomery entry point that OSSL_FN_mod_exp() dispatches to for
* odd moduli; callers that perform many exponentiations against the same
* modulus may call it directly and pass a reused OSSL_FN_MONT_CTX to amortise
* the RR / n0 setup, mirroring BN_mod_exp_mont().
*
* @param[out] r The OSSL_FN for the result. Destination width
* is the caller's choice: if smaller than the
* modulus, the result is truncated; if larger,
* zero-padded. |r| must not alias |m|.
* @param[in] a The base.
* @param[in] p The exponent.
* @param[in] m The modulus. Must be odd and non-zero.
* @param[in] ctx A context to get temporary OSSL_FN instances
* from, sized per OSSL_FN_mod_exp_mont_ctx_size().
* @param[in] in_mont A reusable Montgomery context for |m|, or NULL
* to have this function build and free its own.
* When non-NULL it is borrowed (used as-is, never
* freed here) and its modulus must be |m|.
* @returns 1 on success, 0 on error.
*
* @note This path is not constant-time per se; do not use it for secret
* exponents. See the implementation in crypto/fn/fn_exp.c.
*/
int OSSL_FN_mod_exp_mont(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *p,
const OSSL_FN *m, OSSL_FN_CTX *ctx, OSSL_FN_MONT_CTX *in_mont);
/**
* Calculate the arena payload size that OSSL_FN_mod_exp_mont() needs.
*
* Sizes only the Montgomery sliding-window path; the arena also serves a
* call that passes NULL |in_mont| (the function builds and frees its own
* context then), since the operand modelling makes the two cases the same
* size. Pass a non-NULL |in_mont| to keep the sizing signature parallel to
* OSSL_FN_mod_exp_mont().
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The base
* @param[in] p The exponent
* @param[in] m The modulus
* @param[in] in_mont A reusable Montgomery context for |m|, or NULL
* to model the function-owned context
* OSSL_FN_mod_exp_mont() builds when called
* with in_mont == NULL.
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*/
size_t OSSL_FN_mod_exp_mont_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *p, const OSSL_FN *m, OSSL_FN_MONT_CTX *in_mont);
/**
* Compute the Kronecker symbol (a/b).
*
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns The Kronecker symbol (a/b): 1, -1, or 0 (0 when a and
* b are not coprime). When b is prime, 1 means a is a
* quadratic residue mod b and -1 that it is not; for
* composite b, a result of 1 does not imply that a is a
* quadratic residue mod b.
* @retval -2 on error (-1, 0, and 1 are all valid results).
*
* Uses Cohen's algorithm 1.4.10 (Jacobi/Kronecker symbol). OSSL_FN is
* unsigned, so sign stays at the BIGNUM boundary. Not constant-time:
* branches on values throughout, as needed by mod-sqrt's non-residue search.
*/
int OSSL_FN_kronecker(const OSSL_FN *a, const OSSL_FN *b, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_kronecker() needs.
*
* @param[in] a The first operand
* @param[in] b The second operand
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by
* OSSL_FN_kronecker(). Two temporaries of max(a, b) limbs are needed,
* plus the nested OSSL_FN_mod() call in the loop body.
*/
size_t OSSL_FN_kronecker_ctx_size(const OSSL_FN *a, const OSSL_FN *b);
/**
* Compute a square root of @p a modulo @p p.
*
* @param[out] ret The OSSL_FN for the result (caller-sized,
* non-NULL).
* @param[in] a The operand.
* @param[in] p The prime modulus.
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error.
*
* Computes @p ret such that ret^2 == a (mod p) using the Tonelli/Shanks
* algorithm. @p p must be prime, otherwise an error or an incorrect result
* is returned. OSSL_FN is unsigned, so @p p is |p| and @p a is reduced by
* OSSL_FN_mod(); sign stays at the BIGNUM boundary. Not constant-time:
* branches on values throughout, including mod-sqrt's non-residue search.
*
* @note OSSL_FN requires a non-NULL writable @p ret. The computed root is
* truncated or zero-padded into the caller-sized destination.
*/
int OSSL_FN_mod_sqrt(OSSL_FN *ret, const OSSL_FN *a, const OSSL_FN *p,
OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mod_sqrt() needs.
*
* @param[in] ret The OSSL_FN for the result
* @param[in] a The operand
* @param[in] p The prime modulus
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mod_sqrt().
* Seven temporaries of p->dsize limbs are needed, plus the nested calls
* (mod_exp, mod_sqr, mod_mul, mod, kronecker).
*/
size_t OSSL_FN_mod_sqrt_ctx_size(const OSSL_FN *ret, const OSSL_FN *a,
const OSSL_FN *p);
/**
* Calculate the square of one OSSL_FN number. Truncates the result to fit in r.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX has free
* space for two temporary OSSL_FNs, a->dsize * 2 limbs each, plus one
* frame (currently 32 bytes).
*/
int OSSL_FN_sqr(OSSL_FN *r, const OSSL_FN *a, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_sqr() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The operand
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_sqr().
*/
size_t OSSL_FN_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a);
/**
* Initialize a Montgomery context for modulus mod.
* @param[in] mod The modulus
* @returns An allocated OSSL_FN_MONT_CTX, or NULL on error.
*/
OSSL_FN_MONT_CTX *OSSL_FN_MONT_CTX_new(const OSSL_FN *mod);
/**
* Free a Montgomery context.
*
* @param[in] ctx The context to be freed. This may be NULL.
*/
void OSSL_FN_MONT_CTX_free(OSSL_FN_MONT_CTX *ctx);
/**
* Make a copy of a Montgomery context
*
* @param[in] ctx The context to be duplicated.
* @returns a copy of this context, or NULL on error.
*/
OSSL_FN_MONT_CTX *OSSL_FN_MONT_CTX_dup(OSSL_FN_MONT_CTX *ctx);
/**
* Fulfil the Montgomery multiplication.
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] mont The Montgomery context
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that the OSSL_FN_CTX
* has free space for 2 frame, 7 numbers, and
* 7 * max(a->dsize, b->dsize, mont->N->dsize) + 2 limbs.
* Note that this provides an upper bound. Actual use of the arena may be
* smaller - see OSSL_FN_mul_mont_ctx_size() for an exact, conditional value.
*
* A timing side-channel may leak limb-size misalignment or whether the input
* operands exceed the modulus. However, this leakage is non-critical and
* acceptable from a security perspective.
*/
int OSSL_FN_mul_mont(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
OSSL_FN_MONT_CTX *mont, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mul_mont() needs.
*
* @param[in] r The OSSL_FN for the result (can be NULL)
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] mont The Montgomery context
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_mul_mont().
* If `r == NULL`, the returned size is calculated as if @p r has the same size
* as the modulus.
*
* A timing side-channel may leak limb-size misalignment or whether the input
* operands exceed the modulus. However, this leakage is non-critical and
* acceptable from a security perspective.
*/
size_t OSSL_FN_mul_mont_ctx_size(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
OSSL_FN_MONT_CTX *mont);
/**
* Fulfil the Montgomery multiplication. This is a quick variant that may be
* used if @p r, @p a, @p b, and @p mont->N are of the same size, and
* @p a and @p b are less than @p mont->N
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] mont The Montgomery context
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function currently requires that @p ctx has free space for
* one temporary OSSL_FN with @p mont->N->dsize+2 limbs, plus one frame.
*/
int OSSL_FN_mul_mont_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
OSSL_FN_MONT_CTX *mont, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_mul_mont_quick() needs.
*
* @param[in] r The OSSL_FN for the result
* @param[in] a The first operand
* @param[in] b The second operand
* @param[in] mont The Montgomery context
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by
* OSSL_FN_mul_mont_quick().
* All parameters except @p mont can be NULL.
*/
size_t OSSL_FN_mul_mont_quick_ctx_size(OSSL_FN *r, const OSSL_FN *a,
const OSSL_FN *b, OSSL_FN_MONT_CTX *mont);
/**
* Convert a number to Montgomery representation: r = a * R mod N,
* where R = 2^(length of limb in bits).
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] mont The Montgomery context
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function requires that @p r and @p mont->N are of
* the same size and that the OSSL_FN_CTX has free space for 2 frame,
* 5 numbers, and 5 * max(a->dsize, mont->N->dsize) + 2 limbs.
* Note that this provides an upper bound. Actual use of the arena may be
* smaller - see OSSL_FN_to_mont_ctx_size() for an exact, conditional value.
*
* A timing side-channel may leak limb-size misalignment or whether @p a
* exceeds the modulus. However, this leakage is non-critical and acceptable
* from a security perspective.
*/
int OSSL_FN_to_mont(OSSL_FN *r, const OSSL_FN *a,
OSSL_FN_MONT_CTX *mont, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_to_mont() needs.
*
* @param[in] r The OSSL_FN for the result (can be NULL)
* @param[in] a The operand
* @param[in] mont The Montgomery context
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_to_mont().
* If `r == NULL`, the returned size is calculated as if @p r has the same
* size as the modulus.
*
* A timing side-channel may leak limb-size misalignment or whether @p a
* exceeds the modulus. However, this leakage is non-critical and acceptable
* from a security perspective.
*/
size_t OSSL_FN_to_mont_ctx_size(OSSL_FN *r, const OSSL_FN *a,
OSSL_FN_MONT_CTX *mont);
/**
* Convert a number from Montgomery representation: r = a * R^(-1) mod N,
* where R = 2^(length of limb in bits).
*
* @param[out] r The OSSL_FN for the result
* @param[in] a The operand
* @param[in] mont The Montgomery context
* @param[in] ctx A context to get temporary OSSL_FN
* instances from.
* @returns 1 on success, 0 on error
*
* @note This function requires that @p r, @p a, and @p mont->N are of
* the same size, @p a is less than @p mont->N, @p ctx has free space for
* one temporary OSSL_FN with mont->N->dsize+2 limbs, plus one frame.
*/
int OSSL_FN_from_mont(OSSL_FN *r, const OSSL_FN *a,
OSSL_FN_MONT_CTX *mont, OSSL_FN_CTX *ctx);
/**
* Calculate the arena payload size that OSSL_FN_from_mont() needs.
*
* @param[in] r The OSSL_FN for the result (can be NULL)
* @param[in] a The operand (can be NULL)
* @param[in] mont The Montgomery context
* @returns The arena payload size, in bytes.
* @retval 0 on arithmetic overflow or invalid input.
*
* The returned size includes any frame budget needed by OSSL_FN_from_mont().
*/
size_t OSSL_FN_from_mont_ctx_size(OSSL_FN *r, const OSSL_FN *a,
OSSL_FN_MONT_CTX *mont);
#ifdef __cplusplus
}
#endif
#endif