The TLS TimeToken Secure Protocol (tttps)
draft-helmprotocol-tttps-08
This document is an Internet-Draft (I-D).
Anyone may submit an I-D to the IETF.
This I-D is not endorsed by the IETF and has no formal standing in the
IETF standards process.
| Document | Type | Active Internet-Draft (individual) | |
|---|---|---|---|
| Author | Heime Jorgen | ||
| Last updated | 2026-07-29 | ||
| RFC stream | Independent Submission | ||
| Intended RFC status | Experimental | ||
| Formats | |||
| Stream | ISE state | Response to Review Needed | |
| Consensus boilerplate | Unknown | ||
| Document shepherd | (None) | ||
| IESG | IESG state | I-D Exists | |
| Telechat date | (None) | ||
| Responsible AD | (None) | ||
| Send notices to | (None) |
draft-helmprotocol-tttps-08
Network Working Group H. Jorgen
Internet-Draft Kenosian
Intended status: Experimental 29 July 2026
Expires: 30 January 2027
The TLS TimeToken Secure Protocol (tttps)
draft-helmprotocol-tttps-08
Abstract
This document specifies a Proof-of-Time record: a transport-
independent object in which an issuer asserts that a payload with a
stated digest was presented to it at a stated time, relative to a
stated set of time sources and with an explicit error bound, and
which cannot afterwards be altered without detection. The record is
produced by an issuer that is not a party to the session in which the
record is later presented, and it can be evaluated by a third party
who observed neither endpoint and who evaluates it after that session
has closed. Evaluation additionally requires the issuer's public key
and the context identifier, both obtained out of band: the record is
self-contained with respect to the transport that carries it, not
with respect to those inputs. This document defines the record
format, an extensible integrity algorithm registry whose mandatory-
to-implement member is unkeyed SHA-256, a binding of a record to a
TLS 1.3, QUIC, or HTTP/3 session and to the party entitled to present
it, and the associated IANA registrations.
Status of This Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
This Internet-Draft will expire on 30 January 2027.
Jorgen Expires 30 January 2027 [Page 1]
Internet-Draft TTTPS July 2026
Copyright Notice
Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents (https://trustee.ietf.org/
license-info) in effect on the date of publication of this document.
Please review these documents carefully, as they describe your rights
and restrictions with respect to this document.
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1. Scope and Non-Goals . . . . . . . . . . . . . . . . . . . 4
1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4
2. Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1. Autonomous Agent Interactions . . . . . . . . . . . . . . 7
2.2. Regulated Computation Records . . . . . . . . . . . . . . 7
3. The Proof-of-Time Record . . . . . . . . . . . . . . . . . . 7
3.1. Wire Format . . . . . . . . . . . . . . . . . . . . . . . 8
3.2. Field Definitions . . . . . . . . . . . . . . . . . . . . 9
3.3. Integrity Algorithm . . . . . . . . . . . . . . . . . . . 11
3.3.1. Verdict Arity and Recovery Bounds . . . . . . . . . . 13
3.3.2. Defined Algorithms . . . . . . . . . . . . . . . . . 15
3.4. Generation . . . . . . . . . . . . . . . . . . . . . . . 16
3.5. Verification . . . . . . . . . . . . . . . . . . . . . . 17
4. Session and Holder Binding . . . . . . . . . . . . . . . . . 27
4.1. Session Binding . . . . . . . . . . . . . . . . . . . . . 27
4.2. Holder Binding . . . . . . . . . . . . . . . . . . . . . 28
4.3. What the Bindings Do Not Prove . . . . . . . . . . . . . 29
5. Transport Binding . . . . . . . . . . . . . . . . . . . . . . 29
5.1. TLS 1.3 . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.2. QUIC . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.3. HTTP/3 . . . . . . . . . . . . . . . . . . . . . . . . . 31
6. Tier Structure . . . . . . . . . . . . . . . . . . . . . . . 33
7. Security Considerations . . . . . . . . . . . . . . . . . . . 34
7.1. The Issuer Is Trusted, and Auditable . . . . . . . . . . 34
7.2. Time Source Independence . . . . . . . . . . . . . . . . 35
7.3. Accepting a Resolved Verdict . . . . . . . . . . . . . . 36
7.4. Replay . . . . . . . . . . . . . . . . . . . . . . . . . 37
7.5. Side Channels . . . . . . . . . . . . . . . . . . . . . . 38
8. Privacy Considerations . . . . . . . . . . . . . . . . . . . 38
9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 39
9.1. TLS Exporter Labels Registry . . . . . . . . . . . . . . 39
9.2. HTTP/3 Frame Type . . . . . . . . . . . . . . . . . . . . 39
9.3. TTTPS Integrity Algorithms Registry . . . . . . . . . . . 40
9.4. TTTPS Tier Registry . . . . . . . . . . . . . . . . . . . 41
Jorgen Expires 30 January 2027 [Page 2]
Internet-Draft TTTPS July 2026
9.5. TTTPS Time Source Classes Registry . . . . . . . . . . . 41
9.6. URI Scheme . . . . . . . . . . . . . . . . . . . . . . . 42
10. Intellectual Property . . . . . . . . . . . . . . . . . . . . 42
11. Implementation Status . . . . . . . . . . . . . . . . . . . . 43
12. Normative References . . . . . . . . . . . . . . . . . . . . 43
13. Informative References . . . . . . . . . . . . . . . . . . . 44
Appendix A. Test Vectors . . . . . . . . . . . . . . . . . . . . 45
Changes from draft-helmprotocol-tttps-07 . . . . . . . . . . . . 48
Changes from draft-helmprotocol-tttps-06 . . . . . . . . . . . . 48
Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 58
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 58
1. Introduction
A timestamp asserted by the party that benefits from it is not
evidence. Most deployed mechanisms for establishing when something
happened share this shape: a host reads its own clock, writes the
value into a record, and signs the result. A verifier who trusts the
host learns nothing it did not already assume, and a verifier who
does not trust the host learns nothing at all. Backdating by the
record's own author is not detectable from the record.
Transport security does not close this gap. TLS 1.3 [RFC9846]
authenticates the endpoints of a session and protects the
confidentiality and integrity of data in transit, but makes no
statement about when a payload was produced, and its protections end
when the session ends. Network time protocols solve a different
problem: Network Time Security [RFC8915] authenticates the delivery
of time from a server to a client, but the client's subsequent use of
that time is again self-asserted. Neither produces an artifact that
outlives the session and that a party absent from it can evaluate.
This document specifies such an artifact. A Proof-of-Time record
(PoT record) is issued by a PoT Issuer, which is separate from both
parties to the session in which the record is presented. It states a
synthesised time derived from several mutually independent sources,
an explicit bound on the error of that synthesis, a digest of the
payload it covers, and a signature by the Issuer. Its length is one
of two fixed values, selected by a flag inside the record itself, and
it has no dependence on the transport that carries it.
The design goal is verification by a stranger: a party who was
present at neither end of the session, who holds no state from it,
and who evaluates the record after both endpoints have gone away.
Jorgen Expires 30 January 2027 [Page 3]
Internet-Draft TTTPS July 2026
The information-theoretic model that motivates the synthesis and its
error bound is developed separately in [POT2026]. That material is
not needed in order to implement this document, and is cited
informatively only.
1.1. Scope and Non-Goals
This document specifies:
* the PoT record wire format, including the digest by which a record
is bound to the payload it covers (Section 3);
* an integrity algorithm interface and registry, with unkeyed
SHA-256 as the mandatory-to-implement member (Section 3.3);
* generation and verification procedures (Section 3.4 and
Section 3.5);
* binding of a record to a session and to a holder (Section 4);
* carriage over TLS 1.3, QUIC, and HTTP/3 (Section 5).
This document does not specify:
* the protocol between a client and a PoT Issuer. Issuance is an
out-of-band exchange. A PoT record is obtained before the session
in which it is presented, and TTTPS does not modify, extend, or
participate in the TLS or QUIC handshake in any way;
* the discovery, governance, or operation of PoT Issuers;
* any economic, incentive, or fee model. Verification effort policy
is a local matter;
* time distribution. TTTPS consumes time; it does not distribute
it;
* operation across links whose one-way propagation delay is large
relative to the tolerance windows defined in Section 6. That case
requires a different tier model and is out of scope here.
Nothing in this document alters TLS 1.3 or QUIC processing. A peer
that does not implement TTTPS is unaffected by a peer that does.
1.2. Terminology
PoT record: the object specified in Section 3.
Jorgen Expires 30 January 2027 [Page 4]
Internet-Draft TTTPS July 2026
Issuer: the entity that constructs and signs a PoT record. The
Issuer holds the signing key whose public part the verifier
consults.
Holder: the entity entitled to present a PoT record. For a holder-
bound record (Section 4.2) the Holder is identified by a public
key carried inside the signed payload.
Presenter: the entity that actually transmits a PoT record in a
session. For a correctly functioning holder-bound record the
Presenter and the Holder are the same entity; distinguishing them
is the point of Section 4.2.
Verifier: the entity that evaluates a PoT record. For each record
it evaluates, a verifier acts in exactly one of the two roles
below, and a verifier MUST determine which role it is acting in
before it begins the procedure of Section 3.5. The two roles are
the two sides of a single question of fact: whether the verifier
is still party to the session in which the record was presented to
it. The role is therefore not an election by the verifier, it
does not follow from the age of the record, and it is not settled
by what key material the verifier has chosen to keep. A
deployment that evaluates some records inside the session that
carried them and others from storage acts in both roles, one
record at a time.
Relying Verifier: a verifier that is still party to the session in
which the record was presented to it, and that therefore has
available to it, for that record, the session secret from which
the session binding of Section 4.1 is derived, the role octet of
the peer the record was received from, and the session binding as
presented. A Relying Verifier performs session binding, holder
verification, and replay detection. Availability here follows
from the session being live and not from what the verifier has
retained: once that session has ended the secret is not available
within the meaning of this definition, whether or not a copy of it
has been kept, and the verifier acts as an Auditor for every
record it evaluates thereafter. A Relying Verifier ordinarily
acts on the result at the time it evaluates the record; one that
acts on it after that session has ended MUST NOT report the record
as establishing that the Presenter is party to that session.
Auditor: a verifier that is not, or is no longer, party to the
session in which the record was presented, and that therefore does
not have that secret available to it for the record it is
evaluating. That is the condition of a verifier evaluating a
retained record at a time when the session that carried it has
ended, and equally of a verifier presented with a record over a
Jorgen Expires 30 January 2027 [Page 5]
Internet-Draft TTTPS July 2026
carriage that established no such session at all: the role follows
from the ending or the absence of the session and not from the age
of the record. An Auditor cannot perform session binding or
holder verification and MUST NOT attribute presentation of the
record to any party; Section 4.3 states what it can establish.
Step 11 of Section 3.5 states when an Auditor applies replay
detection and when it MUST NOT.
Integrity algorithm: a single bounded-work evaluation over the
record fields preceding the Commitment, taking also the ctx_id
and, at verification, the Commitment field as received, and
returning a commitment, a verdict, and, where the verdict is
resolved, the recovered fields (Section 3.3).
Verdict arity: the set of verdicts an integrity algorithm can return
(Section 3.3.1).
Payload: the application data a PoT record covers. The payload is
not carried in the record; the record carries a digest of it.
Throughout this document "payload" means this application data and
nothing else.
P, the signed payload: the octets of the record from offset 0
through the end of the Commitment field, that is, every field
except the Signature (Section 3.1). P is what the Issuer's
signature covers. P is never called "the payload".
pop: proof of possession: a signature made with the Holder's private
key that demonstrates control of the key named by the Holder Key
field (Section 4.2).
GRG: the name of a single arity-3 integrity evaluation for which
this document reserves a codepoint without specifying it or
assigning it (Section 3.3.2). The name appears in this document
only as a label for that reservation.
shard: in the informative description of GRG in Section 3.3.2, one
of the fixed number of pieces into which that evaluation divides
its input. The term carries no meaning elsewhere in this
document.
ctx_id: an octet string of at most 255 octets naming the application
context in which a record is valid. It is agreed out of band
among Issuer, Holder, and Verifier, is not carried in the record,
and is an input to the integrity algorithm (Section 3.3). It is a
domain separator, not a secret and not a payload.
Jorgen Expires 30 January 2027 [Page 6]
Internet-Draft TTTPS July 2026
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in
BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
capitals, as shown here.
2. Use Cases
Two deployments motivate the design. Both share one property: the
party that must be convinced is not present when the event occurs and
cannot be assumed to trust either endpoint.
2.1. Autonomous Agent Interactions
When software agents transact with one another, the record of who
acted first is produced by the participants themselves. Reaction
times among automated participants converge, so ordering advantage
that was previously a consequence of human latency becomes a
consequence of whoever writes the log. A dispute over ordering is
then a dispute between two self-asserted records with no independent
third term.
A PoT record supplies that third term. Each agent obtains a record
from an Issuer that is party to neither side, and the resulting
ordering claim is evaluable by an arbiter afterwards without
replaying the interaction and without either agent's cooperation.
2.2. Regulated Computation Records
Regimes that require electronic records to be attributable and
contemporaneous place the burden on the operator to show that a
record was created when it claims and has not been altered since.
Where the computation is performed by a model whose outputs are not
reproducible from the inputs alone, re-running the computation does
not discharge that burden.
Attaching a PoT record to each run converts the operator's claim into
an artifact that can be checked independently, at audit time, without
access to the operator's infrastructure and without trusting the
operator's clock. The property that matters here is durability: the
record must remain evaluable long after the session, the host, and
often the software version that produced it are gone.
3. The Proof-of-Time Record
Jorgen Expires 30 January 2027 [Page 7]
Internet-Draft TTTPS July 2026
3.1. Wire Format
All multi-octet integer fields are in network byte order and are
unsigned. The record consists of a signed payload P followed by an
Ed25519 signature over P. In the diagram below a field wider than 32
bits is drawn across several rows; a field drawn with "~" is
additionally elided and occupies more octets than the rows shown,
while a field drawn with "+" and "|" alone is shown in full. The
octet table that follows the diagram is authoritative in every case.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Vers(4)|Tier(4)| Flags (8) | Integrity Alg (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Src Cnt (8) | Error Bound (24 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Timestamp (64 bits) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Issuer Key ID (64 bits) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Nonce (256 bits) ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Payload Digest (256 bits) ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Holder Key (256 bits, iff Flags bit 0 = 1) ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Commitment (256 bits) ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Signature (512 bits, Ed25519) ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Jorgen Expires 30 January 2027 [Page 8]
Internet-Draft TTTPS July 2026
Offset Length Field
------ ------ --------------------------------------------
0 4 Version, Tier, Flags, Integrity Alg
4 4 Src Cnt, Error Bound
8 8 Timestamp
16 8 Issuer Key ID
24 32 Nonce
56 32 Payload Digest
88 32 Holder Key (present iff Flags bit 0 = 1)
88/120 32 Commitment
120/152 64 Signature
------------------------------------------------------------
Payload P = offset 0 through the end of Commitment
Total = 184 octets, or 216 octets with the Holder Key
The record is self-delimiting: Flags occupies the second octet, and
Flags bit 0 determines whether the Holder Key is present and hence
whether the total length is 184 or 216 octets.
3.2. Field Definitions
Version (4 bits): protocol version. This document defines version 1
(0x1). A verifier MUST reject a record carrying a version it does
not implement. Earlier revisions of this Internet-Draft described
a different layout under the same version number. Pre-publication
revisions are not expected to interoperate and the Version field
does not discriminate among them.
Tier (4 bits): the time resolution tier (Section 6).
Flags (8 bits): bit 0 (most significant) set to 1 indicates that the
Holder Key field is present. Bits 1 through 7 are reserved, MUST
be set to 0 by an Issuer, and MUST be ignored by a verifier.
Because Flags is inside P, it is covered by both the Commitment
and the Signature; a verifier MUST NOT infer the presence of the
Holder Key from the received length alone.
Integrity Alg (16 bits): identifies the integrity algorithm used to
compute the Commitment (Section 3.3). A verifier MUST reject a
record naming an algorithm it does not implement, and MUST NOT
substitute a different algorithm.
Src Cnt (8 bits): the number of mutually independent time sources
consulted in the synthesis. MUST be at least 3. An Issuer SHOULD
use at least 4.
Error Bound (24 bits): an upper bound on the magnitude of the
Jorgen Expires 30 January 2027 [Page 9]
Internet-Draft TTTPS July 2026
difference between the Timestamp field and true time, expressed in
microseconds, as estimated by the Issuer at generation. The
representable range is 0 through 16.777214 seconds. The value
0xFFFFFF is reserved: an Issuer MUST NOT emit it and a verifier
MUST reject a record carrying it. An Issuer MUST NOT emit a value
smaller than its estimate supports, and MUST NOT emit a value
exceeding the nominal tolerance of the Tier it is issuing at; a
verifier MUST reject a record that violates the latter constraint,
as required by step 4 of Section 3.5. Rejecting a value that
exceeds the Tier tolerance is what makes the range above
10 seconds unreachable in practice, rather than singling out one
sentinel. This field replaces the bare confidence figure of
earlier versions: a verifier is expected to compare it against the
tolerance its own application requires and to act on the result,
rather than to treat the Timestamp as exact. A verifier MUST make
this value available to the application.
Timestamp (64 bits): the synthesised time, in nanoseconds since the
UNIX epoch, computed as specified in Section 3.4.
Issuer Key ID (64 bits): the first eight octets of SHA-256 [RFC6234]
applied to the 32-octet Ed25519 public key that verifies the
Signature field. It identifies which of an Issuer's keys signed
the record, so that a verifier can select candidate keys and their
validity intervals, and so that an Issuer can rotate keys without
invalidating records already issued. It is an index into the set
of keys a verifier already trusts. It is not a credential and not
a security boundary: sixty-four bits is not a collision-resistant
width, the field carries no Issuer name, and more than one trusted
key may match it. A verifier MUST obtain the public key itself,
and the interval over which that key is valid, from a source it
trusts; MUST NOT accept a key merely because its digest matches
this field; and, where more than one trusted key matches, MUST
resolve the ambiguity by signature verification as specified in
step 5 of Section 3.5 rather than by choosing among them.
Nonce (256 bits): a value generated by the Issuer with a
cryptographically secure random number generator. Used for replay
detection (Section 3.5).
Payload Digest (256 bits): SHA-256 [RFC6234] of the payload the
record covers. It is computed by the requester, supplied to the
Issuer at issuance, and copied by the Issuer into P without
interpretation. This is the field that makes the record a
statement about something: without it the record would attest only
to its own existence. A verifier that holds the payload MUST
recompute the digest and MUST reject the record if it differs. A
verifier that does not hold the payload MUST report the digest to
Jorgen Expires 30 January 2027 [Page 10]
Internet-Draft TTTPS July 2026
the application rather than treating the record as covering an
unspecified object. This document defines no digest agility: the
digest is SHA-256, and a successor would be a new Version.
Holder Key (256 bits, optional): present if and only if Flags bit 0
is 1. An Ed25519 public key supplied by the requester at issuance
and copied by the Issuer into P. See Section 4.2.
Commitment (256 bits): the commitment returned by the integrity
algorithm named in Integrity Alg, evaluated over the preceding
fields together with a context identifier, as specified in
Section 3.3.
Signature (512 bits): an Ed25519 [RFC8032] signature by the Issuer
over all preceding octets of the record, that is, over P.
Because the Timestamp, the Error Bound, and the Holder Key are all
inside P, and the Signature covers P in its entirety, an Issuer
cannot alter any of them after signing without invalidating the
signature, and no other party can alter them at all. The residual
trust assumption is that the Issuer's signing key is not compromised
and that the Issuer does not sign a time it knows to be false. This
document does not eliminate that assumption; it reduces the set of
parties who must be trusted from "either endpoint" to "a named third
party whose key is published and whose output can be logged".
Section 7.1 discusses the consequences.
3.3. Integrity Algorithm
An integrity algorithm is a single bounded-work evaluation. It takes
the record fields preceding the Commitment -- that is, every field
from Version through Holder Key inclusive, and therefore the Payload
Digest -- the context identifier ctx_id defined in Section 1.2, and,
when it is evaluated for verification, the Commitment field as
received. It returns a 256-bit commitment, a verdict, and, where the
verdict is resolved, the recovered fields.
(commitment, verdict, recovered) = Alg(fields, ctx_id, expected)
The two uses of the evaluation supply different arguments. At
generation (Section 3.4) there is no record yet and so no expected
value: the evaluation is performed with expected absent, and the
commitment it returns is the value the Issuer places in the
Commitment field. With expected absent the verdict and the recovered
fields are undefined, and a generating implementation MUST NOT
consult either. At verification (Section 3.5) expected is the
Commitment field as received; the verdict is intact when the
commitment computed over the fields as given equals expected, and
Jorgen Expires 30 January 2027 [Page 11]
Internet-Draft TTTPS July 2026
recovered is present only where the verdict is resolved. An arity-2
algorithm never returns recovered. The Commitment field is supplied
to the evaluation so that there is something to compare against and,
for an arity-3 algorithm, so that recovery has a target; it is not
itself an input to the computation of the commitment, and
Section 3.3.1 places it outside what any registered algorithm can
recover.
The evaluation is not a pipeline of separately negotiable transforms
and this document does not define, permit, or reserve codepoints for
any proper subset of a registered algorithm. An implementation
either performs the registered evaluation in full or does not
implement that algorithm.
Every registered algorithm MUST satisfy:
* determinism: one evaluation is a function of its arguments. The
same fields, the same ctx_id and the same expected value yield the
same commitment, the same verdict, and the same recovered fields.
Where the expected value is absent the requirement applies to the
commitment alone, the other two results being undefined in that
case as the paragraph above states. Where it is present the
requirement covers all three results and not the commitment alone.
Two verifiers that evaluate the same received record under the
same ctx_id would otherwise be free to reach different verdicts,
so that one accepts a record the other rejects with neither in
violation of this document. The recovered fields carry a further
consequence: Section 3.5 makes them replace the received fields
for the remainder of verification, so they are what the
application is given to act on and what the replay check of that
section's step 11 compares. If they were not a function of the
record, then the committed content of a resolved record would not
be determined by the record, and re-presenting one identical
record would yield a different Nonce on each presentation, which
is exactly the condition replay detection cannot survive;
* context separation: for ctx_id_A different from ctx_id_B, the
commitments differ except with negligible probability. This
prevents a record valid in one application context from being
presented as valid in another;
* bounded work: the specification of the algorithm MUST state an
upper bound on the cost of one evaluation that holds for every
input of the appropriate length, so that a verifier can budget for
the worst case. Computation of the commitment, and any comparison
against it, MUST take an amount of work that does not depend on
the content of the fields or on the expected value. An evaluation
that attempts recovery MAY cost more than that, up to the stated
Jorgen Expires 30 January 2027 [Page 12]
Internet-Draft TTTPS July 2026
bound. Content-independence is required of the commitment path
and not of the recovery path, because no error-correcting
evaluation can offer it on the recovery path: the work of
correcting depends on what is to be corrected.
Context separation is a domain-separation property, not a secrecy
property. ctx_id, and any key an algorithm derives from it, MAY be
public, and an implementation MUST NOT rely on either being secret.
Authenticity and integrity of the Commitment come from the Issuer's
signature over P. This document provides no confidentiality for the
payload, for its digest, or for ctx_id; where confidentiality is
required it is supplied by the transport that carries the record.
3.3.1. Verdict Arity and Recovery Bounds
The set of verdicts an algorithm can return is a property of that
algorithm, and is called its arity. This document defines two
arities.
An arity-2 algorithm returns one of:
* intact -- the presented fields are exactly those committed to;
* unresolvable -- they are not, and the algorithm cannot say more.
An arity-3 algorithm returns one of:
* intact -- as above;
* resolved -- the presented fields differ from those committed to,
but the evaluation recovered the committed fields within the
algorithm's declared capability, and the recovered fields are
returned alongside the verdict;
* unresolvable -- the difference exceeds that capability.
The distinction is operational, not cosmetic. A verifier that
collapses resolved into intact loses the signal that the record
arrived altered; one that collapses it into unresolvable discards a
record whose committed content is known. A verifier MUST report the
verdict to the application distinctly and MUST NOT map resolved onto
either neighbouring value. Whether to accept a resolved record is an
application decision; Section 7.3 states the security constraint on
that decision.
Jorgen Expires 30 January 2027 [Page 13]
Internet-Draft TTTPS July 2026
An arity-3 verdict is a property of a single evaluation, not the
result of retrying an arity-2 evaluation with repaired input.
Nothing in this document permits a verifier to re-evaluate an arity-2
algorithm on modified fields.
Recovery is bounded by field. Wherever an evaluation returns
recovered fields, a verifier MUST reject the record if recovery
altered the Version field, the Integrity Alg field, the Flags field,
the Holder Key field, or the Payload Digest field. Recovery of Flags
or Holder Key would let an attacker strip holder binding from a
record and have the verifier silently restore a record it can then
present as a bearer object; recovery of the Payload Digest would let
an attacker substitute the object the record covers.
Version and Integrity Alg are prohibited for a further reason, which
is that recovering either is incoherent before it is unsafe. Each
names something the evaluation presupposes: the Integrity Alg field
names the algorithm that is doing the recovering, and the Version
field names the layout under which the fields were delimited in order
to be handed to it. An evaluation that changes either has
authenticated a record under an algorithm it did not itself run, or
under a layout it did not itself parse. The consequences are not
symmetric with the others. An attacker who alters the Integrity Alg
could otherwise steer a verifier into a decoder it would never have
entered and out again under a valid signature naming an identifier
this document reserves. An attacker who alters the Version could
otherwise have a record parsed under one layout, recovered to name
another, and accepted by a verifier that implements both -- a
substitution that no field-level check downstream can detect, because
every offset the downstream checks read is an offset of the layout
that has just been swapped out. Only version 1 is defined here, so
the second is latent rather than live; it is prohibited now because
the prohibition is not one a later version can add retroactively.
These five fields are therefore outside the recovery capability of
any algorithm registered under this document, irrespective of what
that algorithm could otherwise correct. Step 6 of Section 3.5 re-
applies the version and algorithm checks to the recovered fields
notwithstanding, so that a verifier which fails to enforce the bound
does not thereby accept a record naming a version or an algorithm it
does not implement.
Recovery is bounded by extent as well, and that bound is structural
rather than declared. The commitment is computed over the fields
preceding the Commitment; neither the Commitment field nor the
Signature field is among the fields it is computed over, and together
they are 96 of the record's 184 or 216 octets. The Commitment field
is supplied to a verification evaluation as the value to compare
Jorgen Expires 30 January 2027 [Page 14]
Internet-Draft TTTPS July 2026
against and to recover towards (Section 3.3), and the Signature field
is not supplied to the evaluation at all; neither is itself
recoverable. No registered algorithm can recover damage to those 96
octets, whatever capability it declares. A record whose Signature
was altered is therefore unrecoverable even by an arity-3 algorithm,
and the recovery branch of Section 3.5 exists only for damage
confined to the earlier fields of P.
3.3.2. Defined Algorithms
*0x0001, SHA-256, arity 2, mandatory to implement.* The commitment is
commitment = SHA-256( ctx_id || 0x00 || fields )
where SHA-256 is as specified in [RFC6234]; ctx_id is encoded as a
single octet giving its length in octets followed by exactly that
many octets, so that this algorithm cannot be used with a ctx_id
longer than 255 octets; and 0x00 is a single separator octet placed
between the encoded ctx_id and the fields. At verification the
verdict is intact if the recomputed commitment equals the expected
value supplied to the evaluation and unresolvable otherwise; 0x0001
is arity 2 and never returns recovered fields. At generation there
is no expected value and the verdict is not defined (Section 3.3).
Every implementation of this document MUST implement 0x0001. It
requires nothing beyond a standard hash function and is available
under no licensing condition.
*0x0100, reserved, arity 3.* This document reserves 0x0100 without
assigning it. It is held for GRG, a single evaluation combining
source coding, erasure and bit-error correction, and keyed context
separation, whose external behaviour is that of an arity-3 integrity
algorithm as defined in Section 3.3.1, with a declared capability of
recovery from the loss of any two of six shards and from up to three
bit errors per 23-bit block. That description is informative and is
given here only to show what the arity-3 interface is for. GRG is
not specified in this document, and this document therefore does not
assign it: the registry created in Section 9.3 is Specification
Required, and an entry with no specification would not survive its
own designated expert. Assignment will be requested in a separate
document that specifies the evaluation in full, as a whole. Until
such a document exists, a verifier MUST reject a record naming
0x0100.
Support for any algorithm other than 0x0001 is not required to
interoperate. A verifier presented with a record naming an algorithm
it does not implement rejects the record; it does not degrade to a
different algorithm.
Jorgen Expires 30 January 2027 [Page 15]
Internet-Draft TTTPS July 2026
3.4. Generation
To generate a PoT record, an Issuer:
1. obtains times T_1 through T_k, k at least 3, from time sources
in distinct administrative domains. Sources MUST be mutually
independent in the sense of Section 7.2;
2. computes T_synth as the median of T_1 through T_k;
3. computes an error bound from the dispersion of the sources about
T_synth, the stated accuracy of each source, and the measurement
path delay, and encodes it in the Error Bound field. If the
resulting bound exceeds the tolerance of the requested tier, the
Issuer MUST either issue at a coarser tier -- that is, at a
numerically lower Tier value, see Section 6 -- or abort; it MUST
NOT issue at the requested tier with an understated bound. If
the bound is not representable in the Error Bound field, the
Issuer MUST abort;
4. generates a 256-bit Nonce;
5. copies the requester-supplied Payload Digest into P without
interpreting it. The Issuer does not see the payload and MUST
NOT be assumed to have validated the digest against anything;
the Issuer attests to the time at which it saw that digest, not
to the existence of a payload matching it;
6. writes the Issuer Key ID of the key it is about to sign with;
7. if the requester supplied a holder public key, sets Flags bit 0
and copies the key into the Holder Key field; if it did not,
clears Flags bit 0 and writes no Holder Key field, so that the
record is 184 octets;
8. writes the Version field, the Tier it is issuing at, the Src Cnt
as the number k of sources consulted, the Timestamp field as
T_synth expressed in nanoseconds since the UNIX epoch
(Section 3.2), and the Integrity Alg field naming the integrity
algorithm it will use, and sets every reserved bit of Flags to
0. The reserved bits are bits 1 through 7 (Section 3.2); bit 0
is written by the preceding item in either case, so that the
Flags octet is 0x00 where no holder key was supplied;
9. assembles the fields preceding the Commitment and computes the
Commitment using that integrity algorithm and the ctx_id agreed
for the application context. The evaluation is performed with
the expected value absent (Section 3.3);
Jorgen Expires 30 January 2027 [Page 16]
Internet-Draft TTTPS July 2026
10. signs P with its Ed25519 private key and appends the signature.
Issuance is an exchange between the requester and the Issuer that is
outside the scope of this document and outside the session in which
the record is later presented. It completes before that session
begins.
The record states how many sources were consulted but not what they
were. An Issuer SHOULD publish the classes of source it consults, as
described in Section 7.2; that is the only use this document makes of
the registry created in Section 9.5.
3.5. Verification
A verifier MUST first establish whether it is acting as a Relying
Verifier or as an Auditor (Section 1.2). It MUST then perform the
following steps in the order given, and MUST reject the record on the
first failure, with one exception: step 5 has three outcomes rather
than two, and one of them is a failure with a defined successor
rather than a rejection. That step names its own outcomes and no
other step in this procedure has more than two. Steps 8 and 10 apply
to a Relying Verifier only, as marked. Step 11 applies to a Relying
Verifier always, and to an Auditor in the case that step identifies.
Every other step applies in both roles.
1. Reject a record whose Version field names a version the verifier
does not implement.
Jorgen Expires 30 January 2027 [Page 17]
Internet-Draft TTTPS July 2026
2. Reject if fewer than two octets are available; then read Flags
bit 0 from the second octet and derive from it the record length
-- 184 octets if the bit is clear, 216 if it is set -- and the
length of the unit being parsed. Over the transports of
Section 5 the unit is the structure of Section 5.1: the record,
then 32 octets of session binding, then, if the bit is set, 64
octets of holder proof, so 216 octets if the bit is clear and
312 if it is set. A carriage that presents a record on its own,
with no session binding -- a stored record, or a record handed
to an Auditor -- delivers a unit that is the record itself, and
the two lengths coincide. A length-delimited carriage outside
Section 5 that does not itself declare which of the two it holds
MAY determine that from the delivered length, the two being
distinct under either value of Flags bit 0: 184 octets against
216 if the bit is clear, and 216 against 312 if it is set. What
the verifier does next depends on the class of the carriage.
Each carriage in Section 5 states its own class. A carriage
outside Section 5 that draws the unit from a stream it also
carries other traffic on is a byte-stream carriage; one that
delivers the unit as a bounded octet string is a length-
delimited carriage.
Jorgen Expires 30 January 2027 [Page 18]
Internet-Draft TTTPS July 2026
For a length-delimited carriage -- one that presents the
verifier with a bounded octet string, such as an HTTP/3 frame
(Section 5.3), a stored object, or a database field -- the
verifier MUST reject unless the delivered length equals the unit
length exactly. A unit delivered short, or with trailing
octets, MUST be rejected here and MUST NOT be padded, trimmed,
or re-parsed under the other length. For a byte-stream carriage
-- one in which the unit is drawn from a stream the application
also uses for other purposes, such as TLS 1.3 application data
(Section 5.1) or a QUIC stream (Section 5.2) -- the verifier
MUST read exactly the unit length from the stream and stop. A
stream that ends before the unit is complete is a truncation and
MUST be rejected here. Octets that follow the unit on such a
stream are the application's own traffic: a verifier MUST NOT
treat them as evidence about the record, and MUST NOT require
that the stream carry nothing after the unit. A verifier that
rejects a unit taken from a byte stream at any of steps 1
through 6 MUST fail the session rather than return the stream to
the application. The unit length was derived from a Flags bit 0
that nothing authenticates until step 5, so a presenting peer
that lies about it shifts the stream by the difference between
the two unit lengths -- 96 octets where the unit is the
structure of Section 5.1, 32 where the unit is the record alone
-- and a verifier that rejects the record and reads on would
hand the application either the tail of the Presenter's own
structure or a request from which that many octets have been
consumed.
The requirement stops after step 6 because that is where the
exposure stops. A record that reaches step 7 has had a
signature over a P verified: on the step 5 path over P as
received, and on the recovery path over a recovered P whose
Flags field Section 3.3.1 forbids recovery to have altered.
Either way the Flags bit 0 the unit length was derived from is
the value the Issuer signed, and the stream is positioned
exactly at the end of the unit. A rejection at step 7 or later
is therefore an application-level condition, this document
requires no session failure for it, and whether to continue is
for the application to decide. Requiring failure there would
hand any party able to re-present a record the verifier has
already seen a guaranteed session teardown at step 11, for the
cost of one replayed structure.
The session-failure requirement and the bound on it apply to a
byte-stream carriage only. On a length-delimited carriage the
boundary is supplied by the carriage, a rejected unit costs the
application nothing, and this document requires no session
failure at any step.
Jorgen Expires 30 January 2027 [Page 19]
Internet-Draft TTTPS July 2026
Flags is not authenticated at this step, so the step establishes
only that the octets to be parsed are present and delimited; it
establishes nothing about the record. A verifier MUST NOT retry
a unit that failed this step under the other length.
3. Reject a record whose Integrity Alg field names an algorithm the
verifier does not implement, or names a value this document
reserves without assigning.
4. Reject a record that fails any of these field-sanity checks: Src
Cnt is less than 3; the Tier value is not assigned in the "TTTPS
Tiers" registry (Section 9.4); the Error Bound is 0xFFFFFF; the
Error Bound exceeds the nominal tolerance of the record's Tier;
or the Timestamp is later than the verifier's own view of the
present by more than the Error Bound, since a record cannot have
been issued in the future. These read octets that are not yet
authenticated, and are performed here so that a record which
cannot be accepted does not cost an elliptic-curve operation;
every field they read lies inside P and is therefore covered by
the signature verified in step 5, so a record that passes step 5
has passed these checks on authenticated values. That reasoning
holds on the step 5 path only. The recovery branch of step 6
authenticates a different octet string from the one read here,
and none of Tier, Src Cnt, Error Bound, Timestamp, Nonce or
Issuer Key ID is outside the recovery capability of an arity-3
algorithm -- they are what remains of P once Section 3.3.1
places Version, Integrity Alg, Flags, Holder Key and Payload
Digest outside it and puts the Commitment and the Signature
structurally out of reach -- so step 6 re-applies these checks,
and the version and algorithm checks of steps 1 and 3, to the
recovered fields. This step is not a recency test: it bounds
the Timestamp from above only, and it applies in both roles.
5. Using the Issuer Key ID, obtain from a source it trusts every
key it trusts whose Issuer Key ID matches, together with the
interval over which each is valid; these are the candidates.
Verify the Ed25519 signature over the P being verified against
each candidate in turn; when this step is reached from step 4,
the P being verified is P as received. Let the satisfying set
be the set of candidates that both verify that signature and
have a validity interval containing the record's Timestamp.
This step has three outcomes.
It succeeds if the satisfying set is not empty and every
candidate in it carries the same public key; that key is carried
forward as the Issuer key. Both conditions are required, and
the first is not implied by the second: the empty set satisfies
the second condition vacuously, so a rule stated only as a
Jorgen Expires 30 January 2027 [Page 20]
Internet-Draft TTTPS July 2026
property that every member of the satisfying set has would be
met by a record for which no signature verified at all. Two
entries carrying the same public key are the rotation overlap a
trust store holds routinely and are not a failure.
It fails terminally, and the record MUST be rejected here, in
either of two cases: no key the verifier trusts carries the
Issuer Key ID at all, so there is no candidate; or the
satisfying set is not empty but holds two different public keys,
which is a collision on the Issuer Key ID and leaves the
verifier unable to tell which Issuer signed the record. Neither
condition is damage to the record, so no integrity algorithm can
repair either, and a verifier MUST NOT pass either to step 6:
doing so would expose the algorithm's decoder to a record that
could never have been accepted (Section 7.3).
Otherwise -- candidates exist, but the satisfying set is empty
-- it fails to step 6. This is the outcome that a record whose
fields reach the verifier altered produces, and it is the only
outcome from which the recovery branch of step 6 is reachable.
It is also produced by an undamaged record whose one verifying
key lay outside its validity interval, which is why step 6
rejects a verdict of intact rather than treating arrival at that
branch as evidence of damage.
A verifier MUST NOT apply a validity interval to a record on the
strength of the Issuer Key ID alone (Section 7.1).
6. If step 5 succeeded, carry the received fields forward to step 7
and record that no recovery was performed. This step is
otherwise reached only from the third outcome of step 5; a
record that failed step 5 terminally was rejected there and does
not arrive here. On arrival by that outcome, and only then,
reject the record unless all of the following hold: the
Integrity Alg is arity 3; the verifier implements recovery for
that algorithm; and the deployment has explicitly enabled the
recovery branch. Recovery is disabled by default, and a
verifier MUST NOT enable it implicitly on the ground that the
algorithm supports it.
Where it is enabled, the verifier evaluates the integrity
algorithm over the received fields, with the ctx_id it expects
and with the Commitment field as received as the expected value,
and then performs the following in the order given, rejecting
the record on the first failure.
Jorgen Expires 30 January 2027 [Page 21]
Internet-Draft TTTPS July 2026
It MUST reject on a verdict of unresolvable, and it MUST reject
on a verdict of intact. An intact verdict here means the
received fields are exactly the fields committed to, and so that
step 5 failed for some reason other than damage to the fields.
There are two such reasons: no candidate verified the signature
although the fields were undamaged, which is what damage
confined to the Signature produces, the Signature being 64 of
the 96 octets that Section 3.3.1 places outside the reach of
every registered algorithm; or the only key that verified the
signature lay outside its validity interval at the record's
Timestamp. Damage confined to the Commitment is not a third
reason: it defeats the signature in the same way, but it also
makes the commitment computed over the received fields unequal
to the Commitment field, so the verdict is unresolvable and the
record was rejected by the preceding rule before this one was
reached. Recovery repairs neither, and a record that reached
this branch by either MUST NOT be rescued onto the resolved
path. A verifier that logs a reason SHOULD NOT report the first
of the two as absence of a trusted key, since a record with no
trusted key at all was rejected at step 5 and never reached this
branch.
A ctx_id the verifier does not share with the Issuer is not a
third reason, and a verifier MUST NOT treat arrival at this
branch as evidence of one, since ctx_id is not an input to the
signature verified in step 5 and so cannot cause that step to
fail. A record issued under a ctx_id the verifier does not
expect reaches step 7 by the ordinary path and is rejected
there.
It MUST reject if recovery altered the Version, Integrity Alg,
Flags, Holder Key, or Payload Digest fields (Section 3.3.1).
These are the five fields that Section 3.3.1 places outside the
recovery capability of every registered algorithm, and this is
the point in this procedure at which that bound is enforced.
Section 9.3 enforces the same bound at registration time.
Otherwise it forms the recovered P as the recovered field block,
Version through Holder Key, followed by the Commitment field
exactly as received.
It MUST then re-apply steps 1, 3 and 4 to the recovered fields
and reject on any failure. Step 4 is re-applied because every
field it reads is inside the recovery capability of an arity-3
algorithm, so the fields it was performed on are not the fields
now being carried forward: without re-applying it, a record
whose committed Timestamp lies in the future, or whose committed
Src Cnt is below 3, would be rejected on the step 5 path and
accepted on this one. Steps 1 and 3 are re-applied as a
Jorgen Expires 30 January 2027 [Page 22]
Internet-Draft TTTPS July 2026
backstop to the field bound itself, so that a verifier which
fails to enforce that bound does not thereby accept a record
naming a version or an algorithm it does not implement. On a
verifier that enforces the bound they are expected to pass,
which is not a reason to omit them: their whole value is in the
case where the bound was not enforced, and a verifier cannot
know it is that case. All three are re-applied before the
signature check below and not after it, for the reason step 4
gives for their position in the procedure at large: the
recovered fields are decoder output over an input the attacker
chose in full, so an attacker who steers recovery towards a
value these checks reject would otherwise obtain a second
complete round of candidate selection and Ed25519 verification
for the cost of the sixty-four arbitrary octets that reached the
decoder in the first place.
It MUST then apply step 5 to the recovered P -- candidate
selection, Ed25519 verification, the validity-interval test,
both halves of that step's success condition alike, and every
other requirement that step states, including its prohibition on
applying a validity interval on the strength of the Issuer Key
ID alone -- and reject the record unless that application
succeeds. That prohibition matters more here than on the step 5
path, because the Issuer Key ID used for candidate selection is
now decoder output over an input the attacker chose in full. On
this application step 5 has two outcomes and not three: any
outcome other than success is a rejection here, since the
recovery branch is not re-entered. Candidate selection uses the
recovered Issuer Key ID and not the received one, because the
recovered value is the one under which the recovered P is
signed.
It then carries the recovered fields forward to step 7, carries
forward the verdict resolved, and records that recovery was
performed. The verdict on this branch is necessarily resolved:
unresolvable and intact are both rejected above, and
Section 3.3.1 defines no fourth verdict. The branch does not
recurse: the paragraph above collapses step 5's third outcome
onto rejection for the duration of this one application, so no
application of step 5 made from within step 6 can return control
to step 6, and the branch terminates after one level. The
references step 5 makes to step 6 describe the procedure's own
control flow and do not survive into an application of step 5
made from within step 6.
On this branch the recovered fields replace the received fields
for the remainder of this procedure. Every later step, and
every requirement this section states after step 12, that reads
Jorgen Expires 30 January 2027 [Page 23]
Internet-Draft TTTPS July 2026
a field of the record reads its recovered value, and the
recovered record -- the recovered field block, followed by the
Commitment field and the Signature field exactly as received --
is the record reported at step 12. Reading a received value at
a later step would apply that step's check to octets the
verifier has just established were not the ones committed to.
Five fields are outside recovery and the Commitment and the
Signature are outside its reach (Section 3.3.1), so this rule
bears on the Tier, the Src Cnt, the Error Bound, the Timestamp,
the Nonce, and the Issuer Key ID, and on nothing else. The
session binding recomputed at step 8 is the one exception, and
step 8 states it.
7. If step 6 recorded that no recovery was performed, evaluate the
integrity algorithm over the fields carried forward, with the
ctx_id the verifier expects and with the Commitment field as the
expected value, and reject unless the verdict is intact. On
that path the fields and the Commitment are both covered by the
signature verified in step 5, so any other verdict means the
record was issued against a different ctx_id and not that it was
damaged. This is the step that binds the record to the
verifier's application context: an otherwise valid record
presented in a context it was not issued for fails here. If
step 6 recorded that recovery was performed, the verdict of the
record is the resolved carried forward from step 6; the verifier
MUST NOT re-evaluate the algorithm over the recovered fields in
order to derive a verdict, because that evaluation compares
recovered fields against the Commitment they were recovered to
match and returns intact by construction, which would erase the
signal that the record arrived altered. In neither case may a
verifier collapse resolved onto intact, here or anywhere else
(Section 3.3.1). The verdict carried forward from this step is
the verdict reported at step 12.
8. Relying Verifier only. Recompute the session binding of
Section 4.1 from the verifier's own side of the session in which
the record was presented, using the role octet of the peer the
record was received from, and reject the record if the
recomputed value differs from the value presented with it. This
computation takes the record exactly as received, on the
recovery branch of step 6 as on every other path, and is the one
place in this procedure where a received value is read in
preference to a recovered one. The exporter input of
Section 4.1 is the octets that crossed the session, and the
Presenter computed its own binding over the octets it sent; a
record carried in a TLS or QUIC session reaches the verifier as
the Presenter sent it, because damage occurring in transit
inside such a session fails the transport's own integrity check
Jorgen Expires 30 January 2027 [Page 24]
Internet-Draft TTTPS July 2026
and no record is delivered. Damage that the recovery branch
repairs was therefore already present in the copy the Presenter
held and bound, and recomputing over the recovered record would
reject every record that branch exists to accept. This
reasoning rests on the record having crossed a session whose
transport authenticates every octet it delivers, and Section 4.1
defines the session binding for no other case. Where the
verifier is not party to such a session in which the record was
presented to it, whether because the carriage established no
such session or because that session has ended, no session
secret is available from which a session binding could be
derived, and a verifier in that position is an Auditor within
the meaning of Section 1.2. It omits this step and step 10 with
it; it does not omit this one alone and then reach step 10,
which delegates to a holder verification that consumes the value
this step recomputes. Step 11 states separately what such a
verifier does about replay. An Auditor cannot perform this step
and MUST report to the application that it was not performed.
9. If the verifier holds the payload, recompute its SHA-256 digest
and reject if it differs from the Payload Digest field. If the
verifier does not hold the payload, it MUST NOT treat the record
as covering any particular object, and MUST report the Payload
Digest to the application so that the binding can be checked
where the payload is available.
10. Relying Verifier only. If Flags bit 0 is set, perform holder
verification as specified in Section 4.2 and reject on failure.
An Auditor MUST NOT attribute the record to the Holder and MUST
report to the application that holder verification was not
performed; it MAY otherwise accept the record as an attestation
over the Payload Digest. Section 4.3 states why a retained
proof is not a substitute for this check.
11. Relying Verifier always, and an Auditor in the case identified
below. Reject a record whose Nonce the verifier has already
seen within its replay window. On the recovery branch of step 6
the value compared is the recovered Nonce, which is the Nonce
the Issuer committed to. Comparing the Nonce as received would
let an attacker re-present a record the verifier has already
seen with its Nonce damaged inside the algorithm's correction
capability: signature verification would fail, step 6 would
restore the committed Nonce and return resolved, and this check
would be applied to a value no Issuer ever issued and no
verifier has ever seen. An Auditor MUST NOT apply this check to
a retained record: re-examining a record that has been examined
before is precisely what an audit does, and applying replay
detection to it would defeat the durability property that
Jorgen Expires 30 January 2027 [Page 25]
Internet-Draft TTTPS July 2026
Section 2.2 depends on. An Auditor to which a record is
presented by a party acting as its Presenter, over a carriage
that established no session of Section 4.1, is not in that case:
it is not re-examining a record it holds, it is being shown one.
Neither session binding nor holder binding is available to it,
so the Nonce is the only means it has of detecting re-
presentation, and it SHOULD apply this check where it retains
the state to do so. A verifier that both retains records and
accepts records presented to it enters in its replay window only
the Nonces of records presented to it, and MUST NOT enter a
Nonce into that window on account of having examined the record
in its own store.
12. Report to the application the record -- on the recovery branch
of step 6, the recovered record -- its Error Bound, its Src Cnt,
its Tier, its integrity verdict, whether recovery was performed,
its Payload Digest, and whether session binding and holder
verification were performed.
Signature verification precedes integrity evaluation. Earlier
revisions of this specification performed the integrity evaluation
first, on the ground that it is cheaper than an elliptic-curve
operation. That ordering ran attacker-supplied input through the
integrity algorithm -- for an arity-3 algorithm, through a decoder --
on every record presented, including records that no key would ever
authenticate. Under the ordering specified here, a decoder is
reached only on the recovery branch of step 6.
That is a reduction in exposure and not an elimination of it, and the
difference should be stated plainly. Step 6 is entered precisely
when signature verification has failed, so the input a decoder sees
on that branch is by construction unauthenticated and may be entirely
attacker-chosen; an attacker who wants to reach the decoder need only
present a record carrying sixty-four arbitrary octets in place of the
Signature. That is why the recovery branch is disabled by default
and must be enabled deliberately: a deployment that leaves it
disabled never runs a decoder over unauthenticated input at all, and
a deployment that enables it is accepting a decoder as attack surface
in exchange for tolerance of damage the record carries by the time it
is verified. Section 7.3 states the residual exposure and states
where that damage can arise at all.
Tier tolerance (Section 6) is an application constraint, not a
property of the record. A verifier that requires recency MUST
compare the difference between its current time and the Timestamp
against the tolerance its application requires, and MUST widen that
comparison by the Error Bound. An Auditor MUST NOT apply a recency
test to a retained record; the audit case of Section 2.2 is the
Jorgen Expires 30 January 2027 [Page 26]
Internet-Draft TTTPS July 2026
principal instance. An Auditor to which a record is presented in the
case identified in step 11 MAY apply one, and where it does, the
requirement to widen the comparison by the Error Bound applies to it
as to any other verifier. The upper bound on the Timestamp imposed
by step 4 is not a recency test and applies in both roles. On the
recovery branch of step 6 the Timestamp and the Error Bound compared
here are the recovered values, by the propagation rule that step
states; this requirement is stated outside the numbered procedure and
is reached by that rule notwithstanding.
4. Session and Holder Binding
A PoT record is a bearer object. On its own it establishes when its
payload existed; it establishes nothing about who is presenting it or
in which session. Two separate bindings address the two separate
questions, and a deployment needs to be explicit about which it
requires.
4.1. Session Binding
Session binding answers: was this record presented in this session,
and in which direction? A Presenter that has established a TLS 1.3
or QUIC session derives
session_binding = TLS-Exporter("EXPORTER-tttps-pot-binding",
role || pot_record, 32)
where TLS-Exporter is the exporter interface of [RFC5705] as
instantiated for TLS 1.3 in Section 7.5 of [RFC9846]; role is the
single octet 0x00 if the Presenter is the client of the session and
0x01 if it is the server; and pot_record is the complete record
including its signature. Over QUIC the same exporter is used, taken
from the TLS 1.3 handshake that QUIC carries [RFC9001]; QUIC defines
no exporter of its own. The verifier recomputes the value from its
own side of the same session, using the role octet of the peer it
received the record from, and rejects on mismatch.
The role octet separates the two directions. Both peers derive from
the same exporter secret, so without the octet the binding a peer
computes over a given record is bit-for-bit the binding its peer
would compute over the same record, and a record captured in a
session could be reflected back to its own sender inside that session
and would pass. With the octet, a binding computed as client does
not verify as a binding computed as server. The octet does not make
the binding unforgeable by the peer: Section 4.2 is explicit that
either peer can compute the binding for any record it holds, and the
role octet does not change that. It removes reflection, and nothing
else.
Jorgen Expires 30 January 2027 [Page 27]
Internet-Draft TTTPS July 2026
The exporter MUST be the one derived from the exporter_master_secret
after the handshake has completed. A Presenter MUST NOT use the
early exporter and MUST NOT send a PoT record in TLS 1.3 early data
or in QUIC 0-RTT data; a verifier MUST discard a PoT record received
in either. Early data carries no transport replay protection, and a
binding derived from the early exporter is reproducible by an
attacker who replays that data, which is the case Appendix F.5.1 of
[RFC9846] warns about directly.
Because the exporter output is derived from the session's own
secrets, a value computed in one session does not verify in another.
4.2. Holder Binding
Session binding does not answer: is the party presenting this record
the party it was issued to? It cannot, because either peer of an
established session can compute the exporter output for any record it
holds. A record obtained by any means -- copied from a log, received
legitimately and retained, intercepted before it was protected -- can
be session-bound by whoever obtained it. Earlier versions of this
specification claimed otherwise; the claim was wrong, and this
section is the correction.
Holder binding answers the second question, and requires the Holder
Key field. At issuance the requester generates an Ed25519 key pair
and supplies the public part; the Issuer copies it into P, where the
Issuer's signature covers it. At presentation, the Presenter
computes
pop = Ed25519-Sign(holder_private_key,
"tttps-holder-binding-v1" || 0x00 ||
session_binding)
and transmits pop with the record. The verifier, having already
recomputed session_binding as in Section 4.1 and having verified the
Issuer's signature over P, verifies pop against the Holder Key
carried in P. It MUST reject the record if pop does not verify.
Possession of the record is then insufficient to present it: an
attacker must also hold the holder private key, which never appears
in the record, in the session, or in any log of either. Binding pop
to session_binding rather than to the record alone additionally
prevents a captured pop from being replayed into a different session.
An Issuer SHOULD issue holder-bound records by default. A deployment
that issues records without a Holder Key MUST treat them as bearer
objects and MUST NOT rely on them to attribute an action to a party.
Jorgen Expires 30 January 2027 [Page 28]
Internet-Draft TTTPS July 2026
4.3. What the Bindings Do Not Prove
Neither binding makes the Timestamp more trustworthy. Both concern
presentation; the time in the record is only as good as the Issuer
and its sources. Neither binding says anything about the payload
either: that is the Payload Digest, and it is only as good as the
requester's honesty in computing it, since the Issuer never sees the
payload.
Holder binding proves control of a key at presentation time, not the
identity of the controller, and not that the same party controlled
the key at issuance if it has since been transferred. A verifier
that needs to name the Holder must obtain that mapping elsewhere.
An Auditor (Section 1.2), of which the audit case of Section 2.2 is
the principal instance, cannot check session binding at all, because
no session secret is available to it. It is tempting to fix this by
retaining the pair (session_binding, pop) alongside the record and
checking it later. That does not preserve the property. The pair is
a static value that verifies against the Holder Key forever, so
anyone who obtains the retained pair can present it, and holder
binding degrades to exactly the bearer credential that Section 4.2
exists to eliminate. Retaining the pair is therefore evidence of
what the verifier that received the presentation saw, and is useful
as such. A verifier MUST NOT treat a retained pair as establishing
that the Holder presented the record unless it received that pair
itself, over the session from which the session binding was derived,
and is reporting its own observation. An Auditor never satisfies
that condition; neither does a verifier to which a record and a pair
are forwarded by the party that received them. What an Auditor can
establish without the session is narrower and should be stated as
such: that the Issuer signed this Payload Digest at this time, with
this error bound, to a Holder Key it recorded. Attribution of the
presentation to the Holder rests on the log, kept by the verifier
that received the presentation over the session, of having performed
step 10 of Section 3.5, and inherits that verifier's trustworthiness.
5. Transport Binding
A PoT record is transport-independent. This section defines carriage
over three transports for interoperability; a record carried by any
other means is not thereby less valid.
Jorgen Expires 30 January 2027 [Page 29]
Internet-Draft TTTPS July 2026
5.1. TLS 1.3
Over TLS 1.3, a PoT record is sent as application data after the
handshake has completed. TTTPS defines no TLS extension, consumes no
extension codepoint, and does not alter the handshake. The exporter
label "EXPORTER-tttps-pot-binding" is registered in Section 9.1.
TLS 1.3 application data is a byte-stream carriage in the sense of
step 2 of Section 3.5. TLS record boundaries are not message
boundaries and are not exposed to the application, so a receiver
reads exactly the length of the structure below from the stream and
stops. The structure is not required to be the only thing the
application sends on the connection, and octets that follow it are
the application's own traffic.
The record is transmitted first, because it is the only element whose
length is self-describing and it is what tells the receiver whether a
holder proof follows:
pot_record 184 octets, or 216 if Flags bit 0 is set
session_binding 32 octets
pop 64 octets, present iff Flags bit 0 is set
A receiver reads the first two octets of the record, takes Flags
bit 0, and thereby knows both the record length and the total length
of the structure. Earlier revisions placed the session binding
first, which made the structure unparseable without knowing in
advance whether the record was holder-bound.
TTTPS defines no ALPN identifier. A peer that wishes to know whether
its peer supports TTTPS before sending a record establishes that at
the application layer. An earlier revision requested an ALPN
registration; that was wrong twice over, because ALPN values are
mutually exclusive and TTTPS is not an alternative to h3 or http/1.1,
and because negotiating in the handshake contradicts the statement in
Section 1.1 that TTTPS does not participate in it.
5.2. QUIC
Over QUIC [RFC9000] used directly by an application, rather than
through HTTP/3, the record and the structure of Section 5.1 are
carried on a stream of the application's choosing. This document
registers no QUIC codepoint of any kind: no frame type, no transport
parameter, and no stream type. A QUIC stream is a byte-stream
carriage in the sense of step 2 of Section 3.5, and the structure is
read from it in the same way. QUIC's stream type space is not an
IANA registry that this document may write into, and an application
using QUIC directly already controls its own stream semantics. What
Jorgen Expires 30 January 2027 [Page 30]
Internet-Draft TTTPS July 2026
this section specifies is the derived value: the session binding of
Section 4.1 is computed from the TLS 1.3 exporter of the handshake
QUIC carries [RFC9001].
5.3. HTTP/3
Over HTTP/3 [RFC9114], a PoT record is carried in a frame whose type
is registered in Section 9.2. The frame MAY appear on a request or
response stream. A receiver that does not understand the frame type
ignores it, as required by [RFC9114]; this yields backward
compatibility without negotiation.
An HTTP/3 frame is a length-delimited carriage in the sense of step 2
of Section 3.5: the frame length delimits the structure exactly, and
a frame whose length exceeds the structure is rejected.
The frame payload is the structure of Section 5.1 in full -- the
record, then the session binding, then pop if Flags bit 0 is set --
and not the bare record. Carrying only the record would leave holder
binding unusable over HTTP/3, because the receiver would have no
session binding to compare and no pop to verify, and this document
would then promise a binding it provides no way to carry. The frame
length is therefore 216 octets when Flags bit 0 is clear and 312
octets when it is set. A receiver MUST reject a frame whose HTTP/3
frame length disagrees with the length derived from Flags bit 0 of
the record it contains.
HTTP is a hop-by-hop protocol whose messages may be forwarded by
intermediaries (Section 3.7 of [RFC9110]), and an HTTP/3 extension is
effective only within the scope of a single connection (Section 9 of
[RFC9114]). The session binding in a TTTPS_POT frame is derived from
the exporter of the connection the frame arrived on, and Section 4.1
makes it unverifiable on any other. An intermediary that implements
this specification and re-emits the frame on its own downstream
connection is the Presenter there and MUST recompute the session
binding of Section 4.1 over that connection, using its own role
octet; it MUST NOT copy the session binding it received. It cannot
recompute pop, which is signed with a key it does not hold, so holder
binding does not survive an intermediary: such an intermediary MUST
NOT re-emit a frame carrying a record whose Flags bit 0 is set, and a
holder-bound record travels from Presenter to verifier over one
connection or not at all. An intermediary that forwards a frame
unchanged does not weaken a verifier -- the stale session binding
fails step 8 of Section 3.5 and the record is rejected -- but it
makes the record unusable, which is why the requirement is stated
here rather than left to be discovered. This document does not
require an intermediary that implements this specification and re-
emits the frame to verify the record first: the Issuer's signature
Jorgen Expires 30 January 2027 [Page 31]
Internet-Draft TTTPS July 2026
covers the record end to end, and the verifier at the far end
performs the procedure of Section 3.5 for itself, so a record that
would have been rejected there is rejected there whether or not the
intermediary looked at it. What the recomputed session binding
attests downstream is that the intermediary presented the record, and
not that the intermediary found it valid; a deployment that needs the
latter has to obtain it by means this document does not provide.
Two things follow from leaving that verification optional, and the
Issuer's signature repairs neither. A verifier that accepts records
through an intermediary that does not itself verify them accepts,
over that connection, records originating with any party able to
reach the intermediary; a deployment that has enabled the recovery
branch of step 6 of Section 3.5 cannot then bound the set of parties
that can reach its decoder by its choice of peers, and Section 7.3 is
to be read accordingly. And where such a record is rejected, the
session binding names the intermediary and this document provides no
means of naming the party the record originated with, so a verifier
that responds to repeated failures by limiting a peer limits the
intermediary.
This document defines no signal for a frame withheld under that
prohibition. An intermediary that declines to re-emit a holder-bound
frame has no TTTPS_POT-level means of saying so, and because
Section 4.2 directs an Issuer to issue holder-bound records by
default, that is the ordinary outcome of interposing an intermediary
rather than an exceptional one. A deployment that requires holder
binding over an HTTP/3 path carrying intermediaries cannot obtain it
from this document.
An intermediary that does not implement this specification ignores
the frame as an unknown type (Section 9 of [RFC9114]). Because an
HTTP/3 extension is effective only within the scope of a single
connection, and because an intermediary forwards the reconstructed
HTTP message rather than the framing it arrived in (Section 3.7 of
[RFC9110]), the frame is not re-emitted on the next connection, and
neither endpoint is signalled that it was not. Tolerance of an
unknown frame type without negotiation is a property of endpoints,
and it is what allows an endpoint that does not implement TTTPS_POT
to interoperate. It does not extend through an intermediary: on such
a path the record does not arrive at all, and the verifier sees a
request carrying no PoT record rather than one carrying a record it
would reject.
Jorgen Expires 30 January 2027 [Page 32]
Internet-Draft TTTPS July 2026
6. Tier Structure
The Tier field names the resolution at which the Issuer intends the
record to be used. It does not alter any cryptographic processing,
but it is not advisory: step 4 of Section 3.5 makes an unassigned
Tier value, and an Error Bound exceeding the nominal tolerance of the
record's Tier, grounds for rejection. What remains an application
matter is the tolerance a verifier requires of a record it accepts,
which may be tighter or looser than the nominal value.
+=======+===========+===================+
| Value | Name | Nominal tolerance |
+=======+===========+===================+
| 0x0 | T0_coarse | 10 s |
+-------+-----------+-------------------+
| 0x1 | T1_second | 1 s |
+-------+-----------+-------------------+
| 0x2 | T2_milli | 100 ms |
+-------+-----------+-------------------+
| 0x3 | T3_fine | 1 ms |
+-------+-----------+-------------------+
Table 1: Tier identifiers
Tier values are ordered: a numerically lower value denotes a larger,
that is a coarser, nominal tolerance. "A coarser tier" means a
numerically lower Tier value. Every tolerance in the table is
representable in the Error Bound field of Section 3.2. Earlier
revisions of this document defined a 60 second tier, which is not
representable there, and defined tolerances that did not decrease
monotonically with the Tier value, which left the instruction to fall
back to a coarser tier without a referent.
Values 0x4 through 0xF are unassigned. An Issuer MUST NOT emit a
record whose Error Bound exceeds the nominal tolerance of its Tier.
The nominal tolerance governs the field-sanity check of step 4 of
Section 3.5, which rejects a record whose Error Bound exceeds it, in
both roles and whatever the verifier's application requires. A
verifier's own tolerance, which may be tighter or looser than the
nominal value, governs only the recency comparison stated after the
numbered steps of that section, and only where that comparison is
permitted at all: an Auditor MUST NOT apply a recency test to a
retained record.
Jorgen Expires 30 January 2027 [Page 33]
Internet-Draft TTTPS July 2026
7. Security Considerations
7.1. The Issuer Is Trusted, and Auditable
The Issuer can sign a time it knows to be false. Nothing in the
record prevents this; the signature proves only that the Issuer
signed it. It can also sign a Payload Digest for a payload that did
not exist, because it never sees the payload. Deployments should be
clear that what a PoT record moves is the trust, not the need for it:
from either endpoint of the session to a named third party whose key
is published and whose output can be logged.
An append-only log of issued records is often proposed as the answer,
and this document does not specify one, so its limits should be
stated rather than implied. A log detects Issuer equivocation only
if a relying party can check that a record it holds appears in the
log, and that the log it is shown is the log everyone else is shown.
The first requires inclusion proofs; the second requires gossip,
witnessing, or an equivalent. Without both, an Issuer that simply
omits a record from its log leaves a log that is perfectly consistent
and a victim with no way to notice. A deployment that depends on
detecting Issuer misbehaviour therefore needs a transparency
mechanism with those properties -- the structure of [RFC9162] is one
-- and this document supplies neither. A deployment without one is
trusting the Issuer in the same way, and to the same degree, that a
relying party trusts a certification authority that is not logged.
Compromise of an Issuer's private key allows arbitrary record
forgery, including backdated records, for as long as the key is
believed valid. Issuers SHOULD publish, for each signing key, its
Issuer Key ID and the interval over which it is valid, and SHOULD
rotate keys. Verifiers MUST check that a record's Timestamp falls
within the validity interval of the key that actually verified its
signature, as required by step 5 of Section 3.5; a record whose
Timestamp falls outside it MUST be rejected. The Issuer Key ID field
is what makes this check performable and key rotation deployable; an
earlier revision required the check while providing no way to carry
it out.
The Issuer Key ID is sixty-four bits and carries no Issuer name, so
it selects candidates rather than identifying a key. Two trusted
keys can share an Issuer Key ID by accident once a verifier trusts of
the order of 2**32 of them, and by construction at a cost an
adversary can pay. This is why step 5 of Section 3.5 requires that
at least one candidate both verify the signature and carry a validity
interval containing the Timestamp, and that every candidate which
does so carry the same public key; and why a validity interval is
never applied on the strength of the identifier alone: a matching
Jorgen Expires 30 January 2027 [Page 34]
Internet-Draft TTTPS July 2026
identifier is not evidence about a record, and the only evidence is
the signature. The two conditions do different work. The first is
what makes the signature check load-bearing at all, and it is the
condition an implementation is most likely to lose when it rewrites
the rule as a predicate quantified over a set, since such a predicate
holds of the empty set. The second is what makes a colliding
identifier fatal rather than silently resolved in the attacker's
favour, while leaving acceptable the case of a key a trust store
holds under two entries across a rotation overlap, since those two
entries are the same key and the verifier is not being asked to
choose. Widening the field would not remove the need for either. A
verifier that trusts exactly one Issuer key at a time may implement
step 5 as a single verification, but the rule is what makes the
general case safe.
7.2. Time Source Independence
The synthesis of Section 3.4 relies on the sources being independent.
Sources in distinct administrative domains may nonetheless share a
single upstream reference, a common satellite navigation receiver, or
a common network path to the Issuer, in which case an adversary who
influences the shared element moves the median without exceeding any
dispersion check. An Issuer SHOULD select sources that differ in
upstream reference, in physical path, and in operator, and SHOULD
widen the Error Bound when it cannot establish that they do. A
dispersion check alone does not establish independence: correlated
sources agree.
An adversary who delays rather than alters the Issuer's queries
biases the synthesis by up to the added delay. The Error Bound is
the defence available to the verifier, which is why understating it
is prohibited in Section 3.4 and why a verifier is required to
surface it in Section 3.5.
Independence is not checkable from the record: Src Cnt says how many
sources were consulted and nothing says what they were. An Issuer
SHOULD therefore publish, alongside each signing key and its validity
interval, the set of source classes from the "TTTPS Time Source
Classes" registry (Section 9.5) that it consults for records signed
with that key, and SHOULD publish any change to that set before
issuing under it. A verifier that cares about independence SHOULD
obtain that set by the same out-of-band means by which it obtains the
key, and judge whether the classes are diverse enough for its
purpose. That is the only use this document makes of the registry.
No field of the record carries a class, and a class carried in the
record would be an unverifiable self-assertion by the very party the
registry exists to constrain.
Jorgen Expires 30 January 2027 [Page 35]
Internet-Draft TTTPS July 2026
7.3. Accepting a Resolved Verdict
Recovery never applies to the Version, Integrity Alg, Flags, Holder
Key, or Payload Digest fields; Section 3.3.1 places all five outside
the capability of any registered algorithm, and Section 3.5 requires
rejection if recovery altered any of them. Without that constraint,
an attacker who strips the Holder Key from a holder-bound record and
clears Flags bit 0 removes 32 octets of 216, which is within the
erasure capability an arity-3 algorithm might plausibly declare, and
the verifier would helpfully repair the record into one whose holder
binding it then cannot check.
A verdict of resolved means the record arrived altered and the
committed content was recovered. Recovery is a statement about the
fields, not about the cause: an alteration within the algorithm's
capability is indistinguishable from accidental damage, and an
adversary who can alter a record before it is verified can choose an
alteration that falls within it. A verifier that accepts a resolved
record therefore MUST proceed to signature verification over the
recovered fields, and MUST NOT treat recovery as evidence of benign
cause. What such a verifier reports to the application is the
recovered fields and not the fields as received: the recovered fields
are the committed content, and the fields as received are the ones
the verdict records as damaged. Section 3.5 states this as a rule of
the procedure and names the single exception. A deployment in which
record alteration is expected to be adversarial rather than
accidental SHOULD reject resolved records and SHOULD log them.
Enabling the recovery branch of step 6 of Section 3.5 exposes the
algorithm's decoder to unauthenticated, attacker-chosen input. That
branch is reached only after signature verification has failed, which
is a condition an attacker produces at will by presenting any sixty-
four octets as the Signature; ordering recovery after signature
verification reduces how often a decoder runs on ordinary traffic,
but it does not prevent an attacker from reaching it. A deployment
that enables recovery is accepting the decoder as attack surface and
SHOULD do so only where that decoder is itself hardened against
malformed input and where damage is common enough to be worth the
exchange. Where that damage can arise depends on the carriage, and a
deployment cannot weigh the exchange without settling that first.
Over the transports of Section 5 it does not arise in transit: a
record altered inside a TLS or QUIC session fails the transport's own
integrity check and is not delivered at all, so the damage the branch
repairs was already present in the copy the Presenter held and bound,
having been introduced at issuance, in storage, in handling, or by
the Presenter itself. That damage need not be contemporaneous with
verification, and the transports of Section 5 are not the only
carriage this document contemplates: that section opens by stating
Jorgen Expires 30 January 2027 [Page 36]
Internet-Draft TTTPS July 2026
that a PoT record is transport-independent and that a record carried
by any other means is not thereby less valid, and the property
Section 2.2 relies on is durability, the record remaining evaluable
long after the session that carried it is gone. A record that is
retained, archived, copied between systems, or delivered to a
verifier over a path that does not authenticate the octets it carries
can acquire damage at any point between issuance and verification.
The deployment with the longest such exposure is the audit deployment
of Section 2.2, whose verifier is an Auditor within the meaning of
Section 1.2 and whose records are evaluated from storage rather than
from a session.
The exchange is therefore weighed against the whole life of the
record and not against its last hop. A deployment gains nothing from
the branch only where every record it verifies was under integrity
protection continuously from issuance to verification, leaving no
interval in which damage could have entered undetected. Carriage
over the transports of Section 5 shows that for the last hop alone;
the intervals before it -- from issuance to the Presenter, any period
the record spent at rest, and any handling in between -- have to be
shown separately, as does the last hop itself where it is not one of
those transports. A deployment that can show that every interval
from issuance to verification was under integrity protection SHOULD
leave the branch disabled. Every other deployment SHOULD weigh the
decoder exposure against the exposure of the intervals it cannot show
were protected, rather than assume that either dominates. Retention,
archival, copying between systems, and acceptance over a carriage
this document does not specify are the ordinary ways an interval is
left unshown, and the audit deployment of Section 2.2 is on that side
by construction. A deployment that leaves recovery disabled never
evaluates an integrity algorithm over input that no Issuer key
authenticated.
7.4. Replay
The Nonce permits a verifier to detect the re-presentation of a
record it has already seen, within whatever window it retains.
Across verifiers, or beyond that window, the Nonce does nothing;
holder binding (Section 4.2) is the mechanism that limits who can re-
present a record at all, and session binding limits where. A
deployment that uses neither, and that relies on nonce tracking
alone, is protected only for as long as its own retention window.
An Auditor (Section 1.2) to which a record is presented by a party
acting as its Presenter, over a carriage that established no session
of Section 4.1, has neither session binding nor holder binding
available to it. For such a verifier the Nonce is the only defence
against re-presentation this document offers, which is why step 11 of
Jorgen Expires 30 January 2027 [Page 37]
Internet-Draft TTTPS July 2026
Section 3.5 provides that it SHOULD apply the check where it retains
the state to do so, and confines the prohibition to the record it is
re-examining from its own store.
7.5. Side Channels
Verification of the record itself handles no secret belonging to the
verifier: the Issuer public key, the Holder Key, the Payload Digest,
and ctx_id are all public. Recomputing the session binding of
Section 4.1 is a different matter -- it consumes the session's
exporter secret -- but that computation is performed by the TLS or
QUIC implementation and inherits whatever side-channel properties
that implementation has. The holder private key used to compute pop
is secret, and an implementation of Section 4.2 SHOULD use a
constant-time Ed25519 signing implementation. A verifier's
comparisons against the session binding and against pop SHOULD be
constant-time, to avoid leaking how much of a forged value was
correct. The corresponding comparison against the expected value is
internal to the integrity evaluation, and Section 3.3 already
requires it of every registered algorithm as part of the bounded-work
property; a verifier does not itself compare a computed commitment
against the Commitment field.
8. Privacy Considerations
A PoT record is designed to be shown to a stranger, so everything in
it should be treated as public once presented.
The Holder Key is a stable identifier for as long as it is reused. A
Holder that obtains many records under one key makes those records
linkable to each other by anyone who sees more than one, including
the Issuer. A Holder for whom this matters SHOULD use a fresh key
pair per record, which costs one key generation and preserves every
property of Section 4.2.
The Issuer necessarily learns that a requester asked for a record at
a given time, learns the Payload Digest, and, if a Holder Key is
supplied, learns that key. It does not learn the payload itself.
A digest is not a secret when the space of payloads is small. A
Payload Digest over a short, structured, or otherwise low-entropy
payload can be inverted by exhaustive search by anyone who sees the
record, including the Issuer. An application for which this matters
SHOULD commit to a salted or otherwise randomised encoding of the
payload rather than to the payload directly, and disclose the salt
only to parties entitled to check the binding. The record is
unchanged either way; the digest is opaque to this document.
Jorgen Expires 30 January 2027 [Page 38]
Internet-Draft TTTPS July 2026
ctx_id is subject to the same reasoning and to a further one.
Applications SHOULD NOT place personal data or content in ctx_id:
this document defines no protection for it, and every verifier must
know it in order to evaluate the record at all.
The Timestamp and Error Bound together disclose the Issuer's clock
quality at the moment of issuance, and the Src Cnt discloses how many
sources it consulted. Neither is sensitive in isolation; an Issuer
serving a small population should be aware that the combination is
distinguishing.
9. IANA Considerations
9.1. TLS Exporter Labels Registry
IANA is requested to add the following entry to the "TLS Exporter
Labels" registry:
Value: EXPORTER-tttps-pot-binding
DTLS-OK: N
Recommended: N
Reference: [this document], Section 4.1
"Recommended" is N because this document is Experimental and has not
been through IETF review. "DTLS-OK" is N because this document
defines no use of the label with DTLS: Section 4.1 derives the
session binding from a TLS 1.3 or QUIC session only, and Section 5
specifies no carriage over DTLS and so places no DTLS carriage in
either of the two classes that step 2 of Section 3.5 distinguishes.
Nothing here is a statement that the label would be unsafe with DTLS;
a document that specifies such a carriage can request the value be
changed.
9.2. HTTP/3 Frame Type
IANA is requested to add the following entry to the "HTTP/3 Frame
Types" registry, using the template required by Section 11.2 of
[RFC9114]:
Value: TBD (to be assigned by IANA)
Frame Type: TTTPS_POT
Status: provisional
Reference: [this document], Section 5.3
Change Controller:
Heime Jorgen <peter@kenosian.com>
Contact: Heime Jorgen <peter@kenosian.com>
Jorgen Expires 30 January 2027 [Page 39]
Internet-Draft TTTPS July 2026
This is the only codepoint this document requests outside its own
"TTTPS Parameters" group. It requests no HTTP/3 stream type: the
frame of Section 5.3 carries the record on an existing request or
response stream, and a stream type would add a second way to do the
same thing. An earlier revision requested a registration in a "QUIC
Stream Types" registry, which does not exist, and then cited an
HTTP/3 stream type as serving carriage over bare QUIC, which it does
not. Carriage over QUIC used directly by an application is that
application's own affair (Section 5.2), and this document registers
no QUIC codepoint of any kind.
9.3. TTTPS Integrity Algorithms Registry
IANA is requested to create a registry "TTTPS Integrity Algorithms"
under a new "TTTPS Parameters" group. The registration procedure is
Specification Required [RFC8126]. Each entry MUST state a verdict
arity as defined in Section 3.3.1. Initial contents:
Value | Name | Arity | Reference
---------------+------------+-------+----------------------------
0x0000 | Reserved | -- | [this document]
0x0001 | SHA-256 | 2 | [this doc], Section 3.3.2
0x0002 - 0x00FF| Unassigned | -- | Specification Required
0x0100 | Reserved | 3 | [this doc], Section 3.3.2
0x0101 - 0xFFFF| Unassigned | -- | Specification Required
0x0100 is reserved and not assigned. It is held for the arity-3
algorithm described informatively in Section 3.3.2, and will be
assigned only on publication of a specification meeting the
requirements of this registry. This document deliberately does not
register it: a registry whose procedure is Specification Required
cannot be opened with an entry that has no specification.
The designated expert is instructed to reject any registration that
names a subset, stage, or variant of an already-registered algorithm
rather than a complete evaluation, and any registration whose
specification does not state a verdict arity. The designated expert
is further instructed to reject any registration whose declared
recovery capability extends to the Version, the Integrity Alg, the
Flags, the Holder Key, or the Payload Digest field (Section 3.3.1).
Those five fields are outside the recovery capability of every
algorithm registered under this document, so a registration declaring
capability over any of them describes an algorithm this document does
not admit.
Jorgen Expires 30 January 2027 [Page 40]
Internet-Draft TTTPS July 2026
9.4. TTTPS Tier Registry
IANA is requested to create a registry "TTTPS Tiers" under the same
group, with the registration procedure Specification Required
[RFC8126]. Each entry states a value, a name, a nominal tolerance,
and a reference. Initial contents:
Value | Name | Nominal tolerance | Reference
------------+------------+-------------------+-----------------
0x0 | T0_coarse | 10 s | [this document]
0x1 | T1_second | 1 s | [this document]
0x2 | T2_milli | 100 ms | [this document]
0x3 | T3_fine | 1 ms | [this document]
0x4 - 0xF | Unassigned | -- | Spec. Required
These are the tiers of Table 1. The designated expert is instructed
to reject any registration whose nominal tolerance is not
representable in the Error Bound field of Section 3.2, and any
registration that would break the ordering stated in Section 6, under
which a numerically lower value denotes a coarser tolerance.
9.5. TTTPS Time Source Classes Registry
IANA is requested to create a registry "TTTPS Time Source Classes"
under the same group, registration procedure Specification Required
[RFC8126]. Entries name classes of time source, not operators.
Initial contents:
Value | Name | Reference
--------+-----------------------------+-----------------
0x00 | Reserved | [this document]
0x01 | National metrology institute| [this document]
0x02 | Satellite navigation | [this document]
0x03 | Public network time service | [this document]
0x04 | Local reference clock | [this document]
others | Unassigned | Spec. Required
Earlier versions of this document listed named operators in this
registry. Naming operators in a protocol registry is inappropriate:
it embeds commercial relationships in a standards artifact and
misstates the property the Issuer relies on, which is independence of
class and path, not identity of vendor.
Jorgen Expires 30 January 2027 [Page 41]
Internet-Draft TTTPS July 2026
9.6. URI Scheme
IANA is requested to register the URI scheme "tttps" provisionally in
the "Uniform Resource Identifier (URI) Schemes" registry, using the
template of Section 7.4 of [RFC7595]. Provisional registration does
not imply endorsement by the IETF or that the scheme is in wide use.
Scheme name: tttps
Status: provisional
Applications/protocols that use this scheme name:
Applications that obtain Proof-of-Time records
from a PoT Issuer, as specified in [this document].
Contact: Heime Jorgen <peter@kenosian.com>
Change controller:
Heime Jorgen <peter@kenosian.com>
References: [this document]
Syntax. A "tttps" URI identifies a PoT Issuer service endpoint. It
uses the generic authority and path syntax of [RFC3986]:
tttps-URI = "tttps:" "//" authority path-abempty [ "?" query ]
Encoding, semantics beyond identification of the endpoint, and the
protocol spoken at that endpoint are deliberately not defined here:
issuance is out of scope for this document (Section 1.1). This is
the reason the registration requested is provisional and not
permanent. No permanent registration is requested, and a permanent
registration would require a specification of the issuance protocol
that this document does not contain.
10. Intellectual Property
The integrity algorithm for which Section 9.3 reserves 0x0100 (GRG)
is the subject of a pending patent application by the author. Any
applicable IPR disclosure is filed with the IETF in accordance with
BCP 79 [RFC8179]; this document states no licensing terms and the
reader is referred to the IETF IPR disclosure system.
This document is fully implementable without GRG. The mandatory-to-
implement integrity algorithm is unkeyed SHA-256 (0x0001), which is
unencumbered, and an implementation that supports only 0x0001 is a
conforming implementation. Interoperability does not depend on
0x0100. This arrangement is deliberate: the specification does not
require any implementer to obtain a licence.
Jorgen Expires 30 January 2027 [Page 42]
Internet-Draft TTTPS July 2026
11. Implementation Status
This section records the status of known implementations at the time
of posting, in accordance with [RFC7942]. It is to be removed before
publication as an RFC.
*OpenTTT* [OPENTTT]. An open-source implementation in Rust.
Coverage: an earlier revision's record format and verification
procedure, including the 0x0001 integrity algorithm; QUIC and TLS 1.3
carriage over quinn 0.11; a no_std verifier suitable for constrained
devices. Nothing in that coverage tracks the record layout of this
revision. The Issuer Key ID field, the Payload Digest field, holder
binding (Section 4.2), the role octet in the session binding
(Section 4.1), and the reordered verification procedure of
Section 3.5 are new in this revision and are not yet implemented; the
184- and 216-octet records specified here are therefore not yet
produced or consumed by any implementation known to the author.
Maturity: experimental. Licence: open source. Contact: the author.
*Independent implementations.* None known. The author is aware of no
interoperability testing between independent implementations, and the
specification should be read as unproven in that respect.
12. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66,
RFC 3986, DOI 10.17487/RFC3986, January 2005,
<https://www.rfc-editor.org/info/rfc3986>.
[RFC5705] Rescorla, E., "Keying Material Exporters for Transport
Layer Security (TLS)", RFC 5705, DOI 10.17487/RFC5705,
March 2010, <https://www.rfc-editor.org/info/rfc5705>.
[RFC6234] Eastlake 3rd, D. and T. Hansen, "US Secure Hash Algorithms
(SHA and SHA-based HMAC and HKDF)", RFC 6234,
DOI 10.17487/RFC6234, May 2011,
<https://www.rfc-editor.org/info/rfc6234>.
[RFC7595] Thaler, D., Ed., Hansen, T., and T. Hardie, "Guidelines
and Registration Procedures for URI Schemes", BCP 35,
RFC 7595, DOI 10.17487/RFC7595, June 2015,
<https://www.rfc-editor.org/info/rfc7595>.
Jorgen Expires 30 January 2027 [Page 43]
Internet-Draft TTTPS July 2026
[RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
Signature Algorithm (EdDSA)", RFC 8032,
DOI 10.17487/RFC8032, January 2017,
<https://www.rfc-editor.org/info/rfc8032>.
[RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for
Writing an IANA Considerations Section in RFCs", BCP 26,
RFC 8126, DOI 10.17487/RFC8126, June 2017,
<https://www.rfc-editor.org/info/rfc8126>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC9000] Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based
Multiplexed and Secure Transport", RFC 9000,
DOI 10.17487/RFC9000, May 2021,
<https://www.rfc-editor.org/info/rfc9000>.
[RFC9001] Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure
QUIC", RFC 9001, DOI 10.17487/RFC9001, May 2021,
<https://www.rfc-editor.org/info/rfc9001>.
[RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "HTTP Semantics", STD 97, RFC 9110,
DOI 10.17487/RFC9110, June 2022,
<https://www.rfc-editor.org/info/rfc9110>.
[RFC9114] Bishop, M., Ed., "HTTP/3", RFC 9114, DOI 10.17487/RFC9114,
June 2022, <https://www.rfc-editor.org/info/rfc9114>.
[RFC9846] Rescorla, E., "The Transport Layer Security (TLS) Protocol
Version 1.3", RFC 9846, DOI 10.17487/RFC9846, July 2026,
<https://www.rfc-editor.org/info/rfc9846>.
13. Informative References
[OPENTTT] Helm Protocol, "OpenTTT: a reference implementation of
TTTPS", 2026, <https://github.com/Helm-Protocol/OpenTTT>.
[POT2026] Jorgen, H., "Proof-of-Time: Byzantine-Resilient Temporal
Ordering in Untrusted Networks -- A Mathematical Extension
of Shannon's Channel Theory", DOI 10.2139/ssrn.6467220,
2026, <https://doi.org/10.2139/ssrn.6467220>.
Jorgen Expires 30 January 2027 [Page 44]
Internet-Draft TTTPS July 2026
[RFC7942] Sheffer, Y. and A. Farrel, "Improving Awareness of Running
Code: The Implementation Status Section", BCP 205,
RFC 7942, DOI 10.17487/RFC7942, July 2016,
<https://www.rfc-editor.org/info/rfc7942>.
[RFC8179] Bradner, S. and J. Contreras, "Intellectual Property
Rights in IETF Technology", BCP 79, RFC 8179,
DOI 10.17487/RFC8179, May 2017,
<https://www.rfc-editor.org/info/rfc8179>.
[RFC8915] Franke, D., Sibold, D., Teichel, K., Dansarie, M., and R.
Sundblad, "Network Time Security for the Network Time
Protocol", RFC 8915, DOI 10.17487/RFC8915, September 2020,
<https://www.rfc-editor.org/info/rfc8915>.
[RFC9162] Laurie, B., Messeri, E., and R. Stradling, "Certificate
Transparency Version 2.0", RFC 9162, DOI 10.17487/RFC9162,
December 2021, <https://www.rfc-editor.org/info/rfc9162>.
Appendix A. Test Vectors
The following two vectors exercise the mandatory-to-implement
integrity algorithm 0x0001 and the Ed25519 signature over P: the
first for a 184-octet record without holder binding, the second for a
216-octet holder-bound record together with its holder proof. All
values are hexadecimal, most significant octet first. An
implementation is expected to reproduce each Commitment, to verify
each Signature, and to reproduce pop.
Hexadecimal strings are wrapped for width; the wrapping is not part
of the value. The Ed25519 private seeds are those of the first two
test cases of Section 7.1 of [RFC8032], so that an implementer can
check the key derivation independently before checking anything
specific to this document.
Common inputs
-------------
ctx_id (ASCII, 18 octets)
example.com/pot-v1
ctx_id as encoded for algorithm 0x0001 (length octet first)
126578616d706c652e636f6d2f706f742d7631
payload (ASCII, 43 octets)
the quick brown fox jumps over the lazy dog
Payload Digest = SHA-256(payload)
05c6e08f1d9fdafa03147fcb8f82f124c76d2f70e3d989dc
8aadb5e7d7450bec
Issuer Ed25519 private seed
9d61b19deffd5a60ba844af492ec2cc44449c5697b326919
Jorgen Expires 30 January 2027 [Page 45]
Internet-Draft TTTPS July 2026
703bac031cae7f60
Issuer Ed25519 public key
d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325
af021a68f707511a
Issuer Key ID = SHA-256(public key)[0..7]
21fe31dfa154a261
Nonce
000102030405060708090a0b0c0d0e0f1011121314151617
18191a1b1c1d1e1f
Timestamp 0x18c5addedb8c0000
= 1785024000000000000 ns = 2026-07-26T00:00:00Z
Tier 0x2 (T2_milli, nominal tolerance 100 ms)
Error Bound 0x00c350 (50000 us)
Src Cnt 4
Integrity Alg 0x0001 (SHA-256, arity 2)
Vector 1: 184-octet record, Flags = 0x00, no holder binding
----------------------------------------------------------
fields (offsets 0..87, the input to the algorithm)
120000010400c35018c5addedb8c000021fe31dfa154a261
000102030405060708090a0b0c0d0e0f1011121314151617
18191a1b1c1d1e1f05c6e08f1d9fdafa03147fcb8f82f124
c76d2f70e3d989dc8aadb5e7d7450bec
Commitment (offsets 88..119)
20ea9777b481577d7e057797dd891afa9d097b46043e181b
baad3eee63ae39de
Signature over P (offsets 120..183)
8081fa5802ecb58a2179e7f7a400d8b83f84ce8e440b7629
a85e969a25a024e6979b401d263a58eb830ea2c0b0725fb8
79012dd1c3e4102512f2c3c47c643e03
complete record (184 octets)
120000010400c35018c5addedb8c000021fe31dfa154a261
000102030405060708090a0b0c0d0e0f1011121314151617
18191a1b1c1d1e1f05c6e08f1d9fdafa03147fcb8f82f124
c76d2f70e3d989dc8aadb5e7d7450bec20ea9777b481577d
7e057797dd891afa9d097b46043e181bbaad3eee63ae39de
8081fa5802ecb58a2179e7f7a400d8b83f84ce8e440b7629
a85e969a25a024e6979b401d263a58eb830ea2c0b0725fb8
79012dd1c3e4102512f2c3c47c643e03
Expected verdict: intact
Vector 2: 216-octet record, Flags = 0x80, holder-bound
-----------------------------------------------------
Holder Ed25519 private seed
4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624
da8cf6ed4fb8a6fb
Holder Key (offsets 88..119)
3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968c
Jorgen Expires 30 January 2027 [Page 46]
Internet-Draft TTTPS July 2026
c0cd55f12af4660c
fields (offsets 0..119, the input to the algorithm)
128000010400c35018c5addedb8c000021fe31dfa154a261
000102030405060708090a0b0c0d0e0f1011121314151617
18191a1b1c1d1e1f05c6e08f1d9fdafa03147fcb8f82f124
c76d2f70e3d989dc8aadb5e7d7450bec3d4017c3e843895a
92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c
Commitment (offsets 120..151)
57c85cba540637962ebf8c6fc6a182709c72a45ed67910b6
98a0b0ae33a5a207
Signature over P (offsets 152..215)
edf2267af4bd1a20313866ac3714078ab139b5a4fa991835
0eba055daeed95d6e2a4ff60ca6f28f2760983adf4d947ae
f54a200f55be50b2f437ec6d2f955c07
complete record (216 octets)
128000010400c35018c5addedb8c000021fe31dfa154a261
000102030405060708090a0b0c0d0e0f1011121314151617
18191a1b1c1d1e1f05c6e08f1d9fdafa03147fcb8f82f124
c76d2f70e3d989dc8aadb5e7d7450bec3d4017c3e843895a
92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c
57c85cba540637962ebf8c6fc6a182709c72a45ed67910b6
98a0b0ae33a5a207edf2267af4bd1a20313866ac3714078a
b139b5a4fa9918350eba055daeed95d6e2a4ff60ca6f28f2
760983adf4d947aef54a200f55be50b2f437ec6d2f955c07
Expected verdict: intact
Holder proof for vector 2. The session binding below is a
sample exporter output, not derived from any real session;
an implementation reproduces pop from it.
role octet
00
session_binding (32 octets)
a1b2c3d4e5f60718293a4b5c6d7e8f900f1e2d3c4b5a6978
8796a5b4c3d2e1f0
pop = Ed25519-Sign(holder_private_key,
"tttps-holder-binding-v1" || 0x00 || session_binding)
0348ed022ea8c68dd2af42e7ffca4abf679148e0da7a566f
3fd315fab8001166d116ff50d7bec104b646718a4291fe65
05955bf305c769c10bde18b518951f04
The session binding in the second vector is a sample 32-octet value,
not one derived from a real TLS or QUIC session: an exporter output
cannot be reproduced from a document. An implementation checks pop
by taking that value as given.
Jorgen Expires 30 January 2027 [Page 47]
Internet-Draft TTTPS July 2026
Changes from draft-helmprotocol-tttps-07
draft-helmprotocol-tttps-07 as published on 26 July 2026 described a
180-octet record (version, holder_auth_type, alg_id, ts, dispersion,
ctx_id, nonce, holder_auth_data, integrity_tag, issuer_key_id,
issuer_sig) in which the integrity_tag is computed over the record's
own preceding octets. That record binds a timestamp to session
credentials; it does not bind a timestamp to a digest of external
content. This revision restores a Payload Digest field, present in
earlier working drafts, so that the record names the specific payload
it attests to rather than only the session under which it was issued.
Substantively:
* The record adds a 32-octet Payload Digest field carrying the
SHA-256 digest of the payload the record attests to (Section 3.4).
The record is now 184 octets, or 216 with a Holder Key, in place
of the published -07 length of 180 octets.
* Worked test vectors for the Payload Digest field, including the
digest of a fixed sample payload, are added so that an independent
implementation can be checked byte for byte (Appendix A).
* Verification (Section 3.5) now includes recomputing the payload
digest from caller-supplied content and rejecting the record if it
differs from the Payload Digest field, in addition to the checks
already required by -07.
This revision does not change the session-binding and holder-key
mechanisms of -07; it adds content binding alongside them. Sections
not listed above are carried forward from -07 without substantive
change.
Changes from draft-helmprotocol-tttps-06
The document has been reduced from fifty-eight pages to this one on
the advice of the Independent Submissions Editor. Substantively:
* The abstract is one paragraph and cites nothing. Former sections
1 through 4 are one introduction. The abstract no longer
describes the record as self-contained without qualification, nor
as attesting that a payload existed: the Issuer never sees the
payload, and evaluation needs the Issuer key and ctx_id from out
of band.
* The session binding of former Section 8.1 was described as
preventing presentation by a party other than the one the record
was issued to. It does not. Holder binding (Section 4.2) is new
and does; the limitation is stated explicitly in Section 4.3.
Jorgen Expires 30 January 2027 [Page 48]
Internet-Draft TTTPS July 2026
* The integrity pipeline is now a registered algorithm with an
unencumbered mandatory-to-implement member, rather than one
hardwired construction. The verdict arity of Section 3.3.1 is the
interface property that lets a single evaluation report recovery.
The placeholder appendix is removed.
* The bare confidence figure is replaced by an Error Bound that the
verifier is required to surface and act on, and Issuers are
forbidden from understating.
* The time source registry names classes, not operators. All vendor
names are removed from the document.
* Material on SS7, 5G and 6G core networks, satellite
constellations, deep space, financial ordering, and the economic
model is removed. The information-theoretic framing moves to
[POT2026], cited informatively.
* The record now carries a Payload Digest. Earlier revisions
asserted that the record attested to a payload while committing to
nothing outside the record's own fields; the central claim of the
abstract was not delivered by the wire format. The record also
gains an Issuer Key ID, without which the required check of a
record's Timestamp against its signing key's validity interval
could not be performed and key rotation could not be deployed.
The record is 184 octets, or 216 with a Holder Key.
* Signature verification now precedes integrity evaluation, so that
ordinary traffic does not reach a decoder before the record has
been authenticated. This reduces the exposure rather than
removing it, because the recovery branch is entered exactly when
signature verification has failed; the branch is therefore
disabled by default and the residual exposure is stated in
Section 7.3. Recovery by an arity-3 algorithm is explicitly
excluded from the Version, Integrity Alg, Flags, Holder Key and
Payload Digest fields, and is structurally incapable of reaching
the Commitment or the Signature.
* Verifiers are divided into two roles, Relying Verifier and Auditor
(Section 1.2). Session binding and holder verification are
required of the first and unavailable to the second, so that
neither is left to a verifier's election. Replay detection is
required of the first, and forbidden to the second where it is re-
examining a record it holds: applying replay detection to an audit
would have made a record unre-examinable, which is the opposite of
the durability the audit case needs. Section 3.5 states the one
case in which an Auditor applies it.
Jorgen Expires 30 January 2027 [Page 49]
Internet-Draft TTTPS July 2026
* The verification procedure gains an explicit session-binding step,
an explicit field-sanity step covering Src Cnt, Tier, and Error
Bound, and the check that a record is not dated in the future.
Earlier revisions described the session-binding comparison without
placing it in the procedure, and never checked Src Cnt or Tier at
all.
* The Issuer Key ID is described as an index rather than an
identifier: a verifier tries every trusted key that matches and
accepts only on a unique valid signature whose key was valid at
the record's Timestamp. Applying a key's validity interval on the
strength of a 64-bit identifier alone is prohibited.
* The HTTP/3 stream type registration is withdrawn; no section of
this document specified a stream, and the frame is sufficient.
The HTTP/3 frame payload is specified as the full structure of
Section 5.1, without which holder binding could not be carried
over HTTP/3.
* "Fixed work" is replaced by bounded work with a stated bound.
Content-independent cost is required of the commitment path only:
no error-correcting evaluation can offer it on the recovery path,
and the earlier wording would have barred the arity-3 case the
interface exists for.
* The encoding of the ctx_id length prefix is specified, the
recovered P is defined, and the "TTTPS Time Source Classes"
registry is given the use it previously lacked.
* Appendix A carries real test vectors.
* The session binding covers a role octet, without which a record
could be reflected back to its own sender inside the session it
was presented in. Use of the early exporter, and carriage in TLS
early data or QUIC 0-RTT data, are prohibited.
* Holder verification is required only where a session exists. The
claim that retaining (session_binding, pop) preserves holder
binding for a later auditor is withdrawn and replaced by a
statement of what an out-of-session auditor can and cannot
establish.
* Tier tolerances are ordered monotonically and are all
representable in the Error Bound field. The former 60 s tier was
not.
Jorgen Expires 30 January 2027 [Page 50]
Internet-Draft TTTPS July 2026
* 0x0100 is reserved rather than registered, because this document
does not specify it and the registry it would enter is
Specification Required.
* The ALPN registration is withdrawn: ALPN values are mutually
exclusive, and negotiating in the handshake contradicts this
document's own statement that it does not participate in one.
* The request against a nonexistent "QUIC Stream Types" registry is
corrected to the HTTP/3 registries, and the claim that the HTTP/3
stream type serves carriage over bare QUIC is withdrawn. This
document now registers no QUIC codepoint at all.
* The URI scheme registration is stated as a request with a complete
RFC 7595 provisional template and a syntax production, rather than
asserted as already complete.
* The Security Considerations no longer imply that an append-only
log by itself detects Issuer equivocation.
* Step 2 of the verification procedure checked the delivered length
against the length of the record, while Section 5.1 and
Section 5.3 deliver the record inside a larger structure; as
written it rejected every record carrying a session binding. The
check is now against the length of the unit being parsed, and is
stated separately for a length-delimited carriage and for a byte-
stream carriage, because a byte stream has no delivered length to
check and octets that follow the unit on one belong to the
application. Section 5.1, Section 5.2 and Section 5.3 each state
which class they are.
* Step 5 requires the set of candidate keys that both verify the
signature and carry a containing validity interval to be non-empty
as well as single-valued. An intermediate revision stated only
the single-valued half, which the empty set satisfies vacuously;
under it a record whose Signature had been replaced with arbitrary
octets would have passed the step with no signature verified.
Jorgen Expires 30 January 2027 [Page 51]
Internet-Draft TTTPS July 2026
* Step 5 is stated as having three outcomes -- succeeds, fails
terminally, fails to step 6 -- and the preamble to the procedure
carries the corresponding exception to its rule that a failure is
a rejection. A revision that stated the non-empty requirement as
a rejection made every failure of step 5 terminal and left the
recovery branch of step 6 unreachable, since a record that reaches
the verifier altered is exactly a record whose satisfying set is
empty. That would have made the resolved verdict, the arity-3
model of Section 3.3.1 and the reservation of 0x0100 dead letters,
and two conforming implementations would have diverged without any
test in Appendix A distinguishing them, those vectors being
arity 2 throughout.
* Recovery of the Version field is forbidden alongside Integrity
Alg, Flags, Holder Key and Payload Digest. Version names the
layout under which the fields were delimited for the evaluation,
so recovering it authenticates a record under a layout the
evaluation did not parse. Only version 1 is defined, so the
prohibition forecloses the case rather than fixing a live one.
* The recovery branch re-applies steps 1, 3 and 4 to the recovered
fields before it applies step 5 to the recovered P, rather than
after. The recovered fields are decoder output over an attacker-
chosen input, so the earlier order let an attacker force a second
full round of signature verification at no cost.
* A verifier that rejects a unit taken from a byte-stream carriage
at any of steps 1 through 6 fails the session rather than
returning the stream to the application, since the unit length was
derived from an unauthenticated Flags bit 0 and a presenting peer
that lies about it shifts the stream by 96 octets. The
requirement is bounded at step 6: from step 7 onward that bit has
been covered by a verified signature, so the stream is positioned
at the end of the unit and a rejection is an application-level
condition. An intermediate revision extended the requirement to
every later step, which would have made a replayed record a
guaranteed session teardown at step 11.
* The five-field recovery bound is stated consistently in
Section 3.3.1, in Section 3.5, in Section 7.3 and in the
designated-expert instruction of Section 9.3. The four statements
are not identical and are not meant to be, since they bind a
registrant at registration time, an algorithm in its declared
capability, and a verifier at two points in the procedure.
Intermediate revisions carried a three-field form in the last two,
under which the only registration-time gate would have admitted an
algorithm declaring recovery capability over the Version and
Integrity Alg fields.
Jorgen Expires 30 January 2027 [Page 52]
Internet-Draft TTTPS July 2026
* The integrity algorithm interface takes the Commitment field as an
argument and returns the recovered fields as a third value.
Earlier revisions wrote it as a two-argument, two-result
evaluation while defining the verdict of 0x0001 as a comparison
against the Commitment field, so the verdict was not computable
from the stated arguments and an arity-3 evaluation had no target
to recover towards.
* The recovered fields of Section 3.3.1 replace the received fields
for the remainder of Section 3.5, with the session binding of
Section 4.1 as the single exception, that computation taking the
record as received because the Presenter's own binding was
computed over the octets it sent. Intermediate revisions carried
the recovered fields no further than step 7 and left steps 8, 11
and 12 reading fields of "the record" without saying which, under
which a verifier comparing the received Nonce at step 11 would
have accepted a replay of a record it had already seen whose Nonce
was damaged inside the algorithm's correction capability.
* The content-independence requirement of Section 3.3 covers the
expected value as well as the content of the fields, and a
generating implementation is forbidden to consult the verdict or
the recovered fields, those being undefined where the expected
value is absent. An intermediate revision left the expected value
out of the first and described the second as merely unused, which
stated no obligation; and a further one required determinism of
results it had just declared undefined. Section 7.5 no longer
restates as a SHOULD the comparison this requirement already binds
as a MUST.
* The recovery-prohibited field bound of Section 3.3.1 is scoped to
any evaluation that returns recovered fields rather than to the
verdict the evaluation reports. An intermediate revision scoped
it by verdict, which, once Section 3.3 made the recovered fields
conditional on a verdict of resolved, no longer reached an
algorithm returning modified fields under any other verdict.
* Section 3.4 writes the Version, Tier, Src Cnt, Timestamp and
Integrity Alg fields, states the Timestamp encoding, and zeroes
Flags in full. Every earlier revision left the five fields
unwritten while Section 3.5 rejected on all five, so the
generation procedure left unspecified the fields its own
verification procedure rejects on.
* The glossary definition of the integrity algorithm, the
description of the Commitment field, and the constant-time
requirement of Section 7.5 follow the interface stated in
Section 3.3. An intermediate revision changed that interface in
Jorgen Expires 30 January 2027 [Page 53]
Internet-Draft TTTPS July 2026
Section 3.3 alone, leaving the definition of the term itself
stating the superseded two-result form and the side-channel
requirement naming a comparison no verifier performs.
* The determinism requirement of Section 3.3 covers the verdict and
the recovered fields as well as the commitment, wherever the
expected value is present. An intermediate revision constrained
the commitment alone, which left two verifiers free to reach
different verdicts on the same record and an arity-3 evaluation
free to return different recovered fields on successive
applications to identical input.
* The verdict rule of 0x0001 is scoped to verification and stated
against the expected value. An intermediate revision stated it
unconditionally and against the Commitment field, which is not an
argument of the generation evaluation, so the rule was not well
formed there.
* Step 6 enforces the recovery-prohibited field bound over all five
fields Section 3.3.1 names. An intermediate revision added
Version to Section 3.3.1 and to the rationale in step 4 but not to
the check in step 6, which would have left the two sections
disagreeing on the size of the bound and the procedure enforcing
the smaller one.
* The enumeration in step 6 of the reasons an intact verdict can
arise on the recovery branch names two. An intermediate revision
named a third, a ctx_id the verifier does not share with the
Issuer, which can neither produce that verdict nor cause step 5 to
fail.
* The recovery branch of step 6 rejects a verdict of intact as well
as one of unresolvable. An intact verdict there means signature
verification failed for a reason recovery does not repair -- no
trusted key, or a key outside its validity interval -- and the
branch would otherwise have rescued such a record onto the
resolved path, accepting a signature that Section 7.1 requires be
rejected.
* The recovery branch re-applies the whole of step 5, including the
validity-interval test, and selects candidates using the recovered
Issuer Key ID rather than the received one.
* Recovery of the Integrity Alg field is forbidden alongside Flags,
Holder Key and Payload Digest. The field names the algorithm
performing the recovery and was checked only before signature
verification, so an attacker could otherwise alter it before
verification and have it restored under a valid signature.
Jorgen Expires 30 January 2027 [Page 54]
Internet-Draft TTTPS July 2026
* The field-sanity checks of step 4, and the version and algorithm
checks of steps 1 and 3, are re-applied to the recovered fields at
step 6. They had been justified by the signature verified at
step 5, which the recovery branch does not reach, so a record
whose committed Timestamp lay in the future, or which named a
Version the verifier does not implement, could be rejected on one
path and accepted on the other.
* The resolved verdict is carried forward from step 6 rather than
re-derived at step 7. Re-deriving it evaluated the algorithm over
fields that had just been recovered to match the Commitment, which
returns intact by construction and left resolved unreachable, and
with it the guidance in Section 7.3.
* Step 5 treats two trust-store entries carrying the same public key
as one candidate. Requiring exactly one matching entry rejected
genuine records during a key rotation overlap. Section 7.1 is
restated to match.
* The Tier field is no longer described as advisory, since step 4
makes an unassigned Tier value, and an Error Bound exceeding the
tier's nominal tolerance, grounds for rejection.
* The stream is stated correctly as an Independent Submission, and
the reference section is rebuilt from the RFC index rather than
edited. BCP 79 is cited as RFC 8179. TLS 1.3 is cited as RFC
9846, which obsoleted RFC 8446 in July 2026; the exporter
interface is Section 7.5 there as before, but the 0-RTT replay
discussion moved from Appendix E.5.1 to Appendix F.5.1.
* The recovery branch is no longer motivated as tolerance of damage
occurring in transit. Over the transports of Section 5 such
damage is not delivered at all: it fails the transport's own
integrity check. The damage the branch repairs is damage the
Presenter's own copy already carried, or damage taken on a
carriage outside Section 5 that does not authenticate what it
delivers, and Section 7.3 now says so where it states the enable
decision. As written, that decision asked an operator to weigh a
benefit that cannot arise on a transport this document specifies
against a decoder attack surface that certainly can.
Jorgen Expires 30 January 2027 [Page 55]
Internet-Draft TTTPS July 2026
* The rule that recovered fields replace received fields reaches the
recency requirement of Section 3.5, which is stated after step 12
and is therefore not a step. It reads the Timestamp and the Error
Bound, both recoverable. Under the earlier wording a stale record
whose Timestamp had been damaged to a recent-looking value within
the algorithm's correction capability would have been recovered to
its true Timestamp for every numbered step and then passed a
recency test applied to the damaged one.
* The prohibition on a recency test by an Auditor, stated at the end
of Section 3.5, is confined to the retained record. Left
unqualified it would have forbidden a recency test to a verifier
shown a record in the case step 11 identifies -- a verifier that
omits step 8 and step 10 -- which would then have had no means at
all of declining a record years out of date.
* Section 3.4 clears Flags bit 0 where no holder key is supplied, in
the same item that sets it where one is. The item that follows
zeroes only the reserved bits, which Section 3.2 defines as bits 1
through 7, so under the earlier wording bit 0 was left unwritten
in the case where no item set it; a record carrying it set is
rejected at step 2 for a length mismatch.
* The exporter label is registered DTLS-OK: N. Section 4.1 derives
the session binding from a TLS 1.3 or QUIC session only and
Section 5 specifies no DTLS carriage, so a registration of Y would
have authorised a use this document does not define.
* Section 5.3 states what an HTTP/3 intermediary must do. An HTTP/3
extension is effective only within one connection, so a frame
forwarded verbatim carries a session binding the next hop cannot
verify; an intermediary that re-emits the frame is the Presenter
on its own connection and cannot produce pop, so holder binding
does not survive one. That section also states that this document
does not require such an intermediary to verify the record before
re-emitting it, and what the recomputed session binding does and
does not attest downstream, together with the two things that
follow from leaving that verification optional: the deployment
cannot bound the set of parties that can reach its decoder by its
choice of peers, and a rejected record names only the
intermediary.
Jorgen Expires 30 January 2027 [Page 56]
Internet-Draft TTTPS July 2026
* The prohibition in Section 4.3 on treating a retained pair of
session binding and pop as establishing that the Holder presented
the record binds every verifier and not only an Auditor. The pair
is a static value that verifies against the Holder Key forever, so
the argument was always about the evidence rather than about the
role; keyed to the role, it left a verifier to which a pair had
been forwarded by the party that received it free to attribute a
presentation it never observed.
* Section 6 separates the two tolerances it had run together. The
nominal tolerance governs the field-sanity check of step 4, in
both roles and whatever the application requires; a verifier's own
tolerance governs the recency comparison alone, and only where
that comparison is permitted. The earlier text said that the
application tolerance governs wherever it differs from the nominal
value, which read as authority to accept a record step 4 rejects,
and referred the reader to the section that contains both rules
rather than to the resolution.
* The Auditor of Section 1.2 is defined by the condition that no
session secret is available to it, rather than by the record being
a retained one. A verifier presented with a record over a
carriage that establishes no session of Section 4.1 is in that
condition, and under the earlier definition was neither a Relying
Verifier nor an Auditor, which Section 1.2 requires every verifier
to be. It was therefore bound by none of the reporting and
attribution obligations this document writes as obligations of an
Auditor. Step 8 of Section 3.5 now classifies such a verifier
rather than excusing it from the step: it omits step 8 and
step 10, where the earlier wording would have let it omit step 8
alone and then reach step 10, which delegates to a holder
verification that consumes the value step 8 recomputes.
* The two roles of Section 1.2 are complementary criteria over one
fact -- whether the verifier is still party to the session in
which the record was presented to it -- and the role is determined
for each record rather than for the deployment. The earlier
definitions did not partition: the Auditor was a one-criterion
negative while the Relying Verifier was a three-part positive, so
a verifier that held the secret but evaluated the record after the
session had closed was neither, which Section 1.2 requires every
verifier to be. Membership turns on participation in the session
rather than on possession of the secret, so that a verifier cannot
enter the Relying Verifier role, and with it the obligation to
apply the replay check of step 11 to every record it evaluates, by
retaining key material after the session has ended. The
requirement that a Relying Verifier act on the result at the time
it evaluates the record is no longer a condition of membership; a
Jorgen Expires 30 January 2027 [Page 57]
Internet-Draft TTTPS July 2026
verifier that acts on the result after that session has ended is
instead forbidden to report the record as establishing that the
Presenter is party to the session.
* Step 11 of Section 3.5 confines its prohibition on replay
detection by an Auditor to the record the Auditor is re-examining
from its own store, and provides that an Auditor to which a record
is presented by a party acting as its Presenter, over a carriage
that established no session, SHOULD apply the check where it
retains the state to do so. Neither session binding nor holder
binding is available to such a verifier, so the Nonce is its only
means of detecting re-presentation. The role summary in the
preamble to Section 3.5 is stated to match: steps 8 and 10 are the
Relying Verifier steps, and step 11 applies to a Relying Verifier
always and to an Auditor in the case it identifies.
* Section 7.3 weighs the recovery branch against the whole life of
the record rather than against its last hop. The earlier wording
enumerated damage arising at issuance, in storage, and in handling
and then scoped its recommendation to acquisition alone, which
told the audit deployment of Section 2.2 -- the one whose records
are held longest -- to disable the branch.
* Section 5.3 scopes its requirements to an intermediary that
implements this specification, states that no signal is defined
for a holder-bound frame withheld under them, and states that an
intermediary that does not implement this specification drops the
frame with no signal to either endpoint.
* [RFC9110] is added as a normative reference. Section 5.3 states
requirements on HTTP intermediaries, and the intermediary model
those requirements are stated against is defined in Section 3.7 of
that document rather than in [RFC9114].
Acknowledgements
The author thanks the Independent Submissions Editor for a review
that identified the session binding defect corrected in Section 4.2
and prompted the reduction in scope recorded above.
Author's Address
Heime Jorgen
Kenosian
Email: peter@kenosian.com
Jorgen Expires 30 January 2027 [Page 58]