Cyphrme / Cyphrme/Cyphr

Genesis recovery: constituent keys can be genuinely absent from wire content

Open
#80 0 comments 0 reactions 0 assignees View on GitHub
enhancement tech-debt
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.