VeilVoice destroys the biometric voiceprint of a speaker — pitch, formants, timbre, micro-timing and the melody of an accent — so that neither software nor a human can re-identify them or reconstruct the original voice, while the words stay clean and transcribable.

WHAT IT ACTUALLY DOES

Anonymise a recording

wav, mp3, flac, ogg, m4a in — a clean WAV out, with metadata stripped. Roughly 90× faster than real time.

Scramble a microphone live

Route the veiled voice into a virtual audio cable and every application on the machine — calls, streams, recorders — receives it instead of you.

Encrypt at rest, by default

Every recording is sealed as it is written — X25519 + ML-KEM-768 hybrid, so one captured today is not readable by a quantum adversary tomorrow. Turning that off makes you read why first.

Lock the app

A separate password gates the desktop app, rate limited and Argon2id-derived. It stops someone who picks up your unlocked computer. It is not tamper-proof, and the unlock screen says so.

Strip metadata

Audio tags, image EXIF and GPS. A de-identified voice is worthless if the file still says who recorded it, where, and on what.

Work as a Rust library

Every crate is a normal dependency. The engine is allocation-free and safe to call from inside an audio callback.

Transcribe without giving up your voice

Speech-to-text needs the words, not the voiceprint. Anonymise first and the service gets speech it can transcribe and a voice belonging to nobody.

Honest scope. “Fill the spectrogram with noise” and “stay understandable” are mutually exclusive — noise that covers the voice covers the words. VeilVoice targets the achievable goal: irreversible speaker de-identification with intelligibility preserved on purpose. If the message must also be secret, encrypt it; that is a separate problem with a separate answer.

The same applies to accent. Its melody and colour do not survive. What no signal-level transform can change is which phonemes you produced — at that level the accent and the words are the same thing, so a strong regional accent may still be audible.

DOWNLOAD

Latest release: see GitHub. Every binary is built twice in separate directories and verified byte-identical before it ships.

Files in the latest release

Always verify before you run it. A download can be corrupted in transit or replaced entirely. Two independent checks are published with every release: a SHA-256 for each file, and an OpenPGP signature over that hash list. The verifier below does the first one in your browser.

SO YOU HAVE DOWNLOADED IT — NOW WHAT

There are two programs in the archive: veilvoice-gui, the desktop app, and veilvoice, the command line. They share one engine, so anything one can do the other can. Nothing installs a service, writes to a registry, or phones home — delete the folder and it is gone.

  1. Give it a recording

    wav, mp3, flac, ogg, m4a and friends. Open the desktop app on the anonymise file tab and choose one, or point the command line at it. Roughly 90× faster than real time, so an hour of audio takes well under a minute.

    veilvoice anonymise interview.mp3 -o clean.wav
  2. The voiceprint is destroyed, the words are kept

    Each frame's measured phase is thrown away and resynthesised, and pitch register, vocal-tract length and spectral tilt are each collapsed onto one canonical value — so a whole population of speakers lands on the same output and there is nothing left to invert. What comes out is understandable, transcribable, and belongs to nobody.

  3. It is encrypted before it reaches the disk

    The result is sealed into a .veil container as it is written, so -o clean.wav produces clean.wav.veil. The WAV is built in memory and encrypted there — the plaintext never exists on disk, not even for a moment, because a file that is written and then deleted cannot be reliably taken back on flash storage.

    veilvoice decrypt clean.wav.veil -o clean.wav   # when you want it back
  4. Or scramble your microphone as you speak

    The live scramble tab routes your veiled voice into a virtual audio cable. Every application on the machine — a call, a stream, a recorder — then receives that instead of you, with no per-app setup.

  5. Check nothing else is listening

    De-identifying your voice on a call achieves little if a second program is recording the raw microphone at the same time. The monitor tab names what is holding your microphone and camera and warns the moment something starts.

  6. Lock the app behind you

    Set a password on the lock tab and VeilVoice will not open without it. The lock button in the header locks it immediately and clears the session passphrase with it.

The two passwords, and why there are two

The app lock

Decides whether VeilVoice opens at all. Argon2id verifier, rate limited, three attempts free and then a doubling wait.

The recording passphrase

Encrypts the files it writes. Argon2id at 256 MiB, or seal to a post-quantum hybrid public key instead.

They are deliberately different secrets. If one password did both, then opening the app would be the same act as unsealing everything it had ever written — the opposite of what a lock is for. VeilVoice keeps the two derivations domain-separated, so typing the same passphrase in both places still does not produce two copies of one value. Use two anyway: one guess that opens both defeats the point regardless of the maths.

The app lock is not tamper-proof, and cannot be. A program running on your computer has nowhere to hide a secret from that computer: anyone who can write to your files can delete the lock, and anyone holding the disk can attack the stored password hash offline. It protects against casual access — the person who sits down at your unlocked session — which is a real and common threat, and is exactly what the unlock screen says it is for. If someone taking your disk is the threat, encrypt the whole volume.

VERIFY A DOWNLOAD

Drop the file you downloaded here. It is hashed locally, in your browser, using the built-in WebCrypto API — there is no upload and no server that could receive it. Read js/verify.js; that file is the whole implementation.

