rttp 0.1.2__tar.gz → 1.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,228 @@
1
+ # Changelog -- `rttp` (Python)
2
+
3
+ All notable changes to the `rttp` package. Format follows
4
+ [Keep a Changelog](https://keepachangelog.com/); versioning is
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ---
8
+
9
+ ## [1.2.7] -- 2026-09-21
10
+
11
+ **Conformance surface grown; wire format untouched.** The shipped
12
+ `rttp/vectors/rttp-conformance-v1.2.6.json` is now 13,460 bytes
13
+ (`sha256 4b743e63...`) and the self-test replays every added case: **83 checks**
14
+ in full, and **80 passed with 3 skipped** on a zero-dependency install -- a check
15
+ that cannot be performed is reported as skipped, never as passed.
16
+
17
+ ### Added
18
+
19
+ * **Nine fail-closed frame cases, one positive frame.** Each of the nine frames
20
+ must be rejected; the positive frame must be accepted with an empty action.
21
+ * **The published Ed25519 envelope vector**, replayed three ways: the canonical
22
+ signing input byte for byte, `AID == SHA-256(public key)`, and the signature
23
+ itself (the third one skips without the optional primitive).
24
+
25
+ ### Changed
26
+
27
+ * **Skipped checks are now counted and printed**, so a default install can no
28
+ longer look like a full pass.
29
+ * Per-section counts are reported: 38 conformance, 16 envelope rules, 22 envelope
30
+ flow, 2 RFC 8032, 5 zero-dependency.
31
+
32
+ ### Note
33
+
34
+ * PyPI and npm carry `1.2.7`; crates.io carries the same code as the pre-release
35
+ `1.2.8-alpha`. The registry version strings differ by publishing policy, not by
36
+ code -- the vectors and their `sha256` are identical everywhere.
37
+
38
+ ## [1.2.6] -- 2026-09-19
39
+
40
+ **Version alignment -- no code change.** Every module, byte layout and
41
+ conformance vector is identical to 0.1.2, and the self-test still reports the
42
+ the same 53 checks (full set, i.e. with the optional Ed25519 backend). Only the version string and the maturity classifier change.
43
+
44
+ ### Changed
45
+
46
+ * **The version number now mirrors the stack version.** PyPI and npm carry
47
+ `1.2.6`, so a single number identifies this code on every distribution
48
+ channel; crates.io carries the same code as the pre-release `1.2.6-alpha`.
49
+ The old `0.1.x` line was a package-maturity number that corresponded to
50
+ nothing in the specification, and it made the same package look like two
51
+ different releases on two registries.
52
+ * **`Development Status` classifier: `3 - Alpha` -> `4 - Beta`.** A
53
+ non-pre-release version must not ship with an "Alpha" classifier; leaving
54
+ the two in conflict invites the question "which one is true?".
55
+ * Install command note: on crates.io every published version of this crate is
56
+ a pre-release, so Cargo will not select it from a plain `rttp` requirement.
57
+ Write `cargo add rttp@1.2.6-alpha` (or pin `rttp = "1.2.6-alpha"`).
58
+
59
+ ## [0.1.2] -- 2026-09-18
60
+
61
+ **Metadata correction -- no code change.** Every module, byte layout and
62
+ conformance vector is identical to 0.1.1, and the self-test still reports the
63
+ the same 53 checks (full set, i.e. with the optional Ed25519 backend).
64
+
65
+ ### Fixed
66
+
67
+ * **The distribution identity now matches the IANA registration.** The package
68
+ was authored as `RTTP Working Group` -- a name that appears in no filing. The
69
+ `rttp` URI-scheme registration on file with IANA (ticket `[IANA #1459939]`)
70
+ names **`RTTP.COM Organization`** as the `Author/Change controller`, and every
71
+ other public surface uses that same name. Both package manifests now say it
72
+ too:
73
+
74
+ | Field | Before | After |
75
+ |:---|:---|:---|
76
+ | `pyproject.toml` -> `authors` (PyPI) | `RTTP Working Group` | **`RTTP.COM Organization`** |
77
+ | `package.json` -> `author` (npm) | `RTTP Working Group` | **`RTTP.COM Organization`** |
78
+
79
+ Package metadata cannot be edited after publication, so 0.1.0 and 0.1.1 keep
80
+ the old string inside their own metadata; this is the version that carries the
81
+ correction. Project pages display the latest version, so the visible author
82
+ name becomes correct once this release is out.
83
+
84
+ ## [0.1.1] -- 2026-09-18
85
+
86
+ **Documentation only -- no code change.** Every module, byte layout and
87
+ conformance vector is identical to 0.1.0, and the self-test still reports the
88
+ the same 53 checks (full set, i.e. with the optional Ed25519 backend).
89
+
90
+ ### Fixed
91
+
92
+ * **A distribution claim that was wrong, not merely outdated.** The 0.1.0 entry
93
+ below said the JavaScript side "will publish under the `@rttp` scope". That
94
+ scope **cannot be created at all**: npm already has a personal account named
95
+ `rttp`, and an organization name may not collide with a user name. The
96
+ JavaScript side is published as **`@aicent/rttp`** -- this project's own
97
+ organization, with the package name itself still just `rttp`.
98
+ * **README distribution table** now names the npm package exactly
99
+ (`@aicent/rttp`), and gives `pip install rttp` for this package, matching the
100
+ table in the JavaScript package's README.
101
+
102
+ ### Distribution status at this release
103
+
104
+ | Registry | Name | State |
105
+ |:---|:---|:---|
106
+ | PyPI | `rttp` | this package -- `pip install rttp` |
107
+ | npm | `@aicent/rttp` | **published 0.1.1** -- 2026-09-18 |
108
+ | crates.io | `rttp` | held by this project |
109
+
110
+ ## [0.1.0] -- 2026-09-17
111
+
112
+ First release. Scope is deliberately narrow: **framing, addressing and sealing**,
113
+ with zero dependencies and no transport.
114
+
115
+ ### Added
116
+
117
+ * **`rttp.pulse_header`** -- `PulseHeader128` codec for the 128-byte
118
+ hardware-aligned frame header (RFC-002 sec. 4.1), including the v1.2.6 extension
119
+ block:
120
+ * `SPEC_REV` `0x66` - `FLAGS` `0x67` - `ACTION_LEN` `0x68` - `ACTION` `0x69`(16B)
121
+ - `RESERVED` `0x79`(7B)
122
+ * bytes `0x00`-`0x65` are **not touched**, `VERSION_ID` stays 130 -- readers
123
+ that only understand the original layout remain conformant
124
+ * `build()` - `build_for_uri()` - `parse()` - `verify()` - `to_hex()` /
125
+ `from_hex()`
126
+ * strict verification (R1-R7): unknown `SPEC_REV` rejected, `SPEC_REV=0` with a
127
+ non-zero block rejected, non-zero `RESERVED` rejected, unknown `FLAGS` bits
128
+ rejected, `ACTION` padding must be zero, `ACTION_LEN` must agree with the
129
+ payload
130
+ * **`rttp.rttp_uri`** -- validation, canonicalisation and `ROUTE_SHARD`
131
+ derivation for `rttp://` URIs (RFC-002 sec. 10.2 / sec. 10.3):
132
+ * `ROUTE_SHARD = SHA-256(ASCII(canonical_authority))[0:16]` -- deterministic,
133
+ pure computation, **no DNS** (sec. 10.5)
134
+ * hash-intent (`8lowhex`) and name-intent forms; open-set `action` vocabulary
135
+ * fail-closed rejection of uppercase, `userinfo`, `port`, `query`,
136
+ `fragment`, multi-segment paths, wrong segment counts, leading/trailing `-`,
137
+ whitespace, and non-`rttp` schemes
138
+ * accepts both `rttp://` and `web+rttp://` -- the second as a **tolerance** for
139
+ the browser protocol-handler form, which RFC-002 no longer defines
140
+ (2026-09-17). Not a conformance claim; see "Known gaps" below.
141
+ * **`rttp.seal`** -- managed profile: HMAC-SHA256 over a pre-shared key table,
142
+ bidirectional switch<->agent signing, `ts|nonce` with a 120-second skew window.
143
+ * **`rttp.seal_asym`** -- **sovereign profile**: Ed25519 seals with
144
+ `AID = SHA-256(public_key)`.
145
+ * self-certifying: the envelope carries the public key, so a verifier
146
+ recomputes the identity instead of trusting a claim -- **no issuance, no
147
+ registry, no directory**
148
+ * `ts` and `nonce` are **inside** the signed input, so they cannot be rewritten
149
+ without breaking the signature
150
+ * freshness enforced by default (`|now - ts| <= 120 s`); archival verification
151
+ available explicitly via `check_freshness=False`
152
+ * lowercase-hex only -- a case variant is rejected, not normalised
153
+ * `generate_keypair()` - `seal()` - `unseal()` - `verify_envelope()` -
154
+ `verify_claims()` - `public_bundle()` - `signing_input()`
155
+ * requires the `ed25519` extra; without it every call raises `SealError` with
156
+ the install instruction rather than degrading to an unsigned path
157
+ * **`rttp.aid`** -- Autonomous Identity derivation (RFC-001), shared by both
158
+ profiles so an AID means one thing across the stack.
159
+ * **`rttp.selftest`** -- `python -m rttp.selftest`, **53 checks with the optional Ed25519 backend (29 by default)**:
160
+ * 25 conformance vectors (6 positive URIs - 15 rejections - 3 deterministic
161
+ frames - 1 `SPEC_REV=0` compatibility vector)
162
+ * RFC 8032 sec. 7.1 TEST 1 / TEST 2, proving the signature backend is standard
163
+ Ed25519 -- so a failure identifies *which* half broke
164
+ * 22 envelope checks, including a 14-case tamper matrix in which every single
165
+ alteration must be rejected, and an explicit replay-window test
166
+ * 4 static-scan checks proving the core modules import nothing outside the
167
+ standard library
168
+ * `--vectors` prints the deterministic envelope vector for the specification;
169
+ `--quiet` prints the summary line only
170
+ * **`rttp/vectors/rttp-conformance-v1.2.6.json`** -- the published vectors, shipped
171
+ as package data so the self-test runs from an installed wheel, offline.
172
+ * Console entry point `rttp-selftest`.
173
+ * **`MANIFEST.in`** -- the source distribution carries `README.md`,
174
+ `CHANGELOG.md`, `LICENSE`, `pyproject.toml` and the published vectors, and
175
+ excludes virtual environments and build noise. Both the wheel and the sdist
176
+ pass `twine check`.
177
+
178
+ ### Notes
179
+
180
+ * **Zero dependencies** in the core, and that is a machine-checked claim rather
181
+ than a promise -- see the static-scan section of the self-test.
182
+ * The reference implementation evaluates the
183
+ **`iqa`** namespace nowhere: this package is the `rttp` protocol only.
184
+ * ~~Distribution: PyPI `rttp`. The npm name `rttp` is held by an unrelated,
185
+ unmaintained project, so the JavaScript side will publish under the `@rttp`
186
+ scope.~~ -- **corrected 2026-09-18.** PyPI `rttp` is now **published** (0.1.0,
187
+ 2026-09-17). The npm name `rttp` is indeed held by an unrelated, unmaintained
188
+ project -- but the **`@rttp` scope cannot be created at all**, because a
189
+ personal account already holds that name. The JavaScript side is therefore
190
+ published as **`@aicent/rttp`**: this project's own organization, with the
191
+ package name still just `rttp`.
192
+
193
+ ### Known gaps
194
+
195
+ Tracked in `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` sec. 8 and sec. 10. Deliberately listed
196
+ here so nobody has to discover them:
197
+
198
+ * No transport and no client. The core encodes, addresses and seals; sending is a
199
+ separate package's job.
200
+ * No revocation, and no key rotation story. Both belong to RFC-003.
201
+ * No replay **cache**: freshness (sec. 3.4) bounds the window, but within it a replayed
202
+ envelope still verifies unless the verifier keeps a short-lived nonce store.
203
+ * No transport-origin binding: the seal proves who signed, not which connection
204
+ delivered it.
205
+ * Rust parity: the published `rttp` crate has no transport layer and no envelope.
206
+ Python and Node are the conforming implementations so far.
207
+ * ~~the browser-registration prefix is accepted because RFC-002 sec. 10.6 requires
208
+ it...~~ -- **superseded 2026-09-17.** That form was removed from both
209
+ specifications and will never be submitted to IANA. `rttp_uri` still accepts it
210
+ as a **tolerance** -- a browser hands the handler that string, and refusing it
211
+ would break the protocol-handler path -- but the specification defines no such
212
+ form, so the acceptance is **outside the specification** and a conforming
213
+ third-party implementation is not required to reproduce it.
214
+ * ~~**Open, and ours to fix:** the published vectors asserted things the
215
+ specification no longer said.~~ -- **resolved 2026-09-18.** The generator now
216
+ classifies every forward case explicitly:
217
+ * `positive_uris` -- each entry carries `tolerance` (boolean) and `note`. The
218
+ case whose `uri` carries the browser-registration prefix is `tolerance: true`,
219
+ with its reason recorded: it is accepted only because that is the scheme name
220
+ under which a handler is registered (RFC-002 sec. 10.6) -- never because the
221
+ specification defines it. It is **not** a conformance claim, and the 25-check
222
+ total is unchanged.
223
+ * `negative_uris` -- the two case-clause citations were corrected from
224
+ `(RFC-002 sec. 10.2)` to **`sec. 10.3`**, the clause that actually carries the
225
+ lowercase rule. sec. 10.2 now appears nowhere in the vector set.
226
+ Regenerated (`SPEC/tools/conformance.py --generate`), replayed (`--check`,
227
+ 25/25), and mirrored byte-identically into both packages. After the change:
228
+ Python self-test 53/53, Node runner 25/25.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rttp
3
- Version: 0.1.2
4
- Summary: RTTP reference implementation: PulseHeader128 framing, rttp:// addressing, and self-certifying Ed25519 seals (RFC-002 §4.1 / §10 / §11).
3
+ Version: 1.2.7
4
+ Summary: RTTP reference implementation: PulseHeader128 framing, rttp:// addressing, and self-certifying Ed25519 seals (RFC-002 sec. 4.1 / sec. 10 / sec. 11).
5
5
  Author: RTTP.COM Organization
6
6
  License-Expression: Apache-2.0
7
7
  Project-URL: Homepage, https://rttp.com/
8
8
  Project-URL: Specification, https://rttp.com/RFC-002/
9
9
  Keywords: rttp,protocol,ai-agents,intent-addressing,uri-scheme,ed25519,conformance
10
- Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python :: 3
@@ -31,35 +31,45 @@ Dynamic: license-file
31
31
  128-byte `PulseHeader128` frame, `rttp://` intent addressing, and self-certifying
32
32
  Ed25519 seals.**
33
33
 
34
- [RFC-002 §4.1](https://rttp.com/RFC-002/) · [§10](https://rttp.com/RFC-002/) · §11 · v1.2.6
34
+ [RFC-002 sec. 4.1](https://rttp.com/RFC-002/) - [sec. 10](https://rttp.com/RFC-002/) - sec. 11 - v1.2.6
35
35
 
36
36
  ---
37
37
 
38
- ## Verify it in one command — no trust required
38
+ ## Verify it in one command -- no trust required
39
39
 
40
40
  ```console
41
41
  $ pip install rttp
42
42
  $ python -m rttp.selftest
43
- rttp 0.1.2 self-test
43
+ rttp 1.2.7 self-test
44
44
  python 3.14.2 on win32
45
45
  ...
46
- [PASS] all 53 checks passed
46
+ [PASS] all 80 checks passed (3 skipped) # default install: the Ed25519 checks are skipped
47
+
48
+ $ pip install rttp[ed25519]
49
+ $ python -m rttp.selftest
50
+ rttp 1.2.7 self-test
51
+ python 3.14.2 on win32
52
+ ...
53
+ [PASS] all 83 checks passed # with the optional Ed25519 backend
47
54
  ```
48
55
 
49
56
  That is the point of this package. A specification is worth exactly what an
50
- independent implementation can reproduce from it — so instead of asking you to
51
- believe a table of numbers, this ships the vectors and replays them locally:
52
-
53
- * **25 conformance checks** — `rttp://` parsing, fail-closed rejections, and the
54
- URI → `ROUTE_SHARD` → 128-byte frame chain, bit for bit.
55
- * **2 RFC 8032 checks** — the Ed25519 backend is shown to be *standard* Ed25519,
57
+ independent implementation can reproduce from it -- so instead of asking you to
58
+ believe a table of numbers, this ships the vectors and replays them locally.
59
+ The 83 checks below are the full set, i.e. with the optional Ed25519 backend
60
+ installed; a default install runs 80 checks and skips 3.
61
+
62
+ * **38 conformance checks** -- `rttp://` parsing, fail-closed rejections, and the
63
+ URI -> `ROUTE_SHARD` -> 128-byte frame chain, bit for bit.
64
+ * **2 RFC 8032 checks** -- the Ed25519 backend is shown to be *standard* Ed25519,
56
65
  not a lookalike, so a failure tells you which half broke.
57
- * **22 envelope checks** — round-trip, self-certification, freshness, and a
58
- 14-case tamper matrix where every alteration must be rejected.
59
- * **4 zero-dependency checks** — a static scan proving the core imports nothing
66
+ * **38 envelope checks** -- 16 rule-layer checks that need no primitive, plus
67
+ round-trip, self-certification, freshness and a 14-case tamper matrix where
68
+ every alteration must be rejected.
69
+ * **5 zero-dependency checks** -- a static scan proving the core imports nothing
60
70
  outside the standard library.
61
71
 
62
- Offline. No account. No network. `[PASS]` or it is not.
72
+ Offline. No account. No network. `[PASS]` or it is not. Every vector file shipped here is listed in `vectors.manifest.json` with its byte count and SHA-256, produced by a generator rather than typed by hand - recompute the hash yourself if you prefer.
63
73
 
64
74
  ---
65
75
 
@@ -73,7 +83,7 @@ pip install rttp[ed25519] # + sovereign-profile seals (Ed25519)
73
83
  Python 3.9+. No compiled extensions in the core.
74
84
 
75
85
  The core deliberately has **no dependencies**. A protocol reference that cannot be
76
- read without resolving a dependency tree is not much of a reference — and an
86
+ read without resolving a dependency tree is not much of a reference -- and an
77
87
  air-gapped reviewer should be able to check the frames.
78
88
 
79
89
  ---
@@ -82,13 +92,13 @@ air-gapped reviewer should be able to check the frames.
82
92
 
83
93
  | Module | What it does | Authority |
84
94
  |:---|:---|:---|
85
- | `rttp.pulse_header` | `PulseHeader128` codec — build / parse / verify the 128-byte hardware-aligned header, including the v1.2.6 extension block at `0x66`–`0x7F` | RFC-002 §4.1 + `SPEC/RTTP-FRAME-EXT-v1.2.6.md` |
86
- | `rttp.rttp_uri` | Validate, canonicalise and derive `ROUTE_SHARD` from an `rttp` URI | RFC-002 §10.2 / §10.3 ABNF |
87
- | `rttp.seal` | **Managed profile** — symmetric HMAC-SHA256 over a pre-shared key table | — |
88
- | `rttp.seal_asym` | **Sovereign profile** — Ed25519, self-certifying, no issuance and no registry | `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` (draft) |
95
+ | `rttp.pulse_header` | `PulseHeader128` codec -- build / parse / verify the 128-byte hardware-aligned header, including the v1.2.6 extension block at `0x66`-`0x7F` | RFC-002 sec. 4.1 + `SPEC/RTTP-FRAME-EXT-v1.2.6.md` |
96
+ | `rttp.rttp_uri` | Validate, canonicalise and derive `ROUTE_SHARD` from an `rttp` URI | RFC-002 sec. 10.2 / sec. 10.3 ABNF |
97
+ | `rttp.seal` | **Managed profile** -- symmetric HMAC-SHA256 over a pre-shared key table | -- |
98
+ | `rttp.seal_asym` | **Sovereign profile** -- Ed25519, self-certifying, no issuance and no registry | `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` (draft) |
89
99
  | `rttp.aid` | Autonomous Identity derivation | RFC-001 |
90
100
 
91
- Plus `rttp.vectors` — the published conformance vectors, shipped inside the wheel
101
+ Plus `rttp.vectors` -- the published conformance vectors, shipped inside the wheel
92
102
  so the self-test works from an installed package with no repository checkout.
93
103
 
94
104
  ---
@@ -106,9 +116,9 @@ parsed["action"] # 'verify'
106
116
  parsed["route_shard"].hex() # 16-byte routing hash, pure computation
107
117
  ```
108
118
 
109
- Addressing is **DNS-free** (RFC-002 §10.5): the routing hash is derived from the
119
+ Addressing is **DNS-free** (RFC-002 sec. 10.5): the routing hash is derived from the
110
120
  authority by SHA-256, so no registry, resolver or network is involved. Malformed
111
- input is rejected rather than normalised — a case variant is not a spelling
121
+ input is rejected rather than normalised -- a case variant is not a spelling
112
122
  difference, it is a different string.
113
123
 
114
124
  ### Build a frame from a URI
@@ -126,9 +136,9 @@ len(raw) # 128
126
136
  pulse_header.verify(raw)["action"] # 'verify'
127
137
  ```
128
138
 
129
- `build_for_uri` performs the mapping RFC-002 §10.4 promises: the URI's authority
139
+ `build_for_uri` performs the mapping RFC-002 sec. 10.4 promises: the URI's authority
130
140
  becomes `ROUTE_SHARD`, its path becomes `ACTION`. Readers that only understand
131
- `0x00`–`0x65` keep working — the extension block occupies bytes that were already
141
+ `0x00`-`0x65` keep working -- the extension block occupies bytes that were already
132
142
  zero, and `VERSION_ID` stays 130.
133
143
 
134
144
  ### Seal with your own identity
@@ -152,7 +162,7 @@ credentials to obtain, and no operator who could refuse to issue them.
152
162
 
153
163
  ## Two profiles, and when each applies
154
164
 
155
- | | **Managed** — `seal` | **Sovereign** — `seal_asym` |
165
+ | | **Managed** -- `seal` | **Sovereign** -- `seal_asym` |
156
166
  |:---|:---|:---|
157
167
  | Primitive | HMAC-SHA256 | Ed25519 |
158
168
  | Key material | pre-shared table | self-generated |
@@ -161,7 +171,7 @@ credentials to obtain, and no operator who could refuse to issue them.
161
171
  | A stranger can participate | no | **yes** |
162
172
  | One leaked key | can forge any peer | forges one identity |
163
173
 
164
- Inside a set of symmetric secrets there is no such thing as a stranger — whoever
174
+ Inside a set of symmetric secrets there is no such thing as a stranger -- whoever
165
175
  holds the shared key can mint anybody's seal. The managed profile is therefore for
166
176
  a closed organism, where a fixed set of roles genuinely do trust each other.
167
177
 
@@ -170,19 +180,19 @@ preference; it is the difference between a private system and a public one.
170
180
 
171
181
  ---
172
182
 
173
- ## Scope — what this package is not
183
+ ## Scope -- what this package is not
174
184
 
175
185
  | | |
176
186
  |:---|:---|
177
- | ✅ **Framing** | Real, and specified. |
178
- | ✅ **Addressing** | Real, and specified. |
179
- | ✅ **Sealing** | Real, and specified (draft). |
180
- | ❌ **Transport** | **Not here.** This package encodes, addresses and seals. It does not open sockets, and there is no `send()` — a client and its transport belong to a separate package, so that the codec stays dependency-free and auditable. |
181
- | ❌ **Routing service** | Not here. `ROUTE_SHARD` is computed locally; delivering a frame to that hash is an operator's job, not the codec's. |
182
- | ❌ **Confidentiality** | Signing is not encryption. |
187
+ | OK **Framing** | Real, and specified. |
188
+ | OK **Addressing** | Real, and specified. |
189
+ | OK **Sealing** | Real, and specified (draft). |
190
+ | NO **Transport** | **Not here.** This package encodes, addresses and seals. It does not open sockets, and there is no `send()` -- a client and its transport belong to a separate package, so that the codec stays dependency-free and auditable. |
191
+ | NO **Routing service** | Not here. `ROUTE_SHARD` is computed locally; delivering a frame to that hash is an operator's job, not the codec's. |
192
+ | NO **Confidentiality** | Signing is not encryption. |
183
193
 
184
194
  **The seal is an envelope around the frame, not bytes inside it.** A reader that
185
- parses only the 128-byte header sees no seal at all — which is why the two
195
+ parses only the 128-byte header sees no seal at all -- which is why the two
186
196
  concerns are specified separately.
187
197
 
188
198
  Unknown revisions, algorithms and malformed input **fail closed** everywhere.
@@ -193,7 +203,7 @@ Nothing in this package is ever accepted because a check could not be performed.
193
203
  ## Conformance vectors
194
204
 
195
205
  `rttp/vectors/rttp-conformance-v1.2.6.json` is generated, not hand-edited. Each
196
- vector is deterministic: fixed sequence numbers, fixed timestamp, fixed AID — so
206
+ vector is deterministic: fixed sequence numbers, fixed timestamp, fixed AID -- so
197
207
  two implementations either agree byte for byte or they do not.
198
208
 
199
209
  The vector set is the intended deliverable for third-party certification: pass it
@@ -207,21 +217,21 @@ needing to trust the authors.
207
217
  | Ecosystem | Name | Status |
208
218
  |:---|:---|:---|
209
219
  | crates.io | `rttp` | held by this project |
210
- | PyPI | `rttp` | **this package** — `pip install rttp` |
211
- | npm | **`@aicent/rttp`** | the unscoped `rttp` name on npm is held by an unrelated, unmaintained 2017 REST helper, and the `rttp` scope cannot be created at all — a personal account already holds that name — so the JavaScript side is published under this project's own organization. The package name itself is still just `rttp` |
220
+ | PyPI | `rttp` | **this package** -- `pip install rttp` |
221
+ | npm | **`@aicent/rttp`** | the unscoped `rttp` name on npm is held by an unrelated, unmaintained 2017 REST helper, and the `rttp` scope cannot be created at all -- a personal account already holds that name -- so the JavaScript side is published under this project's own organization. The package name itself is still just `rttp` |
212
222
 
213
223
  ---
214
224
 
215
225
  ## Specification status
216
226
 
217
- * **`rttp` URI scheme** — submitted to IANA under RFC 7595, ticket **#1459939**,
227
+ * **`rttp` URI scheme** -- submitted to IANA under RFC 7595, ticket **#1459939**,
218
228
  Provisional (First Come, First Served), **under review**. It is **not yet
219
- registered** — as of 2026-09-15 the IANA URI Schemes registry contains no
229
+ registered** -- as of 2026-09-15 the IANA URI Schemes registry contains no
220
230
  `rttp` entry. Please describe it that way.
221
- * **Frame layout** — RFC-002 §4.1, extended by `SPEC/RTTP-FRAME-EXT-v1.2.6.md`.
222
- * **Seal envelope** — `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md`, a **draft**: the format
231
+ * **Frame layout** -- RFC-002 sec. 4.1, extended by `SPEC/RTTP-FRAME-EXT-v1.2.6.md`.
232
+ * **Seal envelope** -- `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md`, a **draft**: the format
223
233
  is implemented and vector-tested, but it is not yet a numbered RFC-002 section.
224
- * **Managed profile** — implementation only; it predates the sovereign profile and
234
+ * **Managed profile** -- implementation only; it predates the sovereign profile and
225
235
  has no standalone specification.
226
236
 
227
237
  Where this package and a specification disagree, **the specification wins and the
@@ -4,35 +4,45 @@
4
4
  128-byte `PulseHeader128` frame, `rttp://` intent addressing, and self-certifying
5
5
  Ed25519 seals.**
6
6
 
7
- [RFC-002 §4.1](https://rttp.com/RFC-002/) · [§10](https://rttp.com/RFC-002/) · §11 · v1.2.6
7
+ [RFC-002 sec. 4.1](https://rttp.com/RFC-002/) - [sec. 10](https://rttp.com/RFC-002/) - sec. 11 - v1.2.6
8
8
 
9
9
  ---
10
10
 
11
- ## Verify it in one command — no trust required
11
+ ## Verify it in one command -- no trust required
12
12
 
13
13
  ```console
14
14
  $ pip install rttp
15
15
  $ python -m rttp.selftest
16
- rttp 0.1.2 self-test
16
+ rttp 1.2.7 self-test
17
17
  python 3.14.2 on win32
18
18
  ...
19
- [PASS] all 53 checks passed
19
+ [PASS] all 80 checks passed (3 skipped) # default install: the Ed25519 checks are skipped
20
+
21
+ $ pip install rttp[ed25519]
22
+ $ python -m rttp.selftest
23
+ rttp 1.2.7 self-test
24
+ python 3.14.2 on win32
25
+ ...
26
+ [PASS] all 83 checks passed # with the optional Ed25519 backend
20
27
  ```
21
28
 
22
29
  That is the point of this package. A specification is worth exactly what an
23
- independent implementation can reproduce from it — so instead of asking you to
24
- believe a table of numbers, this ships the vectors and replays them locally:
25
-
26
- * **25 conformance checks** — `rttp://` parsing, fail-closed rejections, and the
27
- URI → `ROUTE_SHARD` → 128-byte frame chain, bit for bit.
28
- * **2 RFC 8032 checks** — the Ed25519 backend is shown to be *standard* Ed25519,
30
+ independent implementation can reproduce from it -- so instead of asking you to
31
+ believe a table of numbers, this ships the vectors and replays them locally.
32
+ The 83 checks below are the full set, i.e. with the optional Ed25519 backend
33
+ installed; a default install runs 80 checks and skips 3.
34
+
35
+ * **38 conformance checks** -- `rttp://` parsing, fail-closed rejections, and the
36
+ URI -> `ROUTE_SHARD` -> 128-byte frame chain, bit for bit.
37
+ * **2 RFC 8032 checks** -- the Ed25519 backend is shown to be *standard* Ed25519,
29
38
  not a lookalike, so a failure tells you which half broke.
30
- * **22 envelope checks** — round-trip, self-certification, freshness, and a
31
- 14-case tamper matrix where every alteration must be rejected.
32
- * **4 zero-dependency checks** — a static scan proving the core imports nothing
39
+ * **38 envelope checks** -- 16 rule-layer checks that need no primitive, plus
40
+ round-trip, self-certification, freshness and a 14-case tamper matrix where
41
+ every alteration must be rejected.
42
+ * **5 zero-dependency checks** -- a static scan proving the core imports nothing
33
43
  outside the standard library.
34
44
 
35
- Offline. No account. No network. `[PASS]` or it is not.
45
+ Offline. No account. No network. `[PASS]` or it is not. Every vector file shipped here is listed in `vectors.manifest.json` with its byte count and SHA-256, produced by a generator rather than typed by hand - recompute the hash yourself if you prefer.
36
46
 
37
47
  ---
38
48
 
@@ -46,7 +56,7 @@ pip install rttp[ed25519] # + sovereign-profile seals (Ed25519)
46
56
  Python 3.9+. No compiled extensions in the core.
47
57
 
48
58
  The core deliberately has **no dependencies**. A protocol reference that cannot be
49
- read without resolving a dependency tree is not much of a reference — and an
59
+ read without resolving a dependency tree is not much of a reference -- and an
50
60
  air-gapped reviewer should be able to check the frames.
51
61
 
52
62
  ---
@@ -55,13 +65,13 @@ air-gapped reviewer should be able to check the frames.
55
65
 
56
66
  | Module | What it does | Authority |
57
67
  |:---|:---|:---|
58
- | `rttp.pulse_header` | `PulseHeader128` codec — build / parse / verify the 128-byte hardware-aligned header, including the v1.2.6 extension block at `0x66`–`0x7F` | RFC-002 §4.1 + `SPEC/RTTP-FRAME-EXT-v1.2.6.md` |
59
- | `rttp.rttp_uri` | Validate, canonicalise and derive `ROUTE_SHARD` from an `rttp` URI | RFC-002 §10.2 / §10.3 ABNF |
60
- | `rttp.seal` | **Managed profile** — symmetric HMAC-SHA256 over a pre-shared key table | — |
61
- | `rttp.seal_asym` | **Sovereign profile** — Ed25519, self-certifying, no issuance and no registry | `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` (draft) |
68
+ | `rttp.pulse_header` | `PulseHeader128` codec -- build / parse / verify the 128-byte hardware-aligned header, including the v1.2.6 extension block at `0x66`-`0x7F` | RFC-002 sec. 4.1 + `SPEC/RTTP-FRAME-EXT-v1.2.6.md` |
69
+ | `rttp.rttp_uri` | Validate, canonicalise and derive `ROUTE_SHARD` from an `rttp` URI | RFC-002 sec. 10.2 / sec. 10.3 ABNF |
70
+ | `rttp.seal` | **Managed profile** -- symmetric HMAC-SHA256 over a pre-shared key table | -- |
71
+ | `rttp.seal_asym` | **Sovereign profile** -- Ed25519, self-certifying, no issuance and no registry | `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` (draft) |
62
72
  | `rttp.aid` | Autonomous Identity derivation | RFC-001 |
63
73
 
64
- Plus `rttp.vectors` — the published conformance vectors, shipped inside the wheel
74
+ Plus `rttp.vectors` -- the published conformance vectors, shipped inside the wheel
65
75
  so the self-test works from an installed package with no repository checkout.
66
76
 
67
77
  ---
@@ -79,9 +89,9 @@ parsed["action"] # 'verify'
79
89
  parsed["route_shard"].hex() # 16-byte routing hash, pure computation
80
90
  ```
81
91
 
82
- Addressing is **DNS-free** (RFC-002 §10.5): the routing hash is derived from the
92
+ Addressing is **DNS-free** (RFC-002 sec. 10.5): the routing hash is derived from the
83
93
  authority by SHA-256, so no registry, resolver or network is involved. Malformed
84
- input is rejected rather than normalised — a case variant is not a spelling
94
+ input is rejected rather than normalised -- a case variant is not a spelling
85
95
  difference, it is a different string.
86
96
 
87
97
  ### Build a frame from a URI
@@ -99,9 +109,9 @@ len(raw) # 128
99
109
  pulse_header.verify(raw)["action"] # 'verify'
100
110
  ```
101
111
 
102
- `build_for_uri` performs the mapping RFC-002 §10.4 promises: the URI's authority
112
+ `build_for_uri` performs the mapping RFC-002 sec. 10.4 promises: the URI's authority
103
113
  becomes `ROUTE_SHARD`, its path becomes `ACTION`. Readers that only understand
104
- `0x00`–`0x65` keep working — the extension block occupies bytes that were already
114
+ `0x00`-`0x65` keep working -- the extension block occupies bytes that were already
105
115
  zero, and `VERSION_ID` stays 130.
106
116
 
107
117
  ### Seal with your own identity
@@ -125,7 +135,7 @@ credentials to obtain, and no operator who could refuse to issue them.
125
135
 
126
136
  ## Two profiles, and when each applies
127
137
 
128
- | | **Managed** — `seal` | **Sovereign** — `seal_asym` |
138
+ | | **Managed** -- `seal` | **Sovereign** -- `seal_asym` |
129
139
  |:---|:---|:---|
130
140
  | Primitive | HMAC-SHA256 | Ed25519 |
131
141
  | Key material | pre-shared table | self-generated |
@@ -134,7 +144,7 @@ credentials to obtain, and no operator who could refuse to issue them.
134
144
  | A stranger can participate | no | **yes** |
135
145
  | One leaked key | can forge any peer | forges one identity |
136
146
 
137
- Inside a set of symmetric secrets there is no such thing as a stranger — whoever
147
+ Inside a set of symmetric secrets there is no such thing as a stranger -- whoever
138
148
  holds the shared key can mint anybody's seal. The managed profile is therefore for
139
149
  a closed organism, where a fixed set of roles genuinely do trust each other.
140
150
 
@@ -143,19 +153,19 @@ preference; it is the difference between a private system and a public one.
143
153
 
144
154
  ---
145
155
 
146
- ## Scope — what this package is not
156
+ ## Scope -- what this package is not
147
157
 
148
158
  | | |
149
159
  |:---|:---|
150
- | ✅ **Framing** | Real, and specified. |
151
- | ✅ **Addressing** | Real, and specified. |
152
- | ✅ **Sealing** | Real, and specified (draft). |
153
- | ❌ **Transport** | **Not here.** This package encodes, addresses and seals. It does not open sockets, and there is no `send()` — a client and its transport belong to a separate package, so that the codec stays dependency-free and auditable. |
154
- | ❌ **Routing service** | Not here. `ROUTE_SHARD` is computed locally; delivering a frame to that hash is an operator's job, not the codec's. |
155
- | ❌ **Confidentiality** | Signing is not encryption. |
160
+ | OK **Framing** | Real, and specified. |
161
+ | OK **Addressing** | Real, and specified. |
162
+ | OK **Sealing** | Real, and specified (draft). |
163
+ | NO **Transport** | **Not here.** This package encodes, addresses and seals. It does not open sockets, and there is no `send()` -- a client and its transport belong to a separate package, so that the codec stays dependency-free and auditable. |
164
+ | NO **Routing service** | Not here. `ROUTE_SHARD` is computed locally; delivering a frame to that hash is an operator's job, not the codec's. |
165
+ | NO **Confidentiality** | Signing is not encryption. |
156
166
 
157
167
  **The seal is an envelope around the frame, not bytes inside it.** A reader that
158
- parses only the 128-byte header sees no seal at all — which is why the two
168
+ parses only the 128-byte header sees no seal at all -- which is why the two
159
169
  concerns are specified separately.
160
170
 
161
171
  Unknown revisions, algorithms and malformed input **fail closed** everywhere.
@@ -166,7 +176,7 @@ Nothing in this package is ever accepted because a check could not be performed.
166
176
  ## Conformance vectors
167
177
 
168
178
  `rttp/vectors/rttp-conformance-v1.2.6.json` is generated, not hand-edited. Each
169
- vector is deterministic: fixed sequence numbers, fixed timestamp, fixed AID — so
179
+ vector is deterministic: fixed sequence numbers, fixed timestamp, fixed AID -- so
170
180
  two implementations either agree byte for byte or they do not.
171
181
 
172
182
  The vector set is the intended deliverable for third-party certification: pass it
@@ -180,21 +190,21 @@ needing to trust the authors.
180
190
  | Ecosystem | Name | Status |
181
191
  |:---|:---|:---|
182
192
  | crates.io | `rttp` | held by this project |
183
- | PyPI | `rttp` | **this package** — `pip install rttp` |
184
- | npm | **`@aicent/rttp`** | the unscoped `rttp` name on npm is held by an unrelated, unmaintained 2017 REST helper, and the `rttp` scope cannot be created at all — a personal account already holds that name — so the JavaScript side is published under this project's own organization. The package name itself is still just `rttp` |
193
+ | PyPI | `rttp` | **this package** -- `pip install rttp` |
194
+ | npm | **`@aicent/rttp`** | the unscoped `rttp` name on npm is held by an unrelated, unmaintained 2017 REST helper, and the `rttp` scope cannot be created at all -- a personal account already holds that name -- so the JavaScript side is published under this project's own organization. The package name itself is still just `rttp` |
185
195
 
186
196
  ---
187
197
 
188
198
  ## Specification status
189
199
 
190
- * **`rttp` URI scheme** — submitted to IANA under RFC 7595, ticket **#1459939**,
200
+ * **`rttp` URI scheme** -- submitted to IANA under RFC 7595, ticket **#1459939**,
191
201
  Provisional (First Come, First Served), **under review**. It is **not yet
192
- registered** — as of 2026-09-15 the IANA URI Schemes registry contains no
202
+ registered** -- as of 2026-09-15 the IANA URI Schemes registry contains no
193
203
  `rttp` entry. Please describe it that way.
194
- * **Frame layout** — RFC-002 §4.1, extended by `SPEC/RTTP-FRAME-EXT-v1.2.6.md`.
195
- * **Seal envelope** — `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md`, a **draft**: the format
204
+ * **Frame layout** -- RFC-002 sec. 4.1, extended by `SPEC/RTTP-FRAME-EXT-v1.2.6.md`.
205
+ * **Seal envelope** -- `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md`, a **draft**: the format
196
206
  is implemented and vector-tested, but it is not yet a numbered RFC-002 section.
197
- * **Managed profile** — implementation only; it predates the sovereign profile and
207
+ * **Managed profile** -- implementation only; it predates the sovereign profile and
198
208
  has no standalone specification.
199
209
 
200
210
  Where this package and a specification disagree, **the specification wins and the