BN_ADD(3SSL)

πŸ’– BN_ADD β€” the OpenSSL math page, bestie edition πŸ’–

okay so. this is a page from the OpenSSL manual (section 3SSL, so like, a library function page), and it's literally the whole girl-math starter pack: adding, subtracting, multiplying, dividing, modular everything, and gcd. BIGNUMs are the big-number baddies behind all your crypto, and these functions are how you do arithmetic on them. let's get into it πŸŽ€


✨ NAME ✨

BN_add, BN_sub, BN_mul, BN_sqr, BN_div, BN_mod, BN_nnmod, BN_mod_add, BN_mod_sub, BN_mod_mul, BN_mod_sqr, BN_mod_sqrt, BN_exp, BN_mod_exp, BN_gcd β€” arithmetic operations on BIGNUMs. yes, all of them. it's a whole friend group 🫢


✨ SYNOPSIS ✨

#include <openssl/bn.h>

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

int BN_sub(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_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
               BN_CTX *ctx);

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);

BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);

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 ✨

okay so lemme go one by one, no skips, we're doing the full roster πŸ’…

  • BN_add() β€” adds a and b and drops the result in r ("r=a+b"). and get this: r is allowed to be the exact same BIGNUM as a or b. iconic, low-effort in-place vibes.
  • BN_sub() β€” subtracts b from a, result lands in r ("r=a-b"). same deal: r can be the same BIGNUM as a or b.
  • BN_mul() β€” multiplies a and b, result in r ("r=a*b"). r may be the same BIGNUM as a or b. but listen, if you're multiplying by powers of 2, don't do this, use BN_lshift(3) instead okay? it's better for that.
  • BN_sqr() β€” squares a, result in r ("r=a^2"). r and a can be the same BIGNUM. and it's faster than BN_mul(r,a,a), so if you were about to do that, bestie, no. use this one.
  • BN_div() β€” divides a by d, puts the quotient in dv and the remainder in rem ("dv=a/d, rem=a%d"). either of dv and rem can be NULL, and in that case that value just isn't returned (no drama, it's fine). ⚠️ the result is rounded towards zero, so if a is negative, the remainder will be zero or negative. and for dividing by powers of 2, use BN_rshift(3) instead.
  • BN_mod() β€” it's literally BN_div() but with dv set to NULL. that's it. that's the function.
  • BN_nnmod() β€” reduces a modulo m and puts the nonnegative remainder in r. the double-n is doing the work here, nn = nonnegative, iykyk.
  • BN_mod_add() β€” adds a to b modulo m, and the nonnegative result goes in r.
  • BN_mod_sub() β€” subtracts b from a modulo m, nonnegative result in r.
  • BN_mod_mul() β€” multiplies a by b and finds the nonnegative remainder with respect to modulus m ("r=(a*b) mod m"). r can be the same BIGNUM as a or b. and if you're doing repeated computations with the same modulus, there are more efficient algorithms waiting for you in BN_mod_mul_montgomery(3) and BN_mod_mul_reciprocal(3) β€” go look, it's giving optimization ✨
  • BN_mod_sqr() β€” squares a modulo m, result in r.
  • BN_mod_sqrt() β€” returns the modular square root of a such that "in^2 = a (mod p)". ⚠️ the modulus p must be a prime, otherwise you get an error or an incorrect "result" (yes those scare quotes are doing heavy lifting). the result gets stored into in, which can be NULL β€” and in that case the result is newly allocated for you. cute.
  • BN_exp() β€” raises a to the p-th power, result in r ("r=a^p"). this is faster than repeatedly calling BN_mul(), so stop looping, babe.
  • BN_mod_exp() β€” computes a to the p-th power modulo m ("r=a^p % m"). it uses less time and space than BN_exp(). 🚨 but do not call this function when m is even and any of the parameters have the BN_FLG_CONSTTIME flag set. that one's a hard no.
  • BN_gcd() β€” computes the greatest common divisor of a and b, result in r. r may be the same BIGNUM as a or b. love that for us.

now, the house rules for all of them πŸ‘‘:

for every function that takes a ctx parameter, that ctx has to be a previously allocated BN_CTX used for temporary variables β€” peep BN_CTX_new(3). and unless a specific function's own documentation says otherwise, ctx must not be NULL.

and unless noted otherwise, the result BIGNUM must be different from the arguments. (some of them allow aliasing, as noted above β€” but don't just assume, mkay?)


✨ NOTES ✨

for modular operations like BN_nnmod() or BN_mod_exp(), it is an error to use the same BIGNUM object for the modulus as for the output. πŸ’€ like, do not. that's not a vibe check you want to fail.


✨ RETURN VALUES ✨

BN_mod_sqrt() returns the result (which may be incorrect if p is not a prime, and we did warn you), or NULL.

for all the remaining functions: 1 for success, 0 on error. and you should always check that return value, no exceptions, like this:

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

the error codes can be obtained by ERR_get_error(3). 🫢


✨ SEE ALSO ✨

ERR_get_error(3), BN_CTX_new(3), BN_add_word(3), BN_set_bit(3)


Copyright 2000-2026 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>.


and that's the whole page, bestie πŸ’– this was OpenSSL 4.0.3, dated 2026-09-29, and yeah the page id is BN_ADD(3SSL). slay, go do some big-number math responsibly. πŸŽ€βœ¨πŸ’…

πŸ“¦ where this page comes from