click or drop a release archive here
no file hashed yet

The stronger check: the signature

A hash proves the file matches a list. The signature proves the list came from the maintainer. Browsers cannot verify OpenPGP, so this part runs on your machine:

gpg --import veilvoice-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing

Signing key fingerprint — check that gpg --verify names this exact key, not merely “a good signature”:

8101 FB3B B28D 02FB 239E  0CDF 9CC1 C7E7 A9B5 833A

download the public key — user ID is exactly tilas01, with no e-mail address attached.

SECURITY, IN FULL

Why the transform cannot be undone

Three independent mechanisms, each individually lossy. Reversing the output means defeating all three.

MechanismWhat it destroys
Phase discardEvery frame's measured phase is thrown away and a synthetic one generated. Phase encodes the exact waveform and the speaker's micro-timing. It is never stored, and infinitely many waveforms share any given magnitude spectrogram.
Many-to-one normalisationPitch register, vocal-tract length and long-term spectral tilt are each collapsed onto a single canonical value. A whole population of speakers maps to the same output, so there is nothing to invert.
CSPRNG modulationThe residual transform changes every frame from a ChaCha20 stream whose seed comes from the OS CSPRNG, lives only in page-locked RAM, and is zeroized on drop. There is no fixed transform to undo.
Rolling seedEvery two seconds by default the stream draws a fresh seed from its own output and restarts. ChaCha20 does not run backwards, so each roll permanently seals off the audio before it — a long recording is a chain of short streams, not one. Configurable, and inaudible: parameters glide across a roll and phase offsets ease over half a second.

At-rest encryption

LayerPrimitiveWhy
Password → keyArgon2id (RFC 9106)Memory-hard, so GPU and ASIC cracking gains little. Cost parameters travel with the file so old files still open.
Public-keyX25519 + ML-KEM-768 hybridAn attacker must break both. Guards against harvest-now-decrypt-later: a recording stored today may be attacked decades from now.
PayloadXChaCha20-Poly1305192-bit random nonces remove the counter-management failure mode entirely.
HeaderAuthenticated as associated dataAn attacker cannot downgrade the stored KDF cost to make cracking cheap — tampering makes decryption fail.
Keys in memoryPage-locked, zeroized, constant-timeKeys stay out of the swap file and are wiped on drop. Comparison leaks no timing.

Stated plainly: page-locking keeps keys off disk, not away from an attacker who can already read this process's memory, and hibernation writes RAM to disk wholesale and defeats it. A passphrase still sitting in a text field has not reached that protection yet, which is why it is wiped the moment it is used.

Recordings are sealed in memory and written once. An encrypted recording never exists on disk in the clear, because a plaintext file that is written and then deleted cannot be reliably taken back on flash storage.

The app lock, and exactly what it is worth

VeilVoice can sit behind a password of its own — separate from the one that encrypts recordings, so that opening the app is not the same act as unsealing everything it has written.

What it isWhat that means
An Argon2id verifier, not a keyA password hash is stored and compared in constant time. It encrypts nothing, because there is nothing local it could usefully encrypt.
Rate limited, and the limit persistsThree attempts are free; then the wait doubles from 5 s to a 15-minute cap. The count is written to disk after every attempt, so killing the app does not hand an attacker a fresh budget.
Domain separatedType the same passphrase in both places and you still do not end up with two copies of one value.

Not tamper-proof, and it cannot be. A local application has nowhere to hide a secret from the machine it runs on. Anyone who can write to your files can delete the lock; anyone holding the disk can edit the attempt counter, move the clock, or attack the stored hash offline. This protects against casual access — the person who sits down at your unlocked session. If the disk is the threat, the answers are full-volume encryption and the at-rest encryption above, not this.

Libre, and what that buys you

  • GPL-3.0-or-later. You may use, study, modify and redistribute it; derivatives stay free under the same terms.
  • No unsafe anywhere. Every crate carries #![forbid(unsafe_code)], including the page-locking path. Whole classes of memory-corruption bugs are impossible by construction.
  • Offline by construction. No telemetry, no update check. CI fails the build if an HTTP client so much as enters the dependency graph.
  • Reproducible. Pinned toolchain, committed lockfile, path-remapped builds. Rebuild a release and confirm it matches, byte for byte.
  • Artwork generated from source. Every icon and the banner come out of a readable script, not a committed binary blob.
  • This website too. No CDN, no web fonts, no analytics, no cookies. The only third-party request is the optional repository panel below, and it is a button you press.

Audited by tilas01 — the author, who wrote and reviewed it. Be clear about what that is worth: a maintainer audit catches what the author can see, and no external firm or independent researcher has reviewed this code. The cryptography uses standard, well-reviewed primitives rather than anything invented here, and the de-identification argument is verifiable by reading two source files. Until an independent review exists, the source is the strongest verification available to you.

THE REPOSITORY, LIVE

This panel fetches from api.github.com, which learns your IP address. GitHub already serves this page, so for most visitors that changes nothing — but it is your call, so nothing loads until you ask.

stars
forks
open issues
GPL-3.0licence

The README renders here once loaded.