| Internet-Draft | JWP-BBS | July 2026 |
| Bormann | Expires 4 January 2027 | [Page] |
This document defines a digital credential format that uses JSON Web Proofs (JWP) as its container format and Blind BBS Signatures as its signature scheme combined with a modular framework for attaching zero-knowledge sub-proofs. This allows a Holder to reveal some attributes directly while proving predicates such as range or equality over the ones they keep hidden. A credential can additionally be bound to an ECDSA P-256 device key, with possession of the key proven in every presentation without revealing the public key. The credential type definition and data model follow SD-JWT VC [I-D.ietf-oauth-sd-jwt-vc].¶
This note is to be removed before publishing as an RFC.¶
Source for this draft and an issue tracker can be found at https://github.com/c2bo/draft-bormann-jwp-modular-bbs.¶
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 4 January 2027.¶
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. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
The BBS signature scheme [I-D.irtf-cfrg-bbs-signatures] is a multi-message signature (MMS) scheme where the signer produces a single signature over a vector of messages m0 through m(n-1), and the Holder can prove knowledge of the signature in zero knowledge while disclosing only a chosen subset of those messages.¶
The Blind BBS Signatures extension [I-D.irtf-cfrg-bbs-blind-signatures] adds Pedersen commitments to the scheme that allow the Holder to mark each message as disclosed, hidden, or committed at proof time, and the resulting proof carries a fresh Pedersen commitment for every committed message. Those commitments become public inputs to further proofs over the values they hide.¶
Building on those core building blocks, this document defines a digital credential format that:¶
CoreProofGen of [I-D.irtf-cfrg-bbs-blind-signatures], exposing fresh Pedersen commitments to selected messages as public inputs for sub-proofs.¶
This modular architecture builds on prior work [TS14] and [LSZ25], and the credential type model is reused from SD-JWT VC [I-D.ietf-oauth-sd-jwt-vc].¶
+----------------+
| | ---------> +----------------+
| | | Revealed |
| | | Attributes |
| | +----------------+
| | |
| | |
| | ---------> +--------------+ +--------------+
| MMS | | Commitment | ---> | Sub-Proof |
| Signature | +--------------+ +--------------+
| | |
| | |
| | ---------> +--------------+ +--------------+
| | | Commitment | ---> | Sub-Proof |
| | +--------------+ +--------------+
| | |
+----------------+ |
| |
| +-----+------+-------+
| | | |
v v v v
+----------------------------------------> +----------------+
(revealed + commitment openings feed down) | Core Proof |
+----------------+
¶
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.¶
All examples in this document are non-normative.¶
Indexing into vectors is 0-based. The notation m_i denotes the i-th element of the message vector: m_0 is the first element. Ranges are written [a, b] for inclusive endpoints and [a, b) for a half-open interval.¶
This document uses the Issuer-Holder-Verifier model and terminology of [I-D.ietf-oauth-sd-jwt-vc].¶
Additional terms used are:¶
A credential exists in two forms: the Issued Form an Issuer transmits to a Holder, and the Presented Form a Holder derives from it for a Verifier (see Section 4).¶
A credential is issued in the Issued Form (see Section 6.1 of [I-D.ietf-jose-json-web-proof]) consisting of:¶
n Issuer Payloads (Section 6.1.2 of [I-D.ietf-jose-json-web-proof]), where n is the length of the BBS message vector (see Section 2.3). The Issuer Payload at position i is the octet string from which the scalar message m_i is derived per Section 2.5.¶
header_octets and the message vector (m_0, ..., m_(n-1)).¶
header_octets is the Issuer Header as transmitted, i.e., the octets obtained by base64url-decoding the Issuer Header component of the Compact Serialization. All parties MUST use those octets as received and MUST NOT alter the header (e.g., re-encode).¶
The Issued Form is serialized using the Compact Serialization (see Section 7.1 of [I-D.ietf-jose-json-web-proof]). CBOR Serialization is (currently) out of scope for this document.¶
The Issuer Header is a JSON object with the following Header Parameters.¶
alg (REQUIRED):BBS-MOD (see Section 5).¶
vct (string, REQUIRED):cmap (JSON object, REQUIRED):kb (string, OPTIONAL):Temporal claims (exp, nbf, iat) MUST NOT appear as Issuer Header values - see Section 2.7 for more details.¶
The JWP iek, hpk, and hpa Header Parameters (Sections 5.2.5, 5.2.6, and 5.2.7 of [I-D.ietf-jose-json-web-proof]) MUST NOT appear in the Issuer Header.¶
cmap mirrors the credential's JSON tree structurally. Each leaf is replaced by an index annotation: a two-element JSON array [i, scalar], where:¶
i is the 0-based index of the leaf value in the message vector.¶
scalar is a boolean selecting how the leaf becomes the BBS message m_i:¶
false: the leaf is encoded as octets and mapped to a scalar via the cipher suite's hash-to-scalar primitive (see Section 2.5).¶
true: the leaf MUST be a JSON integer in [0, r - 1] (where r is the order of the BBS scalar field) and is used directly as m_i (see Section 2.6).¶
Let n be the length of the message vector, and N the number of payload slots reserved for the device-key encoding (see Section 2.8), with N = 0 when kb is absent. Every index in [N, n-1] MUST appear in exactly one annotation in cmap. Indices [0, N-1] MUST NOT appear in cmap.¶
The top-level member names of cmap MUST NOT be vct, alg, cmap, or kb. This keeps the reconstructed payload (see Section 4.7) free of collisions with the vct member taken from the Issuer Header and prevents claim values from masquerading as header-derived members.¶
Receivers MUST validate cmap before use: every leaf is a two-element annotation of a non-negative integer index and a boolean, every index in [N, n-1] appears in exactly one annotation, no other index appears, and the name restrictions above hold. Holders MUST reject an issued credential and Verifiers MUST reject a presentation that violates any of these constraints.¶
Payload slots defined by the credential type's structural layout (see Section 2.9) but not populated by a given credential MUST carry the decoy value defined in Section 2.10.¶
Starting from an SD-JWT VC-style claim set [I-D.ietf-oauth-sd-jwt-vc]:¶
{
"vct": "https://credentials.example.com/identity_credential",
"given_name": "Erika",
"family_name": "Mustermann",
"email": "erika@example.com",
"phone_number": "+49 123456789",
"address": {
"street_address": "Heidestraße 17",
"locality": "Köln",
"region": "Nordrhein-Westfalen",
"country": "DE"
},
"birthdate": 19630812,
"iat": 1683000000,
"exp": 1786000000
}
¶
The vct claim becomes a Header Parameter and the other 11 attributes become leaves in cmap, with address mirrored as a nested object. No device binding is used, so N = 0 and the leaves occupy indices 0 through 10. The temporal claims iat and exp are carried as scalar = true leaves (see Section 2.7) to allow range sub-proofs over them. The resulting Issuer Header is:¶
{
"alg": "BBS-MOD",
"vct": "https://credentials.example.com/identity_credential",
"cmap": {
"given_name": [0, false],
"family_name": [1, false],
"email": [2, false],
"phone_number": [3, false],
"address": {
"street_address": [4, false],
"locality": [5, false],
"region": [6, false],
"country": [7, false]
},
"birthdate": [8, true],
"iat": [9, true],
"exp": [10, true]
}
}
¶
Indices 0–7 use hash-to-scalar and indices 8–10 carry their integer values directly as scalars, with iat and exp as NumericDate integers ([RFC7519]). A presentation can then mark iat/exp as COMMIT (see Section 4.3) and attach sigma-range sub-proofs (see Section 4.4.3) to prove validity without disclosing the timestamps.¶
A real deployment would define a structural layout covering all optional attributes and array slots up to their maximum length, with absent slots filled by decoys (see Section 2.10).¶
For an annotation [i, false] with leaf value v:¶
o is a JSON serialization of v - a single JSON text [RFC8259] encoded in UTF-8 (e.g., "Erika" for a string, true for a boolean) - carried as Issuer Payload i. The Issuer MAY produce any serialization of v, as the payload octets rather than the abstract value are what is mapped to the message scalar. Holders and Verifiers MUST use the received payload octets as-is and MUST NOT re-serialize them.¶
hash_to_scalar(o, map_dst), with map_dst = api_id || "MAP_MSG_TO_SCALAR_AS_HASH_" and api_id the Interface identifier of Section 5. This is the per-message derivation of BBS.messages_to_scalars (Section 4.1.2 of [I-D.irtf-cfrg-bbs-signatures]).¶
Numeric leaves recovered via JSON parsing are subject to JSON number-precision interoperability limits - Issuers SHOULD keep scalar = false number values within the I-JSON [RFC7493] range.¶
For an annotation [i, true] with leaf value v:¶
o is the canonical decimal octet encoding of v (see Section 2.6), carried as Issuer Payload i.¶
o, interpreted as an element of the BBS scalar field.¶
A leaf with scalar = true MUST be a JSON integer in [0, r - 1], where r is the order of the BBS scalar field. Implementations MUST reject any other value.¶
The Issuer Payload for such a leaf is the canonical decimal octet encoding of the integer: ASCII digits without sign or leading zeros, with 0 represented as the single digit 0. Future extensions MAY define additional scalar encodings provided they deterministically map a JSON value to an element of [0, r - 1].¶
The JWT temporal claims exp, nbf, and iat (Section 4.1 of [RFC7519]), when present in a credential, MUST be declared as scalar = true leaves in cmap carrying their NumericDate values. They MUST NOT appear as Issuer Header values.¶
When present, the kb Header Parameter is a string identifier selecting both the device public key type and its encoding into the BBS message vector. The reserved slots are always indices [0, N-1], where N depends on the kb value. If kb is not present, no slots are reserved. This document defines a single value for kb: ecdsa-p256-db.¶
A kb value and its matching device-binding sub-proof algorithm (see Section 4.4) share the same algorithm identifier string. Valid kb values are the entries of the Sub-Proof Algorithms registry whose Device Binding field is yes - see Section 8. The specification defining such an entry MUST define the number of reserved slots N, the encoding of the device public key into indices [0, N-1], and the matching device-binding sub-proof.¶
For kb = "ecdsa-p256-db", N = 4 and:¶
Each limb is encoded as if scalar = true: the Issuer Payload is its canonical decimal octet encoding (see Section 2.6).¶
The Issuer MUST make sure that (x, y) is a valid non-identity P-256 point [FIPS186-5] before computing the message vector.¶
For claims containing objects, the Issuer either mirrors the object structure within cmap or treats the JSON-encoded object as a single leaf. This is a policy decision by the Issuer and allows some objects to be discloseable only as one object containing all values or not at all.¶
For bounded-length array claims, cmap contains a JSON array of index annotations sized to the credential type's maximum array length. All entries in such an array SHOULD share the same scalar flag to guarantee a single decoy encoding (see Section 2.10).¶
For optional claims, cmap MUST contain the index entry regardless of whether the attribute is present in a given credential.¶
Decoys fill payload slots that the credential type's layout defines, but a specific credential does not populate. They keep the message-vector length and cmap identical across all credentials of a given vct to avoid correlation.¶
Every decoy slot carries the same fixed scalar:¶
m_decoy = hash_to_scalar("JWP-BBS-DECOY", map_dst)
¶
with hash_to_scalar and map_dst as defined in Section 2.5.¶
The Issuer Payload for a decoy slot depends on the slot's scalar flag:¶
scalar = false: the ASCII octets of "JWP-BBS-DECOY".¶
scalar = true: the canonical decimal octet encoding of m_decoy (see Section 2.6).¶
A Verifier detects a disclosed decoy by comparing the disclosed Presentation Payload octets to the fixed decoy octets defined above. The scalar = false decoy octets are deliberately not a valid JSON text, so no payload produced per Section 2.5 can collide with them. Decoys SHOULD NOT be disclosed unless required by the use case (for example, a proof over all members of a bounded-length array).¶
The Issuer key pair is a BBS key pair (Section 3.4 of [I-D.irtf-cfrg-bbs-signatures]) using the cipher suite of Section 5.¶
To issue a credential, the Issuer performs the following steps:¶
(m_0, ..., m_(n-1)) per Section 2.5 and Section 2.8, filling decoys per Section 2.10.¶
CoreSign (Section 3.6.1 of [I-D.irtf-cfrg-bbs-signatures]) over generators = create_generators(n + 1, api_id), header_octets, and the message vector, with api_id as in Section 5. No messages are Holder-committed at issuance, so the Commit/BlindSign flow of [I-D.irtf-cfrg-bbs-blind-signatures] is not used.¶
A non-normative example of the Compact Serialization:¶
<base64url(Issuer Header)> . <m_0>~<m_1>~ ... ~<m_10> . <base64url(BBS signature)>¶
Each <m_i> is the base64url-encoded Issuer Payload for index i (e.g., m_1 is "Mustermann" including the quotes, m_10 is 1786000000). For scalar = true leaves the canonical decimal encoding coincides with the JSON serialization of the integer.¶
The Holder verifies an issued credential by:¶
cmap object per Section 2.3. Reject on violation.¶
CoreVerify (Section 3.6.2 of [I-D.irtf-cfrg-bbs-signatures]) over the same generators, header_octets, and message vector as issuance. Reject on failure.¶
scalar = true leaf, confirming the corresponding Issuer Payload decodes to an integer in [0, r - 1].¶
scalar = false leaf, confirming the corresponding Issuer Payload either is byte-equal to the decoy octets (see Section 2.10) or parses as a single JSON text [RFC8259].¶
kb is present, confirming that the point reconstructed from the limb messages matches the Holder's device public key. How the Holder obtains the corresponding device key pair is out of scope.¶
A presentation is a Presented Form (Section 6.2 of [I-D.ietf-jose-json-web-proof]) consisting of:¶
n Presentation Payloads (Section 6.2.2 of [I-D.ietf-jose-json-web-proof]): disclosed positions carry the corresponding Issuer Payload and undisclosed positions are omitted (see Section 7.1 of [I-D.ietf-jose-json-web-proof]).¶
The Presentation Header is a JSON object with the following Header Parameters.¶
alg (REQUIRED):alg value of the Issuer Header.¶
nonce (string, REQUIRED):aud (string, REQUIRED):Additional Header Parameters MAY be present, but their use is out of scope for this document.¶
presentation_header_octets is the Presentation Header as transmitted, i.e., the octets obtained by base64url-decoding the Presentation Header component of the Compact Serialization. It is bound into the core proof challenge (see Section 4.3). Verifiers MUST use those octets as received.¶
The Holder builds a per-message disclosure map assigning each index in [0, n-1] one of DISCLOSE, HIDE, or COMMIT:¶
DISCLOSE: the message is revealed and its value MUST match the corresponding disclosed Presentation Payload.¶
COMMIT: a fresh Pedersen commitment to the message is carried in the proof. Every index referenced by a sub-proof (see Section 4.4) MUST be marked COMMIT.¶
HIDE: all other indices in [0, n-1]¶
The Holder generates the core proof by invoking CoreProofGen of [I-D.irtf-cfrg-bbs-blind-signatures] with:¶
PK: Issuer public key.¶
signature: BBS signature from the Issuer Proof.¶
generators: create_generators(n + 1, api_id) (see Section 4.1.1 of [I-D.irtf-cfrg-bbs-signatures]).¶
header: header_octets.¶
ph: presentation_header_octets (binds nonce and aud into the challenge).¶
messages: (m_0, ..., m_(n-1)).¶
disclosed_indexes: indices marked DISCLOSE.¶
commits_indexes: indices marked COMMIT.¶
api_id: the cipher suite identifier of Section 5.¶
CoreProofGen returns (proof, add_zkp_info). add_zkp_info contains, per committed index, the Pedersen commitment C_i and the blinding scalar s_i. The Holder retains it locally to build sub-proofs and MUST NOT transmit it. Only proof is carried as the first octet string of the Presentation Proof.¶
The core proof establishes that the Holder knows a BBS signature under the Issuer's public key on a message vector whose disclosed-index values match the disclosed Presentation Payloads, and that each carried C_i commits to the message at index i of that vector.¶
The Verifier verifies the core proof with CoreProofVerify, passing PK, the core proof, the generators, header_octets, presentation_header_octets, the disclosed scalar messages, and api_id. The disclosed and committed indices are recovered from the proof octets, not passed separately. On success, the Verifier recovers the committed indices and the corresponding C_i from the proof octets which are used in the sub-proof verification (see Section 4.4).¶
A sub-proof is a JSON object carried as an additional octet string of the Presentation Proof (see Section 4.1) with the following members:¶
alg (string, REQUIRED):input (JSON object, REQUIRED):i and MAY contain algorithm-specific members.¶
i is a non-empty JSON array of message-vector indices, each of which MUST be a COMMIT-marked index of the core proof. Each algorithm fixes the length of i and the role of its entries.¶
proof (string, REQUIRED):alg.¶
For each sub-proof, the Verifier MUST confirm that every value in i is among the committed indices recovered from the core proof, and MUST then run the algorithm-specific verification routine against the corresponding C_i, input, and proof.¶
Sub-proof freshness is inherited from the core proof: every C_i is randomized per presentation, and the core proof's challenge binds to presentation_header_octets. Sub-proof algorithms that include public material not derived from C_i (for example, the device ECDSA signature in ecdsa-p256-db) MUST bind that material to the current presentation by other means (ecdsa-p256-db does so via db_msg - see Section 4.4.2).¶
Sub-proof transcripts use the BBS encoding primitives of Section 4.2.4.1 of [I-D.irtf-cfrg-bbs-signatures]:¶
I2OSP(int, 8)¶
A Verifier MUST reject a sub-proof carrying an encoded group element (in input or proof) that does not decode to a valid non-identity point of the G1 subgroup.¶
[Editor's Note: Decision needed: Need to define a serialization scheme for the Sigma proofs - Re-use the existing one from the [I-D.irtf-cfrg-sigma-protocols] (although it uses different encodings etc.), or define an optimized one for BLS12-381? Some of the following sub-proofs already propose very concrete choices to make the construction more concrete - all of these are open for discussion and will very likely see significant changes.]¶
schnorr-eq¶
The i field MUST be a single-element array [idx].¶
Inputs (beyond the base sub-proof fields):¶
c_ext: a base64url-encoded BLS12-381 G1 point.¶
The sub-proof attests that C_idx (from the core proof) and c_ext open to the same scalar under the generators (G, H) of Section 5. Cross-group equality is out of scope.¶
The construction is a 3-DL Schnorr discrete-logarithm-equality (DLEQ) proof over BLS12-381 G1 with (G, H), with witness (m, s_1, s_2) such that:¶
C_idx = m * G + s_1 * H c_ext = m * G + s_2 * H¶
The Holder samples fresh random scalars (r_m, r_s1, r_s2) and computes Schnorr commitments T_1 = r_m * G + r_s1 * H and T_2 = r_m * G + r_s2 * H. The challenge is c = hash_to_scalar(transcript, challenge_dst) with challenge_dst = api_id || "SCHNORR_EQ_CHAL_" and hash_to_scalar the base BBS primitive of Section 5.¶
[Editor's Note: describe wire format of proof]¶
This sub-proof MUST be present whenever kb = "ecdsa-p256-db" and MUST NOT be present otherwise. The algorithm identifier deliberately matches the kb value it verifies (see Section 2.8).¶
ecdsa-p256-db¶
The i field MUST be [0, 1, 2, 3], naming the four indices that carry the device public-key limbs (see Section 2.8).¶
Inputs (beyond the base sub-proof fields): none.¶
The device-signed message is not transmitted, it is recomputed as:¶
db_msg = "JWP-BBS-DB-CHAL" || presentation_header_octets¶
where "JWP-BBS-DB-CHAL" is the literal ASCII string. Binding db_msg to presentation_header_octets carries nonce and aud and is therefore sufficient for freshness.¶
The proof bytes encode a non-interactive zero-knowledge proof of knowledge of (dpk, (r, s)) such that:¶
i open to the 128-bit limbs of dpk (in the layout of kb) under (G, H) (see Section 5).¶
(r, s) is a valid ECDSA P-256 signature on db_msg under dpk.¶
[Editor's Note: TODO - This is currently a placeholder until we can reference a construction; expectation is that this will be described in another IETF draft]¶
sigma-range¶
The i field MUST be a single-element array [idx].¶
Inputs (beyond the base sub-proof fields): bounds l and u as JSON integers. The sub-proof attests that m_idx, the message committed in the core proof at index idx, satisfies l <= m_idx < u.¶
[Editor's Note: describe/reference algorithm]¶
The Verifier verifies a presentation by:¶
cmap object of the Issuer Header per Section 2.3. Reject on violation.¶
alg equals the Issuer Header alg, that nonce matches the value the Verifier supplied for this presentation, and that aud identifies this Verifier.¶
scalar = true leaf, the payload MUST be the canonical decimal encoding of an integer in [0, r - 1] (see Section 2.6). Reject otherwise.¶
CoreProofVerify - see Section 4.3. Reject on failure. Confirming that the disclosed indices recovered from the proof are exactly the positions of the non-empty Presentation Payloads.¶
kb is present in the Issuer Header, confirming that exactly one sub-proof with alg equal to the kb value is present. If kb is absent, confirming that no device-binding sub-proof is present.¶
alg the Verifier does not support.¶
Whether the disclosed claims and the predicates established by sub-proofs satisfy the Verifier's requirements is an application-level decision and out of scope for this document. After successful verification, the Verifier reconstructs the JSON payload per Section 4.7.¶
Continuing the example of Section 2.4, a Verifier requests family_name and asks the Holder to prove exp is in the future without disclosing it. The Presentation Header:¶
{
"alg": "BBS-MOD",
"nonce": "f4Oa3wT0r8m2Vn1pQ7sKdA",
"aud": "https://verifier.example.com"
}
¶
The Holder marks index 1 (family_name) as DISCLOSE, index 10 (exp) as COMMIT, and the rest as HIDE. The core proof then carries a fresh Pedersen commitment to m_10. The Holder attaches a sigma-range sub-proof over index 10 proving now <= exp < 2^63 (with now = 1779926400):¶
{
"alg": "sigma-range",
"input": { "i": [10], "l": 1779926400, "u": 9223372036854775808 },
"proof": "..."
}
¶
The Compact Serialization concatenates with .: Presentation Header, Issuer Header, Presentation Payloads, Presentation Proof. The disclosed family_name at index 1 is the only populated payload and the other ten slots are empty:¶
<base64url(Presentation Header)> . <base64url(Issuer Header)> . ~Ik11c3Rlcm1hbm4i~~~~~~~~~ . <core proof>~<sigma-range sub-proof>¶
The Verifier verifies the core proof, recovers C_10, and checks the sub-proof against it. It learns family_name and that the credential has not expired.¶
After verifying the core proof and any sub-proofs, the Verifier SHOULD convey to the application a JSON object reconstructed from the disclosed information, analogous to the Processed SD-JWT Payload of [RFC9901]. Reconstruction presupposes that cmap passed the validation of Section 2.3 - a presentation whose cmap object fails it MUST be rejected, not reconstructed. The procedure:¶
{ "vct": <vct from Issuer Header> }.¶
cmap. For each leaf at a disclosed index i, first compare the Presentation Payload octets to the decoy octets for that leaf's scalar flag (see Section 2.10) - on a byte-equal match, omit the leaf. Otherwise set the leaf's value by parsing the payload octets as a single JSON text [RFC8259] when scalar is false, or as the integer they denote (see Section 2.6) when scalar is true. A presentation containing a disclosed payload that fails to parse MUST be rejected. Hidden and committed-but-not-disclosed leaves are omitted.¶
cmap for surviving leaves. Array entries that were omitted do not appear, so reconstructed array indices may differ from those in the cmap annotations.¶
Predicates established by sub-proofs are not represented as leaf values. The reconstruction procedure MUST NOT populate values for hidden or committed-but-not-disclosed leaves.¶
For Section 4.6, the reconstructed payload is:¶
{
"vct": "https://credentials.example.com/identity_credential",
"family_name": "Mustermann"
}
¶
This profile fixes exactly one cipher suite, so that alg does not vary across a credential population and split its anonymity set (see Section 7.1).¶
JPA Algorithm JSON Label: BBS-MOD.¶
Cipher suite identifier (also used as api_id for hash-to-scalar, generator derivation, and sub-proof domain separation):¶
BBS-MOD_BLS12381G1_XMD:SHA-256_SSWU_RO_BLIND_H2G_HM2S_¶
The BBS-MOD_ prefix separates this profile from both the base BBS JPA (BBS of Section 9.1.2.4 of [I-D.ietf-jose-json-proof-algorithms]) and the base blind BBS Interface (BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_BLIND_H2G_HM2S_). This profile invokes the core proof operations of that Interface directly to expose committed-message proofs - see Section 4.3. It also bypasses hash-to-scalar on a per-message basis under the scalar flag and attaches sub-proofs as described in Section 4.4.¶
BBS-MOD_BLS12381G1_XMD:SHA-256_SSWU_RO_ - identical to BLS12-381-SHA-256 (Section 7.2.2 of [I-D.irtf-cfrg-bbs-signatures], with hash-to-curve SHA-256 SSWU random oracle [RFC9380]) in all parameters except the ciphersuite identifier.¶
api_id.¶
CoreProofGen / CoreProofVerify of [I-D.irtf-cfrg-bbs-blind-signatures] invoked directly (not via BlindProofGen), so implementations MUST apply the commits_indexes and disclosed_indexes checks of CoreProofGen.¶
(G, H) = (Y_1, Y_0) where (Y_0, Y_1) = BBS.create_generators(2, "COM_DIS_" || api_id). Every committed-index commitment has the form C_i = m_i * G + s_i * H with s_i sampled per presentation by CoreProofGen.¶
scalar flag (see Section 2.3).¶
The api_id above follows the Interface identifier rule of Section 4.2 of [I-D.irtf-cfrg-bbs-blind-signatures] - ciphersuite_id || "BLIND_H2G_HM2S_" - applied to the ciphersuite identifier BBS-MOD_BLS12381G1_XMD:SHA-256_SSWU_RO_. All BBS operations used by this document are the Blind BBS Interface operations, or the core operations they wrap, which that document parameterizes with this api_id.¶
All randomness used by this document MUST be generated using a cryptographically secure random number generator. Reuse or predictability of a blinding scalar or proof nonce can break unlinkability or soundness, or even leak the signing key.¶
[Editor's Note: TODO - Check what exactly the attack scenarios are / if there are some]¶
Freshness relies on the Verifier-supplied nonce. Verifiers MUST generate nonces with enough entropy to make them unpredictable and MUST NOT accept a presentation carrying a nonce they did not supply for that transaction - see Section 4.5. The aud binding limits a captured presentation to its intended Verifier.¶
Without device binding (kb absent), possession of the Issued Form is sufficient to derive presentations, so anyone who obtains the credential in its Issued Form can present it. Deployments that need resistance against credential theft or pooling SHOULD use device binding - see Section 2.8.¶
The core proof hides everything except the disclosed messages, the carried commitments, and the sub-proof predicates. Parties observing multiple presentations (including colluding Verifiers, or an Issuer colluding with a Verifier) can still correlate them through disclosed attribute values, sub-proof predicate parameters, or transport-level metadata.¶
The Issuer Header is sent in clear to the Verifier. Any variation in it across Holders of the same vct narrows the anonymity set.¶
Implementations SHOULD make the Issuer Header byte-identical across the entire population of a vct, by:¶
cmap layout (including all optional attributes and maximum-length array slots) with a constant serialization.¶
alg and kb likewise split the anonymity set when they vary across the population of a vct. Implementations SHOULD use a single alg and a single kb value (or omit kb entirely) across all credentials of a vct, and SHOULD NOT mix device-bound and non-device-bound credentials under the same vct.¶
This document requests the following registrations and registry creations.¶
alg Value
IANA is requested to register the following JSON Proof Algorithm in the "JSON Web Proof Algorithms" registry established by [I-D.ietf-jose-json-proof-algorithms]:¶
BBS-MOD¶
CoreProofGen-based committed-message proofs, the per-message scalar flag, and the sub-proof attachment mechanism of Section 4.4. Cipher suite identifier BBS-MOD_BLS12381G1_XMD:SHA-256_SSWU_RO_BLIND_H2G_HM2S_.¶
IANA is requested to register the following Header Parameters in the "JSON Web Proof Header Parameters" registry established by [I-D.ietf-jose-json-web-proof]:¶
cmap¶
Specification Document(s): Section 2.3 of this document.¶
Header Parameter Name: Device Key Binding¶
Header Parameter JSON Label: kb¶
Header Parameter CBOR Label: TBD (requested assignment 12)¶
Header Parameter Usage Location(s): Issued¶
Change Controller: IETF¶
Specification Document(s): Section 2.8 of this document.¶
IANA is requested to create a new "Sub-Proof Algorithms" registry.¶
Allocation policy: Specification Required ([RFC8126]). Designated experts SHOULD verify that each entry pins its underlying group, generators, transcript hash, and Fiat-Shamir domain separation, and that the sub-proof is bound to a commitment attested by the core proof per Section 4.4. For entries with Device Binding set to yes, they SHOULD additionally verify that the reference defines the reserved slot count N and the device-key encoding required by Section 2.8.¶
Registry fields: Identifier (the alg value of a sub-proof object), Description, Device Binding (whether the identifier is also a valid kb value - see Section 2.8), Reference, Change Controller.¶
Initial entries:¶
ecdsa-p256-db¶
Change Controller: IETF.¶
Identifier: sigma-range¶
Description: Sigma-protocol range proof over a committed scalar message.¶
Device Binding: no.¶
Reference: This document, Section 4.4.3.¶
Change Controller: IETF.¶
Identifier: schnorr-eq¶
Description: Schnorr proof of equality between a committed message and an external commitment.¶
Device Binding: no.¶
Reference: This document, Section 4.4.1.¶
Change Controller: IETF.¶
This document rests on the work captured in [TS14] by the EUDI Wallet expert group. The committed-message core proof builds on [I-D.irtf-cfrg-bbs-blind-signatures], and the modular committed-disclosure framework draws on [LSZ25].¶
[[ pre Working Group Adoption: ]]¶
-02¶
claims Header Parameter to cmap to avoid the JPT claims parameter¶
alg to the Presentation Header¶
scalar = false payloads¶
claims validation¶
CoreSign¶
kb registration via a Device Binding registry field¶
-01¶
-00¶