mcl_om_ownership_proof (mcl_om v0.2.2)
View SourceVerifies a caller actually holds the private half of the node key whose node id it asserts as its identity, inside an otherwise- open mesh payload. The 11.x identity is a pq_hybrid node key whose node id is a SHA-256 digest of its carried public key -- so, unlike the 10.x Ed25519 DID (where the id WAS the public key), possession can only be proved by signing {identity, timestamp, procedure} with the private half AND carrying the public key the signature verifies against. procedure is part of the signed message so a proof minted for one gated capability can't be replayed against another this or any other service adds later.
Extracted here after the identical ~40-line verifier had been written twice independently -- hecate-citizens' citizen_ownership_proof` (proving a `register_presence` caller holds the `citizen_did` its registering) and hecate-mail's mailbox_ownership_proof` (proving a caller may read a mailbox) -- each ones own moduledoc naming the same test for when to stop duplicating it: "would a second, unrelated consumer plausibly want this same fact." hecate-graph's learn_link` needing it too (to make graph provenance mind-grained rather than only connection-grained, PLAN_MESH_TRUTHS_AND_PROVENANCE.md) is the third consumer that crosses it. A DIFFERENT mechanism from maculas own {ucan_required, Issuer}` capability gating (`hecate-om/plans/PLAN_UCAN_GATED_CAPABILITIES.md`): that controls who may CALL a procedure at all, enforced by the serving station before any handler runs. This proves WHO ASSERTED a specific claim inside an otherwise-open procedures payload -- provenance, not access control. A procedure can use either, both, or neither.
WIRE ENCODING: macula's frame decoder walks a payload map and converts every CBOR TEXT value to an ATOM via binary_to_existing_atom/1 whenever the RECEIVING VM already has that atom loaded -- if not, it stays a {text, Binary} tuple. Which shape a given value arrives as therefore depends on what atoms this VM happens to already know, not on anything the caller controls: a real identity (effectively random hex) is essentially never already an atom, so it always arrives {text, Bin}-tagged. unwrap_text/1 handles all three shapes (bare binary, bare atom, {text, Bin}) plus undefined; decode_identity/1 layers hex-decoding on top for identity fields, decode_text/1 is the same unwrap alone for any other wire-transported string. The proof itself carries timestamp, signature (hex text of the composite signature) and public (hex text of the carried public key the signature and the node-id derivation are checked against).
Summary
Functions
Unwraps, then hex-decodes, a wire-transported identity (or signature) into its raw bytes.
unwrap_text/1 alone, for any wire-transported string that isn't an identity/signature.
Verify that Proof (a map with timestamp, signature and public) proves possession of the private key behind Identity (a raw 32-byte node id), bound to Procedure. The carried key must derive Identity as its node id AND sign the message -- a node id earns no trust on its own, only after a signature by the same carried key has verified.
Functions
Unwraps, then hex-decodes, a wire-transported identity (or signature) into its raw bytes.
unwrap_text/1 alone, for any wire-transported string that isn't an identity/signature.
Verify that Proof (a map with timestamp, signature and public) proves possession of the private key behind Identity (a raw 32-byte node id), bound to Procedure. The carried key must derive Identity as its node id AND sign the message -- a node id earns no trust on its own, only after a signature by the same carried key has verified.