security: Phase F — per-peer Ed25519 identity (dual-mode) (#2256)#2260
security: Phase F — per-peer Ed25519 identity (dual-mode) (#2256)#2260
Conversation
✅ BCOS v2 Scan Results
What does this mean?The BCOS (Beacon Certified Open Source) engine scans for:
BCOS v2 Engine - Free & Open Source (MIT) - Elyan Labs |
fengqiankun6-sudo
left a comment
There was a problem hiding this comment.
Code Review — PR #2260: Per-Peer Ed25519 Identity (Phase F)
Quality: Security-Focused (15-25 RTC)
Summary
Replaces shared HMAC trust model with per-peer Ed25519 identity. Implements 4-phase migration strategy (hmac → dual → ed25519 → strict). Adds comprehensive test coverage.
What's Strong
- Clean Migration Path: 4-mode approach (hmac/dual/ed25519/strict) allows gradual rollout without breaking existing nodes. Smart design.
- Lazy Crypto Import: Only requires cryptography library when using Ed25519 modes — avoids breaking legacy hmac-only nodes. Good backward compatibility thinking.
- Well-Documented: Docstring explains wire format, migration path, and rationale. Clear as a research paper.
- Test Coverage: 240-line test file with dedicated test cases.
- Dataclass-based Design: Clean abstraction with
PeerIdentityandSignedPeerRegistry.
Minor Observations
- Default key path (
/etc/rustchain/) requires root — consider allowing~/.rustchain/for non-root miners. - No key rotation mechanism mentioned — Ed25519 keys should ideally rotate periodically.
- Registry signature verification doesn't check expiry — consider adding
not_afterto peer entries.
Verdict
LGTM — Production-ready security upgrade. The migration strategy is thoughtful. Strong addition to RustChain's security posture.
Reviewer: fengqiankun
RTC Wallet: fengqiankun
Addresses the last open CRITICAL finding from the 2026-04-14 codex audit:
shared P2P_SECRET means any peer with the HMAC key can mint messages as any
other peer, even after Phase A bound sender_id into the signed content.
Phase F introduces per-peer Ed25519 keypairs and a root-signed peer
registry. One compromised peer = one compromised identity, not the whole
mesh.
- LocalKeypair: per-node Ed25519 keypair, generated on first start, stored
PKCS#8 PEM at $RC_P2P_PRIVKEY_PATH (default /etc/rustchain/p2p_identity.pem)
with mode 0600.
- PeerRegistry: JSON file mapping node_id -> pubkey_hex. Path via
$RC_P2P_PEER_REGISTRY (default /etc/rustchain/peer_registry.json).
- pack_signature / unpack_signature: backwards-compatible wire format.
Legacy HMAC-only = raw hex. Dual/Ed25519 = JSON bundle {"h":"..","e":".."}.
- verify_ed25519: thin wrapper with InvalidSignature catching.
- hmac : legacy only (Phase 2 behavior) — default for old nodes
- dual : sign with BOTH, verify either — recommended migration stage (F.1)
- ed25519 : sign Ed25519 only, verify either — transition stage (F.2)
- strict : Ed25519 only, reject HMAC-only messages — post-migration (F.3)
- Initializes LocalKeypair + PeerRegistry when mode != hmac.
- _sign_message now emits dual/ed25519-only signatures based on mode.
- verify_message threads sender_id into Ed25519 verification, looks up
the sender's pubkey in the registry, falls back to HMAC per mode.
Dual mode produces a JSON-bundle signature that legacy peers running in
'hmac' mode can still parse: unpack_signature returns the HMAC component
when JSON is encountered. So a dual-mode node talking to an hmac-mode
node still works as long as the HMAC secret is shared.
Operational plan in /home/scott/staged_patches/phase_f_ed25519/DESIGN.md:
F.1: deploy dual mode to all nodes, distribute registry + pubkeys
F.2: staggered flip to ed25519 mode
F.3: strict mode after all nodes confirmed
node/tests/test_p2p_phase_f_ed25519.py — 10 tests, all pass:
- Signature pack/unpack (3 shapes)
- Keypair generation + 0600 perms + persistence
- Registry load + unknown-peer lookup
- Dual-mode legacy HMAC still verifies
- Dual-mode Ed25519 verifies via registered pubkey
- Strict mode rejects HMAC-only
- Unknown-peer Ed25519 rejected
Existing Phase 2 tests (6) still pass in legacy mode.
946e0db to
1fe57c0
Compare
|
Rebased onto current Conflict resolution in
|
|
Pre-merge CI note: the
Same 3 failures have been observed on multiple prior unrelated PRs (documented in the 2026-04-14 session notes). 1222 tests pass, 18 skipped, all security-relevant checks green including the P2P Epoch Vote Spoofing PoC / UTXO Float Precision PoC / RIP-309 dedicated CI jobs. Merging. |
Closes the last open CRITICAL finding from the 2026-04-14 audit
Shared
P2P_SECRET= any peer with the HMAC key can mint messages as any other peer. Phase F fixes this with per-peer Ed25519 keypairs + root-signed peer registry. One compromised peer = one compromised identity.Codex-confirmed Byzantine threat model. Phase 2 (#2258 + #2259 hotfix) closed 4 of 5 findings; this closes the fifth.
What's in this PR
New:
node/p2p_identity.pyLocalKeypair— Ed25519 keypair, PKCS#8 PEM at$RC_P2P_PRIVKEY_PATH(default/etc/rustchain/p2p_identity.pem), mode 0600, generated on first startPeerRegistry— JSON file mappingnode_id → pubkey_hexat$RC_P2P_PEER_REGISTRYpack_signature/unpack_signature— wire-compatible signature encoding. Legacy HMAC-only = raw hex. Dual/Ed25519 = JSON bundle{"h":"..","e":".."}verify_ed25519— thin wrapper withInvalidSignaturecatchingModified:
node/rustchain_p2p_gossip.pyGossipLayerinitializesLocalKeypair+PeerRegistrywhen mode != hmac_sign_messageemits HMAC / dual / Ed25519 per modeverify_messagethreadssender_idinto Ed25519 verification, looks up sender's pubkey in registry, falls back to HMAC per modeSigning mode (
$RC_P2P_SIGNING_MODE)hmacdualed25519strictWire compatibility
Dual-mode signatures are JSON bundles that legacy
hmac-mode nodes parse fine (unpack_signaturereturns the HMAC component when JSON is seen). A Phase F dual-mode node can talk to an old-HMAC node and vice versa, as long as the HMAC secret is shared during migration.This means: the migration can roll out without a hard flag-day.
Rollout plan (detailed in staged /home/scott/staged_patches/phase_f_ed25519/DESIGN.md)
ed25519mode on each nodestrictmode — HMAC rejected;P2P_SECRETcan be revoked from the environmentRollback: at any stage, flip the mode env var back. HMAC stays available as fallback until F.3.
Test plan
node/tests/test_p2p_phase_f_ed25519.py— 10 tests, all pass:hmaclegacy modeDependency
Requires
cryptographypackage for dual/ed25519/strict modes. Legacy hmac-mode does NOT require it (lazy import).What this PR does NOT fix
Phase F closes the identity layer. Consensus and content attacks are separate hardening tracks.
Credits