Expand description
AVA1 (Adaptive Verified Assembly, version 1): an encrypted, resumable, multi-lane protocol for moving large files and folders between two devices over TCP. This crate is its Rust implementation, a client and a node; the specification is normative, and a C node in the same repository is tested against this crate on every change.
AVA1 was designed for transfers to a PlayStation 5: in ps5upload the C node runs on the console and this crate is the client on a PC, phone or server. Nothing in the protocol is specific to the PS5, and it works between any two devices.
- Fast. A transfer spreads over up to 8 parallel lanes; the
governorsets lanes and chunk size from whatever is slowest at the moment (network, source disk, receiving disk). - Resumable. The receiver keeps a
journalof what is durably written; a dropped connection or a restarted device picks up where it stopped. - Verified. Every file is checked with BLAKE3 in 1 MiB groups (
verify) before it counts as written. - Encrypted and paired. A Noise XX
handshake, ChaCha20-Poly1305 on every frame, and a one-time pairing code (cpace) after which the devices recognise each other’s keys. - Extensible. A session also carries RPCs; an application adds its own methods and
messages with the
ava1-gencode generator.
§Sending a folder
A client connects to a node, pairs the first time with the code the node shows, and sends a folder as one job:
use std::sync::{Arc, Mutex};
use ava1::keys::Identity;
use ava1::peers::PeerStore;
use ava1::send::{send_job, SendOptions};
use ava1::session::{connect, Timing};
use ava1::source::LocalSource;
let me = Arc::new(Identity::load_or_create("state/identity".as_ref())?);
let peers = Arc::new(Mutex::new(PeerStore::load("state/peers".as_ref())?));
let mut session = connect("192.168.1.20:9120", me, peers, "my laptop", Timing::default())
.await?;
if session.pairing_pending() {
session.confirm_pairing(code_shown_by_the_node).await?;
}
let source = LocalSource::new("photos".into());
let files = Arc::new(ava1::manifest::walk(&source, &|_: &str| false)?);
let mut job = session.job(ava1::keys::random_bytes()?);
let done = send_job(&mut job, files, Arc::new(source), SendOptions::upload("backups/photos"))
.await?;
assert_eq!(done.status, ava1::gen::STATUS_OK);
session.close().await;The examples run as they are: send_folder starts a node and sends a folder to it in one
process, and send_to_node is a complete client that pairs over the network.
§Running a node
A node is a server::ServerCtx (its identity, its paired devices, an RPC handler, and a
job host such as host::FolderHost) served on a listener with server::serve. New
devices pair while server::ServerCtx::open_pairing holds the pairing window open.
§Where things are
| Sessions and RPC | session (client), server (node), router |
| Transfers | send, recv, host, source, seq, manifest, governor |
| Durability | journal, packlog, ranges, verify |
| Identity and trust | keys, peers, handshake, cpace, trust, launch |
| Wire format | gen (generated messages), wire, frame, conn, crc32c |
| Support | diag (where diagnostic lines go), fslock, hex, Ava1Error |
The generated messages live in gen, whose name is a reserved word in Rust 2024: a crate
on edition 2024 writes ava1::r#gen (use ava1::r#gen::{self, NodeInfo};).
The library writes a few diagnostic lines (a transfer’s bottleneck summary, kernel buffer
sizes) to standard error; diag::set_sink sends them elsewhere.
The wire format is version 1 and grows without breaking older peers (tagged extension fields, ignorable frame types, capability bits). The crate follows semantic versioning separately from it.
Modules§
- conn
- Frames on a byte stream, sealed after the handshake (SPEC.md §2, §4.4).
- cpace
- Pairing PAKE (SPEC.md §4.6, §5.5): CPace-style, on top of the Noise session.
- crc32c
- CRC-32C (Castagnoli, reflected), used only for the frame header (SPEC.md §2).
- diag
- Where the library’s diagnostic lines go: a transfer’s bottleneck summary, a stage-timer line
(
AVA1_TIMING=1), the lane buffer sizes the kernel granted. Standard error by default; an application sends them to its own log (or nowhere) withset_sink. - frame
- The 16-byte AVA1 frame header (SPEC.md §2).
- fslock
- Cross-process safety for the small files every process on one data directory shares (the identity, the peer store, the launch tokens, the console pins): an advisory lock on a sidecar file, and temp names no two writers share.
- gen
- The AVA1 core messages, structs and constants (SPEC.md §3).
- governor
- The speed governor (SPEC.md §16): lanes, chunk and bundle size from what the link and the receiver report, once per second. Pure: the sender feeds it samples.
- handshake
- The session handshake: Noise XX in frames Hs1..Hs3, then Welcome (SPEC.md §5).
- hex
- Lowercase hex, for peer files and logs.
- host
- A Rust job host: uploads into, and downloads from, one shared folder (engine↔engine, and the tests). Which folders to share, and with whom, is left to the application.
- journal
- The receiver’s journal (SPEC.md §14): data sync → journal append → Durable. One format, written by both the engine and the console, so either can resume a job the other started.
- keys
- Identities, the Noise XX handshake, and sealed frames (SPEC.md §4).
- launch
- Launch tokens (SPEC.md §5.2): whoever stamps the helper ELF puts a fresh random token in its trust slot and keeps it here. The launched helper proves it holds the token — bound to one handshake — in its Welcome, so the stamping side trusts that console without a pairing code. The token itself never travels after the launch.
- manifest
- Manifests (SPEC.md §11): what a job moves, in file_id order.
- packlog
- Durable-by-log for small files, engine side (SPEC.md §15.7): the pack log a receiver appends
small files to so a batch costs one fsync of the log instead of one per file, and the
bookkeeping of which files are done but not yet durable in place (
unswept). - peers
- Paired devices, one per line:
<64 hex key> <unix seconds> <name>(SPEC.md §5). - ranges
- Which bytes of a file, and which files of a job, are already durable (SPEC.md §14).
- recv
- The receiver on an engine (SPEC.md §12–§15): downloads, relays, the folder host.
- router
- Data-plane routing (SPEC.md §11.1, §12.1). Every data-plane message starts with its 16-byte job id, so a frame reaches its job without a full decode.
- send
- The sender (SPEC.md §11–§12, §16): manifest, map, readers, bundles, chunks, lanes, credit, requeues and the governor.
- seq
- Sequential (forward-only) sources: 7z folders, solid RAR (SPEC.md §17).
- server
- The server side: accept loop, control connections, pairing, RPC (SPEC.md §6–§8).
- session
- The client side of a session (SPEC.md §6–§8).
- source
- Where a sender reads from (SPEC.md §11). Paths are relative to the source’s root and ‘/’-separated; “” is the root itself.
- trust
- The trust slot in the payload ELF (SPEC.md §5.1).
- verify
- Verification groups (SPEC.md §13). A file is hashed in 1 MiB groups; each group’s BLAKE3 chaining value is computed where the bytes are, and the file’s root is merged from them, so a resume never re-reads durable data to finish a hash.
- wire
- Encoding rules shared by every generated message (SPEC.md §3).
Enums§
- Ava1
Error - Every error this crate’s protocol operations return.