AudioTrust: reconciliar C2PA y watermark AudioSeal en audio sintético
Un verificador local que lee las dos marcas de confianza de un audio generado por IA (procedencia C2PA + watermark AudioSeal) y emite un veredicto auditable sobre si coinciden, se contradicen o faltan.
El problema
Un audio sintético puede llevar dos marcas de confianza distintas:
- Procedencia C2PA: un certificado digital embebido en el archivo (su "DNI" de origen — quién, cuándo, con qué herramienta).
- Watermark AudioSeal: un código inaudible incrustado en el sonido, detectable aunque el audio se comparta o transcodifique.
Cada una por separado es útil, pero ninguna es suficiente. La procedencia puede faltar (mucho audio generado no la incluye) y el watermark puede estar presente en audio totalmente legítimo. El caso interesante es cuando se contradicen: el manifest C2PA dice "grabado por un humano con una grabadora" pero el watermark de una herramienta de IA está presente. Eso es una señal de manipulación — el llamado Integrity Clash.
AudioTrust no genera ni firma nada. Es un verificador: lee ambas capas y las reconcilia.
Qué hace
audio.wav ──► AudioTrust verify ──► veredicto + explicación
| C2PA | watermark | Veredicto |
|---|---|---|
| ausente | ausente | unverifiable |
| ausente | presente | partial |
| origen sintético | presente | trusted |
| origen humano | presente |
contradiction (Integrity Clash) |
Salida JSON:
{
"file": "audio.wav",
"verdict": "trusted",
"c2pa": {"present": true, "source_type": null, "claims": ["action=c2pa.created by TestTTS", "generatedBy=TestTTS"]},
"watermark": {"present": true, "detect_prob": 0.92},
"explanation": "C2PA declara origen sintético y hay watermark fuerte: coherentes."
}
Cómo funciona
-
Lectura C2PA con
c2pa-python(el Reader de la librería oficial). Si no hay manifest, devuelvepresent=Falsesin crashear. -
Detección de watermark con
audioseal. Devuelve solodetect_prob(P(audio watermarked) en [0,1]). -
Reconciliación determinista en
reconcile.py.
Dos decisiones de diseño que vale la pena explicitar porque no son obvias:
-
Nunca se usa el mensaje decodificado de AudioSeal. En el spike de validación, el mensaje recuperado fue inconsistente entre corridas (la primera coincidía con el original, las siguientes no) pese a un
detect_probestable. Por tanto el producto se apoya solo endetect_prob, que sí es reproducible. El mensaje se descarta explícitamente en el código. -
El origen se deduce de los claims de acción del manifest, no del campo
source_type. Verificamos con firmas reales dec2patoolque los manifests C2PA reales no incluyensource_typeexplícito por defecto (usanc2pa.actionsconc2pa.created). Clasificar como "sintético" solo por la presencia dec2pa.createdes un error: esa acción está en casi cualquier manifest, sea IA o humano.
El bug que casi se cuela
La lógica de reconciliación original clasificaba como synthetic cualquier claim con c2pa.created genérico, salvo que el nombre del agente contuviera literalmente "human"/"camera"/"capture". Con un agente humano realista —"Zoom H4n", "Voice Memos"— el origen caía en synthetic, y si el detect_prob daba alto, el veredicto era trusted en vez de contradiction.
Eso invertía el propósito del producto: trusted demasiado fácil, contradiction (el caso que justifica la herramienta) casi inalcanzable.
La corrección: el default sin evidencia positiva de origen es indeterminate (→ partial), nunca synthetic. "Sintético" exige una señal explícita de generación por IA (generatedBy, softwareAgent, trained_algorithmic...); "humano" exige señal de captura. Así trusted se gana con evidencia y contradiction es alcanzable.
Este bug lo encontró la auditoría independiente en un clone limpio, no el self-report de quien lo escribió. Se añadió un test con el caso "Zoom H4n" para que no vuelva a colarse.
El proceso (por qué confío en el resultado)
El repositorio no se escribió de una sentada. Siguió gobernanza de tres partes:
-
Spike de viabilidad (¿
c2pa-pythonyaudiosealfuncionan de verdad en local? — sí, verificado con 3 corridas en 2 entornos distintos). - SDD: Constitución → Spec → Tasks.
-
Implement en rama dedicada
feature/audiotrust(nuncamain). - Auditoría externa en clone limpio: encontró el bug de reconciliación arriba.
-
Corrección + re-verificación, luego merge a
maincon aprobación explícita.
En cada paso donde apareció un problema real —un falso positivo de watermark en audio limpio, el bug de reconciliación, la limitación de c2patool con WAV— quedó documentado con evidencia cruda en KNOWN_ISSUES.md, no escondido bajo tests verdes.
Lo que queda abierto (honestamente)
El caso de uso estrella —trusted/contradiction con un archivo de audio real firmado— hoy solo está cubierto por tests unitarios con el manifest mockeado. No hay un fixture de audio con manifest C2PA real que dispare esos dos veredictos end-to-end, porque c2patool 0.9.12 firma imágenes JPG pero no acepta WAV en este entorno (limitación de la build, no del binario). Es trabajo de maduración post-merge, documentado como KI-5, y no bloquea el MVP: partial y unverifiable sí están probados con datos 100% reales (watermark AudioSeal real + WAV sin manifest).
Pruébalo
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
export TORCH_COMPILE_DISABLE=1 TORCHDYNAMO_DISABLE=1 # requerido en CPU
audiotrust verify ruta/al/audio.wav --json
Los pesos de AudioSeal se descargan en la primera ejecución (repo público, sin token).
Enlaces
- Repo: https://github.com/amurlaniakea/audiotrust
- Licencia: AGPL-3.0-or-later — Pedro Sordo Martínez
Top comments (2)
Me parece muy interesante la forma en que AudioTrust combina la verificación de la procedencia C2PA y el watermark AudioSeal para determinar la autenticidad de un audio sintético. La decisión de no utilizar el mensaje decodificado de AudioSeal y enfocarse solo en la probabilidad de detección es razonable, considerando la posible inconsistencia en los resultados. Me gustaría saber más sobre cómo se manejan los casos en los que la procedencia C2PA y el watermark AudioSeal no coinciden, pero no necesariamente se contradicen, como por ejemplo cuando la procedencia indica un origen humano pero el watermark sugiere una posible manipulación. ¿Cómo se determina el veredicto en esos casos?
El núcleo: C2PA y AudioSeal son dos señales de distinta naturaleza y deben combinarse con una
política de precedencia por fortaleza, no por mayoría de votos.
-C2PA es una afirmación de procedencia explicita y firmada (quién/qué generó el asset, cuándo). Su
fortaleza es criptográfica, pero su debilidad es que depende de que el emisor la haya incrustado y de que
la cadena de confianza (certificado) sea válida. Si falta o la firma no verifica → no es "falso", es "sin
procedencia verificable".
-AudioSeal es una marca de agua perceptualmente invisible detectable incluso tras
transformaciones. Su salida es una probabilidad (p. ej. "sintético con p=0.93"). No dice quién, dice
"esto fue generado por un modelo con este watermark".