-
Notifications
You must be signed in to change notification settings - Fork 0
Description
UIP-2: Optional Auxiliary Metadata for Attestation
| Field | Value |
|---|---|
| UIP | 2 |
| Title | Optional Auxiliary Metadata for Attestation |
| Author | @lightsing |
| Status | Draft |
| Type | Standards Track |
| Created | 2026-03-18 |
Abstract
This proposal introduces a backwards-compatible mechanism to append optional auxiliary metadata to existing attestation types.
Motivation
The original OpenTimestamps (OTS) SDK behavior retains pending attestations alongside upgraded Bitcoin attestations by merging them via a FORK operation. While straightforward, this approach makes it difficult for machines to deterministically verify if a timestamp is fully upgraded. The only way to verify is to attempt another upgrade and check if the attestation structure changes, which relies heavily on the liveness of the calendar server and adds implementation complexity.
Conversely, the UniversalTimestamps SDK's default behavior purges pending attestations upon a successful upgrade (though a keep_pending option is available to mirror OTS behavior). This design allows machines to easily determine if a timestamp is fully self-contained (i.e., no pending attestations remain). However, purging results in the loss of contextual information—specifically, the identity of the calendar server that assisted in creating the attestation.
Appending optional auxiliary metadata to attestations resolves this dilemma. It allows the protocol to retain non-authoritative contextual information (such as the calendar server URI) while maintaining a clean, easily verifiable, and self-contained attestation tree.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
1. Trailing Optional Codec Extension
The trailing optional encoding is defined by the following rules:
- If an optional field is the last declared field of a struct, it MUST be treated as a trailing optional field.
- During deserialization, if there is unconsumed data remaining in the buffer and a trailing optional field is defined, the decoder MUST attempt to decode the remaining data as the trailing optional field.
- The trailing optional encoding is recursive; a trailing optional field MAY contain nested trailing optional fields.
Invalid Example:
The following struct is invalid because optional_field_1 is not a trailing field. Currently, there is no generic optional field codec defined in the OTS specification to handle length or presence boundaries for non-trailing fields.
struct Example {
mandatory_field: u64,
optional_field_1: Option<String>, // Invalid: Cannot determine boundary
optional_field_2: Option<u32>,
}Valid Example:
The following struct is valid because nested trailing optional fields are strictly allowed under rule 3.
struct Example {
chain_id: u64,
metadata: Option<Metadata>, // Valid: Trailing optional
}
struct Metadata {
height: u64,
tx: Option<B256>, // Valid: Nested trailing optional
}2. The URI Codec Specification
The original URI specification was defined implicitly as part of the PendingAttestation. This proposal extracts and standardizes it as a standalone URI type.
pub struct URI<'a>(pub Cow<'a, str>);The maximum allowed length is defined as MAX_URI_LEN = 1000.
The URI type is a strict subset of the URI regex defined in RFC 3986 Appendix B: Parsing a URI Reference with a Regular Expression. A valid URI:
- MUST contain only ASCII characters.
- MUST be an absolute URI.
- MUST contain a scheme.
- MUST NOT contain a query string.
- MUST have a length less than or equal to
MAX_URI_LEN.
Consequently, a valid URI MUST strictly match the following PCRE2 regular expression: ^([a-zA-Z][\w+\-.]*):\/\/([\w\-.:\[\]]*)([\/\w\-.:%~]*)$ and its length MUST be <= MAX_URI_LEN.
3. Changes to BitcoinAttestation
The BitcoinAttestation specification is extended to include optional metadata.
From:
pub struct BitcoinAttestation {
pub height: u32,
}To:
pub struct BitcoinAttestation<'a> {
pub height: u32,
pub metadata: Option<BitcoinAttestationMetadata<'a>>
}
pub struct BitcoinAttestationMetadata<'a> {
pub calendar: URI<'a>,
}4. Changes to EASAttestation
The EASAttestation specification is extended.
From:
pub struct EASAttestation {
pub chain: Chain,
pub uid: B256,
}To:
pub struct EASAttestation<'a> {
pub chain: Chain,
pub uid: B256,
pub metadata: Option<EASAttestationMetadata<'a>>
}
pub struct EASAttestationMetadata<'a> {
pub calendar: URI<'a>,
pub tx: Option<TxHash>,
}5. Changes to EASTimestamped
The EASTimestamped specification is extended.
From:
pub struct EASTimestamped {
pub chain: Chain,
}To:
pub struct EASTimestamped<'a> {
pub chain: Chain,
pub metadata: Option<EASTimestampedMetadata<'a>>
}
pub struct EASTimestampedMetadata<'a> {
pub calendar: URI<'a>,
pub tx: Option<TxHash>,
}6. Changes to PendingAttestation
The PendingAttestation structure is updated to utilize the new strict URI type.
From:
pub struct PendingAttestation<'a> {
pub uri: Cow<'a, str>,
}To:
pub struct PendingAttestation<'a> {
pub uri: URI<'a>,
}7. Upgrade Procedure Behavior
Any compliant implementation executing an upgrade operation MUST retain the calendar server's URI upon a successful upgrade. The implementation MUST populate the metadata.calendar field of the newly generated attestation (e.g., BitcoinAttestation, EASAttestation) with this URI.
Implementations SHOULD subsequently purge the original PendingAttestation from the proof to maintain a clean and self-contained timestamp structure, relying instead on the newly appended trailing metadata for provenance.
8. Verify Procedure Behavior
The metadata introduced in this proposal is inherently auxiliary and non-authoritative. Any compliant implementation MUST attempt to actively verify this information before displaying it to the user as factual provenance.
Verifying Calendar Server (calendar):
To verify a calendar server URI embedded in the metadata, the implementation SHOULD initiate an upgrade network request to the specified calendar server to confirm that the server actually attests to the commitment.
Verifying Transaction Hash (tx):
For metadata containing a transaction hash (tx), such as within EASAttestationMetadata or EASTimestampedMetadata, the implementation SHOULD verify the transaction against the respective blockchain network (chain). The implementation SHOULD fetch the transaction receipt and mathematically confirm that it successfully emitted the corresponding on-chain event (e.g., the Attested event for the Ethereum Attestation Service) matching the attestation's core data (such as the uid).
Fallback Behavior:
If active verification is not possible (e.g., the client is operating in an offline environment, the calendar server is unresponsive, or the RPC node for the chain is inaccessible) or if the verification fails (e.g., the transaction receipt does not contain the expected event), the implementation MUST explicitly warn the user through the UI/CLI. The warning MUST clearly indicate that the displayed contextual information (such as the calendar server identity or the transaction hash) is auxiliary, unverified, and cannot be cryptographically trusted.
Backwards Compatibility
This proposal introduces both structural extensions and codec-level breaking changes relative to the original OpenTimestamps specification.
1. URI Codec Incompatibility
The adoption of the strictly defined URI type (Section 2) replaces the legacy PendingAttestation URI validation logic. This introduces a bidirectional incompatibility at the codec layer:
- Tightening (Stricter Structure): The legacy OTS specification merely enforced a character whitelist (
[a-zA-Z0-9.-_//:]) and a length limit, which technically allowed malformed or meaningless strings (e.g.,invalid_stringor://missing_scheme). Implementations of UIP-2 MUST reject these structurally invalid URIs. A new decoder parsing an old, malformed.otsfile will fail. - Relaxation (Expanded Character Set): To comply with RFC 3986 and support modern web infrastructure, the new
URIregex explicitly permits characters previously forbidden by the legacy whitelist, such as[and](for IPv6 addresses like[::1]),+(for schemes),%(for URL encoding), and~. A legacy decoder attempting to parse a UIP-2 generated file containing these new characters in the URI will throw a decoding error.
Practical Impact Mitigation: While theoretically incompatible, the practical impact is negligible. Historically, all known and compliant OpenTimestamps calendar servers have exclusively emitted well-formed, absolute HTTP/HTTPS URIs that fit perfectly within the intersection of both the old and new specifications (e.g., https://a.btc.calendar.org). Therefore, this strictness acts as a necessary protocol sanitation and modernization without disrupting existing real-world timestamp files.
2. Trailing Optional Codec Compatibility
The forward compatibility of the trailing optional metadata mechanism (Sections 3, 4, 5) depends entirely on how strictly the legacy decoder handles the deserialization buffer boundaries:
- Incompatible with Strict EOF Implementations (e.g.,
python-opentimestamps): Legacy decoders that explicitly enforce an End-Of-File (EOF) check on the attestation payload will fail to parse UIP-2 attestations. For example, the original OpenTimestamps Python SDK callspayload_ctx.assert_eof()after extracting known fields. When it encounters the unconsumed trailing metadata bytes introduced by this proposal, it will throw a fatal deserialization error, rendering the entire proof unreadable. - Compatible with Lenient Implementations (e.g., legacy
uts): Legacy decoders that do not strictly enforce payload EOF checks will remain forward-compatible. For instance, older versions of theutsRust implementation read the payload into a byte slice, decode the expected fixed-length fields, and implicitly discard any remaining bytes in the slice. These implementations will naturally ignore the trailing metadata without throwing errors.
Operational Impact: Because strict EOF checks exist in the wild (notably in the reference Python implementation), appending trailing metadata constitutes a structural breaking change for the legacy OTS ecosystem. Applications interacting with UIP-2 extended attestations MUST upgrade their parsers to either explicitly support the new metadata structures or safely ignore unconsumed trailing bytes at the payload level.