CertifiedData.io
Docs/Verification Specification

Verification Specification

Independent verification requires no SDK, no account, and no trust in CertifiedData beyond the published public key. This document specifies the exact verification procedure.

Two levels of verification

Level 1 — Signature verification

Confirms the certificate was genuinely issued by CertifiedData.io and has not been tampered with. Available for all certificates (cert.v1 and cert.v2).

Level 2 — File hash verification

Confirms your downloaded file matches the specific bytes recorded at certification time. Requires a cert.v2 certificate with dataset_hash.

Step 1: Verify the file hash

Compute the SHA-256 hash of your downloaded file and compare it against dataset_hash (for the ZIP) or inner_artifacts["dataset.csv"].sha256 (for the extracted CSV) in the certificate.

# Verify ZIP archive hash
sha256sum your-dataset.zip
# Expected: matches dataset_hash in the certificate (without "sha256:" prefix)

# Verify extracted CSV hash
sha256sum dataset.csv
# Expected: matches inner_artifacts["dataset.csv"].sha256

A mismatch means the file bytes differ from what was certified. Either the file was modified, corrupted in transit, or the wrong file is being verified.

Step 2: Verify the Ed25519 signature

Fetch the active public key from /.well-known/signing-keys.json and verify the certificate signature using any standard Ed25519 library.

# 1. Fetch the certificate
curl https://certifieddata.io/api/certificates/{certId} > cert.json

# 2. Fetch the public key
curl https://certifieddata.io/.well-known/signing-keys.json > keys.json

# 3. Verify using openssl (Ed25519)
# Extract signature and payload, then:
openssl pkeyutl -verify -pubin -inkey pubkey.pem -sigfile sig.bin -in payload.bin

The signature is computed over the RFC 8785 canonical JSON serialization of all certificate fields except the signature field itself. This is the same payload returned by GET /api/certificates/{certId}/download.

API verification endpoint

CertifiedData provides a public verification endpoint that performs both checks server-side. No authentication required.

POST /api/verify

# Request body
{
  "certificate_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "artifact_hash": "sha256:a3f8b2c1..."  // optional — provide for file hash check
}

# Success response (200)
{
  "verified": true,
  "certificate_id": "3fa85f64-...",
  "issuer": "CertifiedData.io",
  "algorithm": "ctgan",
  "timestamp": "2026-03-16T00:00:00Z",
  "hash_match": true,         // present when artifact_hash was provided
  "signature_valid": true
}

# Failure response (200, verified: false)
{
  "verified": false,
  "reason": "hash_mismatch"   // or: "certificate_not_found", "signature_invalid"
}

Browser verification

Upload any file at /verify or navigate to certifieddata.io/verify/{certId} directly. The verification page computes the SHA-256 hash client-side (in-browser) and compares it against the certificate — the file bytes never leave your machine.

Trust model

The verification procedure requires trust in exactly one thing: the public key at /.well-known/signing-keys.json. If you independently confirm this is the genuine CertifiedData public key (via DNS, PKI, or out-of-band confirmation), then:

  • A valid signature proves the certificate was issued by CertifiedData
  • A matching hash proves your file is byte-for-byte identical to what was certified
  • Both together prove the artifact was synthetically generated at the stated time by the stated algorithm