Don't trust us. Verify.
The Verify pillar of the deniability infrastructure. 22 cryptographic tests that run in your browser using the same engine that powers deny.sh, plus reproducible-build hashes, signed releases, and SRI for every served asset. Don't trust us. Run them.
Verify the mechanism yourself.
One ciphertext. One password pair. Two control files. Two plaintexts. Run it locally in your browser, replay the published vectors, then check the bytes this page served you.
Deniable round-trip
Encrypt a real secret, derive a decoy control file for a different plaintext against the same ciphertext and same password pair, then decrypt both. Password 1 and password 2 are one password pair. They do not select real vs decoy; the control file does.
Receipt appears here. Nothing leaves your browser.
Honey KAT vector replay
These vectors are not screenshots. They are the byte contract every SDK port must satisfy: seed derivation, the seeded DRBG stream, uniform integer rejection sampling, the typed decoy generator, and frame verdicts. Your browser re-derives each value and compares byte-for-byte. Passing proves conformance to the contract, not independent cryptographic audit.
Pick a group and replay. Any mismatch is red.
Published spec trail
The published construction and vectors are sufficient for independent implementation review. Read the source, don't take our word.
Asset integrity self-check
Fetch the live manifest, hash every served asset with SHA-384 in your browser, and compare to the manifest. The manifest is the source of truth; the static table below is explanatory only. A dot (●) marks assets currently executing on this page. If an attacker controls both the served asset and the manifest, this check cannot save you; reproducible build and signed release address that part of the chain.
Hashes the exact bytes this server sent you.
Run the tests yourself.
Every test executes in your browser using the same cryptographic engine that powers the API. Pick a seed phrase or use the random one.
Type your own seed phrase or use the random one. Every test runs live with your input. Nothing is pre-recorded.
Everything runs client-side. Nothing leaves your browser.
Statistical Indistinguishability
5 testsByte value distribution: random data (blue) vs deniable control file (green). They should look the same.
Ciphertext Invariance
2 testsLength Independence
2 testsCross-implementation
1 testKnown-Answer Tests
3 testsFuzz Testing
2 testsSecurity Properties
5 testsMultiple Deniable Messages
2 testsReproducible build and integrity.
The 22 tests above run inside your browser. The bundle that runs them is delivered from this server. If a sophisticated attacker compromises the delivery path, the tests still pass, but they pass on whatever JavaScript the attacker injected, not on the published source. The countermeasure is: pin the bundle to known-good hashes, and reproduce the build from public source.
What's served right now.
Every cryptographic asset on deny.sh has a published Subresource Integrity (SRI) hash. These are the SHA-384 digests of the exact bytes our server is sending you. Recompute them locally, paste them into your integrity attribute, and your browser will refuse to execute any byte that doesn't match. This table is generated from the live manifest; for an authoritative, self-running check, use Proof D — Asset integrity self-check above, which hashes the served bytes in your browser and compares them to the manifest.
| Asset | Bytes | SRI hash (sha384) |
|---|---|---|
/js/argon2.js?v=75 |
216,086 | sha384-6bLcbLILNvgBcX8TYQUYYOoePP/iXTwteWiGSloiTYvujkovkjXOM/ybjXgi9kmr |
/js/crypto.js?v=79 |
16,058 | sha384-9267+vM5ve4CM9j/SE70FDGIGtFTxgxd0LHcgzCHnV/MGGdtW/nHVjJYsnAqoKOv |
/js/honey-engine.js?v=3 |
43,587 | sha384-b/d4mz+H84rvFpuQdUAxl1+8L1FQampUlh3l2S9G8eL1CjXVKZoZhFzqzypF+UL8 |
/js/verify.js?v=75 |
50,009 | sha384-5epvYgDfZGTHltCDtZtg2JJ03SgPCCt4e21NM1+gdkT4zi9KrMzLKKZ0B+nFzY5u |
/js/verify-proof.js?v=2 |
24,318 | sha384-sxzjQ1YJG/lPQBFWpWHJxPJ8wx/Y/InXR41tz7rvedc/voUowtwCqePvODV/iudO |
/js/nav.js?v=77 |
1,652 | sha384-BV81ynd3Lsr25LspYx1P9J+PcUjCi3PhBFYVUbUMY5VlqfHPlkIs9U36U3TCr/eL |
/js/copy-code.js?v=76 |
997 | sha384-opZldN672nncovrxNEDmQZCeaLHjrQVKVrgLiYOi2YA1jklqTk3jNqQXeONs6ISk |
/js/back-to-top.js?v=74 |
654 | sha384-GbBBXsssarGIR/ST7jZSFpjfdOD0M/czgfNyxspI9OOrDc+oBScVBg7W4hz/cdRY |
/js/app.js?v=78 |
15,175 | sha384-z/VYuwh6NjFd5UNsIHtMbgo4gO1br0AI+lVO5nRbRDQp9NpN575wAZ19yCkxNx6h |
/css/style.css?v=210 |
146,910 | sha384-NsWdQmf0ul3F/JOwHgnX5OQx1isE0tTILtswMnDs7PbRUeyxMs0mcgIXtO44FmPi |
/css/v2.css?v=275 |
105,107 | sha384-jHK68bO5e1fB5bBW6cZtHKJJPMtcU80QoDQtC8BFTQDNGV8hUdCiv5Dlg1qfgqwv |
Recompute any of these locally with one command:
# pin verify.js by recomputing its hash and comparing
curl -sf https://deny.sh/js/verify.js?v=75 \
| openssl dgst -sha384 -binary \
| base64
# compare against the table above. mismatch = do not trust the bundle.
A live SRI manifest, machine-readable, is published at /.well-known/integrity.json and updated on every deploy. Pin against that if you're integrating deny.sh assets into another origin.
Reproduce the build.
deny-sh-crypto/deny-js is public and readable today. The SRI manifest below, the served bytes, and the in-browser verifier are all live now, so the integrity story for the bundle on this server is verifiable today. The reproducible-build recipe and the first signed GitHub release land at 08:00 BST on Saturday 4 July 2026 when the open beta opens. We pre-announce this rather than backdate it.
From the open beta onward, the published artefact (the JS bundle that powers the in-browser verifier and the SDK on npm) is built from a tagged commit on deny-sh-crypto/deny-js with a single deterministic command. Same source + same Node version + same dependency lockfile = byte-identical output. If your build doesn't match the published SRI hash, either the source changed or someone tampered with the artefact.
# 1. clone the public source at the released tag
git clone https://github.com/deny-sh-crypto/deny-js
cd deny-js
git checkout v2.3.1
# 2. pin Node and reinstall from lockfile (no transitive surprises)
nvm use 22.22.2
npm ci
# 3. build the published bundle
npm run build:web
# 4. hash the bundled crypto.js the same way the server does
cat dist/web/crypto.js | openssl dgst -sha384 -binary | base64
# expect: OLz8xZ6aeZasfCql1pvERSZ2ijXb5SEFl+T4AMRoANaKVeMWym2Xc5IHfaV1IQ7w
Determinism details. The build pins Node v22.22.2 (LTS), uses npm ci against a committed package-lock.json, and disables timestamp-based dependency invalidation. The bundler (esbuild v0.25 in --minify --no-bundle-time-comment mode) writes byte-deterministic output for the same input. We don't ship sourcemap timestamps, build hostnames, or compile-time strings into the bundle.
How publishing and signing work.
Every release of the SDK lands on three independent surfaces, each with its own integrity story:
- npm registry.
npm publishfrom a workstation that holds the publishing token. npm computes its own SHA-512 integrity field and stores it in the package metadata.npm install deny-sh@2.3.1 --integrityverifies on install. The publishedpackage.jsonincludes therepository.urlpointing at the public source mirror, so you can diff what npm shipped against what GitHub holds. - GitHub release. Tagged commit + signed annotated tag. The release page on deny-sh-crypto/deny-js/releases publishes the source tarball + a
SHA256SUMSfile + the maintainer's GPG signature over that file. Verify withgpg --verify SHA256SUMS.sig SHA256SUMS. - This server. The web bundle is rebuilt from the tagged commit and uploaded to the deny.sh origin behind Cloudflare. The SRI manifest at
/.well-known/integrity.jsonis regenerated on every deploy. If the bundle changes without a corresponding GitHub tag and signed release, that's a tamper signal.
Coordinated disclosure for any integrity issue (mismatched hash, unsigned release, source-vs-published divergence) goes to security@deny.sh per the disclosure policy.
Honest caveat. Reproducible builds protect against tampering between source and your browser. They don't protect against bugs in the source itself; that's what the in-browser test suite, the cross-language byte-compatibility KAT vectors in the four SDKs, the cryptographic construction write-up, and the external cryptographic audit on the roadmap are for. Different layers of defence; check all of them.