otp: avoid pow() when computing the otp modulo
What changed, and why it matters
This commit changes how a one-time passcode (OTP) is shortened to the requested number of digits. Previously the code used the floating-point math function pow() to compute 10^digits, which can introduce tiny rounding errors. Now it uses fixed integer constants (1,000,000 for 6 digits and 100,000,000 for 8 digits). The change removes a potential source of incorrect OTP values and also drops an unnecessary math-library dependency, but the commit message does not frame it as a security fix.
Treat as a low-risk correctness/hardening improvement. Verify that otp_ctx->digits is constrained to only 6 or 8 before this function, because the new branch silently assumes those two values. If other digit counts are possible, add explicit handling or bounds checks. Consider adding unit tests for 6- and 8-digit OTP outputs against known test vectors.
Security signals we found
Floating-point arithmetic removed from cryptographic output path
Potential incorrect modulus due to double-to-int cast rounding
OTP token generation correctness improved
Evidence from the diff
In main/otpauth.c, otp_get_auth_code() previously computed the truncation modulus as pow(10, otp_ctx->digits) and cast the double result to int32_t. Because pow() operates on doubles, values like pow(10,8) are not always represented exactly, so the cast could yield 99999999 instead of 100000000. That would make an 8-digit TOTP/HOTP use the wrong modulus, producing an invalid token. The patch replaces the pow() call with an explicit branch selecting 1000000 or 100000000 based on digits. Only 6 and 8 digit OTPs appear to be supported by this code path.
Changed components
main/otpauth.cotp_get_auth_code()TOTP/HOTP token generationInspect captured patch +2 / −2
diff --git a/main/otpauth.c b/main/otpauth.c
index d2120b3..9a76e36 100644
--- a/main/otpauth.c
+++ b/main/otpauth.c
@@ -11,7 +11,6 @@
#include <http_parser.h>
#include <mbedtls/md.h>
-#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -400,7 +399,8 @@ bool otp_get_auth_code(const otpauth_ctx_t* otp_ctx, char* token, const size_t t
const size_t offset = hmac[hmac_last_index] & 0xf;
const int32_t full_code = ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16)
| ((hmac[offset + 2] & 0xff) << 8) | ((hmac[offset + 3] & 0xff));
- const int32_t trunc_code = full_code % (int32_t)pow(10, otp_ctx->digits);
+ const int32_t mod = otp_ctx->digits == 6 ? 1000000 : 100000000;
+ const int32_t trunc_code = full_code % mod;
// Format as a string with leading 0's
const int ret = snprintf(token, token_len, "%0*ld", otp_ctx->digits, trunc_code);
Why this scored 35/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.