BN_ADD(3)

๐Ÿ“ฆ version 4.4.0, in alpine 3.24, arch rolling

๐Ÿ’… BN_ADD(3) โ€” the bignum arithmetic girlies

ok so this is a library functions manual page for BN_ADD(3), and bestie, it's a whole family of functions. like, one man page, twenty-two functions, all doing math on BIGNUMs. sit down, get a snack ๐Ÿ“, we're gonna go through every single one of them, no skipped tracks, periodt.


โœจ NAME โœจ

BN_add, BN_uadd, BN_sub, BN_usub, BN_mul, BN_sqr, BN_div, BN_mod, BN_nnmod, BN_mod_add, BN_mod_add_quick, BN_mod_sub, BN_mod_sub_quick, BN_mod_mul, BN_mod_sqr, BN_mod_lshift, BN_mod_lshift_quick, BN_mod_lshift1, BN_mod_lshift1_quick, BN_exp, BN_mod_exp, BN_gcd โ€” literally all of them are arithmetic operations on BIGNUMs. that's the whole vibe ๐Ÿงฎ๐Ÿ’–


๐ŸŒธ SYNOPSIS ๐ŸŒธ

library โ€œlibcryptoโ€

#include <openssl/bn.h>

int
BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);

int
BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);

int
BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);

int
BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);

int
BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);

int
BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx);

int
BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *a, const BIGNUM *d,
    BN_CTX *ctx);

int
BN_mod(BIGNUM *rem, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);

int
BN_nnmod(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);

int
BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
    BN_CTX *ctx);

int
BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
    const BIGNUM *m);

int
BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
    BN_CTX *ctx);

int
BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
    const BIGNUM *m);

int
BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
    BN_CTX *ctx);

int
BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);

int
BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
    BN_CTX *ctx);

int
BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m);

int
BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m,
    BN_CTX *ctx);

int
BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m);

int
BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);

int
BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
    BN_CTX *ctx);

int
BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

ok this is the main character section, let's go one by one ๐Ÿ’…

  • BN_add() โ€” adds a and b, drops the result in r (r=a+b). and yes queen, r may be the same BIGNUM as a or b. aliasing is allowed, we love that for us.
  • BN_uadd() โ€” adds the absolute values of a and b, result goes in r (r=|a|+|b|). r may be the same BIGNUM as a or b.
  • BN_sub() โ€” subtracts b from a, result in r (r=a-b). r may be the same BIGNUM as a or b.
  • BN_usub() โ€” subtracts the absolute value of b from the absolute value of a, result in r (r=|a|-|b|). โš ๏ธ it requires the absolute value of a to be greater than the absolute value of b, otherwise it will fail. r may be the same BIGNUM as a or b tho.
  • BN_mul() โ€” multiplies a and b, result in r (r=a*b). r may be the same BIGNUM as a or b. multiplying by powers of 2? use BN_lshift(3) instead, bestie.
  • BN_sqr() โ€” squares a, result in r (r=a^2). r and a may be the same BIGNUM. this is faster than BN_mul(r, a, a) โ€” like, noticeably. slay.
  • BN_div() โ€” divides a by d, puts the quotient in dv and the remainder in rem (dv=a/d, rem=a%d). if the flag BN_FLG_CONSTTIME is set on a or d, it operates in constant time ๐Ÿ”ฅ. either of dv and rem may be NULL, and then that value just... isn't returned, no drama. the result is rounded towards zero, so if a is negative, the remainder will be zero or negative. dividing by powers of 2? that's BN_rshift(3)'s job.
  • BN_mod() โ€” this is basically BN_div() with dv set to NULL. it's implemented as a macro, iykyk.
  • BN_nnmod() โ€” reduces a modulo m, puts the non-negative remainder in r.
  • BN_mod_add() โ€” adds a to b modulo m, non-negative result in r.
  • BN_mod_add_quick() โ€” a variant of BN_mod_add() that requires a and b to both be non-negative and smaller than m. if any of these constraints are violated, it silently produces wrong results ๐Ÿ’€ like it will not tell you. it will just be wrong.
  • BN_mod_sub() โ€” subtracts b from a modulo m, non-negative result in r.
  • BN_mod_sub_quick() โ€” a variant of BN_mod_sub() that requires a and b to both be non-negative and smaller than m. violate the constraints and it silently produces wrong results ๐Ÿ’€ same deal.
  • BN_mod_mul() โ€” multiplies a by b and finds the non-negative remainder with respect to modulus m (r=(a*b)%m). r may be the same BIGNUM as a or b. doing repeated computations with the same modulus? there's a more efficient algorithm, see BN_mod_mul_montgomery(3) ๐Ÿ‘€
  • BN_mod_sqr() โ€” squares a modulo m, result goes in r.
  • BN_mod_lshift() โ€” shifts a left by n bits, reduces the result modulo m, non-negative remainder in r (r=a*2^n mod m).
  • BN_mod_lshift1() โ€” shifts a left by one bit, reduces the result modulo m, non-negative remainder in r (r=a*2 mod m).
  • BN_mod_lshift_quick() and BN_mod_lshift1_quick() โ€” variants of BN_mod_lshift() and BN_mod_lshift1() respectively, that require a to be non-negative and less than m. if either of these constraints is violated, they sometimes fail and sometimes silently produce wrong results. yes, sometimes one, sometimes the other. chaotic behaviour honestly ๐Ÿ™ˆ
  • BN_exp() โ€” raises a to the p-th power, result in r (r=a^p). this is faster than repeatedly applying BN_mul(). ate.
  • BN_mod_exp() โ€” computes a to the p-th power modulo m (r=(a^p)%m). if the flag BN_FLG_CONSTTIME is set on p, it operates in constant time ๐Ÿ”ฅ. this function uses less time and space than BN_exp(). queen behaviour.
  • BN_gcd() โ€” computes the greatest common divisor of a and b, result in r. r may be the same BIGNUM as a or b.

