ALTCHA JS Library

April 10, 2026 ยท View on GitHub

ALTCHA TS/JS Library is a lightweight library for creating and verifying ALTCHA challenges on the server.

Installation

npm install altcha-lib

Usage

import { createChallenge, deriveHmacKeySecret, randomInt, verifySolution } from 'altcha-lib';
import { deriveKey } from 'altcha-lib/algorithms/pbkdf2';

const HMAC_SECRET = 'your-secret-key';
const HMAC_KEY_SECRET = 'your-other-secret-key';

// On the server: create a challenge and send it to the client
const challenge = await createChallenge({
  algorithm: 'PBKDF2/SHA-256',
  cost: 5_000,
	counter: randomInt(5_000, 10_000),
  deriveKey,
  hmacSignatureSecret: HMAC_SECRET,
	hmacKeySignatureSecret: HMAC_KEY_SECRET,
});

// On the server: verify the solution submitted by the client
const result = await verifySolution({
  challenge: payload.challenge,
  solution: payload.solution,
  deriveKey,
  hmacSignatureSecret: HMAC_SECRET,
	hmacKeySignatureSecret: HMAC_KEY_SECRET,
});

if (result.verified) {
  // challenge passed
}

Get Started

The library includes plugins for several popular frameworks to simplify integration.

If your framework is not listed, see the Advanced Usage guide for custom integrations.

Documentation

Compatibility

RuntimeVersionNotes
Node.js20+Argon2 available natively in 24.7+
Bun1+Argon2 not available natively
Deno2+Argon2 not available natively
WinterCG runtimesโ€”Use WebCrypto algorithms

Run Examples

Express example (Node.js with tsx):

npx tsx examples/express-example.ts

Hono example (Bun):

bun run --port 3000 examples/hono-example.ts

Hono example (Deno):

deno serve --allow-net --sloppy-imports --port 3000 examples/hono-example.ts

Breaking Changes (v2)

Version 2 introduces a new proof-of-work mechanism and challenge format. See the PoW documentation for details.

While the overall usage remains similar, the library has been refactored and several function signatures have changed. Using the provided framework plugins is recommended. For unsupported frameworks or custom setups, refer to the Advanced Usage guide.

Compatibility with v1

The API for the previous PoW version (v1) remains available under the altcha-lib/v1 path:

import { createChallenge } from 'altcha-lib/v1';

API Reference

The default import path (altcha-lib) uses the v2 API. The v1 API is available at altcha-lib/v1.

v2 (altcha-lib)

createChallenge(options: CreateChallengeOptions): Promise<Challenge>

Creates a new proof-of-work challenge. Generates a random nonce and salt, optionally pre-computes a key prefix from a known counter value, and optionally signs the challenge with HMAC.

OptionTypeDescription
algorithmstringKey derivation algorithm (e.g. 'PBKDF2/SHA-256', 'ARGON2ID', 'SCRYPT').
costnumberAlgorithm-specific cost controlling computational difficulty.
deriveKeyDeriveKeyFunctionKey derivation function.
counternumber?Known counter value for deterministic mode.
counterMode'uint32' | 'string'Counter encoding format. Defaults to 'uint32'.
dataRecord<string, ...>?Arbitrary metadata embedded in the challenge.
expiresAtnumber | Date?Expiry timestamp (seconds) or Date.
hmacAlgorithmHmacAlgorithm?HMAC digest algorithm. Defaults to 'SHA-256'.
hmacKeySignatureSecretstring?HMAC secret for signing derived keys (deterministic mode).
hmacSignatureSecretstring?HMAC secret for signing the challenge payload.
keyLengthnumber?Derived key length in bytes. Defaults to 32.
keyPrefixstring?Required prefix the derived key must match.
keyPrefixLengthnumber?Number of bytes used as prefix in deterministic mode. Defaults to keyLength / 2.
memoryCostnumber?Memory cost in KiB (Argon2id/scrypt only).
parallelismnumber?Parallelism setting (Argon2id/scrypt only).

solveChallenge(options: SolveChallengeOptions): Promise<Solution | null>

Solves a challenge by brute-forcing counter values until the derived key starts with the required prefix. Returns null on timeout or abort.

OptionTypeDescription
challengeChallengeThe challenge to solve.
deriveKeyDeriveKeyFunctionKey derivation function.
controllerAbortController?For cancelling the solve operation.
counterStartnumber?Initial counter value. Defaults to 0.
counterStepnumber?Increment between attempts. Defaults to 1.
counterMode'uint32' | 'string'?Counter encoding format. Defaults to 'uint32'.
timeoutnumber?Timeout in milliseconds. Defaults to 90000.

solveChallengeWorkers(options): Promise<Solution | null>

Solves a challenge using multiple Web Workers in parallel. Each worker tests a different interleaved subset of counter values. Automatically retries with fewer workers on out-of-memory errors.

OptionTypeDescription
challengeChallengeThe challenge to solve.
concurrencynumberNumber of workers to use (max 16).
createWorker(algorithm: string) => Worker | Promise<Worker>Factory function to create a worker.
controllerAbortController?For cancelling the solve operation.
counterMode'uint32' | 'string'?Counter encoding format.
onOutOfMemory(concurrency: number) => number | void?Called on OOM; return new concurrency to retry or falsy to abort.
timeoutnumber?Timeout in milliseconds.

