---
type: research
title: Proof of Work — Sentinel PoW Mechanism (Desktop vs Web)
description: The sentinel proof-of-work chain: who solves it, when, on which hashing, CPU cost, and how it contrasts with DeviceCheck attestation
tags: [openai, pow, sentinel, fingerprint, fnv, sha3, cpu, attestation]
timestamp: 2026-08-26
---

# Proof of Work — Sentinel PoW Mechanism (Desktop vs Web)

Part of [openai-research](openai-research.md). The sentinel PoW is the integrity mechanism used by the **web/browser route** (and by the desktop **fallback** when DeviceCheck is unavailable — the gate flip).

## What it is, where it lives

- The client (renderer) builds a **fingerprint** (array of slots, sPr, 24 slots on desktop — see [sentinel-fingerprint-comparison](sentinel-fingerprint-comparison.md)), serializes `gAAAAAC + base64(fingerprint)` as the **prekey** body for `POST /sentinel/chat-requirements/prepare`.
- The server returns **requirements + a seed**; the client then solves a **PoW** to mutate the fingerprint slots (`counter` and `time` slots — the solver increments/mutates them) and computes the final value.
- PoW hash: **desktop = FNV-1a 32-bit murmur-finalized**; web route (OmniRoute reference) = **SHA3-512** (100k iteration loop, target `0fffff`) — mutually exclusive families per client/route.
- The final key travels in the `OpenAI-Sentinel-*` headers of the protected requests.

## When it runs / who invokes it

- **Web route**: per typing throttle (`/f/conversation/prepare` fires on every keystroke, debounced — the prepare carries the growing partial text), so **longer conversations → heavier continuous PoW** (observed CPU increase / GPU idle in Safari = single-threaded JS solving, no GPU/WASM accelerator, no web worker).
- **Desktop (fallback)**: the same sentinel chain with the desktop fingerprint, `originator: Codex Browser` + plain Chrome UA (`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) … Chrome/151.0.0.0`), one-time per prepare/first request.
- Solver is **in the renderer main thread** (no dedicated worker found in the asar; the murmur2/murmur3 hash primitives are bundled). This is the CPU spike/GPU idle observation: single-thread JS.
- The desktop main route (attestation) has **no PoW** — the prepare still runs on keystrokes (typing throttle) but without the sentinel chain.

## The slot values baked in (desktop, real trailer)

`0` screen dims (e.g. `2494`)? **No** — real: slot 0 = `screen.width + screen.height` derived, slot 1 = `new Date().toString()`, slot 2 = `performance.memory.jsHeapSizeLimit` (real ~4.4GB in the flip run), slot 3 = counter (solver-mutated), slot 4 = UA, slot 5 = real webview chunk (`app://-/assets/index-rLYmMQgS.js`), slot 6 = `<!-- PROD_BUILD_TAG_HERE -->` (confirmed leaving the client, accepted by the server), 7-8 languages, 9 = time (solver-mutated), 10-12 navigator/document/window props, 13 `performance.now()`, 14 uuid, 15 search params, 16 `hardwareConcurrency`, 17 `timeOrigin`, 18-23 flags.

## Contrast with DeviceCheck (the alternative)

| | Sentinel/PoW | DeviceCheck attestation |
|---|---|---|
| Gate | `!vPr()` (no DeviceCheck) | `vPr()` = isDeviceCheckSupported && appVersion ≠ 0.0.0 |
| Cost | CPU-bound single-thread JS, per prepare/typing | ~17ms native (hardware attestation via addon) |
| Header/body | `OpenAI-Sentinel-*` + prekey `p` | `x-sentinel-dc: {token}` → challenge `gAAAAAB…` → body `app_attest_challenge` |
| Detection surface | fingerprint slots + PoW hash family | Apple's DeviceCheck server validation |
| Mobile/web/desktop | web (SHA3-512) + desktop fallback (FNV-1a) | desktop macOS arm64 only |

## For the standalone

The PoW is single-threaded JS on the web route — a standalone harness can solve it far faster with WebGPU/WASM (or wasi/wasix in Node), but for the **desktop flows the attestation path is the better target** (no PoW, ~17ms). The fallback PoW (desktop flavor: FNV-1a + real fingerprint) is reproducible with the captured slot values. `performance.now()`/timeOrigin should be sampled honestly — the server validates ranges (the web-vendor fixed/heap hardcodes (4294705152) are a detectable deviation).

## TypeScript types (solver)

```ts
export type PoWHashFamily = 'fnv1a-32-murmur' | 'sha3-512'

export interface SolverResult { answer: string; slots: unknown[] }
export interface PoWSolver {
  /** Mutate the mutable slots (counter/time) until the hash meets the target. */
  solve(seed: string, difficulty: string): SolverResult
  /** FNV-1a 32-bit murmur-finalized (desktop) — the only family on the desktop fallback. */
  hash: (input: string) => string
}

export interface SentinelRequirements {           // POST /sentinel/chat-requirements/prepare → 200
  token?: string
  prepare_token?: string
  pow?: { seed: string; difficulty: string }       // when non-empty, the client solves and sets
}

// ── headers the solved key lands in ──────────────────────────────────────
export interface OpenAIRequestSentinelHeaders {
  'OpenAI-Sentinel-Chat-Requirements-Token'?: string
  'OpenAI-Sentinel-Chat-Requirements-Prepare-Token'?: string
  'OpenAI-Sentinel-Proof-Token'?: string           // 'gAAAAAB' + base64(seed+~S…)
}

// ── the contrast table as types ──────────────────────────────────────────
export interface IntegrityMechanism {
  gate: 'devicecheck' | 'sentinel-pow'
  cost: 'native ~17ms' | 'cpu-bound single-thread js'
  headers: { 'x-sentinel-dc'?: string; 'OpenAI-Sentinel-*'?: string }
  lifetime: 'one-time challenge' | 'per-prepare'
}
```

## Cross-references

- [sentinel-fallback-validation](sentinel-fallback-validation.md) — the exercised desktop fallback (real fingerprint run)
- [sentinel-fingerprint-comparison](sentinel-fingerprint-comparison.md) — slot-by-slot vs OmniRoute
- [attestation-flow](attestation-flow.md) — the primary mechanism on the desktop
- [vendor-analysis](vendor-analysis.md) — why the web vendors' PoW causes bans