for all functions, ctx is a previously allocated BN_CTX used for temporary variables โ€” see BN_CTX_new(3) ๐Ÿซถ

โš ๏ธ unless noted otherwise, the result BIGNUM must be different from the arguments. (the ones marked "may be the same" above are the exception, don't get it twisted ๐Ÿ’…)

๐ŸŒˆ RETURN VALUES ๐ŸŒˆ

for all functions: 1 = success, 0 = error. and bestie, the return value should always be checked, no exceptions. like this:

if (!BN_add(r,a,b)) goto err;

error codes can be obtained with ERR_get_error(3). ๐Ÿ”ฅ


๐ŸŽ€ SEE ALSO ๐ŸŽ€

BN_add_word(3), BN_CTX_new(3), BN_new(3), BN_set_bit(3), BN_set_flags(3), BN_set_negative(3)

go read them, i'll wait ๐Ÿ’–


๐Ÿ‘‘ HISTORY ๐Ÿ‘‘

ok history lesson, gather round ๐Ÿงš

  • BN_add(), BN_sub(), BN_mul(), BN_sqr(), BN_div(), BN_mod(), BN_mod_mul(), BN_mod_exp(), and BN_gcd() first appeared in SSLeay 0.5.1. all these functions have been available since OpenBSD 2.4.
  • BN_uadd(), BN_usub(), and the ctx argument to BN_mul() first appeared in SSLeay 0.9.1 and have been available since OpenBSD 2.6.
  • BN_nnmod(), BN_mod_add(), BN_mod_add_quick(), BN_mod_sub(), BN_mod_sub_quick(), BN_mod_sqr(), BN_mod_lshift(), BN_mod_lshift_quick(), BN_mod_lshift1(), and BN_mod_lshift1_quick() first appeared in OpenSSL 0.9.7 and have been available since OpenBSD 3.2. that's a whole glow-up era โœจ

๐Ÿ’€ BUGS ๐Ÿ’€

warning time, and these are real warnings, not a vibe:

  • even if the BN_FLG_CONSTTIME flag is set on a or b, BN_gcd() neither fails nor operates in constant time, potentially allowing timing side-channel attacks. so like, the flag says constant time and it's just... not. ๐Ÿšฉ
  • even if the BN_FLG_CONSTTIME flag is set on p, if the modulus m is even, BN_mod_exp() does not operate in constant time, potentially allowing timing side-channel attacks. yeah. even modulus = no constant time. ๐Ÿ˜ญ
  • if BN_FLG_CONSTTIME is set on p, BN_exp() fails instead of operating in constant time. it doesn't even try. it just leaves. ๐Ÿšช

ok that's the whole page, you're officially a bignum girlie now ๐Ÿซถ๐Ÿ’œ this was Debian, June 8, 2025 โ€” mwah, go check your return values, love u, bye ๐Ÿ˜˜โœจ

๐Ÿ“ฆ where this page comes from