R5: consent-gated recruitment + per-hop X25519 sealed credentials

Add the in-band, signature-gated consent handshake that governs whether a
node may be recruited into a measured SOR circuit, plus a per-recipient
sealed box so a hop credential decrypts only with the host's X25519 key.

- crypto.rs: seal_to_pubkey/open_sealed (ephemeral X25519 -> HKDF-SHA256 ->
  Fernet AEAD), reusing the existing fernet crate (no new symmetric primitive).
- sor/consent.rs: signed ConsentRequest (Ed25519 persona), node_evaluate
  (reject unless the signature verifies), CircuitBuilder that recruits a hop
  only on an accept it can open; parse_sor_frame with never-panic proptests.
- net.rs: {"_sor":...} control frames are live-only and classified out-of-band
  by the SOR layer (parse_sor), never surfaced as chat/app events.
- cmd_chat/sor/consent.py + bridge _sor case: bit-compatible Python mirror;
  the agent only observes/classifies consent frames — it never auto-accepts
  and stands up no forwarder (forwarding is R4, isolated-engine-only).

Acceptance check (roadmap R5) green both languages: host recruits a hop only
after an explicit accept; a reject leaves no entry; the credential opens only
with the host key (third party cannot); unsigned/forged request -> rejected.
Cross-language KDF parity pinned by a shared known-answer vector.
Rust 75 passed; Python SOR suite 37 passed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-07-19 16:35:11 -07:00
parent a9308edc5d
commit 7de0f57fa6
9 changed files with 1057 additions and 5 deletions
Generated
+53 -5
View File
@@ -297,6 +297,15 @@ dependencies = [
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
dependencies = [
"libc",
]
[[package]]
name = "crossterm"
version = "0.28.1"
@@ -340,10 +349,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
dependencies = [
"cfg-if",
"cpufeatures",
"cpufeatures 0.2.17",
"curve25519-dalek-derive",
"digest",
"fiat-crypto",
"fiat-crypto 0.2.9",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
"curve25519-dalek-derive",
"fiat-crypto 0.3.0",
"rustc_version",
"subtle",
"zeroize",
@@ -460,7 +484,7 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
dependencies = [
"curve25519-dalek",
"curve25519-dalek 4.1.3",
"ed25519",
"serde",
"sha2",
@@ -515,6 +539,12 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "fiat-crypto"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24"
[[package]]
name = "filedescriptor"
version = "0.8.3"
@@ -713,6 +743,7 @@ dependencies = [
"tungstenite",
"url",
"vt100",
"x25519-dalek",
]
[[package]]
@@ -1502,6 +1533,12 @@ dependencies = [
"getrandom 0.3.4",
]
[[package]]
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rand_xorshift"
version = "0.4.0"
@@ -1830,7 +1867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"cpufeatures 0.2.17",
"digest",
]
@@ -1841,7 +1878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"cpufeatures 0.2.17",
"digest",
]
@@ -2767,6 +2804,17 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
[[package]]
name = "x25519-dalek"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7e8131a03190127fb2263afc72b322ecadae46b6ff8c6f399ff5d02f5559af6"
dependencies = [
"curve25519-dalek 5.0.0",
"rand_core 0.10.1",
"zeroize",
]
[[package]]
name = "xattr"
version = "1.6.1"