# Initialise a new vault
cargo run -- init ./vault
# Lock the vault (encrypt work/ contents)
cargo run -- close ./vault --password secret123
# Unlock the vault (decrypt into work/)
cargo run -- open ./vault --password secret123
# List vault contents
cargo run -- list ./vault --password secret123
# Show storage statistics
cargo run -- stats ./vault --password secret123[VAULT_PATH]: Path to the directory to initialise as a vault. Defaults to..
[VAULT_PATH]: Path to an open vault directory. Defaults to..--password: Password used to wrap the root key.
[VAULT_PATH]: Path to a locked vault directory. Defaults to..--password: Password used to unwrap the root key.
View vault contents without unlocking the working directory.
cargo run -- list [VAULT_PATH] --password <PASSWORD>Prints a CAS storage report for the vault.
cargo run -- stats [VAULT_PATH] --password <PASSWORD>Tracked file count, logical size, total chunk count, unique blob count, total blob references, on-disk size, shared chunks, dedup ratio, approximate saved-space estimate
vault/
work/ # plaintext working directory (present only when open)
.blobs/ # encrypted blob files (content-addressed IDs)
.meta/
manifest.enc # encrypted file index (AES-256-GCM)
root_key.enc # root key wrapped with password-derived key
root_key.raw # root key in plaintext (present only when open)
kdf_params.json # Argon2id parameters and salt
state # "open"/"locked"
- Argon2id key derivation (64 MB memory, 3 iterations, 4 threads)
- HKDF-SHA256 derives subkeys from the root key
- AES-256-GCM chunk encryption (16 MB chunks)
- GCM authentication tag per chunk
Manifest records each file as FileEntry:
{
"logical_path": "folder/file.txt",
"size": 204800,
"content_hash": "<sha256-hex>",
"blob_ids": ["<hex-id>", "..."],
"created_at": "<rfc3339>",
"modified_at": "<rfc3339>"
}The manifest is a JSON document encrypted with a subkey derived from the root key:
{
"version": 1,
"files": {
"folder/file.txt": {
"logical_path": "folder/file.txt",
"size": 204800,
"content_hash": "<sha256-hex>",
"blob_ids": ["<hex-id>", "..."],
"created_at": "<rfc3339>",
"modified_at": "<rfc3339>"
}
}
}ZEROVAULT stores file data as content-addressed chunks. Now, when the chunks are identical, it only keeps one chunk.
The manifest keeps a content_hash for each logical file and a blob_ids list for the chunk chain that makes up that file.
The blob store also tracks reference counts, which lets the vault keep shared chunks on disk until the last file stops referencing them.
The stats command reports the current CAS state of the vault.
It prints:
- tracked files
- logical size
- total chunks
- unique blobs
- total refs
- on-disk size
- shared chunks, when deduplication is actually saving space
- deduplication ratio
- approximate saved space versus an undeduped logical layout
passwordArgon2id(salt fromkdf_params.json)IKM(32 bytes)HKDF-SHA2564.1.zerovault-v1-wrap(K_wrap, wraps/unwraps root key) 4.2.zerovault-v1-mac(K_mac)root_key(256-bit, stored inroot_key.enc)HKDF-SHA2566.1.zerovault-v1-manifest(manifest key) 6.2.zerovault-v1-blob(blob key)