Vote for your favorite SkillMD. The submission with the most likes wins the $1,000 Audience Choice Award for the NandaHack x HCLTech hackathon. Voting is open through September 25.Vote now →
in reviewhumanPR #173Identity

andrea-cola -> ed25519_recoverable: time-locked rotation + K-of-N social recovery (Layer 3 identity)

* Layer: identity (Layer 3)

Author

andrea-cola avatar

@andrea-cola

github profile →
Status
In review
Opened on
Jul 10
Branch
hackathon/andrea-cola-ed25519-recoverable-social-recovery

Description

The pitch.

## Layer / plugin

* **Layer:** identity (Layer 3)
* **Plugin:** `ed25519_recoverable` at `("identity","ed25519_recoverable")`
* **Persona:** security engineer focused on key-compromise recovery in
  production identity systems.
* **Relationship to prior work:**
  * `did_key` — the deliberately simplified default; unchanged.
  * `ed25519_rotating` (PR #25, merged) — real rotation with continuity;
    unchanged.
  * `ed25519_prerotation` (PR #71, in review) — cryptographic KERI-style
    defence against rotation hijack via pre-committed key hashes.
    **This PR is orthogonal:** where PR #71 defends key compromise
    cryptographically (attacker cannot install a successor that does not
    hash to the pre-published commitment), `ed25519_recoverable` defends
    it **operationally** via K-of-N social recovery. The two mechanisms
    address the same threat with different assumptions: KERI requires you
    to have generated a cold key at inception, social recovery requires a
    network of trusted attesters. Time-lock on rotations is additive to
    both and unique to this PR.

## What it does

Real Ed25519 signatures via `cryptography` (RFC 8032), plus two governance
features neither merged plugin has:

1. **Time-locked rotations.** A rotation is only accepted if
   `activates_at >= now + time_lock` (default 3 logical ticks). Even a
   captured current key cannot lock the legitimate owner out immediately —
   the owner sees the pending rotation and has time to counter-rotate or
   trigger recovery.
2. **K-of-N social recovery.** Each agent declares a set of recovery
   attesters at construction (e.g. 3 peers, quorum K=2). Any K of them can
   co-sign a `RecoveryEvent` that force-installs a fresh key chosen by the
   recovering party. This bypasses continuity entirely — the compromised
   key gets no say. The recovery event is publicly verifiable and appears
   in `resolve()`'s metadata.

Verification anchors on an externally-supplied logical tick (via
`.advance(tick)`), never on the attacker-controlled `sig.signed_at` — as
the `Signature` docstring in `nest_core.types` already prescribes.

## Attacks defeated

| Attack | Defeated by | Merged plugins alone |
| --- | --- | --- |
| Instant-rotation after brief key capture | time-lock rejects `activates_at < now + lock` | accepted (continuity is valid) |
| Full key compromise → attacker rotates | K-of-N recovery reinstalls owner's fresh key | no recovery path |
| Unilateral recovery (< K attesters) | quorum check | no concept |
| Duplicate-attester quorum inflation | deduplication before counting | no concept |
| Forged attester signature | Ed25519 verification under declared attester pubkey | no concept |
| Recovery targeting a stale key | recovery must match current active key | no concept |
| Unauthorised rotation | rotation signature verified under current key | rejects |
| Stale-key reuse after supersession | epoch window check | rejects |
| Forged `signed_at` bypass | verifier anchors on own tick | rejects |

## Determinism

* Keys are derived from `(seed, agent_id, epoch)` via SHA-512,
  domain-separated. No `os.urandom`.
* Ed25519 signatures are deterministic per RFC 8032 §5.1.6.
* The plugin exposes only `advance(tick)` as clock input, enforced
  monotonic. No wall-clock time is read.

## API fit

Implements exactly the three-method `nest_core.layers.identity.Identity`
Protocol (`sign` / `verify` / `resolve`) with the same `register_peer`
convention as `did_key` and `ed25519_rotating` (adding optional
keyword-only `recovery_attesters` / `recovery_quorum_k`). Additional
methods (`rotate`, `observe_rotation`, `observe_recovery`,
`sign_recovery`, `advance`) are additive.

## Files

* `packages/nest-plugins-reference/nest_plugins_reference/identity/ed25519_recoverable.py`
* `packages/nest-plugins-reference/nest_plugins_reference/identity/adversarial_validators.py`
* `packages/nest-plugins-reference/tes

…

Try it

Open PR on GitHubView diff

Checkout locally

git fetch origin pull/173/head:pr-173
git checkout pr-173