Internet-Draft MoLE Protocols October 2026
Schlesinger, et al. Expires 11 April 2027 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-jms-mole-protocols-latest
Published:
Intended Status:
Informational
Expires:
Authors:
S. Schlesinger
Google LLC
D. Jackson
Mozilla
T. Meunier
Cloudflare

MoLE Protocols

Abstract

This document defines protocols that instantiate the MoLE architecture: two endorsement protocols, by which a Client proves to a Moderator that it holds an Endorsement from a trusted Anchor without revealing which one, and two credential protocols, by which a Moderator issues, verifies, and updates per-Client state without being able to link presentations. It also establishes the registries that identify these protocols.

About This Document

This note is to be removed before publishing as an RFC.

The latest revision of this draft can be found at https://moderation-of-unlinkable-endorsements.github.io/internet-drafts/draft-jms-mole-protocols.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-jms-mole-protocols/.

Source for this draft and an issue tracker can be found at https://github.com/Moderation-of-unLinkable-Endorsements/internet-drafts.

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 11 April 2027.

▲

Table of Contents

1. Introduction

The MoLE architecture [ARCHITECTURE] defines three roles. Clients obtain Endorsements from Anchors, redeem them at Moderators in exchange for Credentials, and present those Credentials to Moderators to access resources. The architecture states the required properties of Endorsements and Credentials but does not say how to build them. This document does.

TODO: the protocols below reflect our current understanding of how MoLE may work, and showcase agility. They are not final. Some may be removed, others added.

It defines two endorsement protocols and two credential protocols. Each is identified by a type value from a registry established in this document (Section 9). The HTTP carriage of challenges, requests, redemptions, and presentations is defined by [HTTP-TRANSPORT]. This document defines the messages themselves and, for the grant flow, the HTTP exchanges that carry them.

2. Conventions and Definitions

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.

Protocol messages are described in TLS presentation language (Section 3 of [TLS13]). This document also uses the optional-value and variable-size vector conventions (optional<T>, <V>) defined in [HTTP-TRANSPORT]. All constants are in network byte order.

This document uses the following terms for protocol actions:

Grant:

An Anchor gives a Client an Endorsement.

Redeem:

A Client spends an Endorsement at one logical Moderator. A Client MUST NOT attempt to redeem the same Endorsement at a second Moderator. The Moderator enforces replay protection within its configured replay protection scope.

Issue:

A Moderator gives a Client a Credential in return for a redemption.

Present:

A Client shows a Credential to a Moderator. Each Credential can be presented once within the Moderator's configured replay protection scope. The update replaces it.

Update:

The Moderator's adjustment to a presented Credential, returned in the same exchange.

Finalize:

The Client-local step that turns a protocol response into a stored Endorsement or Credential.

3. Common Requirements

3.1. Message Types

Every outer MoLE message that selects a protocol carries a uint16 type field. These messages are EndorsementRequest, EndorsementResponse, CredentialRequest, CredentialResponse, CredentialPresentation, CredentialUpdate, ModeratorChallenge, and CredentialChallenge. Values are assigned in Section 9. A Client ignores an unknown Challenge. An unknown request or response is rejected. A Moderator treats an unknown optional presentation as absent and rejects an unknown required presentation. Challenge wrappers are exchanged only between a Moderator and Client. They are never sent to an Anchor.

The value 0x0000 is reserved in both registries and MUST NOT appear on the wire. Endorsement type 0x0001 means that no Endorsement is required.

3.2. Greasing

In order to prevent Moderators from becoming incompatible with future credential types, Clients SHOULD send presentations whose credential_type is a random value from the reserved greased values (Section 9.2.3), with some non-trivial probability. The body of a greased presentation is random bytes. A Moderator handles it as if no Credential were presented.

The greased values follow the pattern 0x?A?A, spread uniformly across the registry space. Moderators MUST handle them exactly as any other unknown type and MUST NOT special-case the reserved list. A Moderator that enumerates greased values defeats their purpose and will still receive unknown types it did not enumerate.

Additionally, when a credential is not required, Clients SHOULD randomly choose not to send a presentation with some non-trivial probability. This helps ensure that Moderators maintain their behavior for handling Clients without credentials, rather than relying on a presentation always being present.

3.3. Challenges and Contexts

A Moderator Challenge is a message sent by a Moderator to a Client. It selects the operation and carries any type-specific input chosen by the Moderator. A Moderator Challenge, or a value derived from it, MUST NOT be sent to an Anchor.

A Context is a protocol-specific cryptographic input. A protocol defines how the Client and Moderator derive the same Context from authenticated configuration, the operation, and, when required, the Moderator Challenge. A Context can include the complete Moderator Challenge, a digest of it, or selected fields. Moderator Challenge and Context are therefore not interchangeable terms.

Each credential protocol defines the contents of its type-specific CredentialChallenge body. Endorsement protocols use the common Challenge in Section 4.1. For a new operation, a Moderator MUST be able to verify, from retained state or by recomputing the Challenge, that a response uses a Challenge it issued and that remains valid. A credential protocol can return an already accepted result after its Challenge expires, without authorizing a new operation (Section 5.2.5).

4. Endorsement Protocols

An endorsement protocol has two parts. First, before contacting a Moderator, the Client runs one or more request/response exchanges with an Anchor and finalizes the result into an Endorsement. This is the grant. Second, the Client redeems the Endorsement at a Moderator, proving it came from an Anchor in the Moderator's accepted set without revealing which one. Redemption happens inside the Redeem & Issue flow (Section 5).

Client Anchor EndorsementRequest \ EndorsementResponse | one or more ... / exchanges Finalize Moderator Challenge Redemption
Figure 1: Endorsement grant and redemption

Exchanges with the Anchor are HTTP POST requests. The request body has media type application/mole-endorsement-request and contains an EndorsementRequest. The response body has media type application/mole-endorsement-response and contains an EndorsementResponse. The endorsement type determines how many exchanges are needed and what the body field contains at each step.

struct {
  uint16 endorsement_type;
  opaque body<V>;
} EndorsementRequest;

struct {
  uint16 endorsement_type;
  opaque body<V>;
} EndorsementResponse;

The structure fields are:

