roughtime 0.1.0

A no_std-capable Roughtime secure time-sync client with pluggable crypto backends
Documentation

Roughtime

A no_std-capable Rust client for the Roughtime secure time synchronization protocol, with pluggable crypto backends and an anti-rollback time floor. Client-only: this crate queries and verifies Roughtime servers, but does not implement one.

Quickstart (hosted, default features)

With default features, server hostnames are resolved end-to-end-encrypted over DNSCrypt — no manual IP resolution required:

use roughtime::client::{RoughtimeClientConfig, TokioClient};

#[tokio::main]
async fn main() {
    let client = TokioClient::new(RoughtimeClientConfig::default());
    let result = client.query_well_known().await.expect("query failed");
    println!("Verified time: {}s", result.time.as_unix_seconds());
}

See examples/query_dnscrypt.rs (cargo run --example query_dnscrypt). If you'd rather resolve hostnames yourself (e.g. via the plain OS resolver, or your own pinned IPs), build the (RoughtimeServer, IpAddr) list by hand and call client.query(&resolved) instead — see examples/query_tokio.rs.

Feature flags

Exactly one crypto backend must be selected:

Feature Backend
rustcrypto Pure Rust ([ed25519-dalek] + [sha2]), no_std-capable
aws-lc-rs (default) [aws-lc-rs]
aws-lc-rs-fips aws-lc-rs built in FIPS mode

Layered on top:

  • std (default) — enables the networking clients and the Linux os-clock backend.
  • tokio-client (default) — an async, concurrent multi-server query client.
  • blocking-client — a synchronous std::net::UdpSocket-based client.
  • os-clock — an opt-in Linux SystemClock implementation that can set the OS wall clock forward to the verified time floor.
  • dnscrypt (default) — resolves well-known Roughtime server hostnames over DNSCrypt (authenticated, encrypted DNS) instead of the OS's plain, unauthenticated resolver, via resolve_servers/resolve_servers_async and TokioClient/BlockingClient::query_well_known. This closes the one remaining unauthenticated hop before Roughtime's own Ed25519-verified response takes over.
  • build-time-floor — opt-in, not in default. See "The anti-rollback floor" below.

no_std / kernel usage

For a kernel or bootloader that supplies its own networking and randomness:

cargo add roughtime --no-default-features --features rustcrypto

This gives you wire-format parsing, request building, and response verification, with no std, networking, or OS-clock dependency — only a global allocator is required (see below).

use roughtime::{Nonce, build_request, verify_response};

let nonce = Nonce::new(my_hardware_rng_bytes());
let request = build_request(&nonce);
// ... send `request` over your own UDP stack, receive `response_bytes` ...
let verified = verify_response(&response_bytes, &nonce, server_pubkey_base64)?;

See examples/no_std.rs for a complete, runnable version of this (cargo run --example no_std --no-default-features --features rustcrypto).

Requirement: a global allocator

This crate always links alloc (for Vec-backed message parsing), even in no_std builds. no_std consumers must provide a global allocator.

The anti-rollback floor

No time reported by a Roughtime server (or the OS clock) is trusted below a floor: a machine cannot legitimately observe a time earlier than when this crate was built.

Two supported workflows:

  • Default (reproducible builds): the floor is a static constant (src/floor.rs, HARDCODED_FLOOR_SECS) with no dependency on the build machine's clock. Bump it in source as a normal, reviewable commit as time passes. This is required for bit-for-bit reproducible builds (e.g. SEV-SNP attestation measurement matching) — enabling build-time-floor would make the build depend on wall-clock time and break reproducibility.
  • Opt-in build-time-floor: the floor auto-ratchets forward to the build day, using the build machine's wall clock, at the cost of build reproducibility. If the build machine's clock is before the hardcoded floor, the build refuses to compile (this should only happen on a misconfigured build host). Suitable for non-attested hosted deployments that rebuild frequently.

Security notes

This is a client-only crate — it never holds Ed25519 private key material, only verifies server-supplied public keys and signatures. The one client-generated secret-like value is the 64-byte nonce, which is zeroized on drop. Raw response bytes and extracted public keys are intentionally not zeroized: they are bulk public-protocol data (broadcast in the clear by protocol design), and scrubbing them would cost real performance for no confidentiality benefit.

MSRV

Rust 1.89.

License

This project licensed under either the MIT License or the Apache License, Version 2.0 at your option.