Skip to content

refactor(ocap-kernel): neutral remote identity (netlayer phase 2)#971

Draft
rekmarks wants to merge 2 commits into
rekm/netlayer-1from
rekm/netlayer-2
Draft

refactor(ocap-kernel): neutral remote identity (netlayer phase 2)#971
rekmarks wants to merge 2 commits into
rekm/netlayer-1from
rekm/netlayer-2

Conversation

@rekmarks

Copy link
Copy Markdown
Member

Phase 2 of the pluggable-netlayer effort (issue #968), stacked on #970 (base rekm/netlayer-1).

Makes the kernel's peer identity netlayer-neutral and removes libp2p-specific crypto from the identity/URL/error layer. Compatibility breaks by design (no migration); verified against fresh storage.

What changed

  • New remotes/kernel/identity.ts (libp2p-free; @noble/curves/ed25519 + multiformats only): deriveNeutralPeerId(seed), neutralPeerIdToPublicKey(peerId), publicKeyToNeutralPeerId(publicKey), exported from the ocap-kernel barrel. The neutral peerId is multibase base58btc (z…) of the raw 32-byte Ed25519 public key.
  • remote-comms.ts: derives the peerId via deriveNeutralPeerId (replacing @libp2p/crypto/keys + @libp2p/peer-id); encrypts ocap-URL oids with WebCrypto AES-256-GCM (crypto.subtle, 32-byte key used directly, fresh 12-byte IV) instead of @libp2p/crypto AES_GCM. The "amateur cryptography" warning is retained.
  • connection-factory.ts: converts neutral ↔ libp2p peerIds at the libp2p boundary only — #toLibp2pPeerId for dialing, publicKeyToNeutralPeerId(connection.remotePeer.publicKey.raw) for the inbound handler and peer:disconnect. The transport layer only ever sees neutral ids; #inflightDials and #relayPeerIds guards keep their existing keyspaces.
  • @metamask/kernel-errors: drops the @libp2p/interface import — isRetryableNetworkError classifies ChannelResetError and matches MuxerClosedError by error.name (behavior-preserving; the libp2p name/message sniffing is annotated to move to @metamask/netlayer-libp2p in Phase 4).
  • ocap: URL: host is now the neutral z… id; oid = base58btc(iv ‖ ciphertext ‖ tag). String shape unchanged; hints stay opaque libp2p multiaddrs.

ocap-kernel still depends on libp2p

connection-factory.ts still constructs libp2p and now also uses @libp2p/crypto/keys publicKeyFromRaw + @libp2p/peer-id peerIdFromPublicKey for the boundary conversion, so no @libp2p dep is removable this phase (that's Phase 4). Added @noble/curves.

Crypto review flag

The WebCrypto AES-GCM swap is security-sensitive. It reduces surface (drops PBKDF2/salt on an already-random 32-byte key): non-extractable 256-bit key, fresh random 12-byte IV per encryption, auth-tag failure surfaced as ocapURL has bad object reference with no oracle detail.

Verification

  • yarn lint:fix, yarn build, per-package test:dev:quiet --coverage=true for @metamask/ocap-kernel and @metamask/kernel-errors, and @ocap/kernel-test integration (two-kernel remote-comms end-to-end with neutral ids). Coverage held at/above baseline (the changed files are 100% covered).
  • Grep audits: remote-comms.ts and kernel-errors/src are @libp2p-free; connection-factory.ts still uses libp2p; ocap-kernel/package.json retains its libp2p deps.

Plan docs updated: docs/plans/netlayer/master.md (Phase 2 marked done + landed decisions) and docs/plans/netlayer/phase-3.md (reconciled against landed Phases 1–2).

🤖 Generated with Claude Code

rekmarks and others added 2 commits July 10, 2026 12:59
Make the kernel's peer identity netlayer-neutral and remove libp2p-specific
crypto from the identity/URL/error layer:

- Add remotes/kernel/identity.ts: deriveNeutralPeerId / neutralPeerIdToPublicKey
  / publicKeyToNeutralPeerId (base58btc multibase of the raw Ed25519 public key
  via @noble/curves), exported from the package barrel.
- remote-comms.ts derives the neutral peerId from the seed and encrypts ocap-URL
  oids with WebCrypto AES-256-GCM (crypto.subtle, key used directly, random IV)
  instead of @libp2p/crypto AES_GCM/Ed25519.
- connection-factory.ts converts neutral <-> libp2p peerIds at the libp2p
  boundary (dial, inbound handler, peer:disconnect); the transport layer only
  ever sees neutral ids.
- kernel-errors drops its @libp2p/interface import: isRetryableNetworkError
  classifies ChannelResetError and matches MuxerClosedError by name.
- ocap: URL host is now the neutral z... id; format otherwise unchanged.

Compatibility breaks by design (no migration). Verified with fresh storage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 71.58%
⬆️ +0.22%
8935 / 12482
🔵 Statements 71.4%
⬆️ +0.21%
9085 / 12723
🔵 Functions 72.74%
⬆️ +0.17%
2157 / 2965
🔵 Branches 65.03%
⬆️ +0.17%
3599 / 5534
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/kernel-errors/src/utils/isRetryableNetworkError.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/index.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/remotes/kernel/identity.ts 100% 100% 100% 100%
packages/ocap-kernel/src/remotes/kernel/remote-comms.ts 99.32%
⬆️ +0.05%
96.96%
🟰 ±0%
100%
🟰 ±0%
99.31%
⬆️ +0.06%
353
packages/ocap-kernel/src/remotes/platform/connection-factory.ts 96.53%
⬆️ +1.77%
92.59%
⬆️ +3.31%
97.91%
⬆️ +0.55%
96.5%
⬆️ +1.80%
544, 746-747, 752-756, 815, 828
Generated in workflow #4506 for commit 791db3e by the Vitest Coverage Report Action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant