Skip to main content

Trust and verification

In a network you do not fully control, "did this result really come from that node?" has to be answerable. Gnarl answers it with signatures, and keeps the question separate from "should this node be allowed to ask me anything?", which is policy.

Identity

Every node is an ed25519 keypair. The node ID is derived from the public key, so an identity cannot be claimed — only proven.

gnarl identity show
▸ node id n1qh7f2m9x8p4vd6kkzq3r7wjn5tbc2a8
▸ algorithm ed25519
▸ created 2026-02-11T09:14:22Z
▸ rotations 0

What gets signed

ArtifactSigned byProtects against
ManifestPublishing nodeForged claims about what a node holds
QueryOriginating nodeUnattributable or replayed queries
Result batchAnswering nodeTampering by a relay or coordinator

Results carry the signature of the node that produced them, not the node that merged them. A coordinator that alters a hit invalidates the signature it was handed, and the client sees it.

{
"hits": [
{
"score": 12.4,
"node": "n1qh7f…c2a8",
"doc": {"title": "Puget Sound, 2024-06-11", "sensor": "sentinel-2"},
"signature": "ed25519:41ab…77c9"
}
],
"verified": true
}

Set "verify": false to skip verification when you already trust the transport and want the throughput back.

Policy

Signatures establish who. Policy decides whether.

gnarl.yaml
policy:
default: deny

allow:
- nodes: ["n1qh7f…c2a8", "n1m4kd…91b3"]
indexes: [imagery]
fields: [title, captured_at, sensor]
rate_limit: 40/s

- networks: [acme-internal]
indexes: [imagery, reports]
rate_limit: 200/s
require_signed_queries: true

redact:
- index: reports
fields: [author_email, internal_notes]

Policy is evaluated on the node that holds the data, every time, before the index is touched. There is no central policy service to bypass and no cached decision to go stale.

Trust models in practice

Closed network. A pre-shared key gates membership; every member is operated by one organization. Signatures are still checked, mostly to catch bugs and misconfiguration.

Federated. Several organizations, each running their own nodes, each publishing a node ID out of band. Peers pin the IDs they intend to trust.

gnarl peer trust n1m4kd…91b3 --label "partner-lab"

Open. Anyone may join and answer. Results are ranked with node reputation as an input, and clients can require that hits come only from pinned identities.

{"scope": {"trust": "pinned-only"}}

Key rotation

gnarl identity rotate --keep-old 30d

The node publishes a rotation record signed by the old key, so peers can follow the identity forward without re-establishing trust out of band. The old key stays valid for verification of already-published manifests for the grace period.

Threat model, briefly

Gnarl assumes peers may be slow, absent, buggy, or actively lying about their own content. It does not assume a peer can be forced to answer honestly — a node that holds a document may always choose to withhold it. What the protocol guarantees is attribution: whatever you do receive is provably from who it claims to be, unaltered, and everything else is visibly missing.