The Anchor returns 200 (OK) with the response media type only when it produced a complete EndorsementResponse. A Client MUST reject a non-success status, an unexpected media type, a response whose type differs from its request, trailing bytes, or malformed type-specific content. Clients MUST NOT automatically redirect a grant POST carrying protocol state. If the second Rollatini response is lost, the consumed session cannot be replayed. The Client starts a fresh grant session.

Every endorsement protocol defines a Redemption structure. It is the message a Client sends to redeem the Endorsement, carried in the endorsement_presentation field of a CredentialRequest (Section 5).

4.1. Redemption Challenge Binding

The type-specific body of ModeratorChallenge is:

struct {
  opaque redemption_context[32];
} RedemptionChallenge;

The structure fields are:

  • redemption_context scopes the redemption. The Moderator constructs it and the Client uses it as received. It MUST distinguish the Moderator and the policy it issues under, and SHOULD distinguish a time window.

The Client does not send the challenge back. The Moderator either keeps the challenges it sends or recomputes redemption_context when a request arrives, for instance as an authenticated encoding of its origin, policy, and time window, trying adjacent windows.

Endorsement protocols compute the following value when creating or verifying a redemption:

challenge_digest = SHA-256(moderator_challenge)

The values are defined as follows:

  • moderator_challenge is the complete decoded TLS-presentation encoding of the ModeratorChallenge sent by the Moderator. It is not required to contain an origin.

  • challenge_digest is the 32-octet SHA-256 digest of moderator_challenge. It is not computed over a base64url or other textual encoding. SHA-256 is defined in [SHA2].

challenge_digest enters the Fiat-Shamir transcript in both Rollatini and Longfellow, but is not a Longfellow circuit public input. A redemption created for one ModeratorChallenge does not verify under another, so a Moderator that accepts only the redemption_context it constructs rejects a redemption made under another Moderator's challenge. This does not stop a Moderator that relays another Moderator's challenge to the Client.

The Challenge algorithm and ChallengeMessage in Rollatini issuance are defined by [ROLLATINI] and are unrelated to a ModeratorChallenge.

4.2. Abstract Endorsement API

Each endorsement protocol defines these abstract operations:

RedeemRequest(endorsement, moderator_challenge, configuration)
  -> redemption | INVALID
FinalizeRedeem(redemption, moderator_challenge, configuration)
  -> replay_protection_ids | INVALID

RedeemRequest runs at the Client. FinalizeRedeem runs at the Moderator, verifies the redemption and Challenge binding, and returns a possibly empty set of replay_protection_ids or INVALID. Both operations derive challenge_digest from moderator_challenge as specified above. The Moderator MUST atomically insert every returned identifier in the protocol's configured replay protection scope, each only if absent. If any is already present, the Moderator MUST treat the result as INVALID and MUST NOT issue a Credential for the accompanying IssuanceRequest. There is no global replay protection service.

4.3. No Endorsement Required

Endorsement type 0x0001 indicates that the Moderator does not require an Endorsement under its policy. It has no grant. The endorsement input and Redemption are both the distinguished empty value. RedeemRequest returns that empty value. FinalizeRedeem returns the empty set when the Moderator's policy permits issuance without an Endorsement, and INVALID otherwise. How often a Client can obtain a Credential this way is up to Moderator policy, for instance rate limiting.

4.4. Rollatini

Endorsement type: 0x0002.

This protocol uses Rollatini [ROLLATINI], a pairing-free Issuer-Hiding Anonymous Token (IHAT). The Anchor blindly signs a Client-chosen nullifier. The Client later proves, with an issuer-hiding proof, that its Endorsement verifies under one of the Anchor keys the Moderator accepts. The cryptographic operations, and the contents and encodings of every message body, are defined in [ROLLATINI].

The following primitive types are ciphersuite-dependent:

opaque Scalar[Ns];
opaque Element[Ne];

4.4.1. Configuration

The Client needs, from Anchor configuration (Section 6):

Rollatini Ciphersuite

A ciphersuite identifier defined by [ROLLATINI]. It determines Element, Scalar, and all cryptographic encodings.

Anchor Public Key

pkA, an Element, as generated in [ROLLATINI], with a stable key ID.

Issuance Context

ctx_iss, the canonical encoding of the issuance epoch. Endorsements are valid for that epoch, see Section 6.

Redemption Context

ctx_red, the ASCII string "MoLE-Rollatini-ctx_red-v1", without a terminating NUL byte. This fixed, domain-separated value is the same for all Moderators. This is the cryptographic redemption Context defined by [ROLLATINI], not a Moderator Challenge. A specific redemption operation is bound separately by challenge_digest.

4.4.2. Grant

The grant takes two HTTP exchanges and three protocol messages. The Anchor speaks first, as specified by [ROLLATINI]:

  1. The Client sends an EndorsementRequest with an empty body. The Anchor runs Commit(ctx_iss), stores the returned state under a fresh session_id, and returns a CommitMessage in the response body.

  2. The Client runs Challenge(pkA, ctx_iss, ctx_red, commitment), stores the returned state, and sends a ChallengeMessage containing the returned issuance challenge and opaque session_id. The Anchor atomically claims and consumes that identifier before reading the single-use state. Only the instance that wins the claim runs Respond(skA, state, challenge) and returns a ResponseMessage. Tombstones are retained through session expiry. All later requests for the identifier fail without invoking Respond.

  3. The Client runs Finalize(pkA, state, response) as specified by [ROLLATINI]. On failure it MUST discard the session state and MUST NOT retry with that state.

CommitMessage, ChallengeMessage, ResponseMessage, session_id, and the Endorsement encoding are defined by [ROLLATINI]. The session identifier is only transport correlation and is not bound into the Endorsement.

The Anchor learns neither nf nor the final Endorsement. Under the statistical blindness claim in [ROLLATINI], its protocol transcript does not let it recognize the Endorsement when it is later redeemed. Timing, network, and configuration metadata are outside that claim.

4.4.3. Redemption

The type-specific Redemption payload is the encoding of Redemption in [ROLLATINI]. RedeemRequest derives challenge_digest as in Section 4.1 and calls Redeem(anchor_set, index, endorsement, ctx_iss, ctx_red, challenge_digest). The ordered anchor_set comes from Moderator configuration; index selects the Anchor that issued the Endorsement. The Client rejects a set that omits its Anchor.

