Skip to main content

Crate ava1

Crate ava1 

Source
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 governor sets lanes and chunk size from whatever is slowest at the moment (network, source disk, receiving disk).
  • Resumable. The receiver keeps a journal of 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-gen code 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 RPCsession (client), server (node), router
Transferssend, recv, host, source, seq, manifest, governor
Durabilityjournal, packlog, ranges, verify
Identity and trustkeys, peers, handshake, cpace, trust, launch
Wire formatgen (generated messages), wire, frame, conn, crc32c
Supportdiag (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) with set_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§

Ava1Error
Every error this crate’s protocol operations return.