Verify reports.

Every audit-trail report is signed with Ed25519. Anyone can verify its authenticity and integrity independently and offline, using only Vericto's public key — no secrets, and no need to trust our servers.

Overview

When you export the audit trail as CSV or JSON, Vericto also generates a detached digital signature (a .sig file) computed over the exact content of the report. This signature lets you check two things:

  • Authenticity: the report was generated by Vericto and not by a third party.
  • Integrity: the content has not been altered by a single byte since it was generated.

Verification is independent: it uses Vericto's public key and standard tooling (such as openssl), with no secret required and no call to the Vericto API. This is exactly what a SOC 2 or ISO 27001 auditor expects from an evidence-integrity control.

Download both the file and its signature from Dashboard → Reports. You need both to verify: the report (.csv/.json) and its signature (.sig).

Why they are signed (and why asymmetric)

Vericto uses Ed25519, an asymmetric signature scheme: a private key (secret, which never leaves our servers) signs the reports, and a public key (which we publish openly) lets anyone verify them.

The advantage over a symmetric-key checksum (HMAC) is third-party verification: with an asymmetric signature, an external auditor verifies the report using only the public key, without Vericto sharing any secret and without having to take Vericto's word for it. The verification is mathematical and reproducible by anyone.

What you download

From the Reports page in the dashboard, each ready report offers two downloads:

FileDescription
Report (.csv / .json) The exported audit trail. It stays intact byte for byte — it opens in Excel, pandas, or any tool without modification.
Signature (.sig) A text file with the detached signature. It is self-describing and includes the scheme, the key identifier, the SHA-256 hash of the content, and the Ed25519 signature in base64.

Example of the contents of a .sig file:

scheme: ed25519-sha256
key-id: default
sha256: 9f2c1a7b0e5d4c3b2a1908f7e6d5c4b3a2918070f6e5d4c3b2a1908f7e6d5c4b3
signature: MEUCIQC2p...base64...t0Y=

Verify the signature

The scheme is ed25519-sha256: the Ed25519 signature is computed over the report's SHA-256 digest (not the whole file, so reports of any size are supported). Verifying takes two steps: compute the file's SHA-256 and check the Ed25519 signature over that digest. You need the report, its .sig, and Vericto's public key (see the next section).

With OpenSSL

Extract the signature, compute the report's SHA-256 as raw bytes, and verify the signature over that digest:

# 1. Guarda la clave pública de Vericto en vericto-public.pem (ver sección siguiente)

# 2. Extrae la firma base64 del .sig a un archivo binario
grep '^signature:' vericto-audit-abcd1234.csv.sig \
  | sed 's/^signature: //' | base64 -d > report.sig.bin

# 3. Calcula el SHA-256 del reporte como 32 bytes crudos (el mensaje firmado)
openssl dgst -sha256 -binary vericto-audit-abcd1234.csv > report.sha256.bin

# 4. Verifica la firma Ed25519 sobre el digest
openssl pkeyutl -verify \
  -pubin -inkey vericto-public.pem \
  -rawin -in report.sha256.bin \
  -sigfile report.sig.bin

# Salida esperada:
# Signature Verified Successfully

# (Opcional) Confirma que el sha256 del .sig coincide con el del archivo:
openssl dgst -sha256 vericto-audit-abcd1234.csv

The signature covers the report's SHA-256 digest, so verifying it is equivalent to verifying the whole file: if a single byte changes, the SHA-256 changes and the signature no longer matches. The sha256: field in the .sig also lets you compare the hash at a glance.

With Python (cryptography)

from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.exceptions import InvalidSignature
import base64, re, hashlib

pub = load_pem_public_key(open('vericto-public.pem', 'rb').read())

sig_txt = open('vericto-audit-abcd1234.csv.sig').read()
sig_b64 = re.search(r'^signature:\s*(.+)$', sig_txt, re.M).group(1).strip()
signature = base64.b64decode(sig_b64)

# El mensaje firmado es el digest SHA-256 del archivo (esquema ed25519-sha256).
digest = hashlib.sha256(open('vericto-audit-abcd1234.csv', 'rb').read()).digest()

try:
    pub.verify(signature, digest)   # Ed25519: lanza excepcion si no coincide
    print('OK: firma valida - el reporte es autentico e integro')
except InvalidSignature:
    print('ERROR: firma invalida - el reporte fue alterado o no es de Vericto')

Get the public key

The signing public key is non-sensitive information and is published at an open endpoint (no authentication):

curl -s https://api.vericto.com/api/v1/meta/export-signing-key

Response:

{
  "scheme": "ed25519",
  "key_id": "default",
  "public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2Vw...\n-----END PUBLIC KEY-----\n"
}

Save the public_key value to a vericto-public.pem file (with real line breaks) and use it in the verification commands.

The key-id field in the .sig indicates which key signed the report. If Vericto rotates the key in the future, the endpoint will keep exposing the active key, and you can request the historical key matching the key-id of the report you are verifying.

Retention: available for 7 days

Generated reports are available for download for 7 days from creation. After that, both the file and its signature are permanently deleted from object storage, and the report appears as Expired in the dashboard.

This deletion is real, not just a label: a daily process removes expired objects. If you need to keep a report and its signature as long-term evidence, download and store them in your own repository within the 7-day window. The Ed25519 signature remains verifiable indefinitely, since the public key stays published.

Frequently asked questions

Do I need a Vericto secret to verify?

No. Verification uses exclusively the public key, which is open. You never need — and should never request — the private key.

Does verification depend on the Vericto API being available?

No. Once you have the public key saved, verification is fully offline. You only need the API to download the public key the first time.

I modified the file (even by one space) and verification fails. Is that expected?

Yes, that is the correct behavior. The signature covers the exact bytes of the original report. Any change — even reordering columns or re-saving the CSV from Excel — invalidates the signature. Always verify against the file as it was downloaded.

What if a report has no .sig?

Reports generated with signing enabled always include a .sig. Very old reports (predating Ed25519 signing) may not have one; in that case, regenerate the export to get a signed one.