FinalizeRedeem checks that the issuance epoch and Moderator Challenge are accepted, decodes the payload, and calls VerifyRedemption(anchor_set, redemption, ctx_iss, ctx_red, challenge_digest). It returns {nf}, scoped to ctx_iss in the Moderator's store. Any decoding or verification failure returns INVALID. The common replay protection rules apply before Credential issuance. The same nf is exposed on repeated redemptions, including across Moderators; the scheme does not enforce global single use.

4.5. Longfellow

Endorsement type: 0x0003.

Where Rollatini requires Anchors to run new cryptography, this protocol preserves backward compatibility with credentials Clients may hold, such as mdocs. The Client proves in zero knowledge, using the scheme of [LONGFELLOW], that it holds a valid credential from one of an accepted set of issuers, without revealing which issuer or any credential attribute. An experimental circuit is described in [HIDDEN-ISSUER-CIRCUIT].

There is no grant exchange in this protocol. The Client obtains its credential from the Anchor out of band, through whatever legacy issuance that credential uses, before contacting a Moderator. A compressed circuit artifact containing the two Longfellow circuits is likewise distributed out of band and identified by its hash.

4.5.1. Configuration

The Client needs, from Moderator configuration (Section 6):

Circuit Artifact Identifier

circuit_artifact_id, the SHA-256 hash of the compressed circuit artifact both parties use.

Circuit Manifest

An out-of-band manifest that names the artifact version, the two circuit identifiers, and all proof parameters needed to interpret and verify it.

Accepted Issuer Set

the credential-issuer certificates the Moderator accepts, in a fixed published order.

Epoch

the validity window redemptions must fall in.

Moderator Origin

the canonical origin of the Moderator. Its source is trusted configuration. It MUST NOT be derived from a client-controlled HTTP Host value.

Verification Time

verification_time, a Moderator-selected time within the current epoch.

4.5.2. Redemption

The accepted issuer set, circuit artifact, epoch, Moderator origin, and verification time come from authenticated configuration. The selected redemption operation supplies the digest of the complete decoded ModeratorChallenge as challenge_digest, as defined in Section 4.1.

The Client evaluates the two circuits over its credential to produce a proof and a nullifier. The nullifier is derived, inside the circuit, from a credential-bound secret, the canonical Moderator origin, and the current epoch. One credential therefore yields exactly one valid nullifier per Moderator origin and epoch.

struct {
  opaque circuit_artifact_id[32];
  opaque nullifier<V>;
  opaque proof<V>;
} Redemption;

The structure fields are:

  • circuit_artifact_id is the SHA-256 digest of the configured circuit artifact.

  • nullifier is the circuit-produced replay protection identifier.

  • proof is the encoded Longfellow proof.

The circuit public inputs are the accepted issuer set, epoch, canonical Moderator origin, verification_time, and nullifier. The proof establishes validFrom <= verification_time <= validUntil. challenge_digest (Section 4.1) is bound into the Longfellow Fiat-Shamir transcript. It is not a circuit public input.

Longfellow implements the common API in Section 4. RedeemRequest checks that the artifact and manifest match configuration, evaluates the circuits, and returns the encoded Redemption above. FinalizeRedeem checks the artifact identifier, verifies the proof and its transcript binding, and checks that the configured epoch and verification_time remain current. It returns {nullifier}, or INVALID on any failure. Both operations derive challenge_digest from moderator_challenge. The common caller performs the atomic replay protection check.

4.5.3. Differences from Rollatini

Longfellow does not inherently require an Anchor to change its issuance protocol. Scarcity then depends on the legacy credential's own issuance limits and on whether it contains a credential-bound Client secret suitable for nullifier derivation. An Anchor that participates in MoLE can control scarcity and arrange for such a secret to be committed during issuance. Some existing credential formats may already provide a suitable Client-contributed or device-bound secret. The one-nullifier-per-origin-and-epoch rule prevents repeat redemption of one credential in that scope. It does not limit how many credentials a Client can obtain.

  • Editor note. This protocol is blocked on normative circuit definitions, public-input encodings and ordering, transcript binding, artifact lifecycle and size limits, and test vectors.

5. Credential Protocols

A credential protocol has two parts. In Redeem & Issue, the Client redeems an Endorsement and receives a Credential from the Moderator. In Presentation and Update, the Client shows the Credential and receives an update in the same exchange.

Client Moderator ModeratorChallenge Redemption + IssuanceRequest HTTP request IssuanceResponse Finalize | | . . CredentialChallenge PresentationAndUpdate Update? Finalize | | |
Figure 2: Redeem & Issue, then presentation and update

Both parts ride on HTTP requests to the Moderator. Redeem & Issue carries a CredentialRequest in the Authorization header and receives the CredentialResponse in the Mole-Credential response header. The Moderator runs the selected endorsement protocol's FinalizeRedeem operation before it issues a Credential. Presentation uses the same authentication scheme.

struct {
  uint16 endorsement_type;
  opaque endorsement_presentation<V>; /* encoded Redemption */
  uint16 credential_type;
  opaque issuance_request<V>;
} CredentialRequest;

struct {
  uint16 credential_type;
  opaque issuance_response<V>;
} CredentialResponse;

The structure fields are:

A recipient of CredentialResponse MUST reject it unless credential_type matches the type selected by CredentialRequest.

All credential protocols define the same four payloads:

IssuanceRequest

A Client-generated request for a new Credential.

IssuanceResponse

The Moderator's response to IssuanceRequest.

PresentationAndUpdate

A presentation of a Credential and any request needed to replace or update it.

Update

The Moderator's response to PresentationAndUpdate, when the Client remains eligible for a Credential.

The type-specific encodings fill the opaque fields of the outer structures above and of CredentialPresentation and CredentialUpdate from [HTTP-TRANSPORT].

5.1. Abstract Credential API

Each credential protocol defines these abstract operations:

CreateIssuanceRequest(moderator_challenge, configuration)
  -> (issuance_state, issuance_request) | INVALID
IssueCredential(issuance_request, moderator_challenge, policy, configuration)
  -> issuance_response | INVALID
FinalizeIssuance(issuance_state, issuance_response, configuration)
  -> credential | INVALID

CreatePresentationAndUpdate(credential, credential_challenge, configuration)
  -> (presentation_state, presentation_and_update) | INVALID
ProcessPresentation(
    presentation_and_update, credential_challenge, policy, configuration)
  -> INVALID
   | ACCEPTED_NO_UPDATE
   | ACCEPTED_WITH_UPDATE(update)
