vox-trust
OfficialVerify sealed voice recordings and inspect Vox Trust pairing texts — no detection, just proof that a key sealed a WAV file.
Verify a sealed WAV (
verify_audio): returns a verdict —verified,unsealed,warningoralert— plus a plain-language explanation and the exact seconds that changed after sealing.Check against a person: pass their Ed25519 public key (64 hex) or public pairing text as
pinned_public_key; a seal from an unpinned key becomes an alert.Tune the policy: set
strict(missing seal from this speaker = alert) andalways_seals(default true when a key is pinned; missing seal = warning).Feed the audio either way: one of
url(https WAV) orbase64— exactly one, never both.Read pairing texts (
describe_pairing): parsevoxtrust:0:public:<key>[:<label>]into public key, key id and label; circle pairing texts are flagged as secrets and never echoed.Safe by design: both tools are read-only and idempotent, and the server refuses private keys or circle pairing texts.
Limitations: file mode only — sealed files survive bit-exact copies, not MP3/AAC/resampling; "unsealed" means no seal, not "fake", since compression can strip a seal.
Status: v0.6, file mode works. Not audited. You can seal a WAV file, verify it, and see exactly which seconds were altered, in the browser demo or with the command line. Sealed files survive only bit-exact copies. An experimental audio watermark that survives MP3, AAC, Opus and small speed changes is built and measured, but it fails phone-call codecs and noise, and in-band seals can be copied into other audio, so it gives no verdicts yet. Do not use this to protect anyone until it has been reviewed.
The problem
Cloning a voice now takes seconds of audio. Listening can no longer tell a real voice from a cloned one, and detectors chase a moving target: as detection improves, so does generation.
Related MCP server: KeyHalve verify-MCP
The idea
Instead of guessing whether a voice is fake, check whether a real one was sealed.
Seal. The speaker's device signs the audio at the source.
Verify. Anyone with the protocol checks which key sealed it, when, and which chunks of audio were altered.
Decide. A local trust policy turns the result into one of four outcomes.
Outcome | Meaning |
Verified | A valid seal from a key you trust. |
Unsealed | No seal (or a seal under a key you never supplied), from someone you have no expectations of. Neutral, not "fake". |
Warning | No seal from a contact who always seals: worth a second look, since compression can also remove a seal. |
Alert | The seal is broken, comes from a key you didn't pin for that contact, or is missing from a contact who always seals (strict mode). |
Two modes: circle (people who know each other, shared secret) and public (organisations and public figures, Ed25519 keys that verifiers pin).
Try it in 30 seconds
In the browser (nothing is uploaded; the Rust core runs as WebAssembly): open the demo, press Seal, then try to cheat with the buttons and watch the verifier catch each attempt.
On the command line (prebuilt binaries for Linux, macOS and Windows, with checksums and build attestations, are on the releases page; or build from source):
cargo install vox-trust-cli
vox-trust keygen me.key # asks for a passphrase
vox-trust seal speech.wav sealed.wav --mode circle --key me.key
vox-trust verify sealed.wav --circle-key me.key # exit code 0 = verifiedkeygen protects the key with a passphrase (Argon2id and XChaCha20-Poly1305) and asks for it whenever the key is used. In scripts, pass --passphrase-file or set VOX_TRUST_PASSPHRASE; --plain writes an unprotected key.
Edit a single sample of sealed.wav and verify again: the exit code becomes 3 and the altered chunk is printed. Exit codes: 0 verified, 1 unsealed, 2 warning, 3 alert.
As a Rust library:
// A sketch: `wav_bytes` is a 16-bit PCM WAV you already have; run inside a function returning a Result.
use vox_trust_core::file::{seal_wav, verify_wav, SealParams, Signer, Trust};
use vox_trust_core::{circle, SealCheck};
let key = [7u8; 32]; // use a random 32-byte secret in real life
let sealed = seal_wav(
&wav_bytes,
Signer::Circle { key: &key, key_id: circle::key_id(&key) },
SealParams { created_unix: 1_700_000_000, counter: 1, chunk_frames: 16_000 },
)?;
let trust = Trust { circle: Some((circle::key_id(&key), &key)), pinned_public: None };
assert_eq!(verify_wav(&sealed, trust)?.check, SealCheck::Valid);Build it into your app
Vox Trust is an open protocol meant to live inside the apps people already use: messengers, voicemail, podcast and newsroom tools, support platforms. Seal on send, verify on receive.
npm install vox-trust # browsers and Node 20+, WebAssembly, no dependencies, types included
cargo add vox-trust-core # Rust, no unsafe, no I/O
pip install vox-trust # Python 3.9+
npx -y vox-trust-mcp # MCP server: AI assistants verify recordingsimport { load } from "vox-trust";
const vt = await load();
const sealed = vt.seal(wav, { mode: "public", key: seed, createdUnix, chunkFrames: 16000 });
const report = vt.verify(sealed, { pinnedPublicKey });
vt.decide(report.check, { alwaysSeals: true, strict: false }); // "verified" | "unsealed" | "warning" | "alert"The integration guide takes about 10 minutes: keys, pairing, the four verdicts and what to show for each, with runnable examples for Node, the browser (microphone) and Rust. Android (Kotlin) and iOS (Swift) libraries are attached to every release (bindings). Apache-2.0, no service to call, no account.
What this is NOT
It is not deepfake detection and not voice biometrics.
It does not prove a speaker is human or is who they claim. It proves that a key sealed the audio. A stolen key or a compromised device produces valid seals.
"No seal" does not mean "fake": compression and noise suppression can erase a watermark.
File mode does not survive MP3, AAC, resampling or re-recording. That is the carrier's job, and the carrier is experimental (below).
It does not protect against an attacker who controls the sender's device.
Attackers, claims and the weaknesses found so far (including one that is still unsolved) are in the threat model.
How it is tested
Layer | What it checks | Run |
Rust unit and integration tests | Seal layout, HMAC and Ed25519 (against RFC 4231 and RFC 8032 vectors), WAV parsing, manifests, tampering, policy, the C interface and the CLI |
|
Published test vectors | Byte-exact seals and manifests in | included above |
Cross-check in Python |
|
|
WebAssembly end to end | The compiled module reproduces the vectors byte for byte, handles garbage input, and does not leak memory |
|
Real browser | The demo page in headless Chromium, Firefox and WebKit: sealing, six attacks, public-key pinning, five languages, accessibility, phone width, dark mode |
|
Fuzzing | Every parser of untrusted input, with invariants (sealed audio always verifies, any flipped sample bit is found in the right chunk, pairing text has one form) |
|
Coverage | Share of Rust lines the tests execute; CI fails below 96 % |
|
Mutation testing | Changes operators and return values in |
|
Dependencies | Known vulnerabilities, licenses, sources |
|
CI runs the Rust tests on Linux, macOS and Windows.
The Python check is written by the same author, so it is a cross-check, not an independent implementation. An independent implementation is what the spec still needs.
Surviving re-encoding: the experimental carrier
crates/vox-trust-carrier hides the 102-bit seal in the audio itself (spread-transform dither modulation on log-spectral tiles, a convolutional code, a CRC, blind synchronisation and a tempo search; spec section 10.2). The current configuration, stdm-2, measured on 13 recordings in 10 languages (full results):
Through | Seal recovered (9.6 s windows) |
MP3 64 and 128 kbit/s, AAC 64 kbit/s, Opus 24 and 32 kbit/s, G.722, resampling, trimming | 100 % |
MP3, then re-shared as Opus 24 kbit/s | 98 % |
AMR-WB 23.85 kbit/s | 89 % |
A 1 % speed change (same pitch) | 84 % |
White noise at 30 dB SNR | 51 % |
AMR-WB 12.65 kbit/s (phone calls), Opus 12 kbit/s, noise at 20 dB SNR, noise reduction, echo | 0 to 11 % |
Wrong seal returned, or false alarm on unmarked audio | never |
Perceptual quality of the marked audio: PESQ-WB 4.41 out of about 4.64. It does not pass the project's own gate, and a public carrier lets anyone copy a seal into other audio (threat model, A11). Binding the seal to the audio with a robust fingerprint was tried and an adaptive attacker defeats it (study). So the carrier is for research and measurement only: the CLI, the demo and the verdicts use file mode. Re-run it with bench/.
How it compares
Most of the industry marks AI output so it can be recognised later. Vox Trust does the opposite: it vouches for real human speech, with a proof anyone can check.
Vox Trust | Google SynthID | Meta AudioSeal | Resemble PerTh | Deepfake detectors¹ | C2PA | |
Vouches for a real human recording | ✅ | ❌ marks AI output | ❌ marks AI output | ❌ marks AI output | ⚠️ estimates | ✅ if the recording app signs |
Proof bound to the speaker's own key | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ signer certificate |
Points to the seconds that were altered | ✅ | ❌ | ⚠️ marked vs unmarked regions | ❌ | ❌ | ❌ whole file |
Anyone can verify, offline | ✅ in the browser | ❌ Google's detector | ✅ | ⚠️ | ❌ | ✅ |
Open specification and code | ✅ | ❌ for audio | ✅ code | ⚠️ code | ❌ | ✅ specification |
Survives MP3, AAC, Opus | ⚠️ experimental carrier, 100 % measured | ✅ claimed | ✅ measured | ✅ claimed | not applicable | ❌ metadata is often stripped |
Survives phone calls (AMR-WB) | ❌ 11 % | not published | ❌ 0 % measured | not published | ✅ | ❌ |
Cost to verify | milliseconds, no AI model | cloud service | neural network | neural network | cloud service | milliseconds |
Public benchmark, failures included | ✅ | ❌ | research paper | ❌ | vendor figures | not applicable |
"Measured" means run on our benchmark with the same corpus and codecs; "claimed" means the vendor's published figure. ¹ For example Pindrop Pulse: it estimates whether a voice is synthetic, which is useful but a probability, not proof of who spoke. Sources for every cell are in the comparison notes.
Where this fits
Vox Trust builds on and complements existing work rather than replacing it:
C2PA content credentials: provenance for files, with watermarks as "soft bindings".
Audio watermarks such as AudioSeal and WavMark, which could serve as carriers.
Research on public-key speech provenance, e.g. MerkleSpeech.
Apps that rotate family code words (e.g. Trust Onion) and detection vendors attack the same scam from other sides.
STIR/SHAKEN attests the caller's number, not the voice.
Repository layout
spec/ specification, threat model, test vectors
crates/
vox-trust-core/ seal layout, circle and public modes, file mode, policy, replay helpers, pairing text
vox-trust-wasm/ the core as a WebAssembly module (plain C interface, no imports)
vox-trust-cli/ the `vox-trust` command-line tool
vox-trust-carrier/ experimental in-band carrier (research only)
vox-trust-bench/ `vt-bench`, the carrier benchmark
web/ the browser demo (published at vox-trust.github.io/demo/)
bindings/ Kotlin (Android), Swift (iOS, macOS) and Python bindings (UniFFI)
mcp/ MCP server so AI assistants can verify recordings
npm/ the `vox-trust` npm package (WebAssembly + JavaScript wrapper + types)
extension/ browser extension for Chrome, Edge, Firefox and Safari
examples/ integration examples: Node, browser, Rust
tests/ Node (WebAssembly) and browser tests
tools/ independent vector check
fuzz/ fuzz targets (cargo-fuzz) and seed inputs
bench/ carrier benchmark: corpus script, quality script, published results
scripts/ build and publish helpers
docs/ roadmap, decision recordsContributing, security, license
Read CONTRIBUTING.md. The most useful thing right now is scrutiny: attack the threat model, or write an independent implementation from the spec.
Report vulnerabilities privately: see SECURITY.md.
Code: Apache-2.0. Specification text: CC BY 4.0, see spec/LICENSE.md. Changes: CHANGELOG.md.
Governance and name usage: GOVERNANCE.md, TRADEMARKS.md. To cite: CITATION.cff.
Maintainer: Roger Oliveira · @rogeroliveira84.
Available Tools
2 toolsdescribe_pairingRead a pairing textARead-onlyIdempotent
Checks a Vox Trust pairing text (voxtrust:0:public:[:]) and returns the public key, its key id and label. Circle pairing texts are secrets: the tool says so and does not echo the secret.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | The pairing text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so safety is partly covered. The description adds genuinely non-obvious behavioral context: Circle pairing texts are secrets and the tool deliberately refuses to echo them. It does not describe failure behavior on malformed input, keeping it below 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with what the tool does, followed by the security caveat. No filler and nothing repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates the return values and discloses the secret-redaction behavior. It is only slightly short of complete because error/edge-case handling (invalid or foreign pairing texts) is unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% but the schema description for 'text' is only 'The pairing text', so the description compensates by spelling out the accepted format voxtrust:0:public:<key>[:<label>], including the optional label segment. That is meaningful syntax detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb (checks/parses) and resource (Vox Trust pairing text), and states what it returns (public key, key id, label). This is clearly distinguishable from the only sibling, verify_audio, which is about audio verification.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the input-format spec (voxtrust:0:public:<key>[:<label>]), so an agent can infer when the tool applies. However, there is no explicit when-to-use/when-not guidance and no mention of alternatives or what to do with a non-Vox-Trust text.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_audioVerify a voice recordingARead-onlyIdempotent
Verifies a sealed WAV file and returns a verdict (verified, unsealed, warning or alert), a plain-language explanation and the seconds that changed after sealing. Give the file as exactly one of: url, base64. To check it against a person, pass their public key or public pairing text as pinned_public_key. Never pass a private key or a circle pairing text.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | https URL of the WAV file | |
| base64 | No | The WAV file, base64-encoded | |
| strict | No | A missing seal from this speaker is an alert, not a warning | |
| always_seals | No | Whether this speaker always seals (default true when a key is pinned): a missing seal is then a warning | |
| pinned_public_key | No | The speaker's Ed25519 public key (64 hex) or public pairing text (voxtrust:0:public:...) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety/read profile (readOnly, idempotent, openWorld), and the description adds real behavioral content: the verdict vocabulary, the plain-language explanation, and the changed-seconds output, plus a security constraint on key material. It does not discuss failure modes or rate limits, so it falls short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with purpose and outputs before the parameter guidance, and no filler. Slightly dense in the middle sentence where input cardinality and pinning are packed together, but every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does so adequately by naming the verdict set, explanation, and changed-seconds. The security caveat about private keys is a valuable addition. Remaining gaps are minor for a read-only verification tool with full annotation coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description genuinely extends the schema: it declares url and base64 mutually exclusive, clarifies that pinned_public_key accepts either a raw public key or public pairing text, and forbids private keys. That is meaning the schema does not carry.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Verifies a sealed WAV file') and immediately names the concrete output shape (verdict of verified/unsealed/warning/alert, explanation, seconds changed). This is far beyond restating the title and lets an agent distinguish it from the pairing sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit input rules ('exactly one of: url, base64') and conditional usage ('To check it against a person, pass their public key or public pairing text'). Also adds a hard exclusion ('Never pass a private key or a circle pairing text'), but it never names a sibling tool as an alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
describe_pairing - First observed
verify_audio
TDQS
Scored across 2 tools
verify_audio checks a file while describe_pairing parses a pairing string, so the two purposes are largely distinct. There is mild coupling because verify_audio accepts a pinned_public_key that could originate from a pairing text, but the tools still read as clearly separate actions.
Both names use the same verb_noun snake_case convention (verify_audio, describe_pairing). No deviations or mixed styles.
Two tools is thin even for this narrow trust-verification purpose; it is borderline rather than outright wrong. It cannot be called well-scoped with only a verify and a parse action.
The surface covers verification and pairing inspection, but omits the producing side of the lifecycle (no tool to seal audio or mint a pairing text/label). Agents can work around this if sealing happens elsewhere, but there is a notable gap.
Maintenance
Related MCP Connectors
Verify Seal AI decision receipts: signed evidence anyone can check, no account needed.
Free, no-account verification of KeyHalve-sealed documents. Read-only; never receives keys.
Verify Attest agreements, stamp codes, receipts, proofs and SHA-256 fingerprints, with no sign-in.
Verify AI work against criteria and get signed receipts. From Spoolis, guarantees for AI work.
Related MCP Servers
- AlicenseAqualityBmaintenanceVerifies C2PA Content Credentials for local files or URLs and returns an LLM-ready verdict on trust, AI generation, and provenance.411 npm2Apache 2.0

KeyHalve verify-MCPofficial
AlicenseNot gradedqualityBmaintenanceEnables AI to verify KeyHalve-sealed documents from any platform. Verifies status, ciphertext integrity, rail attestation, time lock, and issuer trust without requiring decryption keys.MIT- AlicenseNot gradedqualityCmaintenanceEnables offline verification that a supplied DSH workflow adhered to declared duty-separation constraints, producing a redacted, content-addressed JSON verdict.MIT
- AlicenseAqualityBmaintenanceEnables local analysis of PCM WAV files to produce bounded audio observations such as activity segments, clipping indicators, duration, sample rate, peak, and RMS level without uploading recordings.1MIT