CRUMB a card from devarno-cloud

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

SourceUse caseLegal strength
ROUGHTIMEReal-time operations, anti-backdatingHigh — multiple independent witnesses
RFC3161Long-term archival, TSA-signed tokensHigh — PKI chain of trust
BLOCKCHAINImmutable anchor to public ledgerHigh — public verifiability
INTERNALDevelopment / offline modeLow — 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 RoughtimeProof

Each RoughtimeResponse carries: server name, public_key (32 bytes), timestamp, radius_us (uncertainty in microseconds), signature, and the echoed nonce.

RoughtimeProof records:

  • midpoint — consensus timestamp
  • radius_us — maximum uncertainty (SRS SEAL-NF-003: ≤ 100,000 µs = ±100ms)
  • responses — list of individual server responses
  • threshold — 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 block
  • tx_hash — identifies the transaction within the block
  • merkle_path — inclusion proof within the block’s transaction tree
  • block_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 logic
def 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: ±100ms

neighbors on the map