FinalizeUpdate(presentation_state, update, configuration)
  -> credential | INVALID

CreateIssuanceRequest, FinalizeIssuance, CreatePresentationAndUpdate, and FinalizeUpdate run at the Client. IssueCredential and ProcessPresentation run at the Moderator. State values are local and are not sent on the wire. ACCEPTED_NO_UPDATE means that the presentation succeeded but the Credential was consumed without replacement. ACCEPTED_WITH_UPDATE carries the encoded Update that the Client finalizes into its replacement Credential by calling FinalizeUpdate. The Client does not call FinalizeUpdate for ACCEPTED_NO_UPDATE. A complete protocol specification defines its Context derivation, replay protection, and retry behavior. The Moderator completes that replay protection before returning an accepted result.

5.2. Anonymous Credit Tokens (ACT)

Credential type: 0x0001.

An ACT Credential, specified in [ACT], carries a hidden balance c, a number of credits. The Moderator issues a Credential with an initial balance of its choosing. A presentation spends a public amount s, proving that the balance covers it, and may accept a top-up of at most a that the challenge offers. In the same exchange the Moderator issues a refund message with a return amount t of its choosing, with 0 <= t <= s + a. The Client finalizes this message into a fresh Credential with balance c - s + t. The presentation reveals s, a, and a single-use nullifier; the balance is hidden beyond the public amounts and predicates (Section 7.1).

A Credential is invalid once spent, and its replacement exists only once the Moderator has answered, so one Credential supports one presentation in flight at a time. This gives the Moderator:

Concurrency control:

A Credential copied to several parties can be spent by only one of them; every other copy presents a nullifier the Moderator has already recorded.

Dynamic revocation:

The Moderator ends a Credential chain, and its remaining balance, by declining to refund, without waiting for the Credential to expire.

Per-session adjustment:

A balance changes only through s, a, and t, each of which can follow the Moderator's assessment of the request, subject to Section 7.1.

The abstract credential API maps onto [ACT] as follows:

Table 1
Abstract operation ACT
CreateIssuanceRequest IssueRequest, with key selection (Section 5.2.2)
IssueCredential IssueResponse (Section 5.2.2)
FinalizeIssuance FinalizeIssue
CreatePresentationAndUpdate ProveSpend (Section 5.2.3.2)
ProcessPresentation VerifySpend and IssueRefund (Section 5.2.3.2)
FinalizeUpdate FinalizeRefund

The Client's presentation_state is the ClientSpendState of [ACT], the pkM, credential_context, L, and Moderator identity and endpoint stored with the spent Credential, and the PresentationAndUpdate octets with the HTTP request information needed to resend them to their original destination (Section 5.2.5). ProcessPresentation returns ACCEPTED_WITH_UPDATE with a refund, and ACCEPTED_NO_UPDATE when the Moderator declines to refund. For a retry answered from a record (Section 5.2.5), it returns the recorded result, which carries the Update only and does not authorize the protected operation. The ACT response rules in [HTTP-TRANSPORT] define the HTTP status and Mole-Credential header for each outcome.

5.2.1. Configuration

The Moderator publishes, in its configuration (Section 6):

Public Key

pkM, encoded with SerializeElement. Its identifier is key_id = SHA-256(SerializeElement(pkM)), and truncated_key_id is the last byte of key_id.

Ciphersuite

The ACT ciphersuite identifier; [ACT] defines P256-SHA256.

Balance Width

L, fixed for the lifetime of the key and credential context ([ACT]).

Credential Context

credential_context, an opaque byte string of at most 2^16 - 2 bytes that names the epoch or policy that Credentials under the key are valid for.

Result Retention Period

The recovery interval after acceptance of a presentation. Recovery ends earlier if its key or credential context is retired (Section 5.2.5).

The credential context of [ACT] is

ctx_cred = credential_context || I2OSP(L, 1)

which includes L as [ACT] recommends. A Moderator expires every outstanding Credential under a key by publishing a new credential_context, without changing the key. A refund is issued under the context of the spent Credential, so balances do not carry over to a new context. A Moderator SHOULD announce the successor context and a grace period before expiry. Clients obtain Credentials under the new context through Redeem & Issue; this document does not specify balance migration.

A Moderator MAY have several active keys, for instance during a rotation. It MUST ensure that no two active keys share a truncated_key_id, SHOULD NOT give a new key the truncated_key_id of a recently retired one, and SHOULD keep the number of active keys small (Section 7.1).

5.2.2. Redeem & Issue

struct {
  uint8 truncated_key_id;
  opaque credential_context<V>;
  IssueRequestMessage request;
} IssuanceRequest;

struct {
  IssueResponseMessage response;
} IssuanceResponse;

IssueRequestMessage and IssueResponseMessage are defined in [ACT].

The Client runs IssueRequest(), keeps the returned state, and sends the request with the truncated identifier of the key and the credential_context it holds in its configuration.

The Moderator processes a CredentialRequest in this order:

  1. It selects the active key whose truncated_key_id matches, and checks that credential_context is the context it issues under for that key. It rejects the request if either check fails.

  2. It checks that request deserializes and that its proof verifies, as IssueResponse does, and rejects the request otherwise.

  3. It validates the accompanying redemption with FinalizeRedeem (Section 4).

  4. It chooses the initial balance c under its policy and runs IssueResponse(skM, ctx_cred, c, request). It then records the replay_protection_ids returned by FinalizeRedeem. Recording is atomic and fails if any identifier is already recorded. If any step fails, or it is unknown whether the identifiers were recorded, no response is released.

  5. It returns the result in a CredentialResponse.

The Endorsement is therefore consumed only together with a response, and a malformed request does not cost the Client its Endorsement.

The Client runs FinalizeIssue(pkM, ctx_cred, state, response) and stores the resulting Credential with pkM, credential_context, L, the identity of the Moderator, and its configured Redeem & Issue endpoint. If finalization fails, the Client MUST discard the state, SHOULD refresh its configuration, and MAY run Redeem & Issue again.

5.2.3. Presentation and Update

The ACT Challenge names the amounts, the context the Moderator accepts, and the scope of the authorization it asks for:

struct {
  uint64 s;
  uint64 a;
  opaque credential_context<V>;
  opaque request_context<V>;
} Challenge;

