Roughtime Distributed Timestamp Proofs
vest advanced 7 min read
ELI5
Three independent atomic clocks in different cities each sign a note saying “it is currently 14:03:27.442”. When all three notes agree within 100 milliseconds, you staple them together as proof of the timestamp. No single clock can lie because the other two would disagree — that’s Roughtime.
Technical Deep Dive
Roughtime is a distributed timestamp protocol that prevents backdating by requiring agreement from ≥ N independent time servers. VEST uses it via TimestampProof in proto/protocols/vest.proto.
TimestampSource Selection
| Source | Use case | Legal strength |
|---|---|---|
| ROUGHTIME | Real-time operations, anti-backdating | High — multiple independent witnesses |
| RFC3161 | Long-term archival, TSA-signed tokens | High — PKI chain of trust |
| BLOCKCHAIN | Immutable anchor to public ledger | High — public verifiability |
| INTERNAL | Development / offline mode | Low — not independently verified |
RoughtimeProof Structure
sequenceDiagram participant C as VEST Client participant S1 as Roughtime Server 1 participant S2 as Roughtime Server 2 participant S3 as Roughtime Server 3
C->>S1: Request(nonce) C->>S2: Request(nonce) C->>S3: Request(nonce) S1-->>C: Response(midpoint, radius_us, sig, nonce) S2-->>C: Response(midpoint, radius_us, sig, nonce) S3-->>C: Response(midpoint, radius_us, sig, nonce) Note over C: verify ≥ threshold responses<br/>compute consensus midpoint<br/>check radius_us ≤ 100_000 C->>C: assemble RoughtimeProofEach RoughtimeResponse carries: server name, public_key (32 bytes), timestamp, radius_us (uncertainty in microseconds), signature, and the echoed nonce.
RoughtimeProof records:
midpoint— consensus timestampradius_us— maximum uncertainty (SRS SEAL-NF-003: ≤ 100,000 µs = ±100ms)responses— list of individual server responsesthreshold— minimum required server count
RFC 3161 Proof
RFC3161Proof stores a standard TSA timestamp token (timestamp_token bytes), the TSA certificate, hash algorithm, and message_imprint (hash of the signed data). Suitable for long-term archival because the TSA certificate chain provides verifiability independent of the VEST node.
Blockchain Proof
BlockchainProof anchors the operation to a specific block:
blockchain— chain name (e.g. “ethereum-mainnet”)block_number+block_hash— identifies the blocktx_hash— identifies the transaction within the blockmerkle_path— inclusion proof within the block’s transaction treeblock_timestamp— block production time
SRS Temporal Requirements
From requirements/SRS.md SEAL-NF-003: timestamp accuracy SHALL be ±100ms globally. This maps to radius_us ≤ 100_000 in RoughtimeResponse. SEAL-F-004 requires distributed timestamping to prevent backdating.
Key Terms
- radius_us → timestamp uncertainty in microseconds; must be ≤ 100,000 for ±100ms SRS compliance
- midpoint → consensus timestamp from qualifying Roughtime servers
- nonce → replay-prevention token echoed by each server response
- RFC3161 → ITU-T standard for trusted timestamp tokens; stored as DER-encoded bytes
- BlockchainProof → immutable public ledger anchor; verifiable independently of any VEST node
Q&A
Q: If only threshold - 1 Roughtime servers respond, can a RoughtimeProof still be assembled?
A: Not a valid proof — the threshold field specifies the minimum. Assembling a proof with fewer responses would fail validation by any verifier checking responses.len() >= threshold.
Q: Can a VEST operation have both a RoughtimeProof and a BlockchainProof simultaneously?
A: No — TimestampProof.proof is a oneof field in the proto, meaning only one proof variant can be present per TimestampProof message.
Q: What nonce property prevents a Roughtime server from pre-computing responses? A: The nonce is client-generated per request and echoed in the signed response. A server cannot sign a response before receiving the nonce, preventing pre-computation of backdated timestamps.
Examples
Validating a Roughtime midpoint against the ±100ms SRS requirement:
# Pseudocode — verification logicdef validate_roughtime(proof: RoughtimeProof) -> bool: valid_responses = [r for r in proof.responses if verify_sig(r)] if len(valid_responses) < proof.threshold: return False max_radius = max(r.radius_us for r in valid_responses) return max_radius <= 100_000 # SEAL-NF-003: ±100msneighbors on the map
- VESTProof Wire Format & Proto Schema implementing a gRPC client that submits or fetches VESTProof messages
- Compliance & Regulatory Metadata Model tagging an audit entry for HIPAA or 21 CFR Part 11 before export as legal evidence
- Hybrid Logical Clock deciding ordering between concurrent operations
- FNP Lamport Clocks & Causal Ordering understanding causal ordering in distributed systems