import { OTPError } from './errors.js';
import { HashAlgorithm, SecretOptions, OTPResult } from './types.js';

/**
 * Minimum secret length in bytes (128 bits as per RFC 4226)
 */
declare const MIN_SECRET_BYTES = 16;
/**
 * Maximum secret length in bytes (512 bits)
 *
 * The 64-byte maximum is not part of the RFCs.
 * This is to prevent excessive memory usage in HMAC operations.
 */
declare const MAX_SECRET_BYTES = 64;
/**
 * Recommended secret length in bytes (160 bits as per RFC 4226)
 */
declare const RECOMMENDED_SECRET_BYTES = 20;
/**
 * Minimum period in seconds
 */
declare const MIN_PERIOD = 1;
/**
 * Maximum period in seconds (1 hour)
 */
declare const MAX_PERIOD = 3600;
/**
 * Default period in seconds (30 seconds as per RFC 6238)
 */
declare const DEFAULT_PERIOD = 30;
/**
 * Maximum safe integer for counter (2^53 - 1)
 */
declare const MAX_COUNTER: number;
/**
 * Maximum verification window size
 *
 * Limits the number of HMAC computations during verification to prevent DoS attacks.
 * A window of 100 means up to 201 HMAC computations ([-100, +100] range).
 *
 * For TOTP: window=1 is typically sufficient (allows +-30 seconds clock drift)
 * For HOTP: window=10-50 handles reasonable counter desynchronization
 */
declare const MAX_WINDOW = 100;
/**
 * Configurable guardrails for OTP validation
 *
 * Allows overriding default safety limits for non-standard production requirements.
 * Use with caution - custom guardrails can weaken security.
 */
type OTPGuardrailsConfig = {
    MIN_SECRET_BYTES: number;
    MAX_SECRET_BYTES: number;
    MIN_PERIOD: number;
    MAX_PERIOD: number;
    MAX_COUNTER: number;
    MAX_WINDOW: number;
};
/**
 * Module-private symbol to track guardrail override status
 *
 * This symbol is used as a property key to store whether guardrails contain custom values.
 * Being module-private and a symbol ensures:
 * - Cannot be accessed outside this module (not exported)
 * - Cannot be recreated (each Symbol() call is unique)
 * - Hidden from normal enumeration (Object.keys, JSON.stringify, for-in)
 * - Minimal memory overhead (~1 byte per object)
 * - No garbage collection concerns
 *
 * @internal
 */
declare const OVERRIDE_SYMBOL: unique symbol;
/**
 * Complete guardrails configuration
 *
 * This represents the final, immutable configuration used by validation functions.
 * Internally tracks whether any values were overridden from RFC recommendations,
 * enabling security auditing and compliance monitoring without exposing implementation
 * details in the public API.
 *
 * The override status is stored using a module-private Symbol that cannot be accessed
 * or recreated outside this module, providing true encapsulation.
 *
 * @see {@link OTPGuardrailsConfig} for the base configuration structure
 * @see {@link createGuardrails} for creating guardrails instances
 * @see {@link hasGuardrailOverrides} to check if guardrails were customized
 */
type OTPGuardrails = Readonly<OTPGuardrailsConfig> & {
    [OVERRIDE_SYMBOL]?: boolean;
};
/**
 * Create guardrails configuration object
 *
 * Factory function that merges custom guardrails with defaults and returns
 * an immutable (frozen) object. Validates custom guardrails to ensure they
 * maintain basic safety invariants.
 *
 * When called without arguments or with `undefined`, returns the default guardrails
 * singleton (optimized to avoid unnecessary allocations). When called with custom
 * values, creates a new frozen object and internally marks it as overridden.
 *
 * @param custom - Optional partial guardrails to override defaults
 * @returns Frozen guardrails object
 * @throws {Error} If custom guardrails violate safety invariants
 *
 * @example Basic usage
 * ```ts
 * import { createGuardrails, hasGuardrailOverrides } from '@otplib/core'
 *
 * // Returns default singleton (no overrides)
 * const defaults = createGuardrails();
 * hasGuardrailOverrides(defaults); // false
 *
 * // Creates new object with overrides
 * const custom = createGuardrails({
 *   MIN_SECRET_BYTES: 8,
 *   MAX_WINDOW: 200
 * });
 * hasGuardrailOverrides(custom); // true
 * ```
 *
 * @example Monitoring custom guardrails
 * ```ts
 * import { createGuardrails, hasGuardrailOverrides } from '@otplib/core';
 *
 * const guardrails = createGuardrails({ MAX_WINDOW: 20 });
 *
 * if (hasGuardrailOverrides(guardrails)) {
 *   logger.warn('Non-default guardrails in use', { guardrails });
 * }
 * ```
 *
 * @see {@link hasGuardrailOverrides} to check if guardrails were customized
 */