s is the amount to spend and is the Predicate of [ARCHITECTURE]: a presentation succeeds only if the balance is at least s. a is the largest top-up the Moderator offers in this presentation, 0 if none. A challenge with s = a = 0 asks for a refresh, which replaces the nullifier and leaves the balance unchanged, since t <= s + a = 0. A Moderator that wants to lower balances challenges with s > 0 and returns t < s; one that wants to raise them offers a > 0. credential_context repeats the configured value, so that a Client can tell that its Credential has expired without refetching the configuration. It is the challenge field that partitions cached Credentials ([HTTP-TRANSPORT]).

5.2.3.1. Challenge Binding

The spend context of [ACT] is

ctx_spend = SHA-256(credential_challenge)

where credential_challenge is the complete TLS encoding of the CredentialChallenge of [HTTP-TRANSPORT], including its credential_type and the length-prefixed ACT Challenge. The Client hashes those octets, not their base64url encoding. This digest is separate from the redemption digest of Section 4.1.

The presentation does not carry the challenge. The Moderator determines the challenge a presentation answers from its policy and the request it is authorizing, and selects one of two profiles by what it puts in request_context:

Policy-scoped:

request_context is empty. Every challenge with the same s, a, and credential_context then has the same octets and the same digest, and a presentation is a one-use bearer authorization for those values: the Moderator accepts it once, against whichever request carries it (Section 8.1).

Request-bound:

request_context is non-empty and identifies the request, session, or time window the presentation is for. The Moderator MUST accept a presentation only under a value it issued for the request being authorized. The value MAY be stateless, for instance an authenticated encoding of the origin, the method and target, a session identifier, or a time window, which the Moderator recomputes from the request. The binding is only as specific as what the value encodes; to bind one operation, it MUST distinguish every request field that affects authorization, including the request body where relevant.

When several challenges could apply to a request, for instance for adjacent time windows or for two credential contexts during a rollover, the Moderator runs steps 2 and 3 of Section 5.2.3.2 for each until one succeeds. The two profiles differ only in the challenge octets. The cryptographic operations, the message formats, and the nullifier rules are the same.

5.2.3.2. Spending and Refunds

A Client that holds no Usable Credential (Section 5.2.4) for this Moderator under the challenged credential_context, or whose Credential ProveSpend would reject for the challenged s and a, does not present. It runs Redeem & Issue, first obtaining an Endorsement if the Moderator requires one (Section 4).

Otherwise the Client computes ctx_spend, runs ProveSpend(credential, ctx_cred, s, a, ctx_spend), stores the returned state and the presentation as Section 5.2.4 requires, and sends:

struct {
  opaque key_id[32];
  SpendMessage spend;
} PresentationAndUpdate;

struct {
  RefundMessage refund;
} Update;

SpendMessage and RefundMessage are defined in [ACT]. The full key_id is sent: the Moderator issued the Credential and knows its key, so the identifier tells it nothing more.

The Moderator processes a presentation as follows. Steps 1 and 2 read public state and the nullifier store, step 3 ends by atomically recording the result, and step 4 follows.

  1. It checks that key_id names an active key, then looks up (key_id, spend.k) in the nullifier store. If a record exists, the Moderator answers from it only if it holds the SHA-256 digest of the received PresentationAndUpdate octets, its result is still retained, and its credential context is still accepted for that key (Section 5.2.5). The challenge may have expired. A record that fails any of these checks causes the presentation to be rejected. Only an unrecorded nullifier proceeds to step 2.

  2. It determines the challenge (Section 5.2.3.1), and checks that its credential_context is accepted for that key and that spend.s and spend.a equal its s and a. It rejects the presentation if any check fails.

  3. It runs VerifySpend(skM, ctx_cred, ctx_spend, spend), decides under its policy whether to refund and, if so, the return amount t, and runs IssueRefund(skM, ctx_cred, spend, t) if it refunds. It then records the result under (key_id, spend.k): the digest of the presentation octets, ctx_cred, and the decision, either Refund(t) with the octets of the RefundMessage, or NoUpdate. Recording is atomic and MUST fail if a result is already recorded under that nullifier or if the key or context is no longer accepted, so of two racing presentations at most one is recorded. If any step fails, or it is unknown whether the result was recorded, no refund is released. The Moderator MUST NOT attempt the protected operation unless this request's result was successfully recorded.

  4. It attempts the protected operation. Its HTTP response carries the recorded credential result as an Update: the refund, or, for NoUpdate, an absent update, which leaves the Client without a replacement. The Moderator MUST include this result even when the protected operation fails ([HTTP-TRANSPORT]).

Spending credits authorizes one attempt of the protected operation. A failure after step 3 can charge the Client without completing step 4; a retry recovers the result but does not authorize another attempt. Reliable execution needs application-specific recovery, for example a durable outbox written with the step 3 record and a worker that retries the operation idempotently under the presentation digest. This document does not specify that recovery.

The Client runs FinalizeRefund(pkM, ctx_cred, state, refund) and stores the resulting Credential in place of the spent one, with the same pkM, credential_context, and L. If the refund does not verify, the Client discards it and proceeds as in Section 5.2.5.

5.2.4. Client State

An ACT Credential goes through the following states:

Usable balance c ProveSpend(credential, ctx_cred, s, a, ctx_spend) Spent awaiting refund; the Credential is invalid FinalizeRefund(pkM, ctx_cred, state, refund) Usable balance c - s + t, in [c - s, c + a]
Figure 3: ACT Credential states
Usable:

The Client holds a Credential with balance c, together with pkM, credential_context, and L, and may present it as Section 5.2.3.2 describes.

Spent:

The Client has run ProveSpend, and the Credential is invalid whether or not the presentation is sent or answered ([ACT]). Besides the spend state that [ACT] requires it to store, the Client MUST durably store the presentation octets and the HTTP request needed to resend them before the presentation leaves it.

A valid refund returns the Client to Usable. A Credential chain is therefore serialized: one presentation at a time, each waiting for the Moderator's answer to the previous one. When a Client learns that a key or credential context has been retired, it MUST discard the Credentials and pending spend states under that key or context. It obtains a Credential under the current configuration through Redeem & Issue.

5.2.5. Lost Refunds

A presentation may be sent and its response lost, or the Moderator may fail between recording the result in step 3 of Section 5.2.3.2 and returning it. The Client cannot then finalize, and the spent Credential cannot be reused.

