NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #4362 most downloaded on pub.dev
Server-side Dart library for the ALTCHA Proof-of-Work v2 challenge system. Create, solve, and verify challenges using PBKDF2, SHA, Scrypt, or Argon2id.
Last release 5 days ago
03 Oct 2026
Ships on a steady schedule
a new release about every 3 months
Most releases are documented
notes for 4 of 6 stable releases
Nothing withdrawn
no release was ever pulled
6 months old
6 releases · first in 2026
One column per month.
Breaking changes and upgrade notes
This release brings the Dart port in line with the reference implementation, altcha-lib (JS) v2. A challenge created and signed by either library now verifies in the other. It also fixes several security issues in verification. All changes come from a cross-port compatibility audit and each one was checked against the JS library on identical inputs.
verifySolution was given hmacSignatureSecret: '', or verifyServerSignature was given hmacSecret: '', it accepted any challenge or payload HMAC-signed with the empty key. Anyone can compute such a signature. Both functions now return invalidSignature.verifySolution returns invalidSolution when solution.derivedKey is not valid hex. Before, it threw FormatException or ArgumentError when the challenge had a keySignature.verifyServerSignature handles a non-integer expire (such as 1.5, abc or an empty value). Before, it threw TypeError, even on forged payloads.expiresAt is now compared with the current time including fractions of a second. Before, a challenge was still accepted for up to 1 s after it expired.data keys are sorted, and null values are kept. Before, a challenge whose data had keys out of alphabetical order or a null value never verified, not even in Dart."9", "10", …) come first in numeric order, as they do in JS objects, and a __proto__ key is dropped.JSON.stringify writes them: 1.0 becomes 1, and -0.0 becomes 0.ChallengeParameters.extra map holds keys this class has no field for. They survive fromJson and toJson, so they are signed and verified. createChallenge now merges every key returned by a custom deriveKey, not just five fixed fields.expiresAt. JS challenges with values such as Date.now() / 1000 + 3600 now parse and verify.verifySolution compares an even-length keyPrefix as bytes, as solveChallenge and JS do. Before, it rejected solutions that its own solver had found for prefixes like F2.createChallenge with hmacSignatureSecret: '' returns an unsigned challenge. hmacKeySignatureSecret: '' adds no keySignature, and verifySolution re-derives the key instead.expiresAt: 0 means the challenge never expires. verificationData with expire=0 likewise doesn't expire.timeout: Duration.zero means no timeout in solveChallenge and solveChallengeIsolates.ChallengeParameters.expiresAt is now num? (was int?). Code that reads the field as an int no longer compiles; use num or .toInt(). createChallenge(expiresAt:) accepts a DateTime or any num.signChallenge throws ArgumentError if hmacSignatureSecret is empty.expiresAt: 0 used to make a challenge expire immediately; now it never expires.timeout: Duration.zero used to make the solver return null immediately; now there is no timeout.data contained a whole-number double (e.g. 1.0) or number-like keys. Challenges are short-lived, so the simplest fix is to let them expire or ask users to retry. Challenges whose data had keys out of order or null values are not affected, because they never verified before this release anyway.Challenge.toJson() / ChallengeParameters.toSortedJson() now sort nested keys too. Only the key order in the output changes.data with unsorted keys or null values: createChallenge and verifySolution now both sign altcha-lib's canonical JSON (keys sorted recursively, nulls kept). Before this fix, such challenges never verified, in Dart or in JS.ChallengeParameters.toSortedJson() now sorts nested map keys too.verifySolution now returns invalidSolution instead of throwing when solution.derivedKey is not valid even-length hex on the key-signature path.verifySolution now compares an even-length keyPrefix as bytes, like solveChallenge and altcha-lib, so uppercase hex prefixes verify.verifySolution expiry now matches altcha-lib: expiresAt is compared against the current time in fractional seconds (no up-to-1 s grace), and expiresAt: 0 means no expiry.createChallenge with hmacSignatureSecret: '' returns an unsigned challenge, hmacKeySignatureSecret: '' adds no keySignature and makes verifySolution re-derive the key, and verifySolution with hmacSignatureSecret: '' returns invalidSignature (previously any challenge HMAC'd under the empty key verified). Likewise, verifyServerSignature with hmacSecret: '' returns invalidSignature, and signChallenge with hmacSignatureSecret: '' throws ArgumentError.solveChallenge and solveChallengeIsolates now treat timeout: Duration.zero as no timeout, as in altcha-lib (previously it returned null immediately). solveChallengeIsolates also no longer truncates sub-millisecond timeouts to zero.ChallengeParameters.extra holds keys not modelled as fields, fromJson fills it and toJson emits it, so they are signed and verified (keys in extra that name a modelled field are ignored). createChallenge merges every key returned by deriveKey (like Object.assign), not just a fixed subset.ChallengeParameters.expiresAt is now num? (was int?), and createChallenge(expiresAt:) accepts any num, so fractional expiresAt values from altcha-lib parse and verify instead of throwing.canonicalJson now formats numbers like JSON.stringify: integral doubles have no .0 (1.0 → 1) and -0.0 is 0, so challenges whose data holds such doubles verify across implementations.canonicalJson now orders keys exactly as altcha-lib's JSON.stringify(sortKeys(...)): integer-like keys ("0"…"4294967294") come first in numeric order, then the remaining keys sorted, and a __proto__ key is dropped. Previously, challenges whose data had integer-like keys (e.g. {'9': …, '10': …}) failed signature verification across implementations.verifyServerSignature no longer throws when verificationData has a non-integer expire (e.g. 1.5, abc, empty); such input was client-controlled and crashed the call even for forged payloads. expire is now evaluated like altcha-lib: 0 or empty means no expiry, fractional values are compared as numbers.Nothing published for this version
Nothing published for this version
The PBKDF2 algorithm now uses crypto for improved performance
crypto for improved performanceadaptiveDeriveKey with automatic algorithm detectionUpgraded pointycastle to ^4.0.0.
pointycastle to ^4.0.0.argon2 dependency; Argon2id now uses pointycastle's built-in implementation.lints to ^6.1.0.createChallenge — create signed PoW v2 challenges with optional deterministic mode.
createChallenge — create signed PoW v2 challenges with optional deterministic mode.solveChallenge — brute-force solve a challenge on the current isolate.solveChallengeIsolates — parallel solver using multiple Dart isolates.verifySolution — verify a client-submitted solution.verifyServerSignature — verify an ALTCHA Sentinel server signature payload.verifyFieldsHash — verify a hash of submitted form fields.Your coding agent can read these notes before it upgrades. Set up the MCP server →