HPPR Core Specification

This file is assembled from hppr/spec/*.md. Edit the source files, not this aggregate.

HPPR Specs

Tags: overview

HPPR is Hyper Plex Packet Repository.

Purpose

HPPR specifies a layered protocol for storing, signing, addressing, exchanging, and routing content-addressed packets.

The specs are written for implementers of packet libraries, repository daemons, clients, transports, and route-aware applications.

Architecture at a Glance

  1. Encoding and crypto: B64A and HSB3.
  2. Stored packet format: Blob, Plex, and Seal packets.
  3. Addressing: hash addresses and coordinates.
  4. Command messages and flows: session and message command execution.
  5. Transports: TCP/WebSocket/QUIB session flow; HTTP/UDP message flow.
  6. Repository service: commands, envelopes, ACL, Ring1/Ring2 auth, storage.
  7. Higher-level conventions: links, chunks, replication, admin workflows, routes, names, and attestations.

Reader Paths

Reader Start with Then read
Packet-library implementer 006, 009, 010 011, 012, 070
Client implementer 020, 030, 031, 032 033-036, 041-045
Repository implementer 040-045 050-060, 080-090
Route/application implementer 100 110

Conformance Profiles

MUST and SHOULD requirements apply to implementations claiming the relevant profile.

Profile Required specs
Packet profile 006, 009, 010
Repository client profile 020, 030-035, 041-045
Repository service profile 040-045, 050-060, 080-090
QUIB profile 036 plus repository session-flow specs when used with hpprd
Route resolver profile 100, 110 plus repository client profile

Reading Order

The specs are numbered in recommended reading order. Tags describe each spec’s primary layer or role.

No. Spec Tags
006 Base64-Ascend packet, encoding
009 HSB3 Signatures packet, crypto
010 Packets packet, stored-format
011 Basic Packet Examples packet, example
012 Create Examples packet, example
020 Unified Resource Coordinate packet, addressing
030 Command Messages wire, command
031 Command Flows wire, command-flow
032 HELLO and Endpoint Metadata wire, command-flow, metadata
033 Via Syntax wire, transport
034 HTTP Transport wire, transport, message-flow
035 UDP Datagram Transport wire, transport, message-flow
036 QUIB wire, transport, session-flow
040 Repository Service repo, overview
041 Repository Commands repo, command
042 Repository Request Envelopes repo, command-flow, auth
043 Repository Session Flow repo, command-flow, session
044 Repository Message Flow repo, command-flow, message
045 Repository Identity Text repo, auth, client
050 Repository Access Control repo, auth, policy
051 Ring1 Repository Authentication repo, auth
052 Ring2 Group Authentication repo, auth
060 Filesystem Repository repo, storage
070 Packet Links and Chunks packet, content-convention
080 Replication and Streams repo, command, streaming
090 Admin and Join Conventions repo, workflow
100 Content Routes scheme, route
110 Routes, Names, and Attestation scheme, route, name, attest

Reference Implementation

hpprd is the reference daemon implementation. It implements the repository service specs tagged repo.

HPPR-006 · Base64-Ascend (B64A)

Tags: packet, encoding

B64A is an order-preserving Base64 variant.

Alphabet:

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

Canonical form omits = padding and zero-fills trailing bits.

Alphabet Mapping

~ keeps the alphabet ASCII-sorted and path-safe.

Encoding Rules

Decoding and Validation

Ordering Guarantees

Conformance

Test Vectors

Hex B64A Notes
(empty) empty input
00 00 1 byte
0000 000 2 bytes
000000 0000 3 bytes
FF ~l tail 4 bits zero
FF00 ~l0 tail 2 bits zero
000102 0012 exact 3 bytes

Reject examples: 01, 001, ~m, ~l1, =, +, /.

HPPR-009 · HSB3 Signatures

Tags: packet, crypto

HSB3 is a BIP-340 style Schnorr signature over secp256k1.

HSB3 uses BLAKE3-256 for all hashing and key derivation tags. Reference code lives in rust/libs/hsb3.

Parameters

Helper notation:

Key Generation

  1. Draw random 32-byte d0; reject 0 and d0 >= n.
  2. Set d = d0, compute P = d*G.
  3. If P.y is odd, set d = n - d and recompute P.
  4. Private key is d; public key is bytes(P.x).

The even-y convention is mandatory.

Deterministic Key Derivation

Derive a keypair from arbitrary secret bytes.

  1. Initialize BLAKE3 derive mode with tag hppr-🖧/adhoc-key.
  2. Feed secret bytes.
  3. Enter XOF mode.
  4. Rejection sample 32-byte candidates until 0 < d0 < n.
  5. Apply the same even-y normalization as key generation.

Conformance:

Signing

Inputs:

Rules:

Algorithm:

  1. t = tagged(aux, auxRand32)
  2. mask = t xor bytes(d)
  3. k0 = tagged(nonce, mask || Px || msg32) mod n; reject k0 = 0
  4. R = k0*G; if R.y odd then k = n-k0, else k = k0
  5. e = tagged(challenge, bytes(R.x) || Px || msg32) mod n
  6. s = (k + e*d) mod n
  7. signature bytes are bytes(R.x) || bytes(s)

Text form uses B64A.

Verification

Inputs: signature r||s, public key Px, and msg32.

  1. Parse r, s; reject r >= p or s >= n.
  2. Recover P from Px and take even-y root.
  3. e = tagged(challenge, bytes(r) || Px || msg32) mod n
  4. R' = s*G - e*P; reject infinity or odd y.
  5. Accept iff R'.x == r.

Conformance

Implementations:

HPPR Packet Format

Tags: packet, stored-format

© R.A.Sol

Every stored packet starts with a markline:

🖧: <hash-text>

<hash-text> is the packet type, BLAKE3-256 digest encoded in B64A, and .H3 format suffix. It identifies the canonical payload after the first LF.

HPPR stored packet types:

Shared Rules

Blob

🖧: <hash>
Data-Length: <len>

<data exactly <len> bytes>

Rules:

Plex

🖧: <hash>
Group: <group>
API: <api>
Key: <key>
TAI: <tai>
[Extra headers]*
🖧: <blob_hash>
Data-Length: <len>

<data>

Rules:

TAI Format

TAI format:

<seconds>:<subseconds>

Rules:

TAI seconds use International Atomic Time. Timestamp generation applies the TAI-UTC offset in force for the generation instant.

Header Validation

General:

Group:

API:

Key:

Extra Headers

Extra-header ordering is canonical:

Reserved header names (MUST NOT appear as extra headers):

Limits:

Seal

🖧: <hash>
Seal-By: <verification-key>
Seal-Sig: <signature>
🖧: <plex_hash>
Group: <group>
API: <api>
Key: <key>
TAI: <tai>
[Extra headers (sorted)]*
🖧: <blob_hash>
Data-Length: <len>

<data>

Rules:

Packet-shaped Command Envelopes

Wire protocols may define packet-shaped command envelopes that are not stored packets. The generic Null command packet uses markline 🖧: 0.H3 and is defined in 030-COMMAND-MESSAGES.md. Null packets are command envelopes and response envelopes only. They are not Blob, Plex, or Seal packets and are never stored in repository storage.

Limits

Parsing

  1. Read markline and verify the type prefix in the hash text.
  2. Blob:
    • read Data-Length
    • consume exact data bytes
    • verify Blob hash
  3. Plex:
    • read required headers in required order
    • read extra headers with canonical ordering checks
    • parse embedded Blob
    • verify Plex hash
  4. Seal:
    • read Seal-By, Seal-Sig
    • parse embedded Plex
    • verify Seal hash
    • verify signature

Reject on any of the following:

Trailer-hash Format

Trailer-hash format supports streaming when the final hash is only known at the end.

Open marker:

⋯🖧: <type>[ <coordinate>]

Close marker:

⋯🖧: <hash>

Rules:

Seal trailer example:

⋯🖧: S //<group>/<api>//<key>/|/seal/<verification-key>
<escaped data>
⋯🖧: B.<blob-hash>.H3
Group: <group>
API: <api>
Key: <key>
TAI: <tai>
[Extra headers]*
⋯🖧: P.<plex-hash>.H3
Seal-By: <verification-key>
Seal-Sig: <signature>
⋯🖧: S.<seal-hash>.H3

Additional rules:

Both sides buffer full packet bytes to compute and verify hashes.

Thin Format

Thin format stores only part of a packet.

Thin packets omit embedded content bytes and rely on nested hashes for reconstruction.

Digest computation always requires full packet bytes. Implementations MUST resolve thin references before hash verification.

Thin format is for storage and transfer when inner packets are already present.

HPPR Basic Packet Examples

Tags: packet, example

This file shows one Blob, one Plex, and one Seal packet in readable form. The hashes and signatures below are shortened placeholders; these examples show shape only and are not conformant packet bytes.

Blob Example

🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 34

HPPR Quickstart
This is Blob data.

Plex Example

🖧: P.EXAMPLE_PLEX_HASH.H3
Group: a-group
API: some-api
Key: our-collection/item
TAI: 1640995200:000000000
+Link: source B.EXAMPLE_BLOB_HASH.H3
X-Custom: header value
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 25

This is embedded blob data.

Seal Example

🖧: S.EXAMPLE_SEAL_HASH.H3
Seal-By: V.EXAMPLE_VERIFIER.H3
Seal-Sig: EXAMPLE_SIGNATURE_B64A
🖧: P.EXAMPLE_PLEX_HASH.H3
Group: a-group
API: some-api
Key: our-collection/item
TAI: 1640995200:000000000
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 22

This is signed content.

Reference Script for 011 Examples

Tags: packet, example

This script generates the examples used in 011-PACKETS-BASIC-EXAMPLE.md.

#!/bin/bash -e

blob_msg="HPPR Quickstart

HPPR packets are content-addressed using BLAKE3.
This Blob contains raw markdown data."

plex_msg="Plex
This is a plex packet with metadata and links."

seal_msg="Seal
This is a signed packet that wraps a plex packet."

#- Deterministic test-only signatures.
export _UNSAFE_VULNERABLE_HPP_HSB3_DETERMINISTIC_AUX_SEED="examples"
export HPPR_SIGNING_SECRET="&.ydejWAbshBxyrcKILG3bXkD7fU5c72LtHvLJRfzGXal.H3"
tai="1640995200:000000000"

out="./spec/011-PACKETS-BASIC-EXAMPLE.md"

#- Blob
echo -n "$blob_msg" | mkpac --blob > "$out"
blob_hash=$(head -n 1 "$out" | awk '{print $2}')

#- Plex
echo -n "$plex_msg" | mkpac \
  --group a-group \
  --api some-api \
  --key our-collection/item \
  -t "$tai" \
  -H "+Link: source $blob_hash" \
  -H "X-Custom: header value" \
  -H "Multiple-Values: B" \
  -H "Multiple-Values: A" \
  >> "$out"

#- Seal
echo -n "$seal_msg" | mkpac \
  --seal-with "$HPPR_SIGNING_SECRET" \
  --group a-group \
  --api some-api \
  --key our-collection/item \
  -t "$tai" \
  >> "$out"

Unified Resource Coordinate

Tags: packet, addressing

© R.A.Sol

HPPR supports two address forms:

Hash addresses are immutable. Coordinate addresses are time-dependent and may resolve to different packets as new packets are stored.

A versioned coordinate pins one exact packet.

Terms

Coordinate Syntax

Coordinate form:

//<group>/<api>//<key>

Rules:

Examples:

Coordinate Group API Key
//u/docs//index.html u docs index.html
//lab.eu/chat/message//room-7/1 lab.eu chat/message room-7/1
//lab.eu/chat//message/room-7/1 lab.eu chat message/room-7/1

The API/Key boundary is a design choice. API names should be finite, developer-defined protocol surfaces. Key names may be unbounded, data-defined, or instance-specific.

Version Selectors

Multiple packets can share one coordinate. Add /|/... to select a version.

Example

Packet:

🖧: P.EXAMPLE~HASH~EXAMPLE~HASH~EXAMPLE~HASH~EX.H3
Group: a-group
API: some-api
Key: our-collection/item
TAI: 1640995200:123000000
...

Addresses:

Get resolution

In the tables below, <key> is the Key header value and does not end with /. The <api> value does not end with /.

The tip is the latest packet at a coordinate. Tie-break order is highest TAI, then highest hash.

Path Gets
//<group>/<api>//<key> tip
//<group>/<api>//<key>/ tip
//<group>/<api>//<key>/| tip
//<group>/<api>//<key>/|/plex Plex tip
//<group>/<api>//<key>/|/plex/<tai> Plex tip at tai
//<group>/<api>//<key>/|/plex/<tai>/<hash> exact Plex
//<group>/<api>//<key>/|/seal Seal tip
//<group>/<api>//<key>/|/seal/<verifier> Seal tip for signer
//<group>/<api>//<key>/|/seal/<verifier>/<tai> signer Seal tip at tai
//<group>/<api>//<key>/|/seal/<verifier>/<tai>/<hash> exact Seal

List resolution

LIST operates over two trees: the API tree and the Key tree for one exact API.

Path Lists
//<group>/ top-level API segments
//<group>/<api>/ API child segments, plus // when Key tree exists for exact API
//<group>/<api>// Key roots for exact API
//<group>/<api>//<key>/ Key children, plus |/ when present
//<group>/<api>//<key>/|/ plex/ and or seal/
//<group>/<api>//<key>/|/plex/ TAIs
//<group>/<api>//<key>/|/plex/<tai>/ hashes
//<group>/<api>//<key>/|/seal/ signer verification values
//<group>/<api>//<key>/|/seal/<verifier>/ TAIs
//<group>/<api>//<key>/|/seal/<verifier>/<tai>/ hashes

The // child in API listings is a boundary marker. It means packets exist under the exact API and their Key roots can be listed with //<group>/<api>//.

Parsing

Parsers MUST treat hash addressing as a separate branch before coordinate parsing.

hash-address = "////" hash-text
coordinate = "//" group "/" api "//" key [version-selector]

Reject malformed coordinates including:

| is forbidden in API and Key segments, so /|/ unambiguously starts version selection.

HPPR Command Messages

Tags: wire, command

© R.A.Sol

HPPR endpoints exchange command messages. A command service defines the command names it accepts, the request envelope it requires, and the authorization rules for each command.

A command message is a packet or packet-shaped envelope carrying:

Command names that belong to HPPR itself start with 🖧, for example 🖧GET and 🖧HELLO.

Null Command Packets

The sentinel hash 0.H3 is never computed or verified.

Use 0.H3 for:

Null packets are never stored in repository storage.

🖧: 0.H3
[Header: value]*
Data-Length: <len>

<data>

Header rules follow 010 for format, encoding, control bytes, line endings, and line length. Differences from Plex:

Command Services

A command service chooses:

The HPPR Repository Service defines the standard repository command set in 041.

HELLO Command

🖧HELLO requests command-flow capabilities and endpoint metadata.

A transport MAY deliver equivalent greeting metadata earlier in connection setup. The 🖧HELLO command remains the generic capability query and refresh operation when the endpoint accepts it.

The generic Null HELLO request is:

🖧: 0.H3
API: 🖧HELLO
Data-Length: 0

HELLO response headers are defined in 032.

Errors

Generic network errors are Null packets. Data starts with one status line:

Trusted or local endpoints MAY add Status: ok|error|fatal as an endpoint convention. Clients may use Status when present, but parsing the ERROR or FATAL data prefix is the generic error rule.

Standard generic error types:

Services MAY define additional error types and details.

Example:

🖧: 0.H3
Data-Length: 21

ERROR NOT_FOUND missing

HPPR Command Flows

Tags: wire, command-flow

© R.A.Sol

A command flow defines how an endpoint accepts HPPR command messages.

The command name says what operation is requested. The command flow says how the request is framed, what state the endpoint may rely on, and what result modes are available.

Envelope and Principal

Each command flow has an accepted request envelope. The envelope is the packet shape that carries the command and its arguments.

A service interprets the envelope to produce a command principal. The principal is the identity or capability used for authorization. The flow defines the state available to validate the envelope; the service defines what the resulting principal means.

Session Command Flow

The session command flow has connection-local state.

It uses 🖧HELLO or transport handshake metadata to create connection-local binding state, then requires a session-bound request envelope for every non-HELLO command.

A session flow is the right fit when:

Message Command Flow

The message command flow accepts one complete HPPR request message and returns one complete HPPR response message. It has no connection-local session state.

A message-flow request does not rely on prior per-connection 🖧HELLO state. Message requests are replayable unless the service’s accepted envelope adds its own replay rule.

A message flow is the right fit when:

Result Modes

A command’s result mode describes what happens after the request envelope is accepted. The five modes below are the generic vocabulary used by command specs, including streaming commands.

Single-response packet

The endpoint reads one request packet and returns one response packet.

Most commands use this mode.

Acknowledged stream

The endpoint returns an initial success response, then keeps the connection open and writes a command-defined stream.

Repository 🖧WATCH uses this mode.

Negotiated raw packet exchange

The endpoint returns a negotiation response. Both peers then transfer raw packet bytes according to the command’s negotiated plan.

Repository 🖧EXCHANGE uses this mode.

Relay mode after response

The endpoint returns an initial success response, then treats the rest of the connection as command-defined relay bytes.

Repository 🖧STREAM_PUB uses this mode.

Relay mode without response

The endpoint accepts the request and immediately treats the connection as command-defined relay output, with no success response packet.

Repository 🖧STREAM_SUB uses this mode.

Generic Rules

The HPPR Repository Service defines concrete repository envelopes and flow behavior in 042, 043, and 044.

HPPR HELLO and Endpoint Metadata

Tags: wire, command-flow, metadata

© R.A.Sol

🖧HELLO returns endpoint metadata. It tells the client which command flow this endpoint uses, which commands are accepted on that flow, and which other transport endpoints are reachable.

The generic HELLO request packet is defined in 030.

HELLO Response Shape

A HELLO response is a Null packet:

🖧: 0.H3
Command-Flow: session|message
[Session-Commands: <command-entry> *( " | " <command-entry> )]*
[Message-Commands: <command-entry> *( " | " <command-entry> )]*
[Allow-Null-Command: 0|1]
[Transport: <via> [hints...]]*
[Header: value]*
Data-Length: 0

Other HELLO headers are endpoint-specific or service-specific. The HPPR Repository Service adds repository fields such as Session-ID, Repo-Name, Seal-By, and PHC in 043 and 044.

Command-Flow

Command-Flow names the command execution flow advertised by this HELLO response.

Known values:

Flow Meaning
session connection-local HELLO session, session-bound non-HELLO requests
message one complete request message returns one complete response message

Rules:

Command Capability Headers

Command capability uses flow-specific command-list headers:

Session-Commands: 🖧GET 1 | 🖧STORE 1 | 🖧WATCH 1
Message-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧INGEST 1

Rules:

Formal grammar:

Session-Commands = command-entry *( " | " command-entry )
Message-Commands = command-entry *( " | " command-entry )
command-entry = command-name SP version *(SP option)
version = non-empty base-10 integer
option = non-empty token without SP or the literal separator " | "

Allow-Null-Command

Allow-Null-Command is a boolean capability for trusted local command envelopes.

Rules:

Transport

Transport advertises reachable transport endpoints:

Transport: tcp:4777 flow=session
Transport: quib:4776 flow=session
Transport: ws:4778 flow=session
Transport: http:4778 flow=message path=/hppr
Transport: udp:4777 flow=message

Rules:

Common Endpoint Headers

The following headers are common conventions. Services define whether they are required for that service.

Header Meaning
Seal-By endpoint or repository verifier, or 0 when none exists
Format packet and envelope format identifier; value H3
Status endpoint status; ok indicates success or readiness
Extension endpoint extension token; semantics are endpoint-specific

Via Syntax

Tags: wire, transport

© R.A.Sol

A via string identifies a transport endpoint.

Grammar

Full form:

scheme+host[:port]

Bare form (auto-negotiate transport):

host[:port]

Hostless form (used in HELLO Transport headers where host is already known):

scheme[:port]

HELLO transport header value:

via *(SP hint)

Known hints:

flow=session
flow=message
path=<absolute-path>

Unix domain socket:

unix+<absolute-path>

Schemes

Scheme Default port Transport
tcp 4777 TCP plaintext
quib 4776 QUIB encrypted (036)
ws 4778 WebSocket
udp 4777 UDP datagram message flow
http 80 HTTP POST request
auto 4777 Auto-negotiate (equivalent to bare form)

Host

Host is a hostname, IPv4 address, or bracketed IPv6 address.

IPv6 bracket form: [::1] or [::1]:port.

Port

Port is optional. When omitted, the scheme default applies. Bare form defaults to 4777.

Hostless Resolution

Hostless forms appear in HELLO Transport headers. The client fills in the host from its existing connection. Examples:

HELLO Transport Hints

A Transport HELLO header starts with a via string or transport endpoint. Any remaining space-separated tokens are hints about that endpoint.

Known command-flow hints:

HTTP path hint:

path= applies only to HTTP unless another transport spec defines it. Unknown hints are ignored. Flow hints describe the command flow reachable at that transport endpoint, not the current endpoint that produced the HELLO.

Examples:

Display Form

The canonical display form is:

Examples

Input Scheme Host Port
tcp+10.0.0.1 tcp 10.0.0.1 4777
tcp+10.0.0.1:9000 tcp 10.0.0.1 9000
quib+1.1.1.1:4776 quib 1.1.1.1 4776
udp+10.0.0.1 udp 10.0.0.1 4777
http+example.com:8080 http example.com 8080
ws+example.com ws example.com 4778
auto+example.com auto example.com 4777
example.com auto example.com 4777
example.com:9000 auto example.com 9000
tcp:4777 tcp (from context) 4777
udp udp (from context) 4777
unix+/tmp/hppr.sock

HTTP Transport

Tags: wire, transport, message-flow

© R.A.Sol

The HTTP endpoint carries one complete HPPR request packet in one HTTP POST request and returns one complete HPPR response packet.

Via: http+host[:port] (033). Default port: 80.

Advertised in HELLO or equivalent endpoint greeting metadata as:

Transport: http:<port> flow=message path=/hppr

Protocol

POST /hppr
Content-Type: protocol/hppr
Accept: protocol/hppr

<raw HPPR request packet>

Rules:

The entity media type is protocol/hppr. Implementations must treat it as an explicit HPPR convention and must not apply text, mail, or CRLF normalization.

Repository HTTP Message Flow

Repository HTTP is a message-flow endpoint. Its concrete request envelope and command set are defined in 044.

Repository HTTP HELLO is capability/provisioning discovery and does not create a usable session binding.

HTTP listeners are explicit. all transport binding does not expose HTTP. A repository service advertises Transport: http:<port> flow=message path=/hppr only when an HTTP listener is active.

UDP Datagram Transport

Tags: wire, transport, message-flow

© R.A.Sol

UDP is a single-datagram message-flow transport for fast bounded lookups.

Via: udp+host[:port] (033). Default port: 4777.

Advertised in HELLO or equivalent endpoint greeting metadata as Transport: udp[:port] flow=message.

Supported Commands

UDP is a stricter message-flow subset:

UDP returns INVALID for 🖧LIST, 🖧INGEST, 🖧STORE, and all other commands.

Protocol

No explicit HELLO round-trip runs on UDP itself. Each exchange is one request datagram and one response datagram.

Request is one endpoint-defined message-flow request envelope (031) in a single UDP datagram.

The HPPR Repository Service envelope is defined in 044.

Response is one datagram: raw packet bytes on success, Null packet on error. Unrecoverable failures produce no response.

QUIB

Tags: wire, transport, session-flow

© R.A.Sol

HPPR QUIB transport uses a custom crypto layer instead of TLS 1.3.

Primitives:

No TLS, no X.509, no rust ring. Both peers must run this crypto.

Handshake

Two-message exchange inside QUIC Initial CRYPTO frames. Both messages travel in the Initial encryption space. After ECDH completes, each side writes a single 0x00 confirmation byte into Handshake CRYPTO to signal readiness, then upgrades to Data-space keys.

Message 1 (client to server, Initial CRYPTO)

client_ephemeral_pubkey (33 bytes, SEC1 compressed secp256k1)
client_transport_parameters (variable)

Message 2 (server to client, Initial CRYPTO)

server_ephemeral_pubkey (33 bytes, SEC1 compressed secp256k1)
encrypted_hello_length (2 bytes, big-endian u16)
encrypted_hello (variable, ChaCha20-Poly1305)
server_transport_parameters (variable)

The entire Message 2 is sent in a single CRYPTO frame. The client derives the shared secret from the server’s ephemeral pubkey, then decrypts the hello and parses transport parameters in one step.

Transport parameters use QUIC transport-parameter wire encoding.

Reference implementation note: the Rust implementation uses quinn-proto’s TransportParameters::write and TransportParameters::read helpers for this encoding.

Encrypted HELLO Payload

The server encrypts a HELLO payload into Message 2 using hello_key from the key derivation XOF stream (offset 256, see Key Derivation).

Encryption uses ChaCha20-Poly1305 with a zero nonce (unique key per connection).

Plaintext is the active service’s HELLO advertisement packet. At minimum it follows the generic HELLO metadata from 032: Command-Flow, the selected flow-specific command-list header, optional Transport headers, and any service-specific greeting headers.

Because the handshake is already connection-scoped, a service MAY omit a normally explicit session header here and derive equivalent binding from the transport instead.

The HPPR Repository Service sends its HELLO response payload here with Command-Flow: session, Repo-Name, Seal-By, optional PHC, repeated Transport, Session-Commands, and Allow-Null-Command: 0, and omits Session-ID because it derives the session id from QUIB keying material.

The encrypted hello includes a 16-byte Poly1305 tag appended to the ciphertext.

Post-handshake stream bootstrap

QUIB keeps standard QUIC endpoint roles:

All application streams are client-initiated. The HELLO payload is delivered during the handshake, so no server-initiated stream is needed.

  1. client reads the decrypted HELLO payload
  2. client derives any service-defined connection binding from keying material
  3. client opens a bidirectional stream and sends commands
  4. server accepts streams and dispatches commands

Reference implementation note: the Rust implementation exposes the HELLO payload through handshake_data(), uses accept_bi() for server streams, and uses open_bi() for client command and auxiliary streams.

Service Session Binding

service_session_binding is 32 bytes from the key derivation XOF stream offset 288 (see Key Derivation).

Higher-layer services MAY map this value into a connection-bound session token or other transport binding.

The HPPR Repository Service maps it to Session-ID: Q#<b64a> and uses it in place of the TAI-based session ids used on other transports.

The 🖧HELLO command remains available as an optional application-level request for capabilities refresh or service-specific status queries.

Key Agreement

shared_point = ECDH(client_ephemeral_secret, server_ephemeral_pubkey)
shared_bytes = shared_point.x (32 bytes, big-endian)

Both sides generate fresh ephemeral secp256k1 keypairs per connection.

Key Derivation

All keys for a connection are derived from the ECDH shared secret using a single BLAKE3 XOF stream:

stream = BLAKE3.derive_key_xof("hppr-🖧/quib/keys", shared_bytes)

Stream layout (368 bytes):

Offset Length Name
0 32 hs_c2s_packet
32 32 hs_s2c_packet
64 32 hs_c2s_header
96 32 hs_s2c_header
128 32 c2s_packet
160 32 s2c_packet
192 32 c2s_header
224 32 s2c_header
256 32 hello_key
288 32 service_session_binding
320 12 hs_c2s_iv
332 12 hs_s2c_iv
344 12 c2s_iv
356 12 s2c_iv

Handshake keys (hs_*) protect the Handshake packet space. Data keys protect the 1-RTT (Data) packet space.

Each packet key has a sibling IV derived from the same XOF stream. The IV is used in nonce construction (see Payload Encryption below).

The protocol performs two key upgrades during handshake: Initial to Handshake, then Handshake to Data. Each side writes a 0x00 confirmation byte into Handshake CRYPTO when returning 1-RTT keys, ensuring the peer receives a Handshake-space packet and completes the transition to Data.

Reference implementation note: quinn-proto drives these upgrades through the write_handshake callback.

QUIC Key Update

Each direction derives 44 bytes via BLAKE3 XOF from the current packet key:

stream = BLAKE3.derive_key_xof("hppr-🖧/quib/update", current_packet_key)
next_packet_key = stream[0..32]
next_iv          = stream[32..44]

Both key and IV are replaced. Header keys are not updated.

QUIC Payload Encryption

ChaCha20-Poly1305 (RFC 8439).

Nonce construction (12 bytes), following the TLS 1.3 pattern (RFC 9001 §5.3):

nonce = IV XOR (0x00000000 || BE64(packet_number))

The IV is the 12-byte sibling value derived alongside the packet key (from the XOF stream for initial/handshake/data keys, or from the key update XOF for rotated keys). The packet number is encoded as an 8-byte big-endian integer and XORed into the last 8 bytes of the IV.

Tag length: 16 bytes, appended to ciphertext.

Limits:

QUIC Header Protection

ChaCha20 mask generation per RFC 9001 §5.4.4.

Input: 16-byte sample from encrypted payload at offset pn_offset + 4.

counter = LE_u32(sample[0..4])
nonce   = sample[4..16]
mask    = ChaCha20(hp_key, counter, nonce, zeroes)[0..5]

Apply mask:

Sample size: 16 bytes.

Initial QUIC Keys

Before handshake completes, both peers derive identical keys from the destination connection ID using a single BLAKE3 XOF stream:

stream = BLAKE3.derive_key_xof("hppr-🖧/quib/initial", dst_cid)

Stream layout (152 bytes):

Offset Length Name
0 32 c2s_packet
32 32 s2c_packet
64 32 c2s_header
96 32 s2c_header
128 12 c2s_iv
140 12 s2c_iv

Initial keys use the same ChaCha20-Poly1305 and ChaCha20 algorithms as 1-RTT keys. Initial protection is not secret (the CID is on the wire).

Retry Integrity

Retry tags use BLAKE3 keyed MAC with a fixed public key, truncated to 16 bytes.

tag = BLAKE3.keyed_hash(RETRY_KEY, len(orig_dst_cid) || orig_dst_cid || retry_pseudo_packet)[..16]

RETRY_KEY is a fixed 32-byte constant compiled into both peers:

8a 3f c1 7b 52 e6 d9 04  ab 1e 73 f0 28 95 dc 46
b3 67 0a 5d e4 89 f1 3c  7e b2 05 6f d8 a1 43 97

This mirrors RFC 9001’s public retry integrity key. The tag is tamper-detection, not a secret.

HMAC

BLAKE3 keyed hash with 32-byte output.

mac = BLAKE3.keyed_hash(key, data)

Verification compares all 32 bytes.

Token Encryption

Address validation tokens use per-token derived ChaCha20-Poly1305.

Key derivation:

aead_key = BLAKE3.derive_key("hppr-🖧/quib/token-aead", master_key || random_bytes)

Seal and open use a zero nonce. Each token has a unique derived key, making nonce reuse impossible.

Export Keying Material

output = BLAKE3.derive_key(label, shared_bytes || context)

label is interpreted as a UTF-8 string for the BLAKE3 context parameter. Output length is variable via BLAKE3 XOF.

Peer Identity

The peer identity is the peer’s ephemeral SEC1 compressed secp256k1 public key (33 bytes).

For clients, the HELLO payload is the active service’s greeting packet. For the HPPR Repository Service this includes the repo verifier and advertised capabilities.

Reference implementation note: the Rust implementation exposes the peer public key through peer_identity() and the transport greeting through handshake_data().

No 0-RTT

Early data is not supported.

Reference implementation note: the Rust implementation returns None from early_crypto.

Context Strings

All BLAKE3 derive_key / XOF context strings used by this spec:

Context Use
hppr-🖧/quib/keys XOF for all handshake/data keys, IVs, hello key, service session binding
hppr-🖧/quib/initial XOF for initial keys and IVs
hppr-🖧/quib/update XOF for key update (packet key + IV per direction)
hppr-🖧/quib/token-aead Token AEAD key derivation

HPPR Repository Service

Tags: repo, overview

© R.A.Sol

The HPPR Repository Service is the standard authenticated packet repository layer built on the packet and wire protocols.

hpprd is the reference daemon implementation of these specs.

The Model

A repository stores packet versions at coordinates.

Clients send commands to retrieve, list, store, watch, replicate, and stream those packet versions. Commands arrive through a command flow. The accepted request envelope establishes a principal. The repository evaluates that principal against policy and then performs the command.

The story is:

  1. packet bytes prove content and signatures
  2. coordinates name packet versions
  3. command messages ask a service to do work
  4. command flows define how requests are accepted
  5. repository envelopes bind commands to principals
  6. Ring1 and Ring2 load identity state
  7. ACL maps principals and coordinates to read, write, and list
  8. storage materializes the abstract packet repository
  9. replication, streams, admin, and joins are repository commands and conventions layered on the same model

Repository requests are interpreted in this order:

  1. transport receives one command message;
  2. command flow determines available state;
  3. request envelope determines principal;
  4. command catalog determines semantics;
  5. Ring1/Ring2 and ACL rules determine authorization;
  6. storage or streaming machinery performs the command.

Conformance Boundary

Repository service conformance covers:

Underlying packet data is defined in 010, addressing in 020, and command-flow vocabulary in 030, 031, and 032. Higher-level data schemes are defined in 100 and 110.

Index

HPPR Repository Service Commands

Tags: repo, command

© R.A.Sol

The HPPR Repository Service stores packets, resolves URCs, enforces repository policy, and exposes repository commands over accepted wire endpoints.

Wire message shape, Null packets, HELLO, command flows, and errors are defined in 030, 031, and 032. Repository envelopes are defined in 042.

Security Model

HPPR validates packets at the packet layer, not the channel layer.

Repository authentication, authorization, session binding, and accepted request envelopes are service behavior.

Command Summary

Command Payload Response Result mode
🖧HELLO none capability advertisement single-response packet
🖧GET <urc> (020) full packet bytes single-response packet
🖧HEADERS <urc> markline + headers to blank line single-response packet
🖧LIST <urc-coordinate> LF-separated children, sorted single-response packet
🖧STORE complete packet bytes LF-separated stored hashes single-response packet
🖧ADD headers, blank line, data LF-separated stored hashes single-response packet
🖧WATCH <urc-coordinate-prefix> stream of +/- change events acknowledged stream
🖧TIPS <urc-coordinate-prefix> LF-separated tip coordinates single-response packet
🖧DETACH hash success response single-response packet
🖧AUDIT implementation-defined filter audit log stream acknowledged stream
🖧MEMBERS member URC LF-separated expanded members single-response packet
🖧INGEST full top-level Seal packet LF-separated stored hashes single-response packet
🖧EXCHANGE NEED/HAVE lines negotiated packet transfer negotiated raw packet exchange
🖧STREAM_PUB <coordinate-prefix> OK then relay input relay mode after response
🖧STREAM_SUB <coordinate-prefix> relay output relay mode without response

Flow Availability

Command Session HTTP message UDP message Trusted local Null
🖧HELLO yes yes no yes
🖧GET yes yes yes yes
🖧HEADERS yes yes yes yes, if exposed
🖧LIST yes yes, when advertised no yes, if exposed
🖧STORE yes no no yes, if exposed
🖧ADD yes no no no
🖧WATCH yes no no no
🖧TIPS yes no no no
🖧DETACH yes no no no
🖧AUDIT yes no no no
🖧MEMBERS yes no no no
🖧INGEST yes yes, when advertised no no
🖧EXCHANGE yes no no no
🖧STREAM_PUB yes no no no
🖧STREAM_SUB yes no no no

Endpoint HELLO command lists are authoritative for a concrete endpoint.

Envelope Summary

Envelope layouts are defined in 042. This table summarizes which envelope families can carry each command.

Command Session envelope Message envelope Auth source Response type
🖧HELLO initial Null, then session Seal HTTP Null or trusted local Null endpoint/session HELLO Null packet
🖧GET Ring1, Ring2, or anyone Seal public message Seal, UDP message, trusted local Null request principal or local capability raw packet bytes
🖧HEADERS Ring1, Ring2, or anyone Seal public message Seal, UDP message, trusted local Null when exposed request principal or local capability packet headers
🖧LIST Ring1, Ring2, or anyone Seal public message Seal when advertised, trusted local Null when exposed request principal or local capability Null/command response data
🖧STORE Ring1, Ring2, or anyone Seal trusted local Null when exposed request principal or local capability stored hash list
🖧ADD Ring1, Ring2, or anyone Seal none request principal stored hash list
🖧WATCH Ring1, Ring2, or anyone Seal none request principal acknowledged event stream
🖧TIPS Ring1, Ring2, or anyone Seal none request principal tip coordinate list
🖧DETACH Ring1 ring0 Seal none Ring1 ring0 success response
🖧AUDIT Ring1 ring0 Seal none Ring1 ring0 acknowledged audit stream
🖧MEMBERS Ring1, Ring2, or anyone Seal none request principal expanded member list
🖧INGEST Ring1, Ring2, or anyone Seal public message Seal when advertised submitted packet signer stored hash list
🖧EXCHANGE Ring1, Ring2, or anyone Seal none request principal negotiated raw packet exchange
🖧STREAM_PUB Ring1, Ring2, or anyone Seal none request principal per segment relay input after OK
🖧STREAM_SUB Ring1, Ring2, or anyone Seal none request principal relay output without OK

Authorization Mapping

Repository session flow applies ACL evaluation per 050:

Command ACL check
🖧GET read
🖧HEADERS read
🖧LIST list
🖧STORE write
🖧ADD write
🖧INGEST packet-authorized Ring2 write
🖧WATCH list
🖧TIPS list
🖧DETACH Ring1 ring0
🖧AUDIT Ring1 ring0
🖧MEMBERS read

Ring1 behavior is defined in 051. Ring2 behavior is defined in 052.

🖧STORE

🖧STORE payload is complete packet bytes starting with a markline.

Repository session flow applies these rules:

Thin packets may reference existing nested packets:

Response data lists stored hashes from outermost to innermost:

S.seal~hash.H3
P.plex~hash.H3
B.blob~hash.H3

🖧ADD

Input is LF-separated headers, blank line, optional data.

Type selection:

Defaults:

Seal-By selectors for packet create mode:

No other selector form is valid.

References:

🖧WATCH

Subscribes to index changes under a coordinate prefix.

After acknowledgment, the connection delivers a stream of LF-terminated lines:

+ <versioned-coordinate>
- <versioned-coordinate>

WATCH delivers future changes only. To avoid missing events between subscription and initial state read, subscribe first, then read current state.

Events are filtered by list permission per 050. ACL changes to auth, member, or policy packets take effect on active WATCH streams immediately. No reconnect is required for ACL changes.

🖧DETACH

Payload is one hash. Removes packet from the coordinate index only. Stored packet bytes remain in hash storage. Ring1 ring0 authorization is required.

🖧TIPS

Returns LF-separated versioned coordinates for tip packets. Events are filtered by list permission.

🖧AUDIT

Streams audit log lines. Ring1 ring0 authorization is required.

🖧MEMBERS

Returns expanded member list with tags. Ring2 details are defined in 052.

🖧INGEST

🖧INGEST admits a packet by the submitted packet’s authority, not by the outer request identity.

Rules:

Response data lists stored hashes like 🖧STORE.

Streaming Commands

🖧EXCHANGE, 🖧STREAM_PUB, and 🖧STREAM_SUB are defined in 080.

Errors

In addition to generic error types from 030, the repository service uses:

HPPR Repository Request Envelopes

Tags: repo, command-flow, auth

© R.A.Sol

Repository commands arrive in envelopes. The envelope carries the command name, arguments, identity material, and any flow binding needed to authorize the command.

A repository command envelope answers three questions:

Session Request Envelope

After session HELLO, repository session commands are sent as Seal packets. API values starting with 🖧 are protocol commands.

🖧: S.<hash>.H3
Seal-By: <client-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <group>
API: 🖧<COMMAND>
Key: <key-with-session>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>

<args>

The Key format selects the authentication scheme:

Scheme Group Key Principal
Ring1 repo <repo>/<ring1>/<session-id> Ring1 member or built-in anyone
Ring2 <target-group> <repo>/<session-id> Ring2 group member or non-member runtime path
Anyone repo <repo>/anyone/<session-id> Ring1 anyone

Rules:

Ring1 Session Envelope

Ring1 request form:

🖧: S.<hash>.H3
Seal-By: <member-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/<ring1-name>/<session-id>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>

<args>

Rules:

Anyone Session Envelope

Anyone request form:

🖧: S.<hash>.H3
Seal-By: <client-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/anyone/<session-id>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>

<args>

Rules:

Ring2 Session Envelope

Ring2 request form:

🖧: S.<hash>.H3
Seal-By: <member-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <target-group>
API: 🖧<COMMAND>
Key: <repo-name>/<session-id>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>

<args>

Rules:

Message Request Envelope

Repository message flow processes one complete request packet and returns one complete response packet. It does not create or use a connection-local session.

Non-HELLO message requests are Seal packets with the explicit public message envelope:

🖧: S.<hash>.H3
Seal-By: <ephemeral-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: message/anyone
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>

<args>

Rules:

Message requests are replayable by design. Use them for public reads and packet-authorized admission.

Trusted Local Null Envelope

The trusted Null command envelope is for local object-capability endpoints. It is not a public network envelope and is not accepted by ordinary repository service listeners.

Request packet form:

🖧: 0.H3
API: 🖧GET
Data-Length: <len>

<args>

Rules:

Response shape:

Trusted Null endpoint HELLO responses include:

🖧: 0.H3
Command-Flow: message
Seal-By: 0
Format: H3
Allow-Null-Command: 1
Storage-Backend: indexeddb
Schema-Version: 2
Message-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧STORE 1
Extension: store-top-level-blob
Status: ok
Data-Length: 0

Top-level Blob STORE is a local trusted-envelope extension for browser-local chunk storage and content-addressed caching. Repository service policy may still reject client-written top-level Blob packets on authenticated session flow.

Command Responses

Successful session-flow responses are Seal packets signed by the repo verifier.

🖧: S.<hash>.H3
Seal-By: <repo-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/<session-id>
TAI: <response-tai>
🖧: B.<hash>.H3
Data-Length: <len>

<response-data>

Message-flow responses use the transport’s one-response mapping. Successful repository HTTP and UDP commands return raw packet bytes for 🖧GET and Null or command-defined response packets for other commands. Errors are Null packets as defined in 030.

HPPR Repository Session Flow

Tags: repo, command-flow, session

© R.A.Sol

The repository session flow is the authenticated command flow for long-lived repository connections.

It extends command messages with a connection-bound HELLO state, authenticated Seal request envelopes, repository identity metadata, and ACL enforcement.

Session Lifecycle

Repository session flow requires connection-bound greeting state before ordinary authenticated commands.

Repository HELLO Response

The repository service adds service-specific headers to the generic HELLO response. TCP, WebSocket, and Unix-socket session-flow HELLO responses are Null packets:

🖧: 0.H3
Command-Flow: session
Session-ID: <session-id>
Repo-Name: <repo-name>
Seal-By: <repo-verifier>
[PHC: $argon2id$v=19$m=<m>,t=<t>,p=<p>$]
Format: H3
[Transport: <via> [hints...]]*
Session-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧HEADERS 1 | 🖧LIST 1 | 🖧STORE 1 | 🖧ADD 1 | 🖧WATCH 1 | 🖧TIPS 1 | 🖧DETACH 1 | 🖧AUDIT 1 | 🖧MEMBERS 1 | 🖧INGEST 1 | 🖧EXCHANGE 1 | 🖧STREAM_PUB 1 | 🖧STREAM_SUB 1
Allow-Null-Command: 0
Limit: max-header-line 1024
Limit: max-extra-headers 512
Status: ok
Uptime: <seconds>
[Hpprd-Version: <version>]
Hpprd-Backend: <backend>
Data-Length: 0

QUIB carries a Null HELLO payload in the encrypted transport handshake instead of requiring a HELLO round trip. That handshake payload contains only the shared capability headers:

🖧: 0.H3
Command-Flow: session
Repo-Name: <repo-name>
Seal-By: <repo-verifier>
[PHC: $argon2id$v=19$m=<m>,t=<t>,p=<p>$]
Format: H3
[Transport: <via> [hints...]]*
Session-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧HEADERS 1 | 🖧LIST 1 | 🖧STORE 1 | 🖧ADD 1 | 🖧WATCH 1 | 🖧TIPS 1 | 🖧DETACH 1 | 🖧AUDIT 1 | 🖧MEMBERS 1 | 🖧INGEST 1 | 🖧EXCHANGE 1 | 🖧STREAM_PUB 1 | 🖧STREAM_SUB 1
Allow-Null-Command: 0
Data-Length: 0

Additional header meanings:

Header Status Meaning
Command-Flow required session for repository session flow
Session-ID required in session HELLO, absent from QUIB handshake payload Connection-bound repository session token
Repo-Name required Repository identifier. Default is localhost
Seal-By required Repo verifier derived from the local operational ring0 signing secret, or 0 before bootstrap
PHC optional Argon2id parameters for Ring1 token derivation; clients use defaults when absent
Format required Packet and envelope format identifier; value H3
Session-Commands repeated Session-flow command list from 032
Allow-Null-Command required 0 for repository session flow; non-HELLO Null commands are not accepted
Transport repeated Advertised transport via string plus endpoint hints
Limit implementation extension Repo limits as <name> <value>
Status implementation extension Daemon status; ok indicates readiness
Uptime implementation extension Daemon uptime in seconds
Hpprd-Version optional implementation extension Daemon build/version string
Hpprd-Backend implementation extension Storage backend name

On QUIB, the repository service derives Session-ID from transport keying material and formats it as Q#<b64a>. The derived value is connection state, not a header in the handshake payload. On TCP, WebSocket, and Unix-socket transports, the repository service uses a repository-generated TAI session id and sends it as Session-ID.

Authenticated HELLO

After initial greeting, an authenticated 🖧HELLO request returns the same session HELLO Null response shape and refreshes endpoint status and capabilities. No ACL check is applied. Any authenticated identity may send 🖧HELLO.

Repo Identity

The repository’s verifier is stored at:

//repo/admin/identity//root/|

It is a self-signed Seal. Repo-Name in that identity is returned in HELLO.

Accepted Envelopes and Responses

Session flow accepts the Ring1, Ring2, and anyone session envelopes defined in 042. Non-HELLO Null command packets and public message envelopes are rejected on repository session listeners.

Successful session responses are Seal packets signed by the repo verifier, also defined in 042.

Command Authorization

Repository commands require authentication on session flow and are subject to ACL evaluation per 050. Command semantics and authorization mapping are defined in 041.

Repository Errors

In addition to the generic error types from 030, the repository service uses:

HPPR Repository Message Flow

Tags: repo, command-flow, message

© R.A.Sol

Repository message flow processes one complete request packet and returns one complete response packet. It does not create or use a connection-local session.

Message requests are replayable by design. Use them for public reads and packet-authorized admission.

Accepted Envelopes

Non-HELLO message requests use the public message Seal envelope defined in 042:

Group: repo
API: 🖧<COMMAND>
Key: message/anyone

The server resolves read identity as Ring1 anyone and applies anyone policy. Session envelopes and trusted local Null command envelopes are rejected on repository message-flow listeners.

HTTP /hppr

HTTP is a repository message-flow endpoint. The request body is one complete HPPR request packet and the response body is one complete HPPR response packet. HTTP transport behavior is defined in 034.

Default commands:

🖧STORE, 🖧ADD, 🖧DETACH, 🖧TIPS, 🖧MEMBERS, 🖧EXCHANGE, 🖧WATCH, 🖧AUDIT, 🖧STREAM_PUB, and 🖧STREAM_SUB are not accepted on the default HTTP message flow.

HTTP HELLO advertises endpoint-specific commands and includes these metadata headers:

🖧: 0.H3
Command-Flow: message
Repo-Name: <repo-name>
Seal-By: <repo-verifier>
Format: H3
Transport: tcp:4777 flow=session
Transport: quib:4776 flow=session
Transport: http:4778 flow=message path=/hppr
Message-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧HEADERS 1 | 🖧LIST 1 | 🖧INGEST 1
Allow-Null-Command: 0
Status: ok
Data-Length: 0

Repository message flow uses the public message Seal envelope for non-HELLO commands. It does not accept trusted local Null command envelopes.

UDP

Repository UDP is a stricter datagram message-flow subset. UDP transport behavior is defined in 035.

UDP accepts only:

UDP does not accept 🖧HELLO, 🖧LIST, 🖧INGEST, 🖧STORE, or stream commands. Other HELLO responses advertise it as:

Transport: udp:<port> flow=message

Oversized responses return TOO_LARGE when possible.

Flow-specific Command Notes

Command semantics are defined in 041. 🖧INGEST uses the submitted packet signer as authority; Ring2 validation rules are specified in 052.

🖧STORE remains session flow only because STORE authorizes the request principal rather than the submitted packet signer.

Repository Identity Text

Tags: repo, auth, client

© R.A.Sol

Repository clients use identity text to select request authentication in CLI flags, SDKs, and local route-auth records.

This grammar is repository-service-specific. It is not generic HPPR packet syntax.

Forms

Rules:

Local route-auth records SHOULD store non-contextual explicit identities. Local route-auth records SHOULD store operational signing-secret form rather than raw password form.

Ring1 password derivation is defined in 051. Ring2 adhoc member verifier derivation is defined in 052.

HPPR Repository Access Control

Tags: repo, auth, policy

© R.A.Sol

ACL rules are defined per repository identity.

Each rule targets a coordinate prefix and controls three operations:

Rule evaluation uses longest-prefix match with per-operation inheritance.

Operations

Rule Format

Rule syntax:

<ops> <coordinate-prefix>

<ops> is exactly three characters:

[r|d|.][w|d|.][l|d|.]

Meaning:

Examples:

ACL-Rule: rwl //u/chess//
ACL-Rule: r.l //u/mail//
ACL-Rule: rdl //u/market//
ACL-Rule: .w. //u/market//nl/eindhoven/

Common patterns:

Prefix Forms

ACL prefixes are parsed coordinates or coordinate-tree prefixes. They are not raw string prefixes. Matching compares group, API segments, the API/Key boundary, Key segments, and version-selector components as coordinate tree components.

Common forms:

Prefix Meaning
//g/ all APIs in group g
//g/chat/ API subtree under chat
//g/chat// all Keys in exact API chat
//g/chat//rooms/ Key subtree under rooms
//g/chat//rooms/7/| exact Key version root

//g/chat//x does not match //g/chatty//x. //g/a//b does not match //g/a/b//c.

Rule Ordering

Rules MUST be stored in canonical sorted order.

Sort by parsed coordinate-prefix components:

  1. group
  2. API segments
  3. API/Key boundary marker
  4. Key segments
  5. version selector components

Within each component list, sort bytewise by UTF-8 bytes. A version boundary sorts before a child segment at the same Key.

Resolution

Given a request coordinate:

  1. Parse the request coordinate.
  2. Find the longest matching parsed rule prefix.
  3. For each operation, apply explicit allow or deny when present.
  4. For . values, continue to the next-longest matching rule.
  5. If no explicit decision is found, deny.

For read and write checks, evaluate against the packet versioned coordinate.

Prefix examples:

Prefix Matches
//u/a//README.md/| exact README.md Key version root
//u/a//README.md/ README.md and children
//u/a//README.md also README.md-draft

Policy Storage

Rules are stored as ACL-Rule headers in policy packets.

Policy coordinate depends on identity scheme:

Policy packets carry only ACL-Rule headers. Auth-config headers and member headers are invalid in policy packets.

HPPR Ring1 Repository Authentication

Tags: repo, auth

© R.A.Sol

Ring1 is the repository-auth scheme. Ring1 requests are Seals signed by a Ring1 member verifier and carried in the Ring1 session envelope defined in 042.

The signing secret can be derived from a password or set up explicitly.

Request Envelope

Ring1 uses:

Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/<ring1-name>/<session-id>
Seal-By: <member-verifier>

Rules:

Built-in Ring1 Names

Two names are repository-service built-ins:

Built-in existence is repository-service behavior. Policy for both built-ins lives in policy packets. Other Ring1 names are configured through the packet families below.

Ring1-Name constraints for any name:

Packet Families

Ring1 auth, membership, and policy are in separate packet families. All three are signed by the repo verifier.

All Ring1 packet families use:

Auth Config

Coordinate: //repo/admin/ring1//<name>/auth/|

Required:

Optional:

Validation:

Members

Coordinate: //repo/admin/ring1//<name>/members/|/seal/<repo-verifier>

Required:

Validation:

Member carries a verifier. Password-derived membership uses Ring1-Secret-Token from the auth config packet for derivation parameters.

Policy

Coordinate: //repo/admin/ring1//<name>/policy/|

Required:

Validation:

ACL-Rule format and evaluation are defined in 050.

Operational Signing Material

The repo-owned signing secret lives in local operational storage, not in a canonical auth packet family.

The public repo verifier is derived from that local signing secret and maintained in //repo/admin/identity//root/|.

Auth, member, and policy packets are signed by the repo verifier. They do not carry secret material and are not the canonical source of repo signing-secret state.

Secret Token Derivation

Ring1-Secret-Token format:

<derived-token> <original-secret>

Split on first ASCII space.

Client derives <derived-token> using Argon2id with HELLO PHC. Repo does not recompute Argon2id. Repo uses <derived-token> directly.

Argon2id:

Then HSB3 signing secret derivation input is:

<derived-token>/<ring1-name>/<repo-verifier>

Pre-ACL Defaults

These apply before policy-packet evaluation and are final. They are repository-service runtime code, not packets.

Request/reply provisional access for join workflows is also runtime code, not packetized auth state.

Watch/Reload Trigger Map

Packet coordinate Effect
//repo/admin/identity//root/| refresh repo identity; refresh repo verifier view
//repo/admin/ring1//<name>/auth/| reload Ring1 auth-config cache for <name>
//repo/admin/ring1//<name>/members/|/seal/<repo-verifier> reload Ring1 membership/auth cache for <name>
//repo/admin/ring1//<name>/policy/| reload ACL snapshot; apply ACL changes to active WATCH streams

Load and Evaluation Order

  1. parse the repository request envelope
  2. read auth config from //repo/admin/ring1//<name>/auth/|
  3. resolve membership from //repo/admin/ring1//<name>/members/|/seal/<repo-verifier>
  4. derive or verify member verifier; produce authenticated principal or reject
  5. load policy from //repo/admin/ring1//<name>/policy/|
  6. evaluate read / write / list per 050
  7. workflow packets under //repo/admin/request//... are ordinary stored packets subject to policy, not auth-config state

Ring1-only Commands

These commands require Ring1 ring0 authentication:

🖧ADD may use Seal-By: ring0 packet creation mode only with Ring1 ring0 authentication. Command details are defined in 041.

Errors

Common Ring1 failures:

Security

Ring1 expects encrypted transport for confidentiality. Replay resistance uses HELLO-bound session IDs in request Key.

HPPR Ring2 Group Authentication

Tags: repo, auth

© R.A.Sol

Ring2 is group-based authentication. Signer authorization is based on membership in the target group. Ring2 requests use the Ring2 session envelope defined in 042.

Request Envelope

Ring2 uses:

Group: <target-group>
API: 🖧<COMMAND>
Key: <repo-name>/<session-id>
Seal-By: <member-verifier>

Rules:

Packet Families

Ring2 auth, membership, and policy are in separate packet families.

Auth Config

Coordinate: //<group>/admin/ring2//auth/|/seal/<repo-verifier>

Signed by repo verifier.

Required:

Optional:

Validation:

Members

Coordinate: //<group>/admin/members//root/|/seal/<verifier>

Multiple packets may exist under different signers and versions.

Required (at least one of):

Validation:

Policy

Coordinate: //<group>/admin/ring2//policy/|/seal/<repo-verifier>

Signed by repo verifier.

Required:

Validation:

ACL-Rule format and evaluation are defined in 050. Each ACL-Rule coordinate must start with //<group>/.

Adhoc Member Verifiers

Clients MAY derive a Ring2 member verifier locally from:

Rules:

Contextual form:

This is a client-side derivation convention only. Server behavior is unchanged.

Membership Config Detail

Supported headers in member packets:

Member

Adds one member verifier plus optional tags.

Member: <verifier> [<tags>...]

Member-Delegate

Delegates membership from another config source. Pipe separator | is required.

Member-Delegate: [<group>]|[<verifier>[/<tai>/<hash>]] [<mods>...]

Defaults:

Pinned form:

Modifier:

Tag modifiers:

Traversal is depth-first with max depth 8.

Watch/Reload Trigger Map

Packet coordinate Effect
//<group>/admin/ring2//auth/|/seal/<repo-verifier> reload Ring2 auth-config cache for <group>
//<group>/admin/members//root/|/seal/<verifier> reload group membership cache; revalidate active Ring2 WATCH subscribers for that group
//<group>/admin/ring2//policy/|/seal/<repo-verifier> reload ACL snapshot; apply ACL changes to active WATCH streams

Load and Evaluation Order

  1. parse the repository request envelope
  2. read auth config from //<group>/admin/ring2//auth/|/seal/<repo-verifier>
  3. resolve membership from //<group>/admin/members//root/|/seal/<verifier>
  4. verify member verifier; produce authenticated principal or enter non-member runtime path
  5. load policy from //<group>/admin/ring2//policy/|/seal/<repo-verifier>
  6. evaluate read / write / list per 050
  7. workflow packets under //<group>/admin/request//... are ordinary stored packets subject to policy, not auth-config state

🖧INGEST Ring2 Admission

🖧INGEST uses the submitted Seal’s signer as packet authority.

Validation:

  1. Payload must be a complete full top-level Seal.
  2. The embedded Plex Group selects the Ring2 group.
  3. The submitted Seal Seal-By must resolve through current Member / Member-Delegate expansion for that group.
  4. The Ring2 auth config must exist, be valid, and not be expired.
  5. The Ring2 policy must grant write on the exact submitted Seal coordinate: //<group>/<api>//<key>/|/seal/<seal-by>/<tai>/<seal-hash>.

Ring2 INGEST never uses the non-member runtime path and never falls back to Ring1 anyone ACL rules. A non-member signer is rejected even if public anyone policy would allow writing the target coordinate.

🖧MEMBERS

Returns expanded member list with tags.

Payload is a // URC.

Shorthand:

Response:

WATCH

WATCH events are filtered by list permission per 050. ACL changes to group auth, member, or policy packets take effect on active streams immediately. No reconnect needed.

Errors

Common Ring2 failures:

Filesystem Repository

Tags: repo, storage

© R.A.Sol

This spec defines filesystem storage for HPPR packets.

It follows packet rules in 010-PACKETS.md and address rules in 020-URC.md.

Repository Layout

repo/
├── hash/<Type>/<hh>/<tail>.H3
├── ref/B/<hh>/<tail>/...
├── ref/P/<hh>/<tail>/...
├── index/<group>/<api...>/||/<key...>/|/...
├── detach/<hash>
└── .tmp/

Filesystem requirements:

Hash Storage (hash/)

Path form:

hash/<T>/<hh>/<tail>.H3

Where:

Storage format:

Blob file size defines Data-Length during reconstruction.

Index Storage (index/)

Coordinate syntax uses //<group>/<api>//<key>. Filesystem storage does not store the second // as an empty path component. It maps the API/Key boundary to ||, which is forbidden in API and Key segments because | is forbidden.

Plex path:

index/<group>/<api...>/||/<key...>/|/plex/<tai>/<hash>

Seal path:

index/<group>/<api...>/||/<key...>/|/seal/<verifier>/<tai>/<hash>

Examples:

Coordinate Index prefix
//u/a//b/c index/u/a/||/b/c/|/
//u/a/b//c index/u/a/b/||/c/|/
//u/a//seal index/u/a/||/seal/|/

Rules:

LIST Mapping

LIST over the API tree reads children before ||.

LIST target Filesystem view
//<group>/ children of index/<group>/
//<group>/<api>/ children of index/<group>/<api...>/ before ||
//<group>/<api>// children of index/<group>/<api...>/||/
//<group>/<api>//<key>/ children of index/<group>/<api...>/||/<key...>/ before |
//<group>/<api>//<key>/|/ children of index/<group>/<api...>/||/<key...>/|/

When an exact API has a Key tree, LIST of that API prefix includes // as the API/Key boundary marker. When an exact Key has versions, LIST of that Key prefix includes |/ as the version boundary marker.

The filesystem names || and | are not returned directly by LIST except as these coordinate markers.

Back-Reference Storage (ref/)

Blob to Plex references:

ref/B/<hh>/<tail>/<plex-hash>

Plex to Seal references:

ref/P/<hh>/<tail>/<seal-hash>/<verifier>

These support reverse traversal from inner to outer packet.

Store Flow

  1. Write Blob raw bytes to hash/B/....
  2. For Plex:
    • write thin Plex to hash/P/...
    • add index/.../|/plex/<tai>/<hash>
    • add ref/B/.../<plex-hash>
  3. For Seal:
    • write thin Seal to hash/S/...
    • ensure embedded Plex and Blob exist
    • add index/.../|/seal/<verifier>/<tai>/<seal-hash>
    • add embedded Plex index entry
    • add ref/B/.../<plex-hash> and ref/P/.../<seal-hash>/<verifier>

Duplicates SHOULD succeed as idempotent writes. Use .tmp/ plus atomic rename for final placement.

Detach Cleanup

When detaching Plex or Seal:

  1. remove index entries
  2. remove matching ref/B/.../<plex-hash>
  3. if that ref/B/... directory becomes empty, record blob hash in detach/
  4. never detach the empty-blob constant hash

Reconstruction

Hash verification requires full reconstructed packet bytes.

Tip Tracking

Tip links are required materialized state for the filesystem repository storage profile. They live under index/.../|/.

Required tip links:

Tip update rule:

Tip Recovery

If a tip link is missing while version directories exist, implementation MUST:

  1. scan affected |/plex/ and |/seal/ once
  2. recompute latest entries
  3. recreate missing tips

If scan finds no packets, empty |/ structure SHOULD be cleaned up.

After detach, recompute tip links for the affected coordinate.

Portability

Tags: packet, content-convention

© R.A.Sol

This spec defines packet-level content conventions that are independent of any repository service.

Generic form:

+Link: <tag> <hash>

Common tags:

Typed links are headers named [Type]+Link. Tools should scan header names containing +Link.

Hash links form a DAG. Cycles are impossible because packet hash includes all header bytes.

Chunked Content Convention

Large content can be split into chunk blobs with a manifest packet.

Manifest detection:

Syntax:

Chunk+Link: <start>..<end> <T>.<hash>.H3

Required header:

Optional headers:

Validation:

Nested manifests use 0-relative ranges in each sub-manifest. Depth limit is 8.

Default chunk size is 32 MiB. Smaller chunks improve random access and increase overhead.

HPPR Replication and Streams

Tags: repo, command, streaming

© R.A.Sol

Repository replication and live streams are repository commands with streaming result modes from 031.

🖧EXCHANGE

🖧EXCHANGE synchronizes packets while preserving repository policy decisions. It has three phases:

  1. announce
  2. transfer
  3. finalize

Phase 1: Announce

Requester sends up to 1024 LF-separated lines:

NEED <versioned-coordinate>
HAVE <versioned-coordinate>

Responder returns FIN or PENDING followed by status lines:

SEND <coord>
DENY <coord>
RECV <coord>
HAVE <coord>

Status meanings:

Phase 2: Transfer

Both peers stream raw packets concurrently in both directions.

Implementations MUST perform bidirectional I/O concurrently. Unidirectional blocking can deadlock the exchange.

Packet boundaries are parsed using Data-Length.

Phase 3: Finalize

When Phase 1 returned PENDING, the responder reports final results for the coordinates that entered Phase 2 transfer (SEND and RECV items):

FIN
OK <coord>
FAIL <coord> <type> <msg>

Phase 1 HAVE and DENY items are already terminal negotiation results and do not appear in Phase 3. OK means the Phase 2 action for that coordinate completed: for SEND, the responder wrote the packet bytes; for RECV, the responder received, validated, and stored the matching packet. FAIL is only used for receive/store failures after a RECV, for example invalid received packet, coordinate mismatch, hash mismatch, storage failure, or stream EOF before the expected packet arrived.

A responder MUST NOT skip a packet promised by Phase 1 SEND and report that missing packet as Phase 3 FAIL. Clients count exact raw Phase 2 packets after SEND; a missing raw packet would make the Phase 3 response packet ambiguous. If a responder cannot write a promised SEND packet, it MUST fail the exchange at the connection level, for example with a FATAL error or close.

Repository Authorization in Phase 1

Authorization for NEED and HAVE is repository-service behavior.

The HPPR Repository Service applies the following ACL rules in Phase 1.

For NEED <coord>:

  1. check read
  2. if readable and exists: SEND
  3. else: DENY

For HAVE <coord>:

  1. check read
  2. if denied: DENY
  3. if allowed and exists: HAVE
  4. if missing, check write
  5. if writable: RECV
  6. else: DENY

Blob-Addressed 🖧EXCHANGE

🖧EXCHANGE also accepts blob hash addressing:

NEED ////B.<hash>.H3
HAVE ////B.<hash>.H3

Rules:

Decision rules:

Transfer still uses full raw blob packets.

🖧STREAM_PUB

🖧STREAM_PUB ingests live trailer-format Seal segments.

Request:

Response:

After OK, connection enters relay mode and accepts trailer segments.

Per segment:

  1. relay bytes to matching 🖧STREAM_SUB subscribers
  2. detect segment close marker
  3. verify hash and signature
  4. store packet
  5. emit 🖧WATCH event

Authorization is repository-service behavior. The HPPR Repository Service checks write per segment at store time.

Disconnect behavior:

No FATAL is injected into relay stream. Subscribers detect truncation via trailer parsing.

Size rule:

Continuity recommendation:

🖧STREAM_SUB

🖧STREAM_SUB subscribes to live trailer bytes by prefix.

Request:

Behavior:

Late joiners receive bytes buffered from current in-flight segment and then continue live.

Authorization is repository-service behavior. The HPPR Repository Service checks read at subscription time.

On publisher disconnect, repo closes subscriber sockets. Mid-segment disconnect yields partial trailer data followed by EOF.

Completed segments remain available via 🖧GET and 🖧EXCHANGE.

Relay Chaining

A downstream repo can relay a live stream by:

  1. subscribing upstream with 🖧STREAM_SUB
  2. publishing downstream with 🖧STREAM_PUB

HPPR Repository Admin and Join Conventions

Tags: repo, workflow

© R.A.Sol

This spec defines repository-service operational conventions: repository bootstrap, request/reply workflow, join flows, and ring0-proxy.

Content route conventions live in 100-CONTENT-ROUTES.md. Packet link and chunk conventions live in 070-LINKS-AND-CHUNKS.md.

Bootstrap

A repository needs only the canonical packet families below to operate. Do not bootstrap convenience scaffolding or workflow placeholders.

Bootstrap sequence:

  1. Load or generate repo-owned signing secret in local operational storage.
  2. Derive repo verifier from that local signing secret.
  3. Write //repo/admin/identity//root/| — self-signed Seal carrying Repo-Name.
  4. Write Ring1 ring0 auth config at: //repo/admin/ring1//ring0/auth/| — signed by repo verifier; Ring1-Name: ring0
  5. Write Ring1 ring0 members at: //repo/admin/ring1//ring0/members/|/seal/<repo-verifier> — at least one initial Member verifier (see Initial Token below)
  6. Write Ring1 ring0 policy at: //repo/admin/ring1//ring0/policy/| — signed by repo verifier; ACL-Rule headers defining ring0 access
  7. Write Ring1 anyone auth config at: //repo/admin/ring1//anyone/auth/| — signed by repo verifier; Ring1-Name: anyone
  8. Write Ring1 anyone policy at: //repo/admin/ring1//anyone/policy/| — signed by repo verifier; ACL-Rule headers for public/unauthenticated access

Do not bootstrap:

Default anyone Policy

ACL-Rule: .w. //repo/admin/request//join/
ACL-Rule: r.l //u/

Initial ring0 Token

The default initial ring0 member derives from token init:

secret = "init/ring0/<repo-verifier>"

signing_secret = derive_secret_from_text(secret)

Implementations MAY accept an explicit bootstrap token at repository creation, for example hpprd --default-password <password> or HPPRD_DEFAULT_PASSWORD. Packaged services that listen on public interfaces MUST use a random explicit bootstrap token instead of init.

Rotate the initial member to durable operator-controlled signing material after first connection.

Request/Reply Convention

Administrative request flows use:

<kind> names the workflow. Join flows use join.

Reply packets are expected to include:

Clients use Request-Status for state. +Link gives exact request linkage.

Workflow packets are ordinary stored packets subject to policy. They are not auth or policy state.

Joining a Repository

Standard Ring1 join flow uses <kind> = join:

  1. user watches reply path: //repo/admin/request//join/<name>/reply/|
  2. user writes request to: //repo/admin/request//join/<name>/|
  3. admin approves or denies in reply packet
  4. if approved, admin creates Ring1 auth config, members, and policy packets
  5. user derives signing material and reconnects

Provisional Access

An anyone request gets provisional read/list access to its matching reply path:

//repo/admin/request//join/<name>/reply/|

<name> must match first segment from request Key.

This is repository-service runtime code, not a packetized permission.

Joining a Group

Ring2 join flow uses <kind> = join:

  1. user watches reply path: //<group>/admin/request//join/<requester-verifier>/reply/|
  2. user writes request to: //<group>/admin/request//join/|/seal/<requester-verifier>
  3. admin approves or denies in reply packet

A common client flow derives <requester-verifier> locally from <group>/<username>/<password> as defined in 052-RING2.md. This works before contacting any repo. The password remains local to the client.

Recommended non-member join ACLs:

ACL-Rule: .w. //<group>/admin/request//join/|/seal/
ACL-Rule: r.l //<group>/admin/request//join/

Request headers:

Ring0-Proxy Convention

Ring1 may request a ring0-mediated action.

Request path:

//repo/admin/ring1//<ring1-name>/🖧<COMMAND>/|

Reply path:

//repo/admin/ring1//<ring1-name>/🖧<COMMAND>/reply/|

Supported commands:

🖧GET is excluded. Use 🖧HEADERS to obtain hash, then fetch blob by hash.

HPPR Content Routes

Tags: scheme, route

© R.A.Sol

This spec defines route and content conventions used by higher-level schemes. They are ordinary packet families stored in repositories.

API Content Pointer Convention

Canonical API content should live under:

//u/apis/<publisher>/<api>//...

Each group publishes its API content pointer at:

//<group>/admin/deploy//<api>/|

Required headers:

Meaning:

Runtime intent:

Clients follow the latest API content pointer only. When Content-Authority changes, content signed by the previous authority is no longer reachable through the API URL.

Group forks are supported by pointing Content-Root to a group-owned subtree instead of the canonical //u/apis/... tree.

Public Route Visibility Convention

Public route browsing is a convention, not a core repository-policy requirement.

For a namespace or API intended to be publicly browsable:

If these reads are denied, canonical public route lookup or deploy-pointer lookup fails and the namespace is not publicly browsable.

HPPR Schemes

Tags: scheme, route, name, attest

© R.A.Sol

This spec defines standard schemes that sit above the HPPR packet, wire, and repository service specs:

These schemes are conventions. They use ordinary HPPR packets and ordinary repo commands.

Route discovery maps public or local route records to upstream repositories and content authorities. Authority-local names define stable identity names under a group. Attestations publish signed statements about verifiers or names.

Terms

Common Conditional Headers

Packets defined in this spec MAY include repeated conditional headers after that packet family’s required semantic headers. A packet is valid only while all of its conditions hold.

Headers:

Rules:

Hierarchical Public Group Route Discovery

Public group routing starts at the unnamed public root under //u/route/group//.

The root delegates top-level labels. Each resolved authority group then delegates its own immediate child labels. API routing stays explicit at the final resolved group.

Canonical roots:

Examples:

Group-name Model

Public group names use dotted suffix hierarchy for discovery only.

Examples:

Each delegation step uses one immediate child label only. Canonical records do not repeat or reverse the full suffix.

Full group-name reconstruction:

Child-label Rules

Each child label:

Provisioning

A route-capable client is provisioned out of band with:

Child-group Records

Canonical coordinate for top-level eu:

//u/route/group//eu/|/seal/<u-route-verifier>

Canonical coordinate for lab.eu under eu:

//eu/route/group//lab/|/seal/<eu-route-verifier>

Canonical coordinate for research.lab.eu under lab.eu:

//lab.eu/route/group//research/|/seal/<lab.eu-route-verifier>

Packet form:

🖧: S.<hash>.H3
Seal-By: <parent-route-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <parent-group>
API: route/group
Key: <child-label>
TAI: <tai>
Upstream: <via>
Route-Authority-Key: <child-route-verifier>
[Upstream-Verifier: <repo-verifier>]
[Home-API: <api>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0

Rules:

API Records

Canonical coordinate for API chat in group u:

//u/route/api//chat/|/seal/<u-route-verifier>

Canonical coordinate for API docs in group lab.eu:

//lab.eu/route/api//docs/|/seal/<lab.eu-route-verifier>

Packet form:

🖧: S.<hash>.H3
Seal-By: <group-route-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <group>
API: route/api
Key: <api>
TAI: <tai>
[Upstream: <via>]
[Upstream-Verifier: <repo-verifier>]
[Content-Authority: <content-verifier>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0

Rules:

After route resolution selects an API record, API content resolution continues through the deploy-pointer convention in [100-CONTENT-ROUTES.md].

Group Landing API Convention

Groups commonly expose one public landing API.

Convention:

Resolution Rules

To resolve direct root API //u/chat//...:

  1. connect to the public-root endpoint
  2. fetch //u/route/api//chat
  3. verify Seal with a trusted root route authority verifier
  4. use the API record’s endpoint and optional pins
  5. continue with the API deploy-pointer resolution defined in [100-CONTENT-ROUTES.md]

To resolve group landing page //lab.eu:

  1. connect to the public-root endpoint
  2. fetch //u/route/group//eu
  3. verify Seal with a trusted root route authority verifier
  4. connect to eu upstream
  5. fetch //eu/route/group//lab
  6. verify Seal with trusted eu Route-Authority-Key
  7. read Home-API when present, else fall back to home
  8. continue as //lab.eu/<home-api>//index.html

To resolve //lab.eu/docs//...:

  1. connect to the public-root endpoint
  2. fetch //u/route/group//eu
  3. verify Seal with a trusted root route authority verifier
  4. read Upstream, Route-Authority-Key, and optional repo pin for group eu
  5. connect to eu upstream
  6. fetch //eu/route/group//lab
  7. verify Seal with trusted eu Route-Authority-Key
  8. read Upstream, Route-Authority-Key, and optional repo pin for group lab.eu
  9. connect to lab.eu upstream
  10. fetch //lab.eu/route/api//docs
  11. verify Seal with trusted lab.eu Route-Authority-Key
  12. apply API-level Upstream or repo pin overrides when present
  13. resolve the API deploy pointer at //lab.eu/admin/deploy//docs/| as defined in [100-CONTENT-ROUTES.md]
  14. fetch content from the selected content root

Generic algorithm for a public group with labels:

Local Route Plane

The route scheme also defines a local effective route plane in the home repo.

Canonical roots:

All local route-plane packets use:

For this section, <local-route-authority-verifier> is the currently trusted verifier for the local route plane.

This spec does not require one canonical storage source for that verifier. Repository-service clients commonly use the Seal-By of //repo/admin/identity//root/|, but other clients or local implementations may provision it independently.

These packets are private client-side policy. They are not public namespace authority records.

Local exact-group records

Canonical coordinate:

Packet form:

🖧: S.<hash>.H3
Seal-By: <local-route-authority-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: route/group
Key: <exact-group>
TAI: <tai>
Upstream: <via>
Route-Authority-Key: <verifier>
[Upstream-Verifier: <repo-verifier>]
[Home-API: <api>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0

Rules:

Meaning:

The local plane stores exact groups, not delegation edges.

Local exact-API records

Canonical coordinate:

Packet form:

🖧: S.<hash>.H3
Seal-By: <local-route-authority-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: route/api
Key: <group>/<api>
TAI: <tai>
[Upstream: <via>]
[Upstream-Verifier: <repo-verifier>]
[Content-Authority: <content-verifier>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0

Rules:

Meaning:

Local auth records

Local route auth attaches an identity choice to routed access. Public route records do not carry auth data.

Canonical coordinates:

Packet form:

🖧: S.<hash>.H3
Seal-By: <local-route-authority-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: route/auth
Key: <group>[/<api>]
TAI: <tai>
Auth: <identity-text>
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0

Rules:

Meaning:

Auth: anyone is valid and can explicitly override a non-anonymous group default for one API.

Any non-anyone Auth text is outside generic HPPR scheme semantics. Repository-service clients commonly use the identity-text forms defined in 045-IDENTITY-TEXT.md.

Effective Route Resolution

Effective resolution uses both the public route plane and the local route plane.

For target //<group>/<api>//..., effective resolution proceeds in this order.

Step 0: explicit endpoint override

If the input includes explicit via or CLI --via, that wins.

This bypasses stored endpoint selection. It does not erase separately stored local auth or content metadata that the caller may still apply.

Step 1: local exact-API candidate

Check:

If present, record it as a local exact-API candidate. Do not merge fields yet.

Step 2: determine the effective root anchor

If //repo/route/group//u/| exists, effective mode uses it as the root anchor. Otherwise effective mode starts from the provisioned public root.

Step 3: walk exact groups from root to target

Split the group into dotted labels and reconstruct exact groups from right to left.

Example for research.ops.lab.eu:

For each exact group in order:

  1. check local exact-group anchor:
    • //repo/route/group//<exact-group>/|
  2. if present:
    • use it as the effective anchor for that exact group
    • it shadows the canonical public answer for that exact group
    • descendant public lookup continues from this local anchor’s Route-Authority-Key
  3. otherwise:
    • fetch the canonical public child-group record under the current parent namespace
    • verify it using the current parent anchor’s Route-Authority-Key
    • use that public record as the effective anchor for the exact group

Step 4: resolve the API record

After the final exact-group anchor is known:

  1. read local exact-API candidate when present
  2. attempt canonical public API record:
    • //<group>/route/api//<api>
    • verified with the final exact-group anchor Route-Authority-Key
  3. for non-u groups, allow canonical Content-Authority fallback from:
    • //u/route/api//<api>

Content-Authority fallback applies only to Content-Authority. It never applies to Upstream.

Step 5: allow terminal local exact-API bootstrap

If no effective exact-group chain exists for the target group, a local exact-API record may still be sufficient.

In that case:

Step 6: effective field merge

API-level values override group-level values. Local values override public values at the same level.

Effective endpoint:

  1. local API Upstream
  2. public API Upstream
  3. local exact-group Upstream
  4. public exact-group Upstream
  5. failure if nothing resolves

Effective upstream repo verifier:

  1. local API Upstream-Verifier
  2. public API Upstream-Verifier
  3. local exact-group Upstream-Verifier
  4. public exact-group Upstream-Verifier

Effective content authority:

  1. local API Content-Authority
  2. public API Content-Authority
  3. for non-u groups only, canonical fallback to //u/route/api//<api>

Effective home API:

  1. local exact-group Home-API
  2. public exact-group Home-API
  3. implementation fallback home

Step 7: local auth attachment

After the effective route target is known, attach local auth in this order:

  1. //repo/route/auth//<group>/<api>/|
  2. //repo/route/auth//<group>/|
  3. implicit default anyone

Step 8: route client construction

The effective route client uses:

Canonical Route Resolution

Canonical resolution ignores all //repo/route/...//... packets.

For public names:

  1. start from the provisioned public root
  2. walk delegated public group edges only
  3. resolve the public API record under the final exact group
  4. apply canonical public Content-Authority fallback from //u/route/api//<api> for non-u groups only

For ~ groups:

Conditions and Canonical Truth

Condition-* evaluation uses canonical resolution, not effective local resolution.

For group u, canonical truth is the current provisioned public-root configuration:

A local //repo/route/group//u/| packet affects only effective local routing. It MUST NOT affect canonical Condition-* truth.

Reason:

Authority-Local Name Tree

Public or private identity naming lives under an authority group.

Canonical root:

//<authority-group>/name//...

Examples:

The same mechanism supports public and private identities. Visibility is controlled by the authority group’s repository policy.

Exact-name Syntax

Text form:

<part>[.<part>...]@<authority-group>

Examples:

The local name parts stay in written order. They are not reversed in storage.

Name-part Rules

Each local name part:

Core Model

The exact identity node is the continuity anchor. Each exact node has:

Top-level nodes are created by the authority group. Child nodes are created by the current holder of the parent node’s Name-Key.

Identity Node Records

Canonical coordinate for ops.alice.phone@lab.eu:

//lab.eu/name//ops/alice/phone/|

Packet form:

🖧: S.<hash>.H3
Seal-By: <authority-or-parent-node-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <authority-group>
API: name
Key: <part>[/<part>...]
TAI: <tai>
State: active|withdrawn|compromised|rotated
Name-Key: <verifier>
[Current-Key: <verifier>]*
[Node-Type: role|person|device|team]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[+Link: supersedes <hash>]
🖧: B.<hash>.H3
Data-Length: <len>

<optional note>

Rules:

Authorization rules:

Continuity rules:

Resolution

To resolve ops.alice.phone@lab.eu:

  1. resolve authority group lab.eu through the route scheme
  2. fetch //lab.eu/name//ops/|
  3. read Name-Key and Current-Key for ops@lab.eu
  4. fetch //lab.eu/name//ops/alice/|
  5. read Name-Key and Current-Key for ops.alice@lab.eu
  6. fetch //lab.eu/name//ops/alice/phone/|
  7. read Name-Key and Current-Key for ops.alice.phone@lab.eu

Exact-name resolution is exact. There is no implicit fallback from ops.alice.phone@lab.eu to ops.alice@lab.eu or ops@lab.eu.

Underspecified UX is handled by listing:

Public Attestation Tree

All attestation packets use:

Packet families:

Scope IDs

<scope-id> lets one issuer publish more than one independent statement for the same target and relation.

Typical values:

state/verifier

state/verifier carries attestation state about one signer verifier.

Canonical coordinate:

//u/attest/state/verifier//<subject-verifier>/<scope-id>/<relation>/|/seal/<issuer-verifier>

Packet form:

🖧: S.<hash>.H3
Seal-By: <issuer-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/state/verifier
Key: <subject-verifier>/<scope-id>/<relation>
TAI: <tai>
State: yes|no|withdrawn
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
[Expires: <tai>]
[Meaning: <text-or-urc>]
[+Link: evidence <hash>]*
[+Link: request <hash>]
🖧: B.<hash>.H3
Data-Length: <len>

<free text note>

Rules:

state/name

state/name carries attestation state about one exact identity name. It does not define names. Names are defined by the name scheme in this spec.

Canonical coordinate:

//u/attest/state/name//<scope-id>/<relation>/<authority-group>/<part>[/<part>...]/|/seal/<issuer-verifier>

Packet form:

🖧: S.<hash>.H3
Seal-By: <issuer-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/state/name
Key: <scope-id>/<relation>/<authority-group>/<part>[/<part>...]
TAI: <tai>
State: yes|no|withdrawn
Target-Name: <part>[.<part>...]@<authority-group>
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
[Expires: <tai>]
[+Link: evidence <hash>]*
🖧: B.<hash>.H3
Data-Length: <len>

<free text note>

Rules:

Relation names are ordinary strings. Common examples:

request

request packets are advisory only. They ask another verifier to publish attestation state.

Canonical coordinate:

//u/attest/request//<target-verifier>/<scope-id>/<relation>/<requester-verifier>/|/seal/<requester-verifier>

Packet form:

🖧: S.<hash>.H3
Seal-By: <requester-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/request
Key: <target-verifier>/<scope-id>/<relation>/<requester-verifier>
TAI: <tai>
[Request-Subject: <subject-verifier>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
[+Link: comment <hash>]
[+Link: profile <hash>]
🖧: B.<hash>.H3
Data-Length: <len>

<short free text request>

Rules:

meaning

meaning explains one relation name in issuer-local human terms.

Canonical coordinate:

//u/attest/meaning//<relation>/|/seal/<issuer-verifier>

Packet form:

🖧: S.<hash>.H3
Seal-By: <issuer-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/meaning
Key: <relation>
TAI: <tai>
Label: <short label>
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
🖧: B.<hash>.H3
Data-Length: <len>

<human-readable explanation>

  1. .H3 names the active format extension: BLAKE3-256 hashing, HSB3 signatures, UTF-8 NFC normalization (Unicode 17.0.0), and this packet structure.↩︎