Kolaboro / Public log / Witnesses
Witnesses of the public log
A log we sign ourselves proves little if only we hold it. Witnesses are people and organisations outside Kolaboro who check every day that our log only grows, and sign what they saw with their own key. If we ever rewrote a past line, or showed one history to you and another to someone else, their signatures would stop matching.
Loading the witness list…
Registered witnesses
Loading…
The checkpoint they sign
Our log is a Merkle tree of daily lines (RFC 9162 hashing). Its signed summary, the checkpoint, is at /api/open/checkpoint in the C2SP signed-note format. The same checkpoint with every matching witness cosignature appended is at /api/x/o/checkpoint, so a client can require, say, two witnesses before it trusts an inclusion proof.
Checking the checkpoint in your browser…
Run a witness in five minutes
The witness kit is two open files, MIT licence, standard library only. It runs free on GitHub Actions in your own repository, so the check happens on machines we do not control.
- Copy the two files into a repository you own: kolaboro_witness.py as
witness/kolaboro_witness.py, and the workflow kolaboro-witness.yml as.github/workflows/kolaboro-witness.yml. Read the script: it is about 230 lines. - Make a key on your own computer:
python3 kolaboro_witness.py keygen witness.key. It prints your public key and writes the private seed to a file with owner-only permissions. It never prints the private key. - Store the key as a secret: in your repository, Settings, Secrets and variables, Actions, new secret
KB_WITNESS_KEYwith the content ofwitness.key. Then delete the file or keep it offline. - Run it once by hand (Actions, Kolaboro log witness, Run workflow). From then on it runs every day at 08:41 UTC, after our 07:15 UTC log line.
# or anywhere with Python 3.8+ python3 kolaboro_witness.py selftest # RFC 8032 test vector and a cosignature round trip KB_WITNESS_KEY=$(cat witness.key) python3 kolaboro_witness.py run \ --name github.com/you/kolaboro-witness --state state.json --submit
What a witness checks before it signs
- Our signature on the checkpoint, with the published log key (kolaboro-keys.json, pinned in the script).
- That the tree did not shrink, and that an RFC 9162 consistency proof links the checkpoint it saw last time (kept in its own repository, not on our servers) to the new one. The proof is checked against the root the witness saved, never against a root we send.
- Only then it cosigns. If any check fails it refuses to sign and the job fails, so GitHub emails its owner and the failed run, with its output, is public evidence.
Format
Cosignatures follow C2SP tlog-cosignature (Ed25519, cosignature/v1), the format used by the Go checksum database and Sigstore witnesses, so generic tools can read them.
signed message = "cosignature/v1\n" + "time " + unix_seconds + "\n" + checkpoint body (origin, size, root, extension lines) line = "— " + witness_name + " " + base64( key_id[4] || timestamp[8, big-endian] || ed25519_signature[64] ) key_id = SHA-256( witness_name + "\n" + 0x04 + public_key )[0:4]
Submissions go to POST /api/x/o/witness with {"checkpoint", "cosignature", "public_key", "contact"}. The server checks the key id, the signature, that the time is within the last 48 hours, and that the size and root are exactly our tree at that size. A name is bound to the first key it is used with, a witness can never go back to a smaller tree, and names under kolaboro.com/ are reserved for our own witness. Registered witnesses and their latest cosignature: /api/x/o/witnesses.
Limits, honestly: a witness proves that everyone who checks sees the same append-only history. It does not prove a line is true; that is what the evidence, the verifier and the Bitcoin timestamps are for. Each daily line is also recorded in Sigstore Rekor. Public log · Security · Status