32 lines
1013 B
TypeScript
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;
|
|
}
|