Expand description
Pointers — paid mutable references with an immutable owner.
A pointer is a mutable, owner-signed reference stored at an address derived
from its owner’s public key. Unlike a
DataChunk its address is not its
content hash: the address is fixed for the pointer’s life while the bytes
under it change with every update.
Ownership is fixed at creation. There is no transfer, no lineage, no
certificates and no key rotation: a former owner keeps its key forever, so
transferable ownership cannot be made fork-proof by a local rule. An earlier
draft of this module implemented transfer through a genesis object and a
chain of transfer certificates; it was reviewed and withdrawn. See
ADR-0016 in ant-node.
That choice is what lets the design be this small: the owner key is inlined in the record, so validating a pointer needs nothing but the pointer — no fetch, no cache, no second close group, nothing that can be missing.
§Encoding
Encoded by hand: canonical, fixed-width, big-endian, no length prefixes and
no serde. The signed payload must not depend on a serializer whose output
can change — 1.0’s pointer called rmp_serde inside its signing routine and
silently signed nothing when it failed.
format_version 1 byte
owner 1952 bytes ML-DSA-65 public key
counter 8 bytes big-endian u64
target 33 bytes 1-byte kind tag + 32-byte address, opaque here
signature 3309 bytes ML-DSA-65 over the preceding 1994 bytes
-----
5303 bytes§Identity
A = BLAKE3::derive_key("autonomi.pointer.address.v1", owner)
state_id = BLAKE3::derive_key("autonomi.pointer.state.v1", body)Derive-key, not a hash of a prefix and the input. A chunk is addressed by a plain hash of its content, so a prefix would put both of these inside the chunk address space for anyone who could write the preimage down: squatting an owner’s address before they used it, or buying a pointer and a chunk with one payment. Both modes still produce 32 bytes, so the ranges overlap; what changed is that crossing them is the preimage problem BLAKE3 is assumed to resist.
A routes and decides which nodes are responsible. state_id names the
authenticated state: it is what sync hints carry, what a fetch decision
compares, and what a quote is paid against. They are separate because
A must be stable for the pointer’s life while the paid identifier must
change with every update, or updates after the first would be free — the
defect this design exists to fix.
§What this module does not do
Payment verification, storage and replication. Those are the node’s job.
Structs§
- Parsed
Pointer - Bytes that have been structurally parsed but not yet verified.
- Pointer
- A paid, mutable, owner-signed reference.
- Pointer
State - The parts of a record that determine its authenticated state.
- Pointer
Target - A kind tag plus the address it refers to.
Enums§
- Pointer
Error - Why a pointer was refused.
- Pointer
Target Kind - What a pointer points at, as clients interpret it.
Constants§
- DATA_
TYPE_ POINTER - Data type identifier for pointers, alongside
DATA_TYPE_CHUNK. - ML_
DSA_ 65_ PUBLIC_ KEY_ LEN - Length of a raw ML-DSA-65 public key.
- ML_
DSA_ 65_ SIGNATURE_ LEN - Length of a raw ML-DSA-65 signature.
- POINTER_
BODY_ LEN - Length of the signed body: everything before the signature.
- POINTER_
FORMAT_ VERSION - Wire format discriminator carried by every pointer.
- POINTER_
WIRE_ LEN - Total size of an encoded pointer.
- TARGET_
WIRE_ LEN - Length of an encoded
PointerTarget: a kind tag plus an address.
Functions§
- pointer_
address - Derive a pointer address from an owner key.
- state_
id_ for_ body - Derive the authenticated-state identifier from a signed body.