Files
2026-05-27 23:47:53 +01:00

32 lines
1013 B
TypeScript

import { OTP_CODES, otpError } from "../errors/codes.js";
const MAX_U64 = (1n << 64n) - 1n;
/**
* Encode an HOTP counter as the 8-byte big-endian block required by RFC 4226
* §5.1. `bigint` is the canonical input type — `Number` loses precision past
* `2^53` and the RFC permits counters up to `2^64 - 1`. Negative counters and
* counters past `2^64 - 1` raise `OtpError(OTP.INVALID_OPTIONS)`.
*/
export function encodeCounter(counter: bigint): Uint8Array {
if (counter < 0n) {
throw otpError(
OTP_CODES.INVALID_OPTIONS,
"HOTP counter must be non-negative (RFC 4226 §5.1)"
);
}
if (counter > MAX_U64) {
throw otpError(
OTP_CODES.INVALID_OPTIONS,
"HOTP counter exceeds 2^64-1 (RFC 4226 §5.1 mandates an 8-byte big-endian block)"
);
}
const out = new Uint8Array(8);
let v = counter;
for (let i = 7; i >= 0; i -= 1) {
out[i] = Number(v & 0xffn);
v >>= 8n;
}
return out;
}