Pp2pbuilders
learn › Lessons from our ecosystem

6 min read · also at #/learn/eco-authority

The transport carries no authority

The most important sentence in our codebase, learned the hard way while
hardening peerit (the gossip engine the p2pbuilders web build reuses):

A record is trusted because of its signature — never because of who
delivered it.

The bug class

Early gossip code made an innocent-looking assumption: records arriving on a
connection from peer X are peer X's records. But gossip forwards — X relays
records authored by Y and Z; that is the entire point. The moment any code
path treated "received from X" as "authored by X", a malicious peer could
inject records under other people's names by just… sending them.

The fix, as invariants

Our merge now admits a record only if all of these hold, regardless of
transport:

  1. The signature verifies over the canonical encoding of the record.
  2. The signer is the claimed author — the key that verifies must equal

the record's author field, or it is a well-signed lie.

  1. The storage key matches the fields — a record claiming to be

vote!abc!carol must actually be a vote by carol on abc; otherwise a
valid record can be replayed at the wrong address to overwrite state.

Check 3 is the one people miss. Signature verification tells you the bytes
are authentic; it does not tell you they belong where the sender put them.

Carry-outs

in the UI, not "sometimes".

honest peers can disagree about validity.

Our engine test does exactly this, and it is the test we would rescue from
a fire first.

Hypercore gives you 1 and 2 for free within a core. The moment you gossip
records outside their author's core — we do, for speed — all three checks
are yours again.

« Storyteller 2: passing the pen Orphan-proof your outbox »