A Moderator MUST keep each result until the earlier of the end of its published result retention period (Section 5.2.1), counted from the recording in step 3, and retirement of the key or credential context. It MUST delete the result when this interval ends. A Client missing an Update MAY resend the byte-identical PresentationAndUpdate during the interval. Step 1 of Section 5.2.3.2 checks the record and the continued acceptance of its key and credential context before returning a result. Recovery remains available after the presentation's challenge expires:

  • For a recorded Refund(t), the Moderator returns the refund it stored.

  • For a recorded NoUpdate, the Moderator returns an absent update.

The recovery handle ([HTTP-TRANSPORT]) is key_id || SerializeScalar(spend.k) || SHA-256(PresentationAndUpdate).

The Moderator MUST NOT authorize another operation for a recorded nullifier, and MUST NOT change a recorded decision. It returns the recovered result with HTTP status 409 as specified in [HTTP-TRANSPORT].

Once recovery ends, a retry is rejected, and the Client MUST discard the spend state. To continue, it runs Redeem & Issue. The Moderator MUST retain the nullifier after deleting its result for as long as the key and credential context are accepted (Section 6).

5.2.6. Limitations

A SpendMessage grows linearly in L ([ACT]). With P-256 and L = 32, it is about 4.5 KB when one of s and a is nonzero and 8.7 KB when both are, before base64url encoding in the Authorization header. Deployments with tight header limits should choose L accordingly.

5.3. Privacy Pass with a Reverse Flow

Credential type: 0x0002.

The Credential is a single Privacy Pass token. The Moderator's configuration names both the registered token type used for presentation and the registered token type used for update issuance. Presentation consumes the token. The update, if granted, is a fresh token issued through [REVERSE-FLOW], with redemption in place of attestation.

For the protocol described here, the presented and reissued token use the same token type and Moderator key. Changing either partitions Clients and leaks state.

5.3.1. Redeem & Issue

IssuanceRequest is a TokenRequest and IssuanceResponse is a TokenResponse, both as defined for the configured token type in [PRIVACYPASS-PROTOCOLS]. That token type's finalization operation produces the Credential. These messages implement CreateIssuanceRequest, IssueCredential, and FinalizeIssuance.

5.3.2. Presentation and Update

struct {
  opaque token<V>;
  opaque token_request<V>;  /* TokenRequest */
} PresentationAndUpdate;

struct {
  opaque token_response<V>; /* TokenResponse */
} Update;

The structure fields are:

  • token is the presented Privacy Pass Token.

  • token_request is the encoded replacement TokenRequest.

  • token_response is the encoded replacement TokenResponse.

These structures implement CreatePresentationAndUpdate, ProcessPresentation, and FinalizeUpdate.

The token field carries a Token as defined in [PRIVACYPASS-AUTH]. Privacy Pass names its cryptographic Context TokenChallenge. In MoLE, the type-specific body of CredentialChallenge carries that configured TokenChallenge. It is therefore both sent by the Moderator as part of a Challenge and supplied to the Privacy Pass replacement-issuance and verification operations as their Context. Initial issuance obtains the same TokenChallenge from authenticated configuration.

TokenChallenge is fixed when the token is issued. It MUST be stable for every Client using the same configured credential type, key, and epoch, and MUST NOT contain a per-Client or per-request value. This is necessary because a replacement token is issued before the operation in which it will be presented. The Privacy Pass Token.challenge_digest field MUST equal SHA-256 over the encoded configured TokenChallenge. It is distinct from the MoLE endorsement challenge_digest defined in Section 4.1. The Moderator MUST reject a token carrying any other digest. Replay protection comes from token single use. The Moderator MUST verify the token as specified by [PRIVACYPASS-AUTH] against the configured token type, key, and TokenChallenge, then atomically record its nonce before accepting it. An invalid or previously recorded nonce is rejected, except for the retry behavior below. Holder binding remains an open limitation below.

If the Moderator's policy allows continued access, it returns an Update. If not, it returns no update and the Client is out of credentials.

5.3.3. Retry after a lost response

A Client that receives no response MAY retry the byte-identical PresentationAndUpdate only to recover from that loss. The Moderator MUST return the same accepted result while it retains the idempotency record, including the same Update or the same absence of an update. It MUST reject the replay after that record expires and MUST NOT issue a second Credential. The Client MUST NOT combine the same presented Credential with a different update request. These requirements are the retry semantics of [REVERSE-FLOW].

The recovery handle ([HTTP-TRANSPORT]) is token.token_key_id || token.nonce || SHA-256(PresentationAndUpdate).

5.3.4. Limitations

TODO: define a device binding mechanism, issuing tokens bound to a Client key so that presentation requires proof of possession. This would restore the binding between update and presented credential. Open problem.

6. Key Rotation and Discovery

This draft assumes authenticated configuration supplies endpoints, supported types, keys, epochs, accepted issuer sets, and type-specific inputs. The order of accepted sets is significant because Rollatini proof branches and Longfellow issuer inputs match elements by position.

ACT configuration adds, per key, the ciphersuite, balance width, credential context, and result retention period (Section 5.2.1). ACT nullifiers MUST remain recorded while their credential context is accepted for their key. A Moderator that publishes different keys or contexts to different Clients partitions them ([ARCHITECTURE]).

7. Privacy Considerations

TODO. The list to cover:

  1. Anchor set verification: the Client must be able to verify the number of Anchors in an accepted set, and that these Anchors are real rather than fabricated by the Moderator. A set padded with fake Anchors shrinks the effective anonymity set to the Clients of the real ones.

  2. Configuration partitioning: accepted-set contents and order as a fingerprinting vector (with [ARCHITECTURE]).

  3. Epoch width versus anonymity set size.

During redemption of an Endorsement, the Client uses the accepted Anchor Set from the Moderator's authenticated configuration. If the Client does not have an Endorsement issued by one of the Anchors in the Anchor Set, it must either abort the redemption flow or pause it until it can obtain a suitable Endorsement. The Client must take care to ensure its actions in this case do not inadvertently reveal the issuing Anchor of an accepted Endorsement. For example, if the Client initiates two concurrent redemption flows, the Moderator can select Anchor Sets that differ by just one Anchor. If one flow aborts but the other does not, then the Moderator immediately learns the Anchor of the accepted Endorsement.

7.1. Anonymous Credit Tokens