declare function createGuardrails(custom?: Partial<OTPGuardrailsConfig>): OTPGuardrails;
/**
 * Check if guardrails contain custom overrides
 *
 * Returns `true` if the guardrails object was created with custom values,
 * `false` if using RFC-recommended defaults. Useful for security auditing,
 * compliance monitoring, and development warnings.
 *
 * This function accesses a module-private Symbol property that cannot be
 * accessed or modified outside this module, ensuring reliable detection.
 *
 * @param guardrails - The guardrails object to check
 * @returns `true` if guardrails were customized, `false` if using defaults
 *
 * @example Security monitoring
 * ```ts
 * import { createGuardrails, hasGuardrailOverrides } from '@otplib/core';
 *
 * const guardrails = createGuardrails({ MAX_WINDOW: 20 });
 *
 * if (hasGuardrailOverrides(guardrails)) {
 *   console.warn('Custom guardrails detected:', guardrails);
 *   // Log to security audit system
 * }
 * ```
 *
 * @example Compliance check
 * ```ts
 * function validateGuardrails(guardrails: OTPGuardrails) {
 *   if (hasGuardrailOverrides(guardrails)) {
 *     throw new Error('Custom guardrails not allowed in production');
 *   }
 * }
 * ```
 */
declare function hasGuardrailOverrides(guardrails: OTPGuardrails): boolean;
/**
 * Validate secret key
 *
 * @param secret - The secret to validate
 * @param guardrails - Validation guardrails (defaults to RFC recommendations)
 * @throws {SecretTooShortError} If secret is too short
 * @throws {SecretTooLongError} If secret is too long
 */
declare function validateSecret(secret: Uint8Array, guardrails?: OTPGuardrails): void;
/**
 * Validate counter value
 *
 * @param counter - The counter to validate
 * @param guardrails - Validation guardrails (defaults to RFC recommendations)
 * @throws {CounterNegativeError} If counter is negative
 * @throws {CounterOverflowError} If counter exceeds safe integer
 */
declare function validateCounter(counter: number | bigint, guardrails?: OTPGuardrails): void;
/**
 * Validate time value
 *
 * @param time - The time in seconds to validate
 * @throws {TimeNegativeError} If time is negative
 */
declare function validateTime(time: number): void;
/**
 * Validate period value
 *
 * @param period - The period in seconds to validate
 * @param guardrails - Validation guardrails (defaults to RFC recommendations)
 * @throws {PeriodTooSmallError} If period is too small
 * @throws {PeriodTooLargeError} If period is too large
 */
declare function validatePeriod(period: number, guardrails?: OTPGuardrails): void;
/**
 * Validate token
 *
 * @param token - The token string to validate
 * @param digits - Expected number of digits
 * @throws {TokenLengthError} If token has incorrect length
 * @throws {TokenFormatError} If token contains non-digit characters
 */
declare function validateToken(token: string, digits: number): void;
/**
 * Validate counter tolerance for HOTP verification
 *
 * Prevents DoS attacks by limiting the number of counter values checked.
 *
 * @param counterTolerance - Counter tolerance specification (number or array of offsets)
 * @param guardrails - Validation guardrails (defaults to RFC recommendations)
 * @throws {CounterToleranceTooLargeError} If tolerance size exceeds MAX_WINDOW
 *
 * @example
 * ```ts
 * validateCounterTolerance(1);        // OK: 3 offsets [-1, 0, 1]
 * validateCounterTolerance(100);      // OK: 201 offsets [-100, ..., 100]
 * validateCounterTolerance(101);      // Throws: exceeds MAX_WINDOW
 * validateCounterTolerance([0, 1]);   // OK: 2 offsets
 * ```
 */
