rttp 1.2.6__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.
- {rttp-1.2.6 → rttp-1.2.7}/CHANGELOG.md +89 -60
- {rttp-1.2.6 → rttp-1.2.7}/PKG-INFO +54 -44
- {rttp-1.2.6 → rttp-1.2.7}/README.md +52 -42
- {rttp-1.2.6 → rttp-1.2.7}/pyproject.toml +3 -3
- {rttp-1.2.6 → rttp-1.2.7}/src/rttp/__init__.py +8 -8
- rttp-1.2.7/src/rttp/aid.py +31 -0
- {rttp-1.2.6 → rttp-1.2.7}/src/rttp/pulse_header.py +49 -60
- {rttp-1.2.6 → rttp-1.2.7}/src/rttp/rttp_uri.py +56 -63
- {rttp-1.2.6 → rttp-1.2.7}/src/rttp/seal.py +16 -16
- rttp-1.2.7/src/rttp/seal_asym.py +486 -0
- {rttp-1.2.6 → rttp-1.2.7}/src/rttp/selftest.py +248 -53
- {rttp-1.2.6 → rttp-1.2.7}/src/rttp/vectors/rttp-conformance-v1.2.6.json +103 -13
- rttp-1.2.6/src/rttp/aid.py +0 -35
- rttp-1.2.6/src/rttp/seal_asym.py +0 -371
- {rttp-1.2.6 → rttp-1.2.7}/LICENSE +0 -0
- {rttp-1.2.6 → rttp-1.2.7}/MANIFEST.in +0 -0
- {rttp-1.2.6 → rttp-1.2.7}/setup.cfg +0 -0
- {rttp-1.2.6 → rttp-1.2.7}/src/rttp.egg-info/SOURCES.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Changelog
|
|
1
|
+
# Changelog -- `rttp` (Python)
|
|
2
2
|
|
|
3
3
|
All notable changes to the `rttp` package. Format follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/); versioning is
|
|
@@ -6,11 +6,40 @@ All notable changes to the `rttp` package. Format follows
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## [1.2.
|
|
9
|
+
## [1.2.7] -- 2026-09-21
|
|
10
10
|
|
|
11
|
-
**
|
|
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
|
|
12
41
|
conformance vector is identical to 0.1.2, and the self-test still reports the
|
|
13
|
-
same 53 checks. Only the version string and the maturity classifier change.
|
|
42
|
+
the same 53 checks (full set, i.e. with the optional Ed25519 backend). Only the version string and the maturity classifier change.
|
|
14
43
|
|
|
15
44
|
### Changed
|
|
16
45
|
|
|
@@ -20,23 +49,23 @@ same 53 checks. Only the version string and the maturity classifier change.
|
|
|
20
49
|
The old `0.1.x` line was a package-maturity number that corresponded to
|
|
21
50
|
nothing in the specification, and it made the same package look like two
|
|
22
51
|
different releases on two registries.
|
|
23
|
-
* **`Development Status` classifier: `3 - Alpha`
|
|
52
|
+
* **`Development Status` classifier: `3 - Alpha` -> `4 - Beta`.** A
|
|
24
53
|
non-pre-release version must not ship with an "Alpha" classifier; leaving
|
|
25
54
|
the two in conflict invites the question "which one is true?".
|
|
26
55
|
* Install command note: on crates.io every published version of this crate is
|
|
27
56
|
a pre-release, so Cargo will not select it from a plain `rttp` requirement.
|
|
28
57
|
Write `cargo add rttp@1.2.6-alpha` (or pin `rttp = "1.2.6-alpha"`).
|
|
29
58
|
|
|
30
|
-
## [0.1.2]
|
|
59
|
+
## [0.1.2] -- 2026-09-18
|
|
31
60
|
|
|
32
|
-
**Metadata correction
|
|
61
|
+
**Metadata correction -- no code change.** Every module, byte layout and
|
|
33
62
|
conformance vector is identical to 0.1.1, and the self-test still reports the
|
|
34
|
-
same 53 checks.
|
|
63
|
+
the same 53 checks (full set, i.e. with the optional Ed25519 backend).
|
|
35
64
|
|
|
36
65
|
### Fixed
|
|
37
66
|
|
|
38
67
|
* **The distribution identity now matches the IANA registration.** The package
|
|
39
|
-
was authored as `RTTP Working Group`
|
|
68
|
+
was authored as `RTTP Working Group` -- a name that appears in no filing. The
|
|
40
69
|
`rttp` URI-scheme registration on file with IANA (ticket `[IANA #1459939]`)
|
|
41
70
|
names **`RTTP.COM Organization`** as the `Author/Change controller`, and every
|
|
42
71
|
other public surface uses that same name. Both package manifests now say it
|
|
@@ -44,19 +73,19 @@ same 53 checks.
|
|
|
44
73
|
|
|
45
74
|
| Field | Before | After |
|
|
46
75
|
|:---|:---|:---|
|
|
47
|
-
| `pyproject.toml`
|
|
48
|
-
| `package.json`
|
|
76
|
+
| `pyproject.toml` -> `authors` (PyPI) | `RTTP Working Group` | **`RTTP.COM Organization`** |
|
|
77
|
+
| `package.json` -> `author` (npm) | `RTTP Working Group` | **`RTTP.COM Organization`** |
|
|
49
78
|
|
|
50
79
|
Package metadata cannot be edited after publication, so 0.1.0 and 0.1.1 keep
|
|
51
80
|
the old string inside their own metadata; this is the version that carries the
|
|
52
81
|
correction. Project pages display the latest version, so the visible author
|
|
53
82
|
name becomes correct once this release is out.
|
|
54
83
|
|
|
55
|
-
## [0.1.1]
|
|
84
|
+
## [0.1.1] -- 2026-09-18
|
|
56
85
|
|
|
57
|
-
**Documentation only
|
|
86
|
+
**Documentation only -- no code change.** Every module, byte layout and
|
|
58
87
|
conformance vector is identical to 0.1.0, and the self-test still reports the
|
|
59
|
-
same 53 checks.
|
|
88
|
+
the same 53 checks (full set, i.e. with the optional Ed25519 backend).
|
|
60
89
|
|
|
61
90
|
### Fixed
|
|
62
91
|
|
|
@@ -64,7 +93,7 @@ same 53 checks.
|
|
|
64
93
|
below said the JavaScript side "will publish under the `@rttp` scope". That
|
|
65
94
|
scope **cannot be created at all**: npm already has a personal account named
|
|
66
95
|
`rttp`, and an organization name may not collide with a user name. The
|
|
67
|
-
JavaScript side is published as **`@aicent/rttp`**
|
|
96
|
+
JavaScript side is published as **`@aicent/rttp`** -- this project's own
|
|
68
97
|
organization, with the package name itself still just `rttp`.
|
|
69
98
|
* **README distribution table** now names the npm package exactly
|
|
70
99
|
(`@aicent/rttp`), and gives `pip install rttp` for this package, matching the
|
|
@@ -74,74 +103,74 @@ same 53 checks.
|
|
|
74
103
|
|
|
75
104
|
| Registry | Name | State |
|
|
76
105
|
|:---|:---|:---|
|
|
77
|
-
| PyPI | `rttp` | this package
|
|
78
|
-
| npm | `@aicent/rttp` | **published 0.1.1**
|
|
106
|
+
| PyPI | `rttp` | this package -- `pip install rttp` |
|
|
107
|
+
| npm | `@aicent/rttp` | **published 0.1.1** -- 2026-09-18 |
|
|
79
108
|
| crates.io | `rttp` | held by this project |
|
|
80
109
|
|
|
81
|
-
## [0.1.0]
|
|
110
|
+
## [0.1.0] -- 2026-09-17
|
|
82
111
|
|
|
83
112
|
First release. Scope is deliberately narrow: **framing, addressing and sealing**,
|
|
84
113
|
with zero dependencies and no transport.
|
|
85
114
|
|
|
86
115
|
### Added
|
|
87
116
|
|
|
88
|
-
* **`rttp.pulse_header`**
|
|
89
|
-
hardware-aligned frame header (RFC-002
|
|
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
|
|
90
119
|
block:
|
|
91
|
-
* `SPEC_REV` `0x66`
|
|
92
|
-
|
|
93
|
-
* bytes `0x00
|
|
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
|
|
94
123
|
that only understand the original layout remain conformant
|
|
95
|
-
* `build()`
|
|
124
|
+
* `build()` - `build_for_uri()` - `parse()` - `verify()` - `to_hex()` /
|
|
96
125
|
`from_hex()`
|
|
97
|
-
* strict verification (R1
|
|
126
|
+
* strict verification (R1-R7): unknown `SPEC_REV` rejected, `SPEC_REV=0` with a
|
|
98
127
|
non-zero block rejected, non-zero `RESERVED` rejected, unknown `FLAGS` bits
|
|
99
128
|
rejected, `ACTION` padding must be zero, `ACTION_LEN` must agree with the
|
|
100
129
|
payload
|
|
101
|
-
* **`rttp.rttp_uri`**
|
|
102
|
-
derivation for `rttp://` URIs (RFC-002
|
|
103
|
-
* `ROUTE_SHARD = SHA-256(ASCII(canonical_authority))[0:16]`
|
|
104
|
-
pure computation, **no DNS** (
|
|
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)
|
|
105
134
|
* hash-intent (`8lowhex`) and name-intent forms; open-set `action` vocabulary
|
|
106
135
|
* fail-closed rejection of uppercase, `userinfo`, `port`, `query`,
|
|
107
136
|
`fragment`, multi-segment paths, wrong segment counts, leading/trailing `-`,
|
|
108
137
|
whitespace, and non-`rttp` schemes
|
|
109
|
-
* accepts both `rttp://` and `web+rttp://`
|
|
138
|
+
* accepts both `rttp://` and `web+rttp://` -- the second as a **tolerance** for
|
|
110
139
|
the browser protocol-handler form, which RFC-002 no longer defines
|
|
111
140
|
(2026-09-17). Not a conformance claim; see "Known gaps" below.
|
|
112
|
-
* **`rttp.seal`**
|
|
113
|
-
bidirectional switch
|
|
114
|
-
* **`rttp.seal_asym`**
|
|
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
|
|
115
144
|
`AID = SHA-256(public_key)`.
|
|
116
145
|
* self-certifying: the envelope carries the public key, so a verifier
|
|
117
|
-
recomputes the identity instead of trusting a claim
|
|
146
|
+
recomputes the identity instead of trusting a claim -- **no issuance, no
|
|
118
147
|
registry, no directory**
|
|
119
148
|
* `ts` and `nonce` are **inside** the signed input, so they cannot be rewritten
|
|
120
149
|
without breaking the signature
|
|
121
150
|
* freshness enforced by default (`|now - ts| <= 120 s`); archival verification
|
|
122
151
|
available explicitly via `check_freshness=False`
|
|
123
|
-
* lowercase-hex only
|
|
124
|
-
* `generate_keypair()`
|
|
125
|
-
`verify_claims()`
|
|
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()`
|
|
126
155
|
* requires the `ed25519` extra; without it every call raises `SealError` with
|
|
127
156
|
the install instruction rather than degrading to an unsigned path
|
|
128
|
-
* **`rttp.aid`**
|
|
157
|
+
* **`rttp.aid`** -- Autonomous Identity derivation (RFC-001), shared by both
|
|
129
158
|
profiles so an AID means one thing across the stack.
|
|
130
|
-
* **`rttp.selftest`**
|
|
131
|
-
* 25 conformance vectors (6 positive URIs
|
|
132
|
-
frames
|
|
133
|
-
* RFC 8032
|
|
134
|
-
Ed25519
|
|
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
|
|
135
164
|
* 22 envelope checks, including a 14-case tamper matrix in which every single
|
|
136
165
|
alteration must be rejected, and an explicit replay-window test
|
|
137
166
|
* 4 static-scan checks proving the core modules import nothing outside the
|
|
138
167
|
standard library
|
|
139
168
|
* `--vectors` prints the deterministic envelope vector for the specification;
|
|
140
169
|
`--quiet` prints the summary line only
|
|
141
|
-
* **`rttp/vectors/rttp-conformance-v1.2.6.json`**
|
|
170
|
+
* **`rttp/vectors/rttp-conformance-v1.2.6.json`** -- the published vectors, shipped
|
|
142
171
|
as package data so the self-test runs from an installed wheel, offline.
|
|
143
172
|
* Console entry point `rttp-selftest`.
|
|
144
|
-
* **`MANIFEST.in`**
|
|
173
|
+
* **`MANIFEST.in`** -- the source distribution carries `README.md`,
|
|
145
174
|
`CHANGELOG.md`, `LICENSE`, `pyproject.toml` and the published vectors, and
|
|
146
175
|
excludes virtual environments and build noise. Both the wheel and the sdist
|
|
147
176
|
pass `twine check`.
|
|
@@ -149,51 +178,51 @@ with zero dependencies and no transport.
|
|
|
149
178
|
### Notes
|
|
150
179
|
|
|
151
180
|
* **Zero dependencies** in the core, and that is a machine-checked claim rather
|
|
152
|
-
than a promise
|
|
181
|
+
than a promise -- see the static-scan section of the self-test.
|
|
153
182
|
* The reference implementation evaluates the
|
|
154
183
|
**`iqa`** namespace nowhere: this package is the `rttp` protocol only.
|
|
155
184
|
* ~~Distribution: PyPI `rttp`. The npm name `rttp` is held by an unrelated,
|
|
156
185
|
unmaintained project, so the JavaScript side will publish under the `@rttp`
|
|
157
|
-
scope.~~
|
|
186
|
+
scope.~~ -- **corrected 2026-09-18.** PyPI `rttp` is now **published** (0.1.0,
|
|
158
187
|
2026-09-17). The npm name `rttp` is indeed held by an unrelated, unmaintained
|
|
159
|
-
project
|
|
188
|
+
project -- but the **`@rttp` scope cannot be created at all**, because a
|
|
160
189
|
personal account already holds that name. The JavaScript side is therefore
|
|
161
190
|
published as **`@aicent/rttp`**: this project's own organization, with the
|
|
162
191
|
package name still just `rttp`.
|
|
163
192
|
|
|
164
193
|
### Known gaps
|
|
165
194
|
|
|
166
|
-
Tracked in `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md`
|
|
195
|
+
Tracked in `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` sec. 8 and sec. 10. Deliberately listed
|
|
167
196
|
here so nobody has to discover them:
|
|
168
197
|
|
|
169
198
|
* No transport and no client. The core encodes, addresses and seals; sending is a
|
|
170
199
|
separate package's job.
|
|
171
200
|
* No revocation, and no key rotation story. Both belong to RFC-003.
|
|
172
|
-
* No replay **cache**: freshness (
|
|
201
|
+
* No replay **cache**: freshness (sec. 3.4) bounds the window, but within it a replayed
|
|
173
202
|
envelope still verifies unless the verifier keeps a short-lived nonce store.
|
|
174
203
|
* No transport-origin binding: the seal proves who signed, not which connection
|
|
175
204
|
delivered it.
|
|
176
205
|
* Rust parity: the published `rttp` crate has no transport layer and no envelope.
|
|
177
206
|
Python and Node are the conforming implementations so far.
|
|
178
|
-
* ~~the browser-registration prefix is accepted because RFC-002
|
|
179
|
-
it
|
|
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
|
|
180
209
|
specifications and will never be submitted to IANA. `rttp_uri` still accepts it
|
|
181
|
-
as a **tolerance**
|
|
182
|
-
would break the protocol-handler path
|
|
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
|
|
183
212
|
form, so the acceptance is **outside the specification** and a conforming
|
|
184
213
|
third-party implementation is not required to reproduce it.
|
|
185
214
|
* ~~**Open, and ours to fix:** the published vectors asserted things the
|
|
186
|
-
specification no longer said.~~
|
|
215
|
+
specification no longer said.~~ -- **resolved 2026-09-18.** The generator now
|
|
187
216
|
classifies every forward case explicitly:
|
|
188
|
-
* `positive_uris`
|
|
217
|
+
* `positive_uris` -- each entry carries `tolerance` (boolean) and `note`. The
|
|
189
218
|
case whose `uri` carries the browser-registration prefix is `tolerance: true`,
|
|
190
219
|
with its reason recorded: it is accepted only because that is the scheme name
|
|
191
|
-
under which a handler is registered (RFC-002
|
|
220
|
+
under which a handler is registered (RFC-002 sec. 10.6) -- never because the
|
|
192
221
|
specification defines it. It is **not** a conformance claim, and the 25-check
|
|
193
222
|
total is unchanged.
|
|
194
|
-
* `negative_uris`
|
|
195
|
-
`(RFC-002
|
|
196
|
-
lowercase rule.
|
|
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.
|
|
197
226
|
Regenerated (`SPEC/tools/conformance.py --generate`), replayed (`--check`,
|
|
198
227
|
25/25), and mirrored byte-identically into both packages. After the change:
|
|
199
228
|
Python self-test 53/53, Node runner 25/25.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rttp
|
|
3
|
-
Version: 1.2.
|
|
4
|
-
Summary: RTTP reference implementation: PulseHeader128 framing, rttp:// addressing, and self-certifying Ed25519 seals (RFC-002
|
|
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/
|
|
@@ -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
|
|
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
|
|
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 1.2.
|
|
43
|
+
rttp 1.2.7 self-test
|
|
44
44
|
python 3.14.2 on win32
|
|
45
45
|
...
|
|
46
|
-
[PASS] all
|
|
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
|
|
51
|
-
believe a table of numbers, this ships the vectors and replays them locally
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* **
|
|
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
|
-
* **
|
|
58
|
-
14-case tamper matrix where
|
|
59
|
-
|
|
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
|
|
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
|
|
86
|
-
| `rttp.rttp_uri` | Validate, canonicalise and derive `ROUTE_SHARD` from an `rttp` URI | RFC-002
|
|
87
|
-
| `rttp.seal` | **Managed profile**
|
|
88
|
-
| `rttp.seal_asym` | **Sovereign profile**
|
|
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`
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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**
|
|
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
|
|
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
|
|
183
|
+
## Scope -- what this package is not
|
|
174
184
|
|
|
175
185
|
| | |
|
|
176
186
|
|:---|:---|
|
|
177
|
-
|
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
|
|
|
182
|
-
|
|
|
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
|
|
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
|
|
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**
|
|
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
|
|
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**
|
|
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**
|
|
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**
|
|
222
|
-
* **Seal envelope**
|
|
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**
|
|
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
|