An ACT presentation reveals s, a, and a fresh nullifier, and, because the proof verifies, the key and credential context of the Credential. Its Update reveals t. The unlinkability of [ACT] holds among the Clients that share the key, the context, and the amounts, so each of these partitions Clients:

Keys and contexts:

The truncated key identifier shortens the encoding, but it still selects one active key, and every active key splits the Clients holding Credentials under it. [ACT] requires the credential context to be coarse: a per-Client or per-session context makes presentations linkable without breaking any cryptographic property.

Amounts:

The initial balance, s, a, and t MUST NOT vary per Client under a policy, since a Moderator could recognize a Client by the values it uses. A Moderator SHOULD draw them from a small set of values fixed by policy, so that a value reveals no more than the policy decision it encodes. A Client whose balance plus a reaches 2^L cannot present, which sets it apart. A Moderator SHOULD choose L so that the largest balance its policy lets Clients reach, plus the largest a it offers, is below 2^L.

Balance inference:

A presentation succeeds only if the balance covers s. A Moderator that challenges a Client repeatedly with amounts of its choosing can bound the balance, and in the end recover it and use it to link presentations ([ARCHITECTURE]). The serialized chain of Section 5.2.4 limits such probing to one presentation per round trip. Clients SHOULD limit the number of presentations they make in one context, as [ARCHITECTURE] recommends.

Timing:

The refund arrives in the same exchange as the presentation, so a Client that presents it in another context at once is likely the one that just received it. [ARCHITECTURE] keeps a Credential used in one context locked to that context for a period of time; this applies to the refund that replaces it.

8. Security Considerations

All exchanges defined in this document and [HTTP-TRANSPORT] MUST be carried over HTTPS.

TODO. The list to cover:

  1. Nullifier store sizing and eviction: the store is per epoch, and a Moderator that evicts early re-admits spent Endorsements.

  2. Anchor key compromise: an attacker with an Anchor key in an accepted set can mint Endorsements freely. Blast radius and rotation response.

  3. Reverse-flow update transfer: the two-credential attack of Section 5.3, and why single-credential enforcement cannot be verified.

  4. Timing and error side channels during verification, especially distinguishing "bad proof" from "spent nullifier".

The replay protection store is shared only within its configured scope. A deployment can use one atomic scope across all regions, including by routing each replay protection identifier to an authoritative region. This does not require the Client to know that region. A deployment can instead operate independent regional stores, but then the same Endorsement can be accepted once in each region. Credentials can likewise be presented once in each region, potentially creating divergent updates. Separate Moderators also do not coordinate stores. For ACT, all servers accepting the same key and credential context MUST share one atomic nullifier store; independent stores need disjoint keys or contexts. Otherwise a Client can fork a balance across stores, which breaks the credit conservation of [ACT]. A Rollatini redemption exposes the same nullifier in each scope, making cross-scope reuse linkable if records are compared. Proof rerandomization does not hide that reuse.

8.1. Anonymous Credit Tokens

Nullifier store:

Step 3 of Section 5.2.3.2 is the atomic recording that [ACT] requires. The store MUST be durable: a Moderator that loses it re-admits every Credential spent under a context for as long as that context is accepted. Nullifiers MAY be partitioned by key and context and discarded once the context is no longer accepted; a Moderator MUST NOT accept that key and context again afterwards.

Amounts:

Step 2 of Section 5.2.3.2 requires spend.s and spend.a to equal the challenge's s and a. Accepting another s would let the Client choose its charge, and accepting a larger a would let it choose how far its balance may rise. [ACT] gives the range checks that credit conservation needs.

Credential sharing:

Copies of one Credential yield one presentation: the first to reach the Moderator is recorded in step 3, and every other copy is rejected as a double spend and is linkable to the first ([ACT]).

Recorded results:

A recorded result is returned only for a byte-identical presentation and never authorizes another operation. A party that replays an observed presentation receives a refund it cannot finalize without the spend state. A recorded NoUpdate stays NoUpdate; answering a retry with a refund would undo the Moderator's revocation.

Dynamic revocation:

A Moderator that records NoUpdate ends that Credential chain, and the Client loses its remaining balance with no cryptographic recourse. Clients therefore trust Moderators to refund honest presentations; a Moderator that withholds refunds indiscriminately costs its Clients their Endorsements. Client Vendors can limit their Clients' use of such a Moderator.

Presentation scope:

Under the policy-scoped profile of Section 5.2.3.1, a party that sees a presentation before the Moderator does, such as an intermediary terminating TLS for the Moderator, can attach it to another request under the same policy. The nullifier ensures that only one use is accepted, not which. Deployments that need a presentation tied to one request use the request-bound profile.

Verification cost:

An unrecorded nullifier passes step 1 of Section 5.2.3.2, so a forged presentation costs the Moderator a full VerifySpend, whose cost is linear in L. Mitigations are rate limiting applied before verification, which identifies Clients no more than the transport already does, and a small L.

9. IANA Considerations

This document sketches two candidate registries under a future "MoLE" group. The values below are candidate values for discussion in this -00 draft and are not stable assignments.

New registrations use Specification Required as defined by [IANA]. A specification MUST define the structures and abstract operations required by the relevant common API, including canonical encodings and maximum sizes. An endorsement registration MUST provide issuer hiding where applicable, define its replay protection behavior, and state how a Challenge affects its cryptographic Context. A credential registration MUST define IssuanceRequest, IssuanceResponse, PresentationAndUpdate, Update, finalization, retry behavior, and Challenge-to-Context derivation. Outer type-selecting messages carry the registered uint16 type as specified in Section 3.

9.1. MoLE Endorsement Types

Table 2: Candidate MoLE Endorsement Type Values
Value Name Reference
0x0000 Reserved this document
0x0001 No Endorsement Required Section 4.3
0x0002 Rollatini Section 4.4
0x0003 Longfellow Section 4.5
0xFF00 - 0xFFFF Reserved for testing this document

The registration template contains:

  • Value: The two-byte endorsement type.

  • Name: A short name for the protocol.

  • Exchanges: The number of request/response exchanges with the Anchor, or "none" if the grant is out of band.

  • Publicly Verifiable: Whether the Endorsement can be verified without Anchor secret key material.

  • Reference: Where the protocol is defined.

The following initial registrations are candidates only.

9.1.1. Rollatini

9.1.2. Longfellow

  • Value: 0x0003

  • Name: Longfellow

  • Exchanges: none (out of band)

  • Publicly Verifiable: Yes

  • Reference: Section 4.5

