Internet-Draft | ATHM | June 2025 |
Yun, et al. | Expires 26 December 2025 | [Page] |
This document specifies the Anonymous Tokens with Hidden Metadata (ATHM) protocol, a protocol for constructing Privacy Pass like tokens with hidden metadata embedded within it unknown to the client.¶
This note is to be removed before publishing as an RFC.¶
The latest revision of this draft can be found at https://cathieyun.github.io/draft-athm/draft-yun-cfrg-athm.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-yun-cfrg-athm/.¶
Discussion of this document takes place on the Crypto Forum Research Group mailing list (mailto:cfrg@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/cfrg. Subscribe at https://www.ietf.org/mailman/listinfo/cfrg/.¶
Source for this draft and an issue tracker can be found at https://github.com/cathieyun/draft-athm.¶
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 26 December 2025.¶
Copyright (c) 2025 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.¶
TODO Introduction¶
The following functions and notation are used throughout the document.¶
For any object x
, we write len(x)
to denote its length in bytes.¶
For two byte arrays x
and y
, write x || y
to denote their
concatenation.¶
I2OSP(x, xLen): Converts a non-negative integer x
into a byte array
of specified length xLen
as described in [RFC8017]. Note that
this function returns a byte array in big-endian byte order.¶
The notation T U[N]
refers to an array called U containing N items of type
T. The type opaque
means one single byte of uninterpreted data. Items of
the array are zero-indexed and referred as U[j]
such that 0 <= j < N.¶
All algorithms and procedures described in this document are laid out in a Python-like pseudocode. Each function takes a set of inputs and parameters and produces a set of output values. Parameters become constant values once the protocol variant and the ciphersuite are fixed.¶
String values such as "CredentialRequest", "CredentialResponse", and "Presentation" are ASCII string literals.¶
The PrivateInput
data type refers to inputs that are known only to the client
in the protocol, whereas the PublicInput
data type refers to inputs that are
known to both client and server in the protocol.¶
The following terms are used throughout this document.¶
Client: Protocol initiator. Creates an encrypted request, and uses the corresponding server encrypted issuance to make a presentation.¶
Server: Computes an encrypted issuance for an encrypted request, with its server private keys. Later the server can verify the client's presentations with its private keys. Learns nothing about the client's secret attributes, and cannot link a client's issuance and presentation steps.¶
The construction in this document has two primary dependencies:¶
Group
: A prime-order group implementing the API described below in Section 3.1.
See Section 4 for specific instances of groups.¶
Hash
: A cryptographic hash function whose output length is Nh
bytes.¶
Section 4 specifies ciphersuites as combinations of Group
and Hash
.¶
In this document, we assume the construction of an additive, prime-order
group Group
for performing all mathematical operations. In prime-order groups,
any element (other than the identity) can generate the other elements of the
group. Usually, one element is fixed and defined as the group generator.
In the KVAC setting, there are two fixed generator elements (generatorG, generatorH).
Such groups are uniquely determined by the choice of the prime p
that defines the
order of the group. (There may, however, exist different representations
of the group for a single p
. Section 4 lists specific groups which
indicate both order and representation.)¶
The fundamental group operation is addition +
with identity element
I
. For any elements A
and B
of the group, A + B = B + A
is
also a member of the group. Also, for any A
in the group, there exists an element
-A
such that A + (-A) = (-A) + A = I
. Scalar multiplication by r
is
equivalent to the repeated application of the group operation on an
element A with itself r-1
times, this is denoted as r*A = A + ... + A
.
For any element A
, p*A=I
. The case when the scalar multiplication is
performed on the group generator is denoted as ScalarMultGen(r)
.
Given two elements A and B, the discrete logarithm problem is to find
an integer k such that B = k*A. Thus, k is the discrete logarithm of
B with respect to the base A.
The set of scalars corresponds to GF(p)
, a prime field of order p, and are
represented as the set of integers defined by {0, 1, ..., p-1}
.
This document uses types
Element
and Scalar
to denote elements of the group and its set of
scalars, respectively.¶
We now detail a number of member functions that can be invoked on a prime-order group.¶
Order(): Outputs the order of the group (i.e. p
).¶
Identity(): Outputs the identity element of the group (i.e. I
).¶
Generators(): Outputs the generator elements of the group, (generatorG, generatorH) generatorG = Group.generator generatorH = HashToGroup(SerializeElement(generatorG), "generatorH"). The group member functions GeneratorG() and GeneratorH() are shorthand for returning generatorG and generatorH, respectively.¶
HashToGroup(x, info): Deterministically maps
an array of bytes x
with domain separation value info
to an element of Group
. The map must ensure that,
for any adversary receiving R = HashToGroup(x, info)
, it is
computationally difficult to reverse the mapping.
Security properties of this function are described
in [I-D.irtf-cfrg-hash-to-curve].¶
HashToScalar(x, info): Deterministically maps
an array of bytes x
with domain separation value info
to an element in GF(p).
Security properties of this function are described in [I-D.irtf-cfrg-hash-to-curve], Section 10.5.¶
RandomScalar(): Chooses at random a non-zero element in GF(p).¶
ScalarInverse(s): Returns the inverse of input Scalar
s
on GF(p)
.¶
SerializeElement(A): Maps an Element
A
to a canonical byte array buf
of fixed length Ne
.¶
DeserializeElement(buf): Attempts to map a byte array buf
to
an Element
A
, and fails if the input is not the valid canonical byte
representation of an element of the group. This function can raise a
DeserializeError if deserialization fails or A
is the identity element of
the group; see Section 4 for group-specific input validation steps.¶
SerializeScalar(s): Maps a Scalar
s
to a canonical
byte array buf
of fixed length Ns
.¶
DeserializeScalar(buf): Attempts to map a byte array buf
to a Scalar
s
.
This function can raise a DeserializeError if deserialization fails; see
Section 4 for group-specific input validation steps.¶
Section 4 contains details for the implementation of this interface for different prime-order groups instantiated over elliptic curves. In particular, for some choices of elliptic curves, e.g., those detailed in [RFC7748], which require accounting for cofactors, Section 4 describes required steps necessary to ensure the resulting group is of prime order.¶
A ciphersuite (also referred to as 'suite' in this document) for the protocol wraps the functionality required for the protocol to take place. The ciphersuite should be available to both the client and server, and agreement on the specific instantiation is assumed throughout.¶
A ciphersuite contains instantiations of the following functionalities:¶
Group
: A prime-order Group exposing the API detailed in Section 3.1, with the
generator element defined in the corresponding reference for each group. Each
group also specifies HashToGroup, HashToScalar, and serialization
functionalities. For
HashToGroup, the domain separation tag (DST) is constructed in accordance
with the recommendations in [I-D.irtf-cfrg-hash-to-curve], Section 3.1.
For HashToScalar, each group specifies an integer order that is used in
reducing integer values to a member of the corresponding scalar field.¶
Hash
: A cryptographic hash function whose output length is Nh bytes long.¶
This section includes an initial set of ciphersuites with supported groups and hash functions. It also includes implementation details for each ciphersuite, focusing on input validation.¶
For each ciphersuite, contextString
is that which is computed in the Setup functions.
Applications should take caution in using ciphersuites targeting P-256 and ristretto255.¶
This ciphersuite uses P-256 [NISTCurves] for the Group. The value of the ciphersuite identifier is "P256". The value of contextString is "ARCV1-P256".¶
Group: P-256 (secp256r1) [NISTCurves]¶
Order(): Return 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551.¶
Identity(): As defined in [NISTCurves].¶
Generator(): As defined in [NISTCurves].¶
RandomScalar(): Implemented by returning a uniformly random Scalar in the range
[0, G.Order()
- 1]. Refer to Section 4.2 for implementation guidance.¶
HashToGroup(x, info): Use hash_to_curve with suite P256_XMD:SHA-256_SSWU_RO_
[I-D.irtf-cfrg-hash-to-curve], input x
, and DST =
"HashToGroup-" || contextString || info.¶
HashToScalar(x, info): Use hash_to_field from [I-D.irtf-cfrg-hash-to-curve]
using L = 48, expand_message_xmd
with SHA-256, input x
and
DST = "HashToScalar-" || contextString || info, and
prime modulus equal to Group.Order()
.¶
ScalarInverse(s): Returns the multiplicative inverse of input Scalar s
mod Group.Order()
.¶
SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String method according to [SEC1]; Ne = 33.¶
DeserializeElement(buf): Implemented by attempting to deserialize a 33-byte array to a public key using the compressed Octet-String-to-Elliptic-Curve-Point method according to [SEC1], and then performs partial public-key validation as defined in section 5.6.2.3.4 of [KEYAGREEMENT]. This includes checking that the coordinates of the resulting point are in the correct range, that the point is on the curve, and that the point is not the point at infinity. Additionally, this function validates that the resulting element is not the group identity element. If these checks fail, deserialization returns an InputValidationError error.¶
SerializeScalar(s): Implemented using the Field-Element-to-Octet-String conversion according to [SEC1]; Ns = 32.¶
DeserializeScalar(buf): Implemented by attempting to deserialize a Scalar from a 32-byte
string using Octet-String-to-Field-Element from [SEC1]. This function can fail if the
input does not represent a Scalar in the range [0, G.Order()
- 1].¶
Two popular algorithms for generating a random integer uniformly distributed in the range [0, G.Order() -1] are as follows:¶
Generate a random byte array with Ns
bytes, and attempt to map to a Scalar
by calling DeserializeScalar
in constant time. If it succeeds, return the
result. If it fails, try again with another random byte array, until the
procedure succeeds. Failure to implement DeserializeScalar
in constant time
can leak information about the underlying corresponding Scalar.¶
As an optimization, if the group order is very close to a power of
2, it is acceptable to omit the rejection test completely. In
particular, if the group order is p, and there is an integer b
such that |p - 2b| is less than 2(b/2), then
RandomScalar
can simply return a uniformly random integer of at
most b bits.¶
Generate a random byte array with L = ceil(((3 * ceil(log2(G.Order()))) / 2) / 8)
bytes, and interpret it as an integer; reduce the integer modulo G.Order()
and return the
result. See [I-D.irtf-cfrg-hash-to-curve], Section 5 for the underlying derivation of L
.¶
This document has no IANA actions.¶
TODO acknowledge.¶
[[TODO: update these test vectors to use P256 instead of P384, using the new multi-bit protocol. Also add an allVectors.txt file and link to that here.]]¶
This section contains test vectors for the ATHM ciphersuites specified in this document.¶