Skip to main content

Offline Verification

Offline verification allows checking whether an asset has been revoked without making an API call. This is critical for defence, field inspection, and air-gapped environments.

How It Worksโ€‹

  1. Sync โ€” Download a compact Cuckoo filter from the API containing all revoked serials
  2. Verify locally โ€” Check any serial against the filter in microseconds
  3. Re-sync periodically โ€” Update the filter to catch new revocations

The filter is a binary blob: 19-byte header + bucket data + 64-byte Ed25519 signature. The signature ensures the filter hasn't been tampered with.

Usageโ€‹

import { verifyOffline, parseFilterHeader, StaleFilterError } from 'optropic';

// 1. Download the filter (do this periodically)
const response = await client.sync.downloadFilter();
const filterBuffer = response.data; // ArrayBuffer

// 2. Parse the header to check freshness
const header = parseFilterHeader(filterBuffer);
console.log(`Filter version: ${header.version}`);
console.log(`Generated: ${header.timestamp}`);
console.log(`Entries: ${header.entryCount}`);

// 3. Verify a serial offline
const result = verifyOffline(filterBuffer, 'SER-abc123', {
maxAgeMs: 24 * 60 * 60 * 1000, // reject filters older than 24h
});

if (result.valid) {
console.log('โœ“ Not revoked (as of last sync)');
} else {
console.log(`โœ— ${result.reason}`); // 'revoked' or 'stale_filter'
}

Filter Freshnessโ€‹

The Cuckoo filter includes a timestamp. You can configure a maximum age to reject stale filters:

try {
const result = verifyOffline(filterBuffer, serial, {
maxAgeMs: 3600_000, // 1 hour
});
} catch (err) {
if (err instanceof StaleFilterError) {
// Filter is too old โ€” re-sync
const fresh = await client.sync.downloadFilter();
}
}

Defence Use Caseโ€‹

For air-gapped environments, the filter can be transferred via USB or secure file transfer. The Ed25519 signature ensures integrity even when transferred over untrusted channels.

Limitations

Offline verification can only detect revoked assets. It cannot confirm an asset exists or verify its full provenance chain. For full verification, use the online client.assets.verify() method.