verifySolution(options: VerifySolutionOptions): Promise<VerifySolutionResult>

Verifies a submitted solution against a challenge. Checks expiration, challenge signature integrity, and that the derived key matches the solution.

OptionTypeDescription
challengeChallengeThe original challenge.
solutionSolutionThe solution to verify.
hmacSignatureSecretstringHMAC secret used when the challenge was created.
deriveKeyDeriveKeyFunctionKey derivation function.
counterMode'uint32' | 'string'?Counter encoding format.
hmacAlgorithmHmacAlgorithm?HMAC digest algorithm. Defaults to 'SHA-256'.
hmacKeySignatureSecretstring?HMAC secret for verifying derived-key signatures.

Returns VerifySolutionResult:

FieldTypeDescription
verifiedbooleanWhether the solution is valid.
expiredbooleanWhether the challenge has expired.
invalidSignatureboolean | nullWhether the challenge signature is invalid.
invalidSolutionboolean | nullWhether the solution is incorrect.
timenumberTime taken to verify in milliseconds.

verifyFieldsHash(options): Promise<boolean>

Verifies the SHA hash of specified form fields.

OptionTypeDescription
formDataFormData | Record<string, unknown>The form data to verify.
fieldsstring[]Field names to include in the hash.
fieldsHashstringThe expected hash value.
algorithmstring?Hash algorithm. Defaults to 'SHA-256'.

verifyServerSignature(options): Promise<VerifyServerSignatureResult>

Verifies a server signature payload from ALTCHA Sentinel.

OptionTypeDescription
payloadServerSignaturePayloadThe payload to verify.
hmacSecretstringThe HMAC secret.

Returns VerifyServerSignatureResult (extends VerifySolutionResult):

FieldTypeDescription
verifiedbooleanWhether the signature is valid.
verificationDataServerSignatureVerificationData | nullParsed verification data.

obfuscate(str: string, options?): Promise<string>

Import from altcha-lib/obfuscation

Encrypts a string using AES-GCM, with the key derived from a PoW challenge. Returns a base64-encoded payload.

OptionTypeDescription
counterMinnumber?Minimum counter value. Defaults to 20.
counterMaxnumber?Maximum counter value. Defaults to 200.
deriveKeyDeriveKeyFunction?Key derivation function. Defaults to PBKDF2.
...Any CreateChallengeOptions fields.

deobfuscate(obfuscatedData: string, options?): Promise<string>

Import from altcha-lib/obfuscation

Decrypts an obfuscated string by solving the embedded PoW challenge and using the derived key.

OptionTypeDescription
concurrencynumber?Worker concurrency. Defaults to up to 4.
createWorker(algorithm: string) => Worker?Factory to create a worker for solving.
deriveKeyDeriveKeyFunction?Key derivation function. Defaults to PBKDF2.

randomInt(max: number, min?: number): number

Returns a cryptographically random integer between min (default 1) and max.

class CappedMap<K, V>

A Map subclass with a fixed maximum size. When full, the oldest entry is evicted on insertion.

new CappedMap({ maxSize: number })

enum HmacAlgorithm

ValueString
HmacAlgorithm.SHA_256'SHA-256'
HmacAlgorithm.SHA_384'SHA-384'
HmacAlgorithm.SHA_512'SHA-512'

v1 (altcha-lib/v1)

createChallenge(options: ChallengeOptions): Promise<Challenge>

Creates a v1 SHA-based proof-of-work challenge.

OptionTypeDescription
hmacKeystringRequired. HMAC key for signing.
algorithm'SHA-1' | 'SHA-256' | 'SHA-512'?Hash algorithm. Defaults to 'SHA-256'.
expiresDate?Expiry date embedded in the salt.
maxNumbernumber?Maximum random number. Defaults to 1000000.
numbernumber?Fixed number (skips random selection).
paramsRecord<string, string>?Extra parameters embedded in the salt.
saltstring?Custom salt value.
saltLengthnumber?Random salt length in bytes. Defaults to 12.

verifySolution(payload: string | Payload, hmacKey: string, checkExpires?: boolean): Promise<boolean>

Verifies a v1 solution payload.

verifyFieldsHash(formData, fields, fieldsHash, algorithm?): Promise<boolean>

Verifies the hash of specified form fields.

verifyServerSignature(payload: string | ServerSignaturePayload, hmacKey: string): Promise<{ verified: boolean, verificationData: ServerSignatureVerificationData | null }>

Verifies a v1 server signature.

solveChallenge(challenge, salt, algorithm?, max?, start?): { promise: Promise<Solution | null>, controller: AbortController }

Solves a v1 challenge by brute force.

solveChallengeWorkers(workerScript, concurrency, challenge, salt, algorithm?, max?, startNumber?): Promise<Solution | null>

Solves a v1 challenge using Web Workers.

extractParams(payload: string | Payload | Challenge): Record<string, string>

Extracts URL parameters embedded in a challenge salt.

License

MIT