declare function validateCounterTolerance(counterTolerance: number | number[], guardrails?: OTPGuardrails): void;
/**
 * Validate epoch tolerance for TOTP verification
 *
 * Prevents DoS attacks by limiting the time range checked.
 * Also validates that tolerance values are non-negative.
 *
 * @param epochTolerance - Epoch tolerance specification (number or tuple [past, future])
 * @param period - The TOTP period in seconds (default: 30). Used to calculate max tolerance.
 * @param guardrails - Validation guardrails (defaults to RFC recommendations)
 * @throws {EpochToleranceNegativeError} If tolerance contains negative values
 * @throws {EpochToleranceTooLargeError} If tolerance exceeds MAX_WINDOW periods
 *
 * @example
 * ```ts
 * validateEpochTolerance(30);            // OK: 30 seconds (default period 30s)
 * validateEpochTolerance([5, 0]);        // OK: 5 seconds past only
 * validateEpochTolerance([-5, 0]);       // Throws: negative values not allowed
 * validateEpochTolerance(3600);          // Throws: exceeds MAX_WINDOW * period
 * validateEpochTolerance(6000, 60);      // OK with 60s period (MAX_WINDOW * 60 = 6000)
 * ```
 */
declare function validateEpochTolerance(epochTolerance: number | [number, number], period?: number, guardrails?: OTPGuardrails): void;
/**
 * Convert counter to 8-byte big-endian array
 *
 * Per RFC 4226 Section 5.1, the counter value is represented as an 8-byte
 * big-endian (network byte order) unsigned integer.
 *
 * @see {@link https://tools.ietf.org/html/rfc4226#section-5.1 | RFC 4226 Section 5.1 - Symbol Descriptions}
 *
 * @param value - The counter value to convert
 * @returns 8-byte big-endian array
 */
declare function counterToBytes(value: number | bigint): Uint8Array;
/**
 * Perform Dynamic Truncation as per RFC 4226 Section 5.3
 *
 * The algorithm:
 * 1. Take the low-order 4 bits of the last byte as offset
 * 2. Extract 4 bytes starting at offset
 * 3. Mask the most significant bit to get a 31-bit unsigned integer
 *
 * This ensures consistent extraction across different HMAC output sizes
 * while producing a value that fits in a signed 32-bit integer.
 *
 * @see {@link https://tools.ietf.org/html/rfc4226#section-5.3 | RFC 4226 Section 5.3 - Generating an HOTP Value}
 *
 * @param hmacResult - HMAC result (at least 20 bytes for SHA-1)
 * @returns Truncated 31-bit unsigned integer
 */
declare function dynamicTruncate(hmacResult: Uint8Array): number;
/**
 * Convert truncated integer to OTP string with specified digits
 *
 * Computes: Snum mod 10^Digit (RFC 4226 Section 5.3)
 *
 * The result is zero-padded to ensure consistent length,
 * as required for proper token comparison.
 *
 * @see {@link https://tools.ietf.org/html/rfc4226#section-5.3 | RFC 4226 Section 5.3 - Generating an HOTP Value}
 *
 * @param value - The truncated integer value (Snum)
 * @param digits - Number of digits for the OTP (Digit, typically 6-8)
 * @returns OTP string with leading zeros if necessary
 */
declare function truncateDigits(value: number, digits: number): string;
/**
 * Validate that two byte arrays have equal length
 *
 * Useful as a preliminary check before performing byte-by-byte comparisons.
 *
 * @param a - First byte array
 * @param b - Second byte array
 * @returns true if arrays have equal length, false otherwise
 */
declare function validateByteLengthEqual(a: Uint8Array, b: Uint8Array): boolean;
/**
 * Constant-time comparison to prevent timing attacks
 *
 * This implements a timing-safe equality check as recommended in
 * RFC 4226 Section 7.2 for token validation to prevent
 * timing side-channel attacks.
 *
 * @see {@link https://tools.ietf.org/html/rfc4226#section-7.2 | RFC 4226 Section 7.2 - Validation and Verification}
 *
 * @param a - First value to compare
 * @param b - Second value to compare
 * @returns true if values are equal, false otherwise
 */
declare function constantTimeEqual(a: string | Uint8Array, b: string | Uint8Array): boolean;
/**
 * Get HMAC digest size in bytes for a given algorithm
 *
 * @param algorithm - The hash algorithm
 * @returns Digest size in bytes
 */
