oxedyne/daimond/verify/README.md
10.1 KiB, 1 run
created by r2519314175:1003, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | # Verifying Daimond |
| 2 | |
| 3 | Daimond's privacy claim is meant to be **checked, not trusted**. The client is |
| 4 | open source, it rebuilds byte-for-byte from that source, and every shipped build |
| 5 | is sealed in a public, tamper-evident log. So you can confirm three things |
| 6 | yourself, with no need to take anyone's word: |
| 7 | |
| 8 | 1. **The source is public** — read it. |
| 9 | 2. **The running site is that source** — build it and compare the hashes. |
| 10 | 3. **That build was really published** — check it is a sealed entry in the log. |
| 11 | |
| 12 | This directory is the machinery for (2) and (3). |
| 13 | |
| 14 | The **machine hand** — the program outside the page that runs commands on your |
| 15 | computer — is published too, and is sealed by a weaker check that is set out in |
| 16 | full under [The machine hand](#the-machine-hand). Read that section before |
| 17 | building and installing it. Nothing on this page claims the hand's binary is |
| 18 | reproducible, because it is not. |
| 19 | |
| 20 | ## Check the running site (the honest way) |
| 21 | |
| 22 | ```sh |
| 23 | git clone https://github.com/oxedyne-com/daimond |
| 24 | cd daimond |
| 25 | rustup target add wasm32-unknown-unknown |
| 26 | bash dev/build-wasm.sh # rebuilds the wasm from source |
| 27 | node verify/check.mjs --url https://daimond.oxedyne.com |
| 28 | ``` |
| 29 | |
| 30 | Use `dev/build-wasm.sh`, not `wasm-pack` directly. Rust bakes the path of every |
| 31 | source file into the binary, so a plain build stamps your own home directory |
| 32 | into the wasm and the hashes then cannot match anyone else's. The script maps |
| 33 | those paths to fixed stand-ins first, which is what makes your rebuild and the |
| 34 | published build comparable at all. It is a two-line script -- read it. |
| 35 | |
| 36 | Green means: every file the site served hashes to what the manifest says, the |
| 37 | manifest's bundle hash is the hash of its own file list, and that bundle is a |
| 38 | sealed entry in an unbroken chain in `verify/transparency.jsonl`. Red names |
| 39 | exactly what differs. The verifier trusts nothing the server says beyond the |
| 40 | bytes it serves — the authority is the source you cloned and the log in this |
| 41 | repo. |
| 42 | |
| 43 | Being in the chain proves a bundle was published at some point, not that it is |
| 44 | the one meant to be live now — so a server could serve an older, still-sealed, |
| 45 | still-green build (a roll-back). By default that is reported as a warning; add |
| 46 | `--latest` to fail unless the served build is the chain's tip, or `--expect |
| 47 | <bundlehash>` to fail unless it is exactly the build you name. |
| 48 | |
| 49 | You can also check a local build directly (`node verify/check.mjs --dir www`), |
| 50 | and there is an in-browser check at `/verify.html` on the running site — handy, |
| 51 | but weaker, because a tampered server could tamper with that page too. Its one |
| 52 | load-bearing check is against the public log on GitHub, an origin the site does |
| 53 | not control. |
| 54 | |
| 55 | ## How a build is fingerprinted |
| 56 | |
| 57 | - **File hash** — SHA-256 of the file's bytes. |
| 58 | - **Manifest** (`www/manifest.json`) — a file hash for every served file of |
| 59 | Daimond's own code (JS, CSS, HTML, and the `pkg/` wasm), plus one **bundle |
| 60 | hash** over them all. `vendor/` (the third-party Typst tooling) is excluded: |
| 61 | it is not built from Daimond's source and carries its own integrity story. |
| 62 | - **Transparency log** (`verify/transparency.jsonl`) — an append-only chain, one |
| 63 | entry per release, each `entry` hash covering the entry before it. Rewriting |
| 64 | any past release breaks every entry after it, and the file's git history is |
| 65 | public, so the history is tamper-evident. |
| 66 | |
| 67 | `verify/lib.mjs` is the single definition of this algorithm; the browser's |
| 68 | `www/js/verify.js` recomputes the identical fingerprint with Web Crypto, and |
| 69 | `verify/verify.test.mjs` asserts the two agree. |
| 70 | |
| 71 | ## The machine hand |
| 72 | |
| 73 | Daimond can run a real command on your computer — `cargo test`, a build, a |
| 74 | script. A web page cannot start a program, so that capability lives in a small |
| 75 | separate program, the **hand**, which your browser starts on the extension's |
| 76 | behalf and which runs each command inside a kernel fence. It is the most |
| 77 | dangerous thing Daimond does, and until 2026-08-02 it was the one component that |
| 78 | was not published, so it was also the only one you could not check. It is |
| 79 | published now: `hand/` in this repository. |
| 80 | |
| 81 | Check your copy is the one that was sealed: |
| 82 | |
| 83 | ```sh |
| 84 | node verify/check.mjs --hand |
| 85 | ``` |
| 86 | |
| 87 | **What that proves.** Every file under `hand/` hashes to what `verify/hand.json` |
| 88 | records, and that seal is committed to this repository, so its history is public |
| 89 | in the same way the transparency log's is. The seal also names the toolchain |
| 90 | (`rust-toolchain.toml`) and the exact command that turns the source into the |
| 91 | binary. Together: *the source you are about to build is the source the maintainer |
| 92 | sealed for this release, and this is how it is built.* |
| 93 | |
| 94 | **What it does not prove, and will not.** |
| 95 | |
| 96 | - **Nothing about a binary.** No hand binary is published, signed or hashed. You |
| 97 | build your own from the source you just checked, with `cargo build --release |
| 98 | --manifest-path hand/Cargo.toml`. If somebody hands you a `daimond-hand` |
| 99 | binary, nothing here says anything whatever about it. |
| 100 | - **Not reproducible.** A Rust release binary is not byte-identical across |
| 101 | toolchain versions, and this project has not demonstrated that it is identical |
| 102 | even within one. The wasm bundle's reproducibility was *measured* — two builds, |
| 103 | two directories, two cargo homes, compared — and until it has been measured for |
| 104 | the hand there is no such claim to make. Building the same source twice on the |
| 105 | same machine and getting the same bytes would prove nothing anyway: that is the |
| 106 | one arrangement guaranteed to agree with itself. |
| 107 | - **`hand.json` is not chained.** The transparency log chains its entries, so a |
| 108 | rewritten past release breaks every entry after it. `hand.json` has no such |
| 109 | chain: it is one file per release, and what protects it is this repository's |
| 110 | public history and nothing more. That is weaker, and it is stated rather than |
| 111 | blurred by putting a hash into the chained log where a reader would assume the |
| 112 | chain covered it. |
| 113 | - **Not a security review.** That the source is genuine says nothing about |
| 114 | whether the fence in it holds. The hand's own `README.md` sets out what it does |
| 115 | and does not guarantee; read it before installing. |
| 116 | |
| 117 | The release check (`dev/repro-check.sh`) also **builds** the published hand from |
| 118 | a fresh clone. That is not a reproducibility check — it is the check that the |
| 119 | published source compiles at all for somebody who is not the author, which is |
| 120 | exactly what a `path` dependency into the author's home directory silently broke |
| 121 | for the wasm between 2026-07-21 and 2026-07-27. The hand's `Cargo.toml` pins |
| 122 | fe2o3 by git revision for the same reason, and `dev/publish.mjs` refuses to carve |
| 123 | a revision that has not been pushed. |
| 124 | |
| 125 | ## Sealing a build (maintainers, at deploy time) |
| 126 | |
| 127 | Run after building the wasm and before the files leave for the server: |
| 128 | |
| 129 | ```sh |
| 130 | node dev/publish.mjs # carve the public mirror, hand/ included |
| 131 | bash dev/build-wasm.sh # in the PUBLIC tree — see below |
| 132 | node dev/stamp-build.mjs # www/build.json — the staleness id + a note |
| 133 | node verify/hand.mjs # seal the carved hand → verify/hand.json |
| 134 | node dev/publish.mjs # carry hand.json across (one file) |
| 135 | node verify/manifest.mjs # www/manifest.json + a transparency-log entry |
| 136 | # commit verify/transparency.jsonl, verify/hand.json and www/manifest.json, |
| 137 | # then deploy www/ |
| 138 | ``` |
| 139 | |
| 140 | The carve runs twice, and that is not a slip. `verify/hand.mjs` seals **the |
| 141 | public tree's** hand, because that is the one a stranger builds — this tree's |
| 142 | `hand/Cargo.toml` depends on fe2o3 by path, into a working copy that exists on no |
| 143 | machine but the author's, and sealing it would seal a manifest nobody outside can |
| 144 | build. So the seal has to come after a carve, and its output has to be carried |
| 145 | across by another. `verify/hand.mjs` also regenerates the mirror's |
| 146 | `hand/Cargo.lock` against the mirror's own git pin, which is why that lock is one |
| 147 | of the files the mirror owns. |
| 148 | |
| 149 | **Seal the build a stranger can reproduce, which is the one built in the public |
| 150 | tree.** Development builds fe2o3 as a path dependency out of a neighbouring |
| 151 | working copy; the public tree pins it by git revision. The two are different |
| 152 | builds of the same source and they do not agree hash for hash, so a bundle |
| 153 | sealed from a development build is one that nobody outside can ever match. Build |
| 154 | the wasm in the public tree, copy `www/pkg/` from there, and seal that. |
| 155 | |
| 156 | `manifest.json` is a pure function of the bundle (no timestamps), so an |
| 157 | identical build seals identically; redeploying an unchanged bundle does not add |
| 158 | a duplicate log entry. Commit the log — it is the public record the whole claim |
| 159 | rests on. |
| 160 | |
| 161 | ## What this does and does not prove |
| 162 | |
| 163 | It proves the bytes a site served are a published, unmodified Daimond release, |
| 164 | and (because the build is reproducible) that those bytes are the public source. |
| 165 | It does **not** vouch for a remote server's internals: web fetch, mail and |
| 166 | metered-credit inference genuinely transit the gateway, which is a matter of |
| 167 | published policy and audit, not of this cryptographic check. "With your own key, |
| 168 | your chats and files never leave in the clear, and you can watch only ciphertext |
| 169 | leave" is the client-side claim this makes checkable. |
| 170 | |
| 171 | ## What reproducibility here does and does not cover |
| 172 | |
| 173 | Verified, by building the same source twice in two different directories with |
| 174 | two different cargo homes and comparing: **the output does not depend on where |
| 175 | it is built, or by whom.** That is the property the claim needs, and until |
| 176 | 2026-07-27 it did not hold -- absolute build paths went into the wasm, so the |
| 177 | hashes only ever matched for someone rebuilding on the machine that sealed them. |
| 178 | Anyone else who checked would have seen a mismatch and had no way to tell it |
| 179 | from a tampered server. |
| 180 | |
| 181 | Not covered: **different toolchain versions.** Byte-identical output is |
| 182 | established only within one rustc and wasm-pack version, so build with the ones |
| 183 | `rust-toolchain.toml` and the `README` pin before concluding that a mismatch |
| 184 | means anything. Making the build stable across toolchain versions is a further |
| 185 | step, and is not claimed. |
| 186 | |
| 187 | Also not covered: **the machine hand.** Everything in this section is about the |
| 188 | wasm bundle the browser runs. The hand is a native binary and none of it applies |
| 189 | to one — see [The machine hand](#the-machine-hand) for what is claimed there |
| 190 | instead, which is less. |