# Witnesses

Macs running MLX Node 0.9.7 or later check every new checkpoint against the last one they cosigned and sign it with their Secure Enclave key, so a split view would have to fool every one of them.

## What a witness Mac does

Witnessing is built into MLX Node from version 0.9.7 and runs on its own while MLX Node is open (`Core/Witness.swift`):

1. **Pin the keys.** The first time, it remembers the sequencer's public key and the Solana anchor account from `GET /api/log`. If mlx.app later signs with another sequencer key, it flags it.
2. **Fetch and verify.** Periodically it fetches `GET /api/log/checkpoint` and verifies the signature with the pinned key ([Checkpoints](/integrity/checkpoints)).
3. **Compare with what it cosigned last.** It keeps only the newest checkpoint it cosigned.
   - A smaller size than that one, or the same size with a different root: evidence of a rewrite.
   - A larger size: it asks for a consistency proof from its size to the new one and verifies it ([Proofs](/integrity/proofs#consistency-proofs)). A proof that fails is evidence too.
4. **Cosign.** If everything holds, it signs the checkpoint with the Mac's Secure Enclave key and posts the cosignature.
5. **Check the anchor.** About once an hour it reads the newest anchor memo straight from Solana's public RPC (not through mlx.app) and checks it is consistent with the checkpoint it cosigned ([Anchors](/integrity/anchors)).

When something doesn't add up, MLX Node saves both signed notes as evidence in its Application Support folder and shows "Inconsistency found" in **Settings → Ledger witness**, with a button to show the evidence. Otherwise that row says "Witnessing the MLX ledger" and what it checked last.

## The cosignature

A cosignature says: *as of time t, this is the newest consistent checkpoint I have seen.* The Mac signs this text (`cosignMessage` in `lib/chain/tlog.ts`):

```text title="What a witness signs"
mlx-cosignature/v1
time 1793116011
mlx.app/ledger/mlx-1
398
y5euvUWfr1GfTZZ9W2qY+v/y3w9qaB9L+J00VgslPX4=
```

That is `mlx-cosignature/v1`, then `time <Unix seconds>`, then the checkpoint's body (its first three lines, each ending in `\n`). The signature is ECDSA P-256 over SHA-256 of that text, with the Mac's device key, as raw `r‖s` (128 hex characters).

## Post a cosignature

```endpoint
POST /api/log/cosign
```

Device-signed like every request a Mac makes: the header `x-mlx-device` carries `<device public key>|<ms>|<signature>` over the request ([Worker protocol](/node/worker-protocol)). Each signed request is accepted once.

| Parameter | Type | Notes |
|---|---|---|
| `size` | integer | The size of the checkpoint being cosigned. It must be a checkpoint the log signed. |
| `time` | integer | The `time` in the signed text, Unix seconds, close to the server's clock. |
| `sig` | string | The P-256 signature over the cosignature text, raw `r‖s` hex. |

```json title="Request body"
{ "size": 398, "time": 1793116011, "sig": "<128 hex characters>" }
```

```json title="Response"
{ "ok": true, "size": 398 }
```

The server keeps one cosignature per Mac per checkpoint, and remembers the largest size each Mac cosigned.

| Status | Body | When |
|---|---|---|
| `400` | `{"error":"Bad cosignature"}` | `size`, `time` or `sig` malformed. |
| `400` | `{"error":"Clock is off"}` | `time` too far from the server's clock. |
| `401` | `{"error":"Unsigned request"}`, `{"error":"Bad signature"}` | The `x-mlx-device` header is missing or doesn't verify, or its time is too far from the server's clock. |
| `403` | `{"error":"Signature doesn't match"}` | `sig` doesn't verify for this device over this checkpoint. |
| `404` | `{"error":"No checkpoint of that size"}` | The log never signed a checkpoint of that size. |
| `409` | `{"error":"Older than your last cosignature","last":<size>}` | This Mac already cosigned a larger size: a witness never goes back. |
| `409` | `{"error":"Request already used"}` | The same signed request was sent twice. |
| `429` | `{"error":"Slow down"}` | Too many cosignatures from this Mac in a minute. |

## Who has cosigned

`GET /api/log` lists the Macs that cosigned the newest checkpoint under `witnesses`, each with an opaque `id` (derived from its device key; the same id MLX World uses) and the `time` it signed:

```json title="From GET /api/log (trimmed)"
"witnesses": [
  { "id": "2b372dd759bf0d89", "time": 1793116011 },
  { "id": "9547fd72c3308a3d", "time": 1793116266 }
]
```

The cosignatures themselves and the witnesses' keys are not published, and any device key can post one; a Mac doesn't have to be linked to a wallet. Witnesses can therefore be the operator's own Macs: what they add is that every honest one would have caught a rewrite it was shown. Independent outside witnesses are planned.

## Run a witness

Install [MLX Node](https://mlx.app/download) 0.9.7 or later and leave it open; nothing to turn on. A witness Mac doesn't need a dedicated seat. To witness without a Mac, do what it does in your own code: keep the last checkpoint you verified, check every new one with a consistency proof ([Checkpoints](/integrity/checkpoints#keep-what-you-saw)), and compare it with the [Solana anchors](/integrity/anchors#check-a-memo-against-the-log).
