Genesis recovery: constituent keys can be genuinely absent from wire content
- Dominant language
- Rust
- Stars
- 3
- Forks
- 0
- Avg merge
- 1d 42m
- Merged PRs (30d)
- 11
Description
## Summary
For a real explicit multi-key genesis, a constituent key's material is
often not embedded in *any* wire-visible cozy at all. Genesis membership
is supplied entirely out-of-band (a caller parameter, or a local
keystore record), not recoverable from stored blob content alone. This
affects any server-side code path that tries to reconstruct genesis
purely from what's durably stored — both the raw/legacy reindex path and
the manifest-backed path share this limitation, since both ultimately
depend on what was actually observed on the wire at ingest time.
## Evidence
`rs/cyphr-storage/tests/f40_multi_key_genesis.rs` builds a real,
production-shaped explicit two-key genesis (`Genesis::Explicit`) and
submits it through the real `StorageEngine::submit_commit` path. The
actual wire bundle for that genesis commit is just a `principal/create`
cozy (asserted `id` = the combined genesis digest, `tmb` = the signer's
own thumbprint) followed by the `commit/create` finalizer — neither key's
public material appears in either blob.
`StorageEngine::submit_commit`'s `extracted_keys` (in
`rs/cyphr-storage/src/engine/mod.rs`) is populated purely by parsing each
blob's own `key` JSON field on transactions the protocol classifies as
"key-introducing" (`key/create`, `key/replace` — see
`cyphr::parsed_coz::typ::is_key_introducing`). `principal/create` and
`commit/create` are categorically excluded from that classification. So
for F40's real bundle, the manifest captured at ingest time also records
zero keys for this commit — there is nothing embedded anywhere for a
later reader (raw scan or manifest replay) to recover either key from.
`rs/cyphr-cli`'s real production code confirms this is the expected
shape, not an edge case: `cyphr-cli/src/commands/init.rs`'s `--keys`
path constructs an explicit multi-key genesis that produces *no commit
at all* until a later operation anchors it, and its own comment notes
that without a local record of which keys compose it, "it would be
unrecoverable to any subsequent command." `load_principal_from_engine`
and `resolve_local_genesis` (in `cyphr-cli/src/commands/common.rs`)
correspondingly resolve explicit genesis from a local keystore record
(`record_genesis`/`lookup_genesis`) or a caller-supplied parameter —
never by scanning wire content for multiple key-introducing cozies.
## Why this isn't a protocol gap
Key storage and distribution are explicitly out of the protocol's scope:
as long as the server can obtain a key *somehow*, that's sufficient. How
a key reaches the server — embedded in a cozy, sent through a side
channel, fetched from a canonical location in deployment-specific
metadata — is a deployment choice, not something the wire format is
required to carry.
## Proposed direction (separate future work, not attempted here)
A durable, thumbprint-indexed cache of every key the server has ever
observed (from any cozy, any principal, any point in time), consulted as
a fallback during genesis recovery whenever a specific commit's own
embedded material is insufficient to reconstruct a candidate. This is a
real, standalone feature — it needs its own design pass (storage shape,
eviction/retention policy, trust implications of caching keys across
principal boundaries) rather than a bootstrap-loop tweak, so it's
intentionally left unscoped here.
## Relationship to #33
#33 asked whether the raw/non-manifest reindex bootstrap loops need to
correlate multiple wire-visible genesis-marker cozies into one shared
explicit genesis. Investigation for that issue found no real scenario
that needs this: every real and test-covered explicit multi-key genesis
either produces zero wire-visible key-introducing cozies for its
constituent keys (the F40/cyphr-cli pattern above) or supplies genesis
material as an out-of-band caller parameter. That issue's other,
unconditional deliverable (a loud diagnostic instead of a silent break
when an incomplete commit is found during raw reindex) has been
addressed separately. This issue is scoped narrowly to the broader
key-availability gap that investigation surfaced, which is out of
that issue's boundary.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with rs/cyphr-storage/tests/f40_multi_key_genesis.rs and StorageEngine::submit_commit in rs/cyphr-storage/src/engine/mod.rs to confirm that the wire bundle contains no constituent key material. Read cyphr-cli/src/commands/common.rs and init.rs for the existing local-genesis assumptions; done requires a designed, durable thumbprint-indexed key cache and a defined fallback recovery path, including storage, retention, and trust behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100