Skip to content

Verify it yourself

Reproduce a published certificate without trusting VeriLib’s UI alone. You check: (1) same image digest, (2) same INPUT_MANIFEST_SHA256 / image manifest, (3) extract counts/hashes match the published numbers, and (4) the on-chain record matches what you computed.

Steps 1–3 verify the lab: that the image you pulled is the one that produced the certificate. Step 4 verifies the claim independently of VeriLib — it reads Ethereum directly, so a compromised or simply wrong certificate page cannot fake it. If you only do steps 1–3 you are still trusting verilib.org to report the numbers honestly.

1. Pull by digest

docker pull --platform linux/amd64 \
  YOUR_DOCKERHUB_USER/dalek-lite-probe@sha256:YOUR_DIGEST_HERE

2. Quick check (no Verus run)

docker run --rm --platform linux/amd64 --entrypoint '' \
  IMAGE@sha256:DIGEST \
  sh -c 'echo INPUT_MANIFEST_SHA256=$(cat /etc/dalek-probe-input-hash.txt); cat /etc/dalek-probe-image-manifest.json'

Compare to the certificate page / published manifest fields (dalek_lite_resolved_commit, etc.).

3. Full extract

docker run --rm --platform linux/amd64 IMAGE@sha256:DIGEST
# or from a clone of this repo:
./scripts/verify-local.sh YOUR_DOCKERHUB_USER/dalek-lite-probe:v1
./scripts/verify-local.sh --local dalek-lite-probe:local

Compare end-of-log verification counts, UNIFIED_EXTRACT_SHA256, and bundle hash.

4. Check the on-chain record

Certificates anchored on-chain emit a Certified event from the Certify contract. Reading it requires nothing from VeriLib except the transaction hash or the identifier — both of which are printed on the certificate page and can be independently confirmed on Etherscan.

Network Contract
Mainnet 0x4f2a70eC878E9Adae88FF0c7528ebEbf83dFD83c
Sepolia 0x125721f8a45bbABC60aDbaaF102a94d9cae59238

By transaction — open https://etherscan.io/tx/<mainnet_certify_tx_hash> (or the Sepolia explorer for sepolia_certify_tx_hash) and read the decoded Certified event.

By identifier — scan the logs yourself. Both identifierHash and contentHash are indexed, so this is a cheap filtered query:

# keccak256("owner/repo") — the indexed identifierHash
cast keccak "owner/repo"

cast logs --rpc-url "$RPC_URL" \
  --address 0x4f2a70eC878E9Adae88FF0c7528ebEbf83dFD83c \
  --from-block <certify-deploy-block> \
  'Certified(bytes32,bytes32,address,string,bytes32,string,uint8,uint256)' \
  <identifierHash>

Then confirm, from the event fields:

Field Check against
contentHash The content hash you recomputed — keccak256(results_hash \|\| specs_hash [\|\| proofs_hash]). See doc/computing_hashes_locally.md.
commitHash The dalek_lite_resolved_commit from the image manifest you read in step 2, as zero-padded bytes32.
sender The expected authorized certifier — the BAIF Safe 0x8EAb4dB55DCEfb6D8bF76e1C6132d48D2048ef0e on mainnet. A different sender means a different contract instance.
schemaVersion 2 for the current contract.
timestamp Plausible relative to the certificate's claimed date.

You can also verify with the upstream CLI:

uv run python3 -m certify_cli verify --rpc-url "$RPC_URL" --contract 0x4f2a...

Not every certificate is anchored

On-chain anchoring is optional (ETH_CERTIFY_ENABLED, and a per-certificate eth_certify_enabled override on the request). A certificate with no sepolia_certify_tx_hash or mainnet_certify_tx_hash was never anchored — steps 1–3 are all the verification available for it. Mainnet anchoring is a separate, later promote action, so a valid certificate may be on Sepolia only.

Stats-site checklist

Upstream docs/CERTIFICATION_AND_VALIDATION_PSEUDOCODE.md lists what the public /cert/… page should expose for comparison. Optional HTML sketch: website/docker-hub-verify.html in the repo (if present on your branch).

Unknowns

Exact production Docker Hub org/tag for every language may differ from the dalek-lite examples; use the digest printed on the certificate you are validating.