9.2. MoLE Credential Types

One MoLE credential type identifies the issuance, presentation, and update payloads defined by a credential protocol.

Table 3: Candidate MoLE Credential Type Values
Value Name Reference
0x0000 Reserved this document
0x0001 ACT Section 5.2
0x0002 Privacy Pass Reverse Flow Section 5.3
0x0A0A, 0x1A1A, ..., 0xFAFA Reserved for greasing Section 3.2
0xFF00 - 0xFFFF Reserved for testing this document

The registration template contains:

  • Value: The two-byte credential type.

  • Name: A short name for the protocol.

  • Bound Update: Whether updates provably apply to the presented credential.

  • Reference: Where the protocol is defined.

9.2.1. ACT

9.2.2. Privacy Pass Reverse Flow

  • Value: 0x0002

  • Name: Privacy Pass Reverse Flow

  • Bound Update: No

  • Reference: Section 5.3

9.2.3. Greased Values

  • Value: 0x0A0A, 0x1A1A, 0x2A2A, 0x3A3A, 0x4A4A, 0x5A5A, 0x6A6A, 0x7A7A, 0x8A8A, 0x9A9A, 0xAAAA, 0xBABA, 0xCACA, 0xDADA, 0xEAEA, 0xFAFA

  • Name: RESERVED

  • Bound Update: N/A

  • Reference: Section 3.2

These values MUST NOT be assigned. Message bodies carrying them contain random bytes (Section 3.2).

9.3. Media Types

Table 4: MoLE Media Types
Media Type Reference
application/mole-endorsement-request Section 4
application/mole-endorsement-response Section 4
  • Editor note. The final registry names and expert-review instructions remain to be specified.

10. References

10.1. Normative References

[ACT]
"Anonymous Credit Tokens (ACT)", n.d., <https://moderation-of-unlinkable-endorsements.github.io/internet-drafts/draft-authors-mole-act.html>.
[ARCHITECTURE]
Schlesinger, S., Jackson, D., and T. Meunier, "Moderation of unLinkable Endorsements (MoLE) Architecture", Work in Progress, Internet-Draft, draft-jms-mole-architecture-00, , <https://datatracker.ietf.org/doc/html/draft-jms-mole-architecture-00>.
[HTTP-TRANSPORT]
Schlesinger, S., Jackson, D., and T. Meunier, "MoLE HTTP Transport", Work in Progress, Internet-Draft, draft-jms-mole-http-transport-00, , <https://datatracker.ietf.org/doc/html/draft-jms-mole-http-transport-00>.
[IANA]
Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 8126, DOI 10.17487/RFC8126, , <https://www.rfc-editor.org/rfc/rfc8126>.
[LONGFELLOW]
Frigo, M. and A. shelat, "Longfellow ZK", Work in Progress, Internet-Draft, draft-google-cfrg-libzk-03, , <https://datatracker.ietf.org/doc/html/draft-google-cfrg-libzk-03>.
[PRIVACYPASS-AUTH]
Pauly, T., Valdez, S., and C. A. Wood, "The Privacy Pass HTTP Authentication Scheme", RFC 9577, DOI 10.17487/RFC9577, , <https://www.rfc-editor.org/rfc/rfc9577>.
[PRIVACYPASS-PROTOCOLS]
Celi, S., Davidson, A., Valdez, S., and C. A. Wood, "Privacy Pass Issuance Protocols", RFC 9578, DOI 10.17487/RFC9578, , <https://www.rfc-editor.org/rfc/rfc9578>.
[REVERSE-FLOW]
Meunier, T., "Privacy Pass Reverse Flow", Work in Progress, Internet-Draft, draft-meunier-privacypass-reverse-flow-07, , <https://datatracker.ietf.org/doc/html/draft-meunier-privacypass-reverse-flow-07>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[ROLLATINI]
"Rollatini: An Issuer-Hiding Anonymous Token", n.d., <https://moderation-of-unlinkable-endorsements.github.io/internet-drafts/draft-authors-mole-rollatini.html>.
[SHA2]
Eastlake 3rd, D. and T. Hansen, "US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)", RFC 6234, DOI 10.17487/RFC6234, , <https://www.rfc-editor.org/rfc/rfc6234>.
[TLS13]
Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, , <https://www.rfc-editor.org/rfc/rfc8446>.

Appendix A. Example

A Client requests a resource protected by a Moderator that uses credential type 0x0002 (Privacy Pass Reverse Flow) and accepts endorsement type 0x0002 (Rollatini). The Client obtains the Endorsement before contacting that Moderator.

Client Anchor Moderator empty body CommitMessage - ChallengeMessage ResponseMessage Finalize | ModeratorChallenge Redemption + IssuanceRequest IssuanceResponse Finalize | CredentialChallenge PresentationAndUpdate Update | |
Figure 4: Complete exchange

The first Rollatini request has an empty body. The Anchor returns a CommitMessage. The Client then sends the corresponding ChallengeMessage, and the Anchor returns a ResponseMessage:

POST <anchor-grant-link> HTTP/1.1
Host: anchor.example
Content-Type: application/mole-endorsement-request

EndorsementRequest { 0x0002, "" }

The Client finalizes the ResponseMessage into an Endorsement. It then obtains a ModeratorChallenge from the Moderator, computes its digest, and sends an HTTP request with a CredentialRequest containing the Rollatini Redemption and a Privacy Pass TokenRequest to its Redeem & Issue endpoint:

POST /issue HTTP/1.1
Host: moderator.example
Authorization: Mole credential-request="<credential-request>"

The Moderator verifies the redemption against the Challenge it sent and atomically records its nullifier. It then processes the issuance request and returns a CredentialResponse carrying a TokenResponse in the Mole-Credential header. The Client finalizes the issuance response. On a later request, it obtains a CredentialChallenge carrying the configured Privacy Pass TokenChallenge before presenting the resulting token:

GET /resource HTTP/1.1
Host: moderator.example
Authorization: Mole presentation="<credential-presentation>"

The Moderator verifies the presentation and serves the resource. Its response carries an Update for a fresh token, or no update if it chose to consume the Credential.

Acknowledgments

TODO acknowledge.

Authors' Addresses

Samuel Schlesinger
Google LLC
Dennis Jackson
Mozilla
Thibault Meunier
Cloudflare