Skip to main content
Glama
vox-trust

vox-trust

Official

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.

  1. Seal. The speaker's device signs the audio at the source.

  2. Verify. Anyone with the protocol checks which key sealed it, when, and which chunks of audio were altered.

  3. 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 = verified

keygen 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 recordings
import { 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

cargo test --workspace

Published test vectors

Byte-exact seals and manifests in spec/test-vectors/

included above

Cross-check in Python

tools/check_vectors.py rebuilds every vector from the spec text (standard library, plus cryptography for Ed25519)

pip install cryptography && python3 tools/check_vectors.py --strict

WebAssembly end to end

The compiled module reproduces the vectors byte for byte, handles garbage input, and does not leak memory

scripts/build-web.sh && node --test tests/node/*.mjs

Real browser

The demo page in headless Chromium, Firefox and WebKit: sealing, six attacks, public-key pinning, five languages, accessibility, phone width, dark mode

BROWSER=firefox node tests/browser/demo.mjs

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)

cd fuzz && cargo +nightly fuzz run verify_wav

Coverage

Share of Rust lines the tests execute; CI fails below 96 %

scripts/coverage.sh

Mutation testing

Changes operators and return values in vox-trust-core and the key-file code, one at a time, and checks that a test fails; the few changes that cannot alter behaviour are listed with the reason in .cargo/mutants.toml

cargo mutants -p vox-trust-core; cargo mutants -p vox-trust-cli -f crates/vox-trust-cli/src/keyfile.rs

Dependencies

Known vulnerabilities, licenses, sources

cargo deny check

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 records

Contributing, security, license

Available Tools

2 tools
describe_pairingRead a pairing textA
Read-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.

NameRequiredDescriptionDefault
textYesThe pairing text

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 recordingA
Read-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.

NameRequiredDescriptionDefault
urlNohttps URL of the WAV file
base64NoThe WAV file, base64-encoded
strictNoA missing seal from this speaker is an alert, not a warning
always_sealsNoWhether this speaker always seals (default true when a key is pinned): a missing seal is then a warning
pinned_public_keyNoThe speaker's Ed25519 public key (64 hex) or public pairing text (voxtrust:0:public:...)

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 2 tool updatesv0.1.0
    • First observeddescribe_pairing
    • First observedverify_audio

TDQS

A4.1/5.0

Scored across 2 tools

Disambiguation4/5

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.

Naming Consistency5/5

Both names use the same verb_noun snake_case convention (verify_audio, describe_pairing). No deviations or mixed styles.

Tool Count3/5

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.

Completeness3/5

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

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Verifies C2PA Content Credentials for local files or URLs and returns an LLM-ready verdict on trust, AI generation, and provenance.
    4
    11 npm
    2
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables 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
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables offline verification that a supplied DSH workflow adhered to declared duty-separation constraints, producing a redacted, content-addressed JSON verdict.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables 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.
    1
    MIT