What this project defends, against whom, and what it knowingly leaves open, row by row against the code it ships.
The first model was written on 30 August 2026, in French and outside the repository, against a commit three hundred and twenty eight commits older than this revision. On 25 September it was read again row by row against the code, and nineteen of its thirty seven rows turned out to be contradicted or qualified by what had been found since. A model a reader cannot reach and nobody keeps in step is the same kind of claim as a figure nothing holds, so this one lives beside the code and moves with it.
Each row names a threat, what stands in its way and where, the test that
holds that, and what is left. What is left is written as the identifiers of
the findings that show it, from the audit wave of 25 and 26 September 2026:
NN-Fk is a defect, NN-Ik an improvement and NN-Qk a question. An empty
residue means the mitigation holds as far as anybody has looked, which is not
the same as holding. Every file this document names is checked to exist by
crates/cairn-explorer/tests/site.rs, and every item named beside a file is
checked to appear in it, so a row that points at code which has moved fails a
test rather than standing.
In order of how bad a failure would be.
| Asset | What stands in the way | Held by | Left open |
|---|---|---|---|
| Money: no pebble created or destroyed outside the rules | the coinbase cap and the running supply in the state root, crates/cairn-ledger/src/validation.rs, CoinbaseOverpay; crates/cairn-ledger/src/state.rs, supply_after; the ceiling, crates/cairn-primitives/src/amount.rs, MAX_MONEY | crates/cairn-ledger/tests/audit_emission.rs, crates/cairn-ledger/tests/audit_supply_and_overflow.rs | |
| Funds: nothing spent without its key, nothing spent twice | strict verification, crates/cairn-crypto/src/lib.rs, verify_strict; keys outside the prime order subgroup refused, is_torsion_free; a cold note emptied in place | crates/cairn-crypto/tests/audit_the_verification_rule.rs, crates/cairn-crypto/tests/audit_a_key_nobody_holds.rs | |
| Agreement: two honest nodes reach the same state | commit and revert through one replay, crates/cairn-ledger/src/state.rs, fn revert; the handover held field by field, crates/cairn-ledger/src/handover.rs, pub fn accept | crates/cairn-ledger/tests/invariants.rs, crates/cairn-ledger/tests/handover.rs | 09-F1, 05-F1, 05-F2, 07-F1 |
| Availability: no message anyone can send stops a node | a frame ceiling before any allocation, crates/cairn-net/src/wire.rs, MAX_FRAME_BYTES; a per-peer allowance, crates/cairn-net/src/sync.rs, ALLOWANCE; a connection ceiling, crates/cairn-net/src/node.rs, MAX_PEERS | crates/cairn-net/tests/hostile_peer.rs, crates/cairn-net/tests/fuzz_wire.rs | 13-F1, 16-F1, 16-F2, 16-F3, 14-F1, 15-F1, 04-F1 |
| A newcomer's start: nobody below the honest majority puts one on a false chain | the sampled weighing, crates/cairn-ledger/src/sampling.rs, pub const SAMPLES, the count taken from the age the tip claims against the reader's clock; a fresh draw priced by holding the tip to its run, crates/cairn-ledger/src/sampling.rs, pub const MOST_FALL | crates/cairn-ledger/tests/audit_the_bound.rs, crates/cairn-ledger/tests/the_price_of_a_seed.rs | 12-F1 |
| Privacy: the software adds nothing to what the chain shows | by decision the chain is public, amounts and owners included; what the software must not do is tell anyone more than that | 38-F1, 38-F2, 38-F3, 38-F4, 38-F5, 44-I7 | |
| The rules and their schedule: they change only as the source says, and visibly | a rule changes at a height written into the build, crates/cairn-ledger/src/validation.rs, version_at; a node past its schedule says so and stops, crates/cairn-node/src/main.rs, rules_running_out; nobody votes | crates/cairn-ledger/tests/audit_rule_change.rs, crates/cairn-chain/tests/audit_rule_change.rs | 05-F1, 05-F2, 44-I1 |
The 30 August model put privacy outside the model, as a property a public chain does not have. That was the wrong row. The chain is public by decision, and the open questions paper says what it shows; but a wallet that tells a peer which notes are its own, or a node that advertises the address of the phone it runs on, spends privacy the protocol never asked for. That is a failure of the software, and the model counts it as one.
It also said governance was none. There is no key, no vote and no authority, and that part holds. But whoever writes the build decides the rules and the height they change at, and the release is published by a workflow; that is a party, and it is in the table of actors below.
| Actor | What it can do | What stands in the way | Left open |
|---|---|---|---|
| A user | sign transfers of its own notes | every input signed over the network, the version, the identifier, the index and the note spent, crates/cairn-ledger/src/transaction.rs, fn message | |
| A miner | order a block, date it within bounds, claim the reward and fees, fill its own block space for free | the retarget, the median of past times and the drift a reader allows, crates/cairn-ledger/src/validation.rs, max_timestamp_drift; the coinbase cap; the eviction cap, max_evictions_per_block | 04-F1, 04-F2, 44-F1 |
| A majority miner | rewrite recent history, censor, spend twice deep | nothing: it is the assumption. A node will not undo past crates/cairn-chain/src/lib.rs, MAX_REORG_DEPTH, which is a local policy tied to the burial and the maturity | |
| A miner with a third to a half of the work | earn more than its share by withholding blocks, as on every Nakamoto chain; try to mislead a newcomer's start | selfish mining is untreated, and the only lever taken is keeping the branch already followed at equal work; the start is bounded at the share the papers publish, measured and not proved | 06-F2, 44-I4 |
| A hostile peer | send malformed or costly messages, poison an address book, try to eclipse a node | the frame ceiling and allowance above; a ceiling on connections from any one address, crates/cairn-net/src/node.rs, MAX_PER_HOST; a bounded share of the book per address group, crates/cairn-net/src/book.rs, MAX_PER_GROUP | 14-F1, 14-F2, 13-F1, 08-F1 |
| An adversary on the path | read every message, delay or withhold blocks, eclipse a node without any Sybil | nothing on the wire is private or bound to a peer; what it cannot do is forge, since every block needs work and every transfer a signature. Transport privacy is a decision not yet taken | 44-I3, 38-F3 |
| An operator | control a node's disk, its clock and its settings | a node replays its block log at start and validates it again rather than trusting its own disk; the clock is read for the drift a block may run ahead and nothing else | 05-F2, 11-F2, 21-F1, 25-F1 |
| The maintainer and the release | decide the rules and their heights; publish the binaries people run | every action pinned by hash; a provenance attestation, .github/workflows/release.yml, attestations; reproducible bytes; a schedule visible in the source months before its height. Nothing bounds what a schedule may change | 28-F1, 28-F2, 28-F3, 27-F2, 44-I1 |
| An archivist | serve paths for fallen notes; stay silent; watch who asks; vanish | every answer is folded against roots the asker's own node worked out, so it cannot lie; crates/cairn-net/src/message.rs, GetProofs. A wallet offline past its node's retention depends on one, which is the design's stated cost, and the archive's durability is not yet the software's | 37-F1, 38-F1, 38-F4, 20-F1, 44-I2 |
| The seed operator | see every first contact and every wallet session; hand a newcomer only addresses it chooses | one name, crates/cairn-net/src/seeds.rs, seed.cairnchain.org; the sampling makes any chain it shows checkable, so the harm is eclipse and observation rather than a false chain | 38-F5, 14-Q3, 44-I6 |
| Absent by design | no validator set, no admin key, no checkpoint, no oracle, no bridge | none of them exists in the source, so none of them is a surface |
| Assumption | If it is false | Held by | Left open |
|---|---|---|---|
| Most of the work is honest | history is rewritten, and a newcomer can be misled | the root assumption of proof of work; nothing holds it | 12-F1 |
| Clocks are roughly right | a node refuses valid blocks or takes future ones, a drift local to it while the median holds | crates/cairn-ledger/tests/retarget_timewarp.rs, crates/cairn-chain/tests/clock_skew.rs | 04-F1, 06-F1, 07-Q1 |
| Each network's first block is written into the build | a newcomer believes whichever first block a peer hands it | crates/cairn-ledger/src/validation.rs, for_network; crates/cairn-ledger/tests/network_rules.rs | |
| The sampling bound holds | a forger below half the work puts a newcomer on its chain | crates/cairn-ledger/tests/audit_the_bound.rs | 06-F2, 12-F1 |
| Undoing a block is the exact inverse of applying it | after a reorganisation a node's state root parts from the network's, with no attacker needed | crates/cairn-ledger/tests/invariants.rs, crates/cairn-chain/tests/audit_a_reorganisation_is_the_inverse.rs | 09-F1, 11-F1, 11-F2, 11-F3, 17-F1 |
| A handed ledger is the ledger a node would have built | a node started from one follows another chain | crates/cairn-ledger/tests/handover.rs, crates/cairn-ledger/tests/audit_forged_join.rs | 07-F1, 16-F3 |
| The hot set never passes its capacity | the one bound the whole design rests on is not a bound | crates/cairn-ledger/src/state.rs, plan_evictions; crates/cairn-ledger/tests/tiers.rs | 44-F1 |
| The operating system's randomness is there and good | keys are guessable; there is no weaker fallback for a key, so a failure is an error | crates/cairn-crypto/src/lib.rs, random_bytes | |
| Arithmetic does not wrap in a release build | an unchecked sum wraps where a checked one refuses | Cargo.toml, overflow-checks = true, with unchecked arithmetic denied in every crate | 31-F3 |
The 30 August model named three of these as the ones whose failure ends the project rather than costs it something, because each one false is a disagreement between honest nodes. Where each stands now:
None of the three has the shape it had on 30 August, and none is closed.
| Surface | What stands in the way | Held by | Left open |
|---|---|---|---|
| The peer protocol | every message capped at decode; an allowance per peer | crates/cairn-net/tests/protocol.rs, crates/cairn-net/tests/fuzz.rs | 13-F1, 16-F1, 16-F2, 16-F3, 14-F1, 14-F2, 15-F1 |
| The wallet's page | served on the loopback, behind a secret drawn for the run, refusing another host or origin; it moves money, crates/cairn-wallet/src/serve.rs, /api/send; a body read only for a POST and capped, crates/cairn-http/src/http.rs, MAX_BODY_BYTES | crates/cairn-wallet/tests/page.rs, crates/cairn-http/tests/fuzz_request.rs | 22-F1, 24-F1, 24-F6 |
| The explorer | public by design, read only, bounded per request | crates/cairn-explorer/tests/answers.rs | 25-F1, 26-F1 |
| The pool | bounded in count and in bytes, conflicts refused, a fee floor asked again when the state moves, crates/cairn-chain/src/lib.rs, MAX_POOL_BYTES | crates/cairn-chain/tests/pool.rs | 21-F3 |
| A wallet as a node | a wallet joins the network as a node of its own, listening, crates/cairn-wallet/src/lib.rs, 0.0.0.0:0; every cost a greeted peer can impose lands on the device the design exists for | 38-F2, 16-F1, 13-F1, 14-F1, 44-I5 | |
| The sampled start | new, and the part of the design with no deployed precedent in this form | crates/cairn-ledger/tests/sampling.rs, crates/cairn-ledger/tests/audit_the_bound.rs | 06-F2, 12-F1 |
| The two tiers and cold proofs | new; a proof is checked against the forest as it stands and nothing older, crates/cairn-accumulator/src/forest.rs, pub fn verify; a fallen note stays spendable without a proof for a window, crates/cairn-ledger/src/state.rs, GRACE_BLOCKS | crates/cairn-ledger/tests/tiers.rs, crates/cairn-ledger/tests/cold_spends.rs | 44-F1, 21-Q2 |
| Files read back from disk | every record framed and checked; the block log validated again at start | crates/cairn-store/tests/fuzz_record_framing.rs, crates/cairn-store/tests/block_log.rs | 17-F1, 18-F1 |
| The installer and the units | one script, deploy/install.sh, writes the units deploy/cairnd.service and deploy/cairn-explorer.service | 27-F1, 27-F2 | |
| Dependencies | the crates a shipped program pulls in, few on purpose, checked against the advisory database every week, .github/workflows/audit.yml, cargo audit | ||
| Contracts, a virtual machine, a bridge | none exists |
There is no finality. A node will not undo more than MAX_REORG_DEPTH
blocks, and that is its own policy, not a rule of the chain: two
nodes with different limits part company only over a reorganisation deeper
than one of them accepts.
The bound on what a node holds is itself a claim this model has to carry. If the state a validator holds is not bounded after all, the thesis falls without anyone losing money: it is a failure of the promise rather than of consensus. The papers state every term of it and a test computes each one.
And two mechanisms carry the security that have no deployed precedent in this form, the sampled start and the handover. That is where review is most worth spending, and where every row above that ends in an open finding points.