BN_ADD(3)
๐ 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()โ addsaandb, drops the result inr(r=a+b). and yes queen,rmay be the sameBIGNUMasaorb. aliasing is allowed, we love that for us.BN_uadd()โ adds the absolute values ofaandb, result goes inr(r=|a|+|b|).rmay be the sameBIGNUMasaorb.BN_sub()โ subtractsbfroma, result inr(r=a-b).rmay be the sameBIGNUMasaorb.BN_usub()โ subtracts the absolute value ofbfrom the absolute value ofa, result inr(r=|a|-|b|). โ ๏ธ it requires the absolute value ofato be greater than the absolute value ofb, otherwise it will fail.rmay be the sameBIGNUMasaorbtho.BN_mul()โ multipliesaandb, result inr(r=a*b).rmay be the sameBIGNUMasaorb. multiplying by powers of 2? useBN_lshift(3)instead, bestie.BN_sqr()โ squaresa, result inr(r=a^2).randamay be the sameBIGNUM. this is faster thanBN_mul(r, a, a)โ like, noticeably. slay.BN_div()โ dividesabyd, puts the quotient indvand the remainder inrem(dv=a/d, rem=a%d). if the flagBN_FLG_CONSTTIMEis set onaord, it operates in constant time ๐ฅ. either ofdvandremmay beNULL, and then that value just... isn't returned, no drama. the result is rounded towards zero, so ifais negative, the remainder will be zero or negative. dividing by powers of 2? that'sBN_rshift(3)'s job.BN_mod()โ this is basicallyBN_div()withdvset toNULL. it's implemented as a macro, iykyk.BN_nnmod()โ reducesamodulom, puts the non-negative remainder inr.BN_mod_add()โ addsatobmodulom, non-negative result inr.BN_mod_add_quick()โ a variant ofBN_mod_add()that requiresaandbto both be non-negative and smaller thanm. 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()โ subtractsbfromamodulom, non-negative result inr.BN_mod_sub_quick()โ a variant ofBN_mod_sub()that requiresaandbto both be non-negative and smaller thanm. violate the constraints and it silently produces wrong results ๐ same deal.BN_mod_mul()โ multipliesabyband finds the non-negative remainder with respect to modulusm(r=(a*b)%m).rmay be the sameBIGNUMasaorb. doing repeated computations with the same modulus? there's a more efficient algorithm, seeBN_mod_mul_montgomery(3)๐BN_mod_sqr()โ squaresamodulom, result goes inr.BN_mod_lshift()โ shiftsaleft bynbits, reduces the result modulom, non-negative remainder inr(r=a*2^n mod m).BN_mod_lshift1()โ shiftsaleft by one bit, reduces the result modulom, non-negative remainder inr(r=a*2 mod m).BN_mod_lshift_quick()andBN_mod_lshift1_quick()โ variants ofBN_mod_lshift()andBN_mod_lshift1()respectively, that requireato be non-negative and less thanm. 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()โ raisesato thep-th power, result inr(r=a^p). this is faster than repeatedly applyingBN_mul(). ate.BN_mod_exp()โ computesato thep-th power modulom(r=(a^p)%m). if the flagBN_FLG_CONSTTIMEis set onp, it operates in constant time ๐ฅ. this function uses less time and space thanBN_exp(). queen behaviour.BN_gcd()โ computes the greatest common divisor ofaandb, result inr.rmay be the sameBIGNUMasaorb.
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(), andBN_gcd()first appeared in SSLeay 0.5.1. all these functions have been available since OpenBSD 2.4.BN_uadd(),BN_usub(), and thectxargument toBN_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(), andBN_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_CONSTTIMEflag is set onaorb,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_CONSTTIMEflag is set onp, if the modulusmis 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_CONSTTIMEis set onp,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
- alpine 3.24: libressl-doc 4.3.1-r0 ยท custom
- arch rolling: libressl 4.4.0-1 ยท ISC AND custom:OpenSSL
- Copyright (c) 2021 Ingo Schwarze <schwarze@openbsd.org>
- Copyright (c) 2000, 2015 The OpenSSL Project. All rights reserved
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms