Statement

Resolution is cryptographic wherever the exact claimant intersection allows it. Only monads holding the mutual .me refs and keys can derive the route. Everything else stays invisible — pure emergent, sovereign topology.

Definitions

kernel
an instance of ME; one root seed, one secret-derivation chain
seed
64-hex namespace authority key; never leaves the kernel
path
SemanticPath — ordered sequence of string segments
secret scope
a path marked _("key"); data under it encrypted from that scope's key material
noise boundary
a path marked ~("nonce"); cuts secret-derivation inheritance (A3)
blob key
(encKey, macKey, pathContext) from deriveBlobV3Keys()
audience
A ⊆ { kernel identityHash }

Kernel Identity as Audience Element

identityHash(K) = keccak256("this.me/identity:v1::" + K.seed)
(P256_priv_K, P256_pub_K) = generateP256KeyPair(HKDF(K.seed, "this.me/p256/v1"))

P256_pub_K — encryption target, shareable. identityHash(K) — membership identifier. (identityHash, P256_pub) — the kernel's public audience credential.

Existing Primitives

3.1 symmetric, v3, single-owner
collectSecretChainV3(path, mode) → deriveBlobV3Keys(chain, mode, path)
  → { encKey, macKey, pathContext }
encryptBlobV3 / decryptBlobV3 — keccak XOR stream + MAC

3.2 asymmetric, v1
wrapSecretV1(P256_pub, secret)   → { ephemeralPublicKey, iv, ciphertext, tag }
unwrapSecretV1(P256_priv, W)     → secret
kex: ECDH-ES(P-256)  kdf: HKDF-SHA-256  aead: AES-256-GCM

3.3 Ed25519
signEd25519Proof(priv, data)     → signature
verifyEd25519Signature(pub, data, sig) → boolean
— identity proof, not audience encryption

Audience Algebra

Union — A = K₁ ∪ K₂ ∪ ... ∪ Kₙ

S ← random(32)
ciphertext = encryptSymmetric(S, V)
∀ Kᵢ ∈ A:  Wᵢ = wrapSecretV1(P256_pub(Kᵢ), S)
publish { ciphertext, wraps: [(identityHash(Kᵢ), Wᵢ)] }

decrypt(Kⱼ ∈ A):
  Wⱼ ← match identityHash(Kⱼ) in wraps
  S  = unwrapSecretV1(P256_priv(Kⱼ), Wⱼ)
  V  = decryptSymmetric(S, ciphertext)

O(|A|) wrapped keys. Any single member suffices. Removing a member requires re-encryption of S for all remaining members — no backward secrecy otherwise.

Intersection — A = K₁ ∩ K₂ ∩ ... ∩ Kₙ

S₁, ..., Sₙ₋₁ ← random(32) each
Sₙ = S ⊕ S₁ ⊕ ... ⊕ Sₙ₋₁
∀ Kᵢ ∈ A:  Wᵢ = wrapSecretV1(P256_pub(Kᵢ), Sᵢ)
publish { ciphertext, shares: [(identityHash(Kᵢ), Wᵢ)] }

decrypt: requires all Kᵢ
  each Kᵢ unwraps Sᵢ; ⊕ all Sᵢ → S → decrypt(ciphertext)

Requires out-of-band coordination for share assembly. Threshold-k needs Shamir's Secret Sharing, not XOR splitting.

Set Difference — A = K₁ \ K₂

Not directly constructible via wrapping alone. Requires revocation: re-encrypt S for A \ {K₂} and rotate. Old ciphertext and W₂ invalidated only if S rotates.

Blob Format

type AudienceBlobV1 = {
  version: "audience/v1";
  ciphertext: Uint8Array;        // encryptSymmetric(S, value)
  audience: AudienceMember[];
};

type AudienceMember = {
  identityHash: string;          // hex — audience kernel fingerprint
  wrapped: WrappedSecret;        // wrapSecretV1(P256_pub_K, S)
};

Stored at the target path in the kernel's encrypted branch, alongside or replacing the v3 blob, depending on whether the path is self-owned or audience-scoped.

Axiom Compatibility

Key Exchange Prerequisite

wrapSecretV1 requires the sender to already know P256_pub(K_recipient) — a distribution problem the kernel does not solve itself.

Not solved anywhere in the current stack, checked directly against source. monad's real discovery surface, /__surface, does publish a public key — but it is Ed25519, used for routing-continuity signatures, not paired with identityHash, and not usable for ECDH-ES wrapping. /claims is POST-only — self-declaration, not third-party discovery. NRP's own spec excludes this explicitly: "namespace key distribution across monads" is listed under its own "What Is Not Specified Here." netget resolves network routing only; cleaker binds identity to namespace, not key discovery. This exchange is unencrypted by design once it exists — P256_pub is meant to be public — but no component currently makes it discoverable.