Verify any CaseGuardian capture against Bitcoin, and see exactly how we earn your trust.
Every capture is SHA-256 hashed on the device that recorded it, then the hash is submitted to OpenTimestamps, a free, neutral, Bitcoin-anchored timestamping service. This page lets anyone, including opposing counsel, confirm that a given hash was witnessed by the Bitcoin blockchain at or before a specific block.
No file is ever uploaded here. Verification works on the 64-character fingerprint of the file, nothing personal, nothing identifying, nothing reversible.
Two halves of one promise: this half proves your record to anyone. The Trust & Security half below shows how we protect it on the way there.
1. Check a hash against Bitcoin
Paste the 64-character SHA-256 hash shown on the entry-detail “Vault integrity seal.” We’ll show what the live verifier will return for that hash. In preview mode, only our pre-loaded sample returns a real anchored result.
2. Verify a device signature (offline)
Each entry's hash is also signed with the originating device's Ed25519 key. This check runs entirely in your browser — no file, and no CaseGuardian server, is involved. Paste the three values from the entry's “Vault integrity seal” (or from the JSON / Attorney Package appendix) to confirm the signature matches the hash and the public key.
Honest scope: a valid result proves the signature was produced by this exact key over this exact hash — i.e. the originating device, and that the hash hasn't changed since signing. It is a software-protected key, not a hardware-attested identity, and it does not verify a person's legal identity.
3. Decrypt a share without the browser page (headless)
If you consume a CaseGuardian share from a script instead of this page — an intake pipeline, an e-discovery tool, a CI verifier — request it as JSON and decrypt locally. Fetch the share URL with Accept: application/json; the response carries the share metadata plus, for encrypted shares, wrapped_to_share_key (the AES-256-KW-wrapped case key) on the share object. The per-share key K_s arrives only in the URL fragment (#k=…), which is never sent to our server.
Decryption is AES-KW unwrap → AES-256-GCM with AAD = utf8(entry_id) || crypto_version byte, over the blob layout [1B version][12B nonce][ciphertext+16B GCM tag]. Field ciphertexts (title, summary, transcript) and attachment bytes are all base64 of that blob. crypto_version=0 rows are already plaintext — read the column directly.
Copy-paste reference (zero dependencies, pure WebCrypto)
// Node 18+ / Deno / modern browser. Pure WebCrypto, no dependencies.
//
// const { share, entries } = await (await fetch(shareUrl, {
// headers: { Accept: "application/json" },
// })).json();
// const Ks = decodeShareKeyFromUrl(location.hash.replace(/^#k=/, ""));
// const dek = await unwrapDek(b64ToBytes(share.wrapped_to_share_key), Ks);
// for (const e of entries) {
// if (e.crypto_version !== 1) continue; // legacy plaintext
// e.title = await decryptText(b64ToBytes(e.title), dek, e.id);
// }
const b64ToBytes = (b64) =>
Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
// #k= fragment is Base64URL (no padding).
function decodeShareKeyFromUrl(fragment) {
const s = fragment.replace(/-/g, "+").replace(/_/g, "/");
const key = b64ToBytes(s);
if (key.length !== 32) throw new Error("Share key is the wrong length.");
return key;
}
// AES-256-KW unwrap of the case DEK (RFC 3394), keyed by K_s.
async function unwrapDek(wrapped, ks) {
const kek = await crypto.subtle.importKey(
"raw", ks, { name: "AES-KW" }, false, ["unwrapKey"]
);
const dek = await crypto.subtle.unwrapKey(
"raw", wrapped, kek, "AES-KW",
{ name: "AES-GCM" }, true, ["decrypt"]
);
return new Uint8Array(await crypto.subtle.exportKey("raw", dek));
}
// AAD = utf8(entryId) || [crypto_version byte] — must match capture exactly.
function buildAad(entryId, cryptoVersion = 1) {
const id = new TextEncoder().encode(entryId);
const aad = new Uint8Array(id.length + 1);
aad.set(id, 0);
aad[id.length] = cryptoVersion & 0xff;
return aad;
}
// blob = [1B version=1][12B nonce][ciphertext+16B GCM tag]
async function decryptBytes(blob, dek, entryId, cryptoVersion = 1) {
if (blob.length < 1 + 12 + 16) throw new Error("Ciphertext blob is too short.");
if (blob[0] !== 1) throw new Error(`Unsupported blob version ${blob[0]}.`);
const nonce = blob.subarray(1, 13);
const sealed = blob.subarray(13); // ciphertext || 16B tag
const key = await crypto.subtle.importKey(
"raw", dek, { name: "AES-GCM" }, false, ["decrypt"]
);
const plain = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: nonce, additionalData: buildAad(entryId, cryptoVersion) },
key, sealed
);
return new Uint8Array(plain);
}
async function decryptText(blob, dek, entryId, cryptoVersion = 1) {
return new TextDecoder().decode(await decryptBytes(blob, dek, entryId, cryptoVersion));
}
The server never sees K_s or plaintext. A wrong key, tampered ciphertext, or mismatched entry_id all fail the GCM tag and throw — there is no silent-corruption path. Decryption proves confidentiality, not authenticity; recompute the SHA-256 and check the Ed25519 device signature above to confirm what / when / which device.
4. The four possible outcomes
When the live verifier opens, every check returns exactly one of these:
The hash has been included in a confirmed Bitcoin block. The capture provably existed at or before that block’s timestamp. This is the result a judge wants to see.
The hash was submitted to OpenTimestamps and is queued for the next aggregation window (typically under 6 hours). Still valid evidence, just not yet permanently anchored.
The file you have produces a different hash than the receipt claims. Someone modified the file after it was captured. This is the result that catches tampering.
No OpenTimestamps calendar has ever seen this hash. Either it was never anchored, or the hash was mistyped. Not evidence of tampering, just no record exists.
Alongside the Bitcoin proof, each entry's hash carries an Ed25519 signature from a key that was registered to the account before the evidence was created. When you open a sealed Attorney Package, every entry that checks out shows a “✓ signed by device” badge. This proves which device produced the record, not just when it existed. It is a software-protected key held in the device's secure storage, not a hardware-attested identity. It confirms the originating device, it does not verify a person's legal identity.
How does this prove anything?
- The device hashed the capture’s metadata + every attachment byte into a 32-byte fingerprint.
- That fingerprint was submitted to OpenTimestamps, which aggregated it with thousands of others into a Merkle tree and committed the tree’s root to Bitcoin.
- The “upgraded receipt” returned by an OTS calendar contains the Bitcoin block header that includes that Merkle root.
- If the calendar returns the receipt today, the hash provably existed at or before that Bitcoin block. No central authority, including CaseGuardian, can backdate it.
What does the “✓ signed by device” badge mean?
- When the app first runs on a device, it generates an Ed25519 keypair. The private key never leaves the device; only the public key and a short key id are registered to the account.
- That registration is written into the immutable, Bitcoin-anchored custody log, so a verifier can prove the key existed and was tied to the account before any evidence it signed.
- At capture, the device signs the entry's SHA-256 hash with its private key. The signature travels with the record.
- The Attorney Package view re-verifies that signature against the registered public key. A valid check shows “✓ signed by device · <key id>”; a record that can't be verified is flagged instead of silently trusted.
- Honest scope: this is a software-protected key, not a hardware Secure Enclave key, and it is not a legal identity check. It proves the originating device and that the record hasn't changed since signing.
Why this matters in court
Tamper-evident timestamps shift the burden of proof. If the opposing party claims a capture was fabricated after the fact, the Bitcoin block height in the OTS receipt is a public, immutable upper bound on when the evidence could have been created. Bitcoin block timestamps are independently checkable by any full node operator on Earth.
CaseGuardian is not a substitute for legal counsel. Authentication, chain of custody, and admissibility are decided by the court. We give your attorney a starting point that is mathematically harder to dismiss than a screenshot.
How we protect your record
Verification proves your record to the outside world. These five controls protect it from the moment you capture it until you choose to share it, the full explanation our Privacy Policy points to.
Your evidence never leaves your device until you approve it
Every sealed package, share links, Attorney Packages, and Kid Calendar exports, is shown to you in a full review screen before anything is transmitted. You can remove items, edit captions, or cancel the seal entirely. Nothing is uploaded until you explicitly confirm.
The only thing that ever leaves your device automatically is the 64-character hash sent to OpenTimestamps, a one-way fingerprint that reveals nothing about the underlying file.
AI parsing is opt-in, and hardened against attack
CaseGuardian does not send your captures, documents, or Kid Calendar entries to any AI service unless you explicitly turn on the “Parse with AI” toggle for that specific item. It is off by default on every capture and every document.
When you do turn it on, the device first runs an on-device PII pass that redacts your name, phone number, email, address, payment details, and the names of people in your life before anything leaves the device. Only the redacted item is sent, over an encrypted connection, to our AI sub-processor (Anthropic), which is contractually prohibited from training on or retaining your content.
Every AI request wraps your file in safety instructions telling the model to treat the contents as data, not commands, so a court order or screenshot containing hidden text like “ignore previous instructions” cannot hijack the parser. We enforce an 8 MB input ceiling (oversized files are rejected before they leave your device), clamp every output field to a safe length so a misbehaving response can’t bloat your storage, and strip document contents and any extracted personal information from every diagnostic error log before it is written.
AI output is informational only. It is not legal advice and may contain errors, always confirm with your attorney before relying on it.
Destructive actions are gated behind your biometrics
Account deletion, profile deletion, and other irreversible actions require your device’s biometric authentication (Face ID, Touch ID, or Android biometric prompt), with a passcode fallback. We never see or store your biometric data, verification happens entirely on your device using the operating system’s secure enclave.
When you delete your account, your data is purged from active systems within 30 days, with encrypted backups overwritten within 90. Bitcoin anchors on the public ledger remain (they’re cryptographic fingerprints only, with no personal information attached) but cannot be retracted, that’s the nature of the public ledger.
Split-channel delivery for sealed shares
When you share a sealed package, the recipient must verify possession of both their email inbox and their mobile number before the materials decrypt. The one-time access code travels by SMS; the share link travels separately by email, so neither message alone can unlock the package.
Before you create the share, you attest that you have the recipient’s permission to be contacted at that phone and email for this purpose, the share won’t go out without your confirmation. Share links can be set to auto-expire (24 hours to forever) and revoked instantly from your Vault.
No trackers. No ad SDKs. No selling your data.
We ship zero third-party trackers, zero ad SDKs, and zero IDFA collection. Your evidence never trains a model, never feeds an ad network, and never leaves your device until you personally review and approve it. We do not sell, rent, or share your phone number, consent records, or personal information with third parties for their marketing.
Backed by GDPR & CCPA right-to-erasure: you can export or delete your data at any time, and we’ll action verified requests within 30 days. Full detail in our Privacy Policy and Terms of Service.
Verification proves the record. Trust protects the person behind it. We engineer for both.