declare function getDigestSize(algorithm: HashAlgorithm): number;
/**
 * Convert a string or Uint8Array to Uint8Array
 *
 * This utility function normalizes input to Uint8Array, converting strings
 * using UTF-8 encoding. Uint8Array inputs are returned as-is.
 *
 * @param value - The value to convert (string or Uint8Array)
 * @returns The value as a Uint8Array (UTF-8 encoded for strings)
 *
 * @example
 * ```ts
 * import { stringToBytes } from '@otplib/core'
 *
 * const bytes1 = stringToBytes('1234567890123456')
 * // Returns: Uint8Array([49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54])
 *
 * const bytes2 = stringToBytes(new Uint8Array([1, 2, 3]))
 * // Returns: Uint8Array([1, 2, 3]) - returned as-is
 * ```
 */
declare function stringToBytes(value: string | Uint8Array): Uint8Array;
/**
 * Convert a hex string to a Uint8Array
 *
 * This is useful for working with RFC test vectors and debugging HMAC outputs,
 * which are commonly represented as hexadecimal strings.
 *
 * If your environment supports it, consider using `Uint8Array.fromHex()` instead.
 *
 * @param hex - The hex string to convert (lowercase or uppercase, no 0x prefix)
 * @returns The bytes as a Uint8Array
 *
 * @example
 * ```ts
 * import { hexToBytes } from '@otplib/core'
 *
 * // Convert RFC 4226 HMAC test vector
 * const hmac = hexToBytes('cc93cf18508d94934c64b65d8ba7667fb7cde4b0')
 * // Returns: Uint8Array([0xcc, 0x93, 0xcf, ...])
 * ```
 */
declare function hexToBytes(hex: string): Uint8Array;
/**
 * Normalize secret input to Uint8Array
 *
 * Accepts either a Base32-encoded string or Uint8Array and returns Uint8Array.
 * If a Base32Plugin is provided, string secrets will be automatically decoded.
 *
 * @param secret - The secret to normalize (string or Uint8Array)
 * @param base32 - Optional Base32Plugin to decode string secrets
 * @returns The secret as Uint8Array
 * @throws {Error} If secret is a string but no Base32Plugin is provided
 *
 * @example
 * ```ts
 * import { normalizeSecret } from '@otplib/core'
 * import { ScureBase32Plugin } from '@otplib/plugin-base32-scure'
 *
 * const base32 = new ScureBase32Plugin()
 *
 * // Uint8Array - returned as-is
 * const secret1 = normalizeSecret(new Uint8Array([1, 2, 3]))
 *
 * // Base32 string - automatically decoded
 * const secret2 = normalizeSecret('JBSWY3DPEHPK3PXP', base32)
 * ```
 */
declare function normalizeSecret(secret: string | Uint8Array, base32?: {
    decode: (str: string) => Uint8Array;
}): Uint8Array;
/**
 * Generate a random Base32-encoded secret
 *
 * Creates a cryptographically secure random secret suitable for OTP generation.
 * The default length of 20 bytes (160 bits) matches RFC 4226 recommendations
 * and provides good security margin.
 *
 * @param options - Secret generation options
 * @returns Base32-encoded secret string (without padding for Google Authenticator compatibility)
 *
 * @example
 * ```ts
 * import { generateSecret } from '@otplib/core';
 * import { NodeCryptoPlugin } from '@otplib/plugin-crypto-node';
 * import { ScureBase32Plugin } from '@otplib/plugin-base32-scure';
 *
 * const secret = generateSecret({
 *   crypto: new NodeCryptoPlugin(),
 *   base32: new ScureBase32Plugin(),
 * });
 * // Returns: 'JBSWY3DPEHPK3PXP...' (32 characters)
 * ```
 *
 * @example Custom length
 * ```ts
 * const secret = generateSecret({
 *   crypto: new NodeCryptoPlugin(),
 *   base32: new ScureBase32Plugin(),
 *   length: 32, // 256 bits for SHA-256
 * });
 * ```
 */
declare function generateSecret(options: SecretOptions): string;
/**
 * Normalize counter tolerance to an array of offsets
 *
 * Converts a number or array counter tolerance specification into an array of offsets
 * - Number: creates symmetric range [-tolerance, +tolerance]
 * - Array: uses the array as-is (already contains specific offsets)
 *
 * @param counterTolerance - Counter tolerance specification (number or array of offsets)
 * @returns Array of offsets to check
 *
 * @example
 * ```ts
 * normalizeCounterTolerance(0)  // [0]
 * normalizeCounterTolerance(1)  // [-1, 0, 1]
 * normalizeCounterTolerance(2)  // [-2, -1, 0, 1, 2]
 * normalizeCounterTolerance([0, 1])  // [0, 1]
 * normalizeCounterTolerance([-1, 0, 1])  // [-1, 0, 1]
 * ```
 */
declare function normalizeCounterTolerance(counterTolerance?: number | number[]): number[];
/**
 * Normalize epoch tolerance to [past, future] tuple
 *
 * Converts a number or tuple epoch tolerance specification into a [past, future] tuple
 * - Number: creates symmetric tolerance [tolerance, tolerance]
 * - Tuple: uses the tuple as-is
 *
 * @param epochTolerance - Epoch tolerance specification (number or tuple [past, future])
 * @returns Tuple [pastTolerance, futureTolerance] in seconds
 *
 * @example
 * ```ts
 * normalizeEpochTolerance(0)        // [0, 0]
 * normalizeEpochTolerance(30)       // [30, 30]
 * normalizeEpochTolerance([5, 0])   // [5, 0]
 * normalizeEpochTolerance([10, 5])  // [10, 5]
 * ```
 */
declare function normalizeEpochTolerance(epochTolerance?: number | [number, number]): [number, number];
/**
 * Require crypto plugin to be configured
 *
 * @param crypto - The crypto plugin
 * @throws {CryptoPluginMissingError} If crypto plugin is not set
 */
declare function requireCryptoPlugin<T>(crypto: T | undefined): asserts crypto is T;
/**
 * Require Base32 plugin to be configured
 *
 * @param base32 - The Base32 plugin
 * @throws {Base32PluginMissingError} If Base32 plugin is not set
 */
declare function requireBase32Plugin<T>(base32: T | undefined): asserts base32 is T;
/**
 * Require secret to be configured
 *
 * @param secret - The secret value
 * @throws {SecretMissingError} If secret is not set
 */
declare function requireSecret<T>(secret: T | undefined): asserts secret is T;
/**
 * Require label to be configured (for URI generation)
 *
 * @param label - The label value
 * @throws {LabelMissingError} If label is not set
 */
declare function requireLabel(label: string | undefined): asserts label is string;
/**
 * Require issuer to be configured (for URI generation)
 *
 * @param issuer - The issuer value
 * @throws {IssuerMissingError} If issuer is not set
 */
declare function requireIssuer(issuer: string | undefined): asserts issuer is string;
/**
 * Require secret to be a Base32 string (for URI generation)
 *
 * @param secret - The secret value
 * @throws {SecretTypeError} If secret is not a string
 */
declare function requireBase32String(secret: string | Uint8Array): asserts secret is string;
/**
 * Wrap a synchronous function to return OTPResult instead of throwing
 *
 * Preserves the original OTPError subclass so users can access
 * specific error information via instanceof checks.
 *
 * @internal
 */
declare function wrapResult<T, Args extends unknown[]>(fn: (...args: Args) => T): (...args: Args) => OTPResult<T, OTPError>;
/**
 * Wrap an async function to return OTPResult instead of throwing
 *
 * Preserves the original OTPError subclass so users can access
 * specific error information via instanceof checks.
 *
 * @internal
 */
declare function wrapResultAsync<T, Args extends unknown[]>(fn: (...args: Args) => Promise<T>): (...args: Args) => Promise<OTPResult<T, OTPError>>;

export { DEFAULT_PERIOD, MAX_COUNTER, MAX_PERIOD, MAX_SECRET_BYTES, MAX_WINDOW, MIN_PERIOD, MIN_SECRET_BYTES, type OTPGuardrails, type OTPGuardrailsConfig, RECOMMENDED_SECRET_BYTES, constantTimeEqual, counterToBytes, createGuardrails, dynamicTruncate, generateSecret, getDigestSize, hasGuardrailOverrides, hexToBytes, normalizeCounterTolerance, normalizeEpochTolerance, normalizeSecret, requireBase32Plugin, requireBase32String, requireCryptoPlugin, requireIssuer, requireLabel, requireSecret, stringToBytes, truncateDigits, validateByteLengthEqual, validateCounter, validateCounterTolerance, validateEpochTolerance, validatePeriod, validateSecret, validateTime, validateToken, wrapResult, wrapResultAsync };
