BN_ADD(3ossl)

πŸ’– BN_ADD(3ossl) β€” arithmetic operations on BIGNUMs πŸ’–

okay bestie, pull up a chair πŸͺ‘ because this is the page where OpenSSL does math. big math. like, numbers-so-big-they-don't-fit-in-a-normal-int math. this is BN_ADD(3ossl) from the OpenSSL manual, and yes it covers 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 and BN_gcd. that's fifteen functions. fifteen. she's booked and busy πŸ’…


✨ 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 🌸

the no-ctx girlies (aka the easy ones) 🧚

  • BN_add() β€” adds a and b, drops the answer in r (r=a+b). plot twist: r is allowed to be the same BIGNUM as a or b. slay, in-place πŸ’–
  • BN_sub() β€” takes b away from a, puts the result in r (r=a-b). and yeah, r can be the same BIGNUM as a or b again.
  • BN_mul() β€” multiplies a and b, result goes in r (r=a*b). r may be the same BIGNUM as a or b. oh and if you're multiplying by powers of 2 specifically? use BN_lshift(3) instead, that's the move 🫢
  • BN_sqr() β€” squares a, result in r (r=a^2). r and a can be the same BIGNUM. this one is faster than BN_mul(r,a,a) β€” no cap, it's literally built different ✨
  • 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 may be NULL, and if it is, that value just… doesn't come back. it's giving "no thoughts, no return value". the result rounds towards zero, which means if a is negative, the remainder will be zero or negative. and if you're dividing by powers of 2? BN_rshift(3), bestie.
  • BN_mod() β€” it's just BN_div() with dv set to NULL. that's it. that's the whole vibe.
  • BN_nnmod() β€” reduces a modulo m and puts the nonnegative remainder in r. nn = nonnegative, iykyk πŸ’…
  • BN_mod_add() β€” adds a to b modulo m, nonnegative result lands in r.
  • BN_mod_sub() β€” subtracts b from a modulo m, nonnegative result lands 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 may be the same BIGNUM as a or b. and if you're doing repeated computations with the same modulus, there are more efficient algorithms β€” go peek at BN_mod_mul_montgomery(3) and BN_mod_mul_reciprocal(3) πŸ‘‘
  • 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). 🚨 important 🚨: the modulus p must be a prime, otherwise you get an error or an incorrect "result". like, it will hand you something and act normal about it. the result is stored into in, which can be NULL β€” in that case the result gets newly allocated.
  • BN_exp() β€” raises a to the p-th power, result in r (r=a^p). faster than calling BN_mul() over and over, thank god 😭
  • BN_mod_exp() β€” computes a to the p-th power modulo m (r=a^p % m). 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 real warning, not a vibe check.
  • BN_gcd() β€” computes the greatest common divisor of a and b, result in r. r may be the same BIGNUM as a or b. the iconic GCD, we love her 🌈

the ctx rules πŸ“‹

for all functions that take a ctx parameter, it must be a previously allocated BN_CTX used for temporary variables β€” see BN_CTX_new(3). unless the documentation for a specific function says otherwise, ctx must not be NULL. periodt.

and unless noted otherwise, the result BIGNUM must be different from the arguments. no sharing, bestie, we don't do that here πŸ™ˆ


πŸ’€ 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 genuinely an error. don't. πŸ’€


⭐ RETURN VALUES ⭐

BN_mod_sqrt() returns the result β€” which, reminder, may be incorrect if p is not a prime β€” or NULL. yes she can lie to you. be careful 🫢

for all the remaining functions: 1 means success, 0 means error. and you should always check the return value, like:

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

the error codes can be obtained with ERR_get_error(3). always check, never guess, that's the rule ✨


πŸ¦‹ SEE ALSO πŸ¦‹


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 BN_ADD(3ossl) from OpenSSL 3.5.9, dated 2026-09-29 β€” go do huge math responsibly, check your return values, and don't pass an even m with BN_FLG_CONSTTIME. mwah πŸŽ€βœ¨

πŸ“¦ where this page comes from