W3C Candidate Recommendation Draft
Copyright © 2024 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
This specification describes a Data Integrity Cryptosuite for use when generating digital signatures using the BBS signature scheme. The Signature Suite utilizes BBS signatures to provide selective disclosure and unlinkable derived proofs.
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
The Working Group is actively seeking implementation feedback for this specification. In order to exit the Candidate Recommendation phase, the Working Group has set the requirement of at least two independent implementations for each feature, both mandatory and optional, in the specification. For details on the conformance testing process, see the test suites listed in the implementation report.
This document was published by the Verifiable Credentials Working Group as a Candidate Recommendation Draft using the Recommendation track.
Publication as a Candidate Recommendation does not imply endorsement by W3C and its Members. A Candidate Recommendation Draft integrates changes from the previous Candidate Recommendation that the Working Group intends to include in a subsequent Candidate Recommendation Snapshot.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 03 November 2023 W3C Process Document.
This specification defines a cryptographic suite for the purpose of
creating, verifying, and deriving proofs using the BBS Signature Scheme in
conformance with the Data Integrity [VC-DATA-INTEGRITY] specification. The
BBS signature scheme directly provides for selective disclosure and unlinkable
proofs. It provides four high-level functions that work within the issuer,
holder, verifier model. Specifically, an issuer uses the BBS Sign
function to
create a cryptographic value known as a "BBS signature" which is used in signing
the original credential. A holder, on receipt of
a credential signed with BBS, then verifies the credential with the BBS Verify
function.
The holder then chooses information to selectively disclose from the
received credential and uses the BBS ProofGen
function to generate a
cryptographic value, known as a "BBS proof", which is used in creating a proof
for this "derived credential". The cryptographic "BBS proof" value is not linkable
to the original "BBS signature" and a different, unlinkable "BBS proof" can be
generated by the holder for additional "derived credentials", including any
containing the exact same information.
Finally, a verifier uses the BBS ProofVerify
function to verify the derived
credential received from the holder.
Applying the BBS signature scheme to verifiable credentials involves the
processing specified in this document.
In general the suite uses the RDF Dataset Canonicalization Algorithm
[RDF-CANON] to transform an input document into its canonical
form. An issuer then uses selective disclosure primitives to separate the
canonical form into mandatory and non-mandatory statements. These are processed
separately with other information to serve as the inputs to the BBS Sign
function along with appropriate key material. This output is used to
generate a secured credential. A holder uses a set of selective disclosure
functions and the BBS Verify
function on receipt of the credential
to ascertain validity.
Similarly, on receipt of a BBS signed credential, a holder uses the RDF Dataset
Canonicalization Algorithm [RDF-CANON] to transform an input
document into its canonical form, and then applies selective disclosure
primitives to separate the canonical form into mandatory and selectively
disclosed statements, which are appropriately processed and serve as inputs to
the BBS ProofGen
function. Suitably processed, the output of this function
becomes the signed selectively disclosed credential sent to a verifier. Using
canonicalization and selective disclosure primitives, the verifier can then use
the BBS verifyProof
function to validate the credential.
Terminology used throughout this document is defined in the Terminology section of the Verifiable Credential Data Integrity 1.0 specification.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, MUST NOT, OPTIONAL, REQUIRED, and SHOULD 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.
A conforming proof is any concrete expression of the data model that complies with the normative statements in this specification. Specifically, all relevant normative statements in Sections 2. Data Model and 3. Algorithms of this document MUST be enforced.
A conforming processor is any algorithm realized as software and/or hardware that generates or consumes a conforming proof. Conforming processors MUST produce errors when non-conforming documents are consumed.
This document contains examples of JSON and JSON-LD data. Some of these examples
are invalid JSON, as they include features such as inline comments (//
)
explaining certain portions and ellipses (...
) indicating the omission of
information that is irrelevant to the example. Such parts need to be
removed if implementers want to treat the examples as valid JSON or JSON-LD.
The following sections outline the data model that is used by this specification for verification methods and data integrity proof formats.
These verification methods are used to verify Data Integrity Proofs [VC-DATA-INTEGRITY] produced using BLS12-381 cryptographic key material that is compliant with [CFRG-BBS-SIGNATURE]. The encoding formats for these key types are provided in this section. Lossless cryptographic key transformation processes that result in equivalent cryptographic key material MAY be used during the processing of digital signatures.
The Multikey format, as defined in [VC-DATA-INTEGRITY], is used to express public keys for the cryptographic suites defined in this specification.
The publicKeyMultibase
property represents a Multibase-encoded Multikey
expression of a BLS12-381 public key in the G2 group. The encoding of this field
is the two-byte prefix 0xeb01
followed
by the 96-byte compressed public key data.
The 98-byte value is then encoded using base58-btc (z
) as the prefix. Any
other encodings MUST NOT be allowed.
Developers are advised to not accidentally publish a representation of a private
key. Implementations of this specification will raise errors in the event of a
value other than 0xeb01
being used in a publicKeyMultibase
value.
{
"id": "https://example.com/issuer/123#key-0",
"type": "Multikey",
"controller": "https://example.com/issuer/123",
"publicKeyMultibase": "zUC7EK3ZakmukHhuncwkbySmomv3FmrkmS36E4Ks5rsb6VQSRpoCrx6
Hb8e2Nk6UvJFSdyw9NK1scFXJp21gNNYFjVWNgaqyGnkyhtagagCpQb5B7tagJu3HDbjQ8h
5ypoHjwBb"
}
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1"
],
"id": "https://example.com/issuer/123",
"verificationMethod": [{
"id": "https://example.com/issuer/123#key-1",
"type": "Multikey",
"controller": "https://example.com/issuer/123",
"publicKeyMultibase": "zUC7EK3ZakmukHhuncwkbySmomv3FmrkmS36E4Ks5rsb6VQSRpoCr
x6Hb8e2Nk6UvJFSdyw9NK1scFXJp21gNNYFjVWNgaqyGnkyhtagagCpQb5B7tagJu3HDbjQ8h
5ypoHjwBb"
}]
}
A proof contains the attributes specified in the Proofs section of [VC-DATA-INTEGRITY] with the following restrictions.
The verificationMethod
property of the proof MUST be a URL.
Dereferencing the verificationMethod
MUST result in an object
containing a type
property with the value set to
Multikey
.
The type
property of the proof MUST be DataIntegrityProof
.
The cryptosuite
property of the proof MUST be bbs-2023
.
The value of the proofValue
property of the proof MUST be a BBS signature or
BBS proof produced according to [CFRG-BBS-SIGNATURE] that is serialized and encoded
according to procedures in section 3. Algorithms.
The following algorithms describe how to use verifiable credentials with the BBS Signature Scheme [CFRG-BBS-SIGNATURE]. When using the BBS signature scheme the SHA-256 variant SHOULD be used.
Implementations SHOULD fetch and cache verification method information as early as possible when adding or verifying proofs. Parameters passed to functions in this section use information from the verification method — such as the public key size — to determine function parameters — such as the cryptographic hashing algorithm.
When the RDF Dataset Canonicalization Algorithm [RDF-CANON] is used, implementations of that algorithm will detect dataset poisoning by default, and abort processing upon detection.
This algorithm is used to configure a cryptographic suite to be used by the Add Proof and Verify Proof functions in Verifiable Credential Data Integrity 1.0. The algorithm takes an options object (map options) as input and returns a cryptosuite instance (struct cryptosuite).
DataIntegrityProof
, return cryptosuite.
bbs-2023
then:
The following algorithm creates a label map factory function that uses an HMAC to shuffle canonical blank node identifiers. The required input is an HMAC (previously initialized with a secret key), HMAC. A function, labelMapFactoryFunction, is produced as output.
bnodeIdMap
as follows:
hmacIds
to be the sorted array of values from the bnodeIdMap
, and set
bnodeKeys
to be the ordered array of keys from the bnodeIdMap
.
bnodeKeys
, replace the bnodeIdMap
value for that key with the
index position of the value in the hmacIds
array prefixed by "b", i.e.,
bnodeIdMap.set(bkey, 'b' + hmacIds.indexOf(bnodeIdMap.get(bkey)))
.
It should be noted that step 1.2 in the above algorithm is identical to step 1.2
in
Section 3.3.4 createHmacIdLabelMapFunction
of [DI-ECDSA],
so developers might be able to reuse the code or call the function if implementing
both.
The following algorithm serializes the base proof value, including the BBS signature, HMAC key, and mandatory pointers. The required inputs are a base signature bbsSignature, bbsHeader, publicKey, an HMAC key hmacKey, an array of mandatoryPointers, featureOption, and depending on the featureOption value the pid, and signer_blind values. A single base proof string value is produced as output.
"baseline"
:
0xd9
, 0x5d
, and 0x02
.
"anonymous_holder_binding"
:
0xd9
, 0x5d
, and 0x04
.
"pseudonym_issuer_pid"
:
0xd9
, 0x5d
, and 0x06
.
"pseudonym_hidden_pid"
:
0xd9
, 0x5d
, and 0x08
.
proofValue
. That is, return a string starting with "u
" and ending with the
base64url-no-pad-encoded value of proofValue.
The following algorithm parses the components of a bbs-2023
selective
disclosure base proof value. The required input is a proof value
(proofValue). A single object, parsed base proof, containing
six or seven elements, using the names "bbsSignature", "bbsHeader",
"publicKey",
"hmacKey", "mandatoryPointers", "featureOption", and possibly optional feature
parameter "pid" or
"signer_blind", is produced as output.
proofValue
string does not start with
u
(U+0075
LATIN SMALL LETTER U
),
indicating that it is a multibase-base64url-no-pad-encoded
value,
an error MUST be raised and SHOULD convey an error type of
PROOF_VERIFICATION_ERROR.
u
in proofValue
.
0xd9
, 0x5d
, and 0x02
, set
featureOption to "baseline"
.
0xd9
, 0x5d
, and 0x04
, set
featureOption to "anonymous_holder_binding"
.
0xd9
, 0x5d
, and 0x06
, set
featureOption to "pseudonym_issuer_pid"
.
0xd9
, 0x5d
, and 0x08
, set
featureOption to "pseudonym_hidden_pid"
.
components
to an array that is the result of CBOR-decoding the
bytes that follow the three-byte BBS base proof header.
"baseline"
, set the property names for the object
based on components to "bbsSignature", "bbsHeader", "publicKey", "hmacKey",
and "mandatoryPointers", in that order, and add featureOption as a property.
"anonymous_holder_binding"
, set the property names
for the object based on components to "bbsSignature", "bbsHeader",
"publicKey", "hmacKey", "mandatoryPointers", and "signer_blind", in that order, and
add featureOption as a property.
"pseudonym_issuer_pid"
, set the property names
for the object based on components to "bbsSignature", "bbsHeader",
"publicKey", "hmacKey", "mandatoryPointers", and "pid", in that order, and
add featureOption as a property.
"pseudonym_hidden_pid"
, set the property names
for the object based on components to "bbsSignature", "bbsHeader",
"publicKey", "hmacKey", "mandatoryPointers", and "signer_blind", in that order, and
add featureOption as a property.
The following algorithm creates data to be used to generate a derived proof. The inputs include a JSON-LD document (document), a BBS base proof (proof), an array of JSON pointers to use to selectively disclose statements (selectivePointers), an OPTIONAL BBS presentationHeader (byte array that defaults to an empty byte array if not present), a featureOption indicator, additional inputs as required by the featureOption (see Add Derived Proof), and any custom JSON-LD API options (such as a document loader). A single object, disclosure data, is produced as output, which contains the bbsProof, labelMap, mandatoryIndexes, selectiveIndexes, presentationHeader, revealDocument, and pseudonym (if computed) fields.
proofValue
from proof
.
"mandatory"
and value of mandatoryPointers; key of the string
"selective"
and value of selectivePointers; and key of the string "combined"
and value of combinedPointers.
combinedIndexes.indexOf(key)
), and add this value to the
mandatoryIndexes array.
nonMandatoryIndexes.indexOf(key)
), and add
this value to the selectiveIndexes array.
"baseline"
,
set bbsProof
to the value computed by the ProofGen
procedure from
[CFRG-BBS-SIGNATURE], i.e.,
ProofGen(PK, signature, header, ph, messages, disclosed_indexes)
,
where PK
is the original issuers public key, signature
is the
bbsSignature
, header
is the bbsHeader
, ph
is the presentationHeader
messages
is bbsMessages
, and disclosed_indexes
is selectiveIndexes
.
"anonymous_holder_binding"
,
set bbsProof
to the value computed by the BlindProofGen
procedure from
[CFRG-Blind-BBS-Signature], where PK is the original issuers public key,
signature is the
bbsSignature, header is the bbsHeader, ph is the presentationHeader,
messages is bbsMessages, disclosed_indexes is selectiveIndexes,
commitment_with_proof
, and signer_blind
. The holder will also furnish its
holder_secret, and proverBlind that was used to compute the
commitment_with_proof. This is the
Anonymous Holder Binding feature option.
To
be updated when IETF API is finalized.
"pseudonym_issuer_pid"
, compute the pseudonym
according to the Calculate Pseudonym
procedure given
in [CFRG-Pseudonym-BBS-Signature],
and set bsProof to the value computed by the
Signer Provided PID Proof Generation
procedure from
[CFRG-Pseudonym-BBS-Signature], where PK is the original issuers public key,
signature is the
bbsSignature, header is the bbsHeader, ph is the presentationHeader
messages is bbsMessages, disclosed_indexes is selectiveIndexes, and
pseudonym is the pseudonym
. This is for the
Pseudonyms with Issuer-known PID
feature option. To be updated when IETF API is finalized.
"pseudonym_hidden_pid"
, compute the pseudonym
according to the Calculate Pseudonym
procedure given
in [CFRG-Pseudonym-BBS-Signature],
and set bsProof to the value computed by the
Hidden PID Proof Generation with Pseudonym
procedure from
[CFRG-Pseudonym-BBS-Signature], where PK is the original issuers public key,
signature is the
bbsSignature, header is the bbsHeader, ph is the presentationHeader
messages is bbsMessages, disclosed_indexes is selectiveIndexes,
commitment_with_proof, pid, proverBlind, signer_blind, and
pseudonym is the pseudonym
. This is for the
Pseudonyms with Hidden PID
feature option. To be updated when IETF API is finalized.
"anonymous_holder_binding"
or
"pseudonym_hidden_pid"
, set the lengthBBSMessages parameter
to the length of the bbsMessages array.
If featureOption equals "pseudonym_issuer_pid"
set the lengthBBSMessages
parameter to the length of the bbsMessages array + 1. This
is due to the known-issuer PID being considered a "BBS message".
document
, and combinedPointers
as pointers
.
inputLabel
) and value (verifierLabel
) in `canonicalIdMap:
verifierLabelMap
, using verifierLabel
as the key, and the
value associated with inputLabel
as a key in labelMap
as the value.
The following algorithm compresses a label map. The required input is label map (labelMap). The output is a compressed label map.
map
to an empty map.
k
, v
) in labelMap
:
map
, with a key that is a base-10 integer parsed from the
characters following the "c14n" prefix in k
, and a value that is a base-10
integer parsed from the characters following the "b" prefix in v
.
map
as compressed label map.
The following algorithm decompresses a label map. The required input is a compressed label map (compressedLabelMap). The output is a decompressed label map.
map
to an empty map.
k
, v
) in compressedLabelMap
:
map
, with a key that adds the prefix "c14n" to k
, and a value
that adds a prefix of "b" to v
.
map
as decompressed label map.
The following algorithm serializes a derived proof value. The required inputs are a BBS proof (bbsProof), a label map (labelMap), an array of mandatory indexes (mandatoryIndexes), an array of selective indexes (selectiveIndexes), and a BBS presentation header (presentationHeader), the featureOption indicator, and, depending on the featureOption value, a pseudonym and/or lengthBBSMessages value. A single derived proof value, serialized as a byte string, is produced as output.
compressedLabelMap
to the result of calling the algorithm in
Section 3.3.4 compressLabelMap, passing labelMap
as the parameter.
"baseline"
:
0xd9
, 0x5d
, and 0x03
.
"anonymous_holder_binding"
:
0xd9
, 0x5d
, and 0x05
.
"pseudonym_issuer_pid"
or "pseudonym_hidden_pid"
:
0xd9
, 0x5d
, and 0x07
.
u
" and ending with the base64url-no-pad-encoded value of
proofValue
.
The following algorithm parses the components of the derived proof value. The required input is a derived proof value (proofValue). A single derived proof value object is produced as output, which contains a set of six or seven elements, having the names "bbsProof", "labelMap", "mandatoryIndexes", "selectiveIndexes", "presentationHeader", "featureOption", and, depending on the value of the featureOption parameter, "pseudonym" and/or "lengthBBSMessages".
proofValue
string does not start with
u
(U+0075
,
LATIN SMALL LETTER U
), indicating that
it is a multibase-base64url-no-pad-encoded
value,
an error MUST be raised and SHOULD convey an error type of
PROOF_VERIFICATION_ERROR.
u
in proofValue
.
0xd9
, 0x5d
, and
0x03
, set featureOption to "baseline"
.
0xd9
, 0x5d
, and
0x05
, set featureOption to "anonymous_holder_binding"
.
0xd9
, 0x5d
, and
0x07
, set featureOption to "pseudonym"
.
components
to an array that is the result of CBOR-decoding the
bytes that follow the three-byte BBS disclosure proof header. If the result
is not an array of five, six, or seven elements —
a byte array, a map of integers to integers,
two arrays of integers, and one or two byte arrays;
an error MUST be raised and SHOULD convey an error type of
PROOF_VERIFICATION_ERROR.
components
using the result of calling the
algorithm in Section 3.3.5 decompressLabelMap, passing the existing
second element of components
as compressedLabelMap
.
The following algorithm creates the data needed to perform verification of a BBS-protected verifiable credential. The inputs include a JSON-LD document (document), a BBS disclosure proof (proof), and any custom JSON-LD API options (such as a document loader). A single verify data object value is produced as output containing the following fields: bbsProof, proofHash, mandatoryHash, selectiveIndexes, presentationHeader, nonMandatory, featureOption, and, possibly, pseudonym and/or lengthBBSMessages.
labelReplacementCanonicalize
"
algorithm of [DI-ECDSA], passing document, labelMapFactoryFunction, and
any custom
JSON-LD API options. Note: This step transforms the document into an array of
canonical N-Quads with pseudorandom blank node identifiers based on labelMap.
hashMandatory
"
primitive, passing mandatory.
The bbs-2023
cryptographic suite takes an input document, canonicalizes
the document using the RDF Dataset Canonicalization Algorithm
[RDF-CANON], and then applies a number of transformations and cryptographic
operations resulting in the production of a data integrity proof. The algorithms
in this section also include the verification of such a data integrity proof.
The following algorithm specifies how to create a data integrity proof given an unsecured data document. Required inputs are an unsecured data document (map unsecuredDocument), a set of proof options (map options), an array of mandatory JSON pointers (mandatoryPointers), a featureOption indicator parameter, and, depending on the featureOption, a commitment_with_proof byte array. A data integrity proof (map), or an error, is produced as output.
The featureOption parameter is used to indicate which optional feature, if
any, is being used. It can take one of the following values "baseline"
,
"anonymous_holder_binding"
, "pseudonym_issuer_pid"
, or
"pseudonym_hidden_pid"
. Note that "baseline"
is used to denote the case of
no optional features. If featureOption is set to
"anonymous_holder_binding"
or "pseudonym_hidden_pid"
, the
commitment_with_proof input MUST be supplied.
The following algorithm specifies how to transform an unsecured input document into a transformed document that is ready to be provided as input to the hashing algorithm in Section 3.4.3 Base Proof Hashing (bbs-2023).
Required inputs to this algorithm are an unsecured data document (unsecuredDocument) and transformation options (options). The transformation options MUST contain a type identifier for the cryptographic suite (type), a cryptosuite identifier (cryptosuite), and a verification method (verificationMethod). The transformation options MUST contain an array of mandatory JSON pointers (mandatoryPointers) and MAY contain additional options, such as a JSON-LD document loader. A transformed data document is produced as output. Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.
labelMapFactoryFunction
to the result of calling the
createShuffledIdLabelMapFunction
algorithm passing hmac
as HMAC
.
groupDefinitions
to a map with an entry with a key of the string
"mandatory
" and a value of mandatoryPointers.
groups
to the result of calling the algorithm in
Section 3.3.16
canonicalizeAndGroup of the [DI-ECDSA] specification, passing
labelMapFactoryFunction
,
groupDefinitions
, unsecuredDocument
as document
, and any custom JSON-LD
API options. Note: This step transforms the document into an array of canonical
N-Quads whose order has been shuffled based on 'hmac' applied blank node
identifiers, and groups
the N-Quad strings according to selections based on JSON pointers.
mandatory
to the values in the groups.mandatory.matching
map.
nonMandatory
to the values in the groups.mandatory.nonMatching
map.
hmacKey
to the result of exporting the HMAC key from hmac
.
mandatoryPointers
" set to mandatoryPointers
,
"mandatory
" set to mandatory
, "nonMandatory
" set to nonMandatory
,
and "hmacKey
" set to hmacKey
.
The following algorithm specifies how to cryptographically hash a transformed data document and proof configuration into cryptographic hash data that is ready to be provided as input to the algorithms in Section 3.4.5 Base Proof Serialization (bbs-2023).
The required inputs to this algorithm are a transformed data document (transformedDocument) and canonical proof configuration (canonicalProofConfig). A hash data value represented as an object is produced as output.
proofHash
to the result of calling the RDF Dataset Canonicalization
algorithm [RDF-CANON] on canonicalProofConfig
and then cryptographically
hashing the result using the same hash that is used by the signature algorithm,
i.e., SHA-256. Note: This step can be performed in parallel;
it only needs to be completed before this algorithm terminates, as the result is
part of the return value.
mandatoryHash
to the result of calling the the algorithm in
Section 3.3.17
hashMandatoryNQuads of the [DI-ECDSA] specification, passing
transformedDocument.mandatory
and using the SHA-256
algorithm.
hashData
as a deep copy of transformedDocument, and
add proofHash
as "proofHash
" and mandatoryHash
as "mandatoryHash
" to that
object.
hashData
as hash data.
The following algorithm specifies how to generate a proof configuration from a set of proof options that is used as input to the base proof hashing algorithm.
The required inputs to this algorithm are proof options (options). The proof options MUST contain a type identifier for the cryptographic suite (type) and MUST contain a cryptosuite identifier (cryptosuite). A proof configuration object is produced as output.
DataIntegrityProof
and/or
proofConfig.cryptosuite is not set to bbs-2023
, an error MUST be raised
and SHOULD convey an error type of
PROOF_GENERATION_ERROR.
The following algorithm, to be called by an issuer of a BBS-protected Verifiable
Credential, specifies how to create a base proof. The base proof is to be
given only to the holder, who is responsible for generating a derived proof from
it, exposing only selectively disclosed details in the proof to a verifier. This
algorithm is designed to be used in conjunction with the algorithms defined
in the Data Integrity [VC-DATA-INTEGRITY] specification,
Section 4: Algorithms. Required inputs are
cryptographic hash data (hashData),
featureOption, and, if required,
commitment_with_proof.
If featureOption is set to "anonymous_holder_binding"
or
"pseudonym_hidden_pid"
, the
commitment_with_proof input MUST be supplied; if not supplied,
an error MUST be raised and SHOULD convey an error type of
PROOF_GENERATION_ERROR.
A single digital proof value represented as series of bytes is produced
as output.
proofHash
, mandatoryPointers
, mandatoryHash
, nonMandatory
,
and hmacKey
to the values associated with their property names in
hashData.
bbsHeader
to the concatenation of proofHash
and mandatoryHash
in
that order.
bbsMessages
to an array of byte arrays containing the values in the
nonMandatory
array of strings encoded using the UTF-8 character encoding.
bbsSignature
using the procedures below, dependent on the values
of featureOption.
"baseline"
, compute the
bbsSignature
using the Sign
procedure of [CFRG-BBS-Signature],
with appropriate key material, bbsHeader for the header
, and bbsMessages
for the messages
.
"anonymous_holder_binding"
, compute the
bbsSignature
using the BlindSign
procedure of [CFRG-Blind-BBS-Signature],
with appropriate key material, commitment_with_proof for the
commitment_with_proof
, bbsHeader for the header
, and bbsMessages
for the messages
. If the signing procedure uses the optional signer_blind
parameter, retain this value for use when calling
3.3.1 serializeBaseProofValue (below). This provides for the
Anonymous Holder Binding feature.
"pseudonym_issuer_pid"
, generate a
cryptographically random 32 byte pid value. Compute the
bbsSignature
using the Signer Provided PID Signature Generation
procedure
of [CFRG-Pseudonym-BBS-Signature],
with appropriate key material, bbsHeader for the header
, bbsMessages
for the messages
, and pid for the pid
. Retain the pid value for use when
calling 3.3.1 serializeBaseProofValue below.
This provides for Pseudonym with
Issuer-known PID feature.
"pseudonym_hidden_pid"
, compute
the bbsSignature
using the Hidden PID Signature Generation
procedure of
[CFRG-Pseudonym-BBS-Signature], with appropriate key material, bbsHeader
for the header
, bbsMessages for the messages
, and commitment_with_proof
for the commitment_with_proof
. If the signing procedure uses the optional
signer_blind parameter retain this value for use when calling
3.3.1 serializeBaseProofValue below.
This provides for the Pseudonym with
Hidden PID feature.
publicKey
is a byte array of the public key, encoded according to
[CFRG-BBS-SIGNATURE].
proofValue
as digital proof.
The following algorithm, to be called by a holder of a bbs-2023
-protected
verifiable credential, creates a selective disclosure derived proof.
The derived proof is to be given to the verifier. The inputs include a
JSON-LD document (document), a BBS base proof
(proof), an array of JSON pointers to use to selectively disclose
statements (selectivePointers), an OPTIONAL BBS
presentationHeader (a byte array), a featureOption parameter, additional
parameters supporting the featureOption selected (see below),
and any custom JSON-LD API options,
such as a document loader. A single selectively revealed document
value, represented as an object, is produced as output.
If featureOption equals "anonymous_holder_binding"
, the
REQUIRED additional inputs are holderSecret and proverBlind. These would
have been precomputed by the holder. See
Anonymous Holder Binding for background
information.
If featureOption equals "pseudonym_issuer_pid"
, the REQUIRED
additional input is the verifier_id which is communicated to the holder by the
verifier. See Pseudonyms with
Issuer-known PID for background information.
If featureOption equals "pseudonym_hidden_pid"
, the REQUIRED
additional inputs are the pid, proverBlind (both known to
holder), and verifier_id which is communicated to the holder by the verifier.
See Pseudonyms with
Hidden PID for background information.
proof
" property in revealDocument to newProof.
The following algorithm specifies how to verify a data integrity proof given an secured data document. Required inputs are a secured data document (map securedDocument). This algorithm returns a verification result, which is a struct whose items are:
true
or false
false
; otherwise, an unsecured data document
To verify a derived proof, perform the following steps:
proof
value removed.
"baseline"
, initialize verified to the result of
applying the verification algorithm ProofVerify(PK, proof, header, ph,
disclosed_messages, disclosed_indexes)
of [CFRG-BBS-SIGNATURE] with PK
set
as the public key of the original issuer, proof
set as bbsProof
, header
set as bbsHeader
, disclosed_messages
set as disclosedMessages
, ph
set as
presentationHeader
, and disclosed_indexes
set as selectiveIndexes
.
"anonymous_holder_binding"
,
initialize verified to the result of
applying the ProofVerify
verification algorithm of
[CFRG-Blind-BBS-Signature] using lengthBBSMessages for the "L"
parameter.
To be updated when IETF API is finalized.
"pseudonym"
, initialize verified
to the result of
applying the ProofVerifyWithPseudonym
verification algorithm of
[CFRG-Pseudonym-BBS-Signature] using lengthBBSMessages for the "L"
parameter. To be updated when IETF
API is finalized.
true
, otherwise
Null
This section is non-normative.
The cryptographic properties of BBS signatures permit variants that can support advanced functionalities. This specification is limited to supporting only the most relevant of these enhancements, which we explain in the following sections. The variables commitment_with_proof, pid, and pseudonym are associated with these features and are not otherwise needed for BBS signatures and proofs.
The optional BBS features described in this section, and included in the algorithms in this specification, are at risk and will be removed before the finalization of this specification if their respective specifications at the IETF do not reach RFC status on the same timeline or if there are not at least two independent implementations for each optional feature.
This feature binds, at the time of issuance, a document with base proof, to a secret, known only to a holder, in such a way, that only that holder can generate a revealed document with derived proof that will verify. For example, if an adversary obtained the document with base proof, they could not create a revealed document with derived proof that can verify.
To provide for this functionality, a holder generates a holder_secret value which should generally be at least 32 bytes long and cryptographically randomly generated. This value is never shared by the holder. Instead, the holder generates a commitment along with a zero knowledge proof of knowledge of this value, using the "Commitment Generation" procedure of [CFRG-Blind-BBS-Signature]. This computation involves cryptographically random values and computes the commitment_with_proof and secret_prover_blind values. The commitment_with_proof is conveyed to the issuer while the secret_prover_blind is kept secret and is retained by the holder for use in generation of derived proofs. Note that a holder can run the "Commitment Generation" procedure multiple times to produce unlinkable commitment_with_proof values for use with different issuers.
The issuer, on receipt of the commitment_with_proof, follows the procedures of [CFRG-Blind-BBS-Signature] to produce a base proof (signature) over the document with the commitment furnished by the holder. If the issuer chooses to use the signer_blind parameter when creating the signature in [CFRG-Blind-BBS-Signature], this value needs to be conveyed to the holder as part of the base proof value.
When the holder wants to create a selectively disclosed document with derived proof, they use their holder_secret (as a "commited message"), the secret_prover_blind, and, if supplied in the base proof, the signer_blind in the proof generation procedure of [CFRG-Blind-BBS-Signature].
Verification of the revealed document with derived proof uses the "regular" BBS proof verification procedures of [CFRG-BBS-SIGNATURE].
This feature is a privacy preserving enhancement that allows a verifier that has seen a selectively revealed document with derived proof from a holder to recognize that the same holder is presenting a new selectively revealed document with derived proof. Note that this may just be a new unlinkable proof (derived proof) on the same selectively revealed information. By "privacy preserving," we mean that no uniquely identifiable information is added that would allow tracking between different verifiers that may share information amongst themselves. This variant does allow for the issuer to monitor usage if verifiers share information with the issuer.
To furnish this capability, before creating the base proof for a document, an issuer generates a value known as a pid (prover id) which should be cryptographically random and at least 32 bytes long. This value is shared with the holder but otherwise kept secret. This value is then used in creating the base proof via the signing procedure in [CFRG-Pseudonym-BBS-Signature].
The holder receives the document with base proof which includes the pid value from the issuer. The holder obtains a verifier_id associated with the verifier for which they intend to create a revealed document with derived proof. Using the procedures of [CFRG-Pseudonym-BBS-Signature], a cryptographic pseudonym value is generated. The derived proof value is generated via the proof generation procedure of [CFRG-Pseudonym-BBS-Signature], and this value along with the pseudonym are given to the verifier. Note that the pid value cannot be recovered from the pseudonym.
When the verifier receives the revealed document with derived proof and pseudonym, they use the proof verification procedures of [CFRG-Pseudonym-BBS-Signature].
This section is non-normative.
This section provides summaries of the inputs, outputs, proof serialiation, tasks, and procedures for "baseline" BBS proofs as well as those for the optional features. By baseline BBS, we mean BBS base and derived proofs without additional features. All the optional features are "additive" in the sense that some additional input, task, or output is generated in addition to those of the "baseline" BBS signatures/proofs.
Name | Tasks | Inputs | Signing Algorithm |
---|---|---|---|
Baseline BBS | baseline: BBS signature generation from VC | baseline: document, proof options, key material, mandatory pointers | BBS |
Anonymous Holder Binding | baseline + selected index adjustment | baseline + commitment with proof to holder secret from holder | Blind BBS |
Pseudonym with Issuer Pid | baseline + Generate pid | baseline | Pseudonym BBS |
Pseudonym with Hidden Pid | baseline | baseline + commitment with proof to secret pid from holder | Pseudonym/Blind BBS |
Name | Proof Header Bytes | Serialized Output |
---|---|---|
Baseline BBS | 0xd9 , 0x5d , and 0x02 |
baseline: bbsSignature, bbsHeader, publicKey, hmacKey, and mandatoryPointers |
Anonymous Holder Binding | 0xd9 , 0x5d , and 0x04 |
baseline + signerBlind |
Pseudonym with Issuer Pid | 0xd9 , 0x5d , and 0x06 |
baseline + pid |
Pseudonym with Hidden Pid | 0xd9 , 0x5d , and 0x08 |
baseline + signerBlind |
Name | Tasks | Inputs | Proof Generation Algorithm |
---|---|---|---|
Baseline BBS | BBS derived proof generation from VC with base proof | baseline: (from base proof serialization) bbsSignature, bbsHeader, publicKey, hmacKey, and mandatoryPointers; selectivePointers (holders choice) | BBS |
Anonymous Holder Binding | baseline | baseline + holder secret, prover blind (both known to holder), signer blind (included in base proof from issuer) | Blind BBS |
Pseudonym with Issuer Pid | baseline + Generate pseudonym | baseline + verifier id (from verifier), pid (included in base from issuer) | Pseudonym BBS |
Pseudonym with Hidden Pid | baseline + Generate pseudonym | baseline + pid, prover blind (both known to holder), signer blind (included in base from issuer), verifier id (from verifier) | Pseudonym/Blind BBS |
Name | Proof Header Bytes | Serialized Output |
---|---|---|
Baseline BBS | 0xd9 , 0x5d , and 0x03 |
baseline: bbsProof, compressedLabelMap, mandatoryIndexes, selectiveIndexes, presentationHeader |
Anonymous Holder Binding | 0xd9 , 0x5d , and 0x05 |
baseline |
Pseudonym (issuer known and hidden) | 0xd9 , 0x5d , and 0x07 |
baseline + pseudonym |
Name | Inputs | Proof Verification Algorithm |
---|---|---|
BBS baseline | baseline: (from derived proof serialization) bbsProof, compressedLabelMap, mandatoryIndexes, selectiveIndexes, presentationHeader | BBS |
Anonymous Holder Binding | baseline | Blind BBS |
Pseudonym (issuer known and hidden) | baseline + verifier id (known to verifier), pseudonym (included in derived proof) | Pseudonym BBS |
Before reading this section, readers are urged to familiarize themselves with general security advice provided in the Security Considerations section of the Data Integrity specification.
This section is non-normative.
The security of the base proof is dependent on the security properties of the associated BBS signature. Digital signatures might exhibit a number of desirable cryptographic properties [Taming_EdDSAs] among these are:
EUF-CMA (existential unforgeability under chosen message attacks) is usually the minimal security property required of a signature scheme. It guarantees that any efficient adversary who has the public key of the signer and received an arbitrary number of signatures on messages of its choice (in an adaptive manner): , cannot output a valid signature for a new message (except with negligible probability). In case the attacker outputs a valid signature on a new message: , it is called an existential forgery.
SUF-CMA (strong unforgeability under chosen message attacks) is a stronger notion than EUF-CMA. It guarantees that for any efficient adversary who has the public key of the signer and received an arbitrary number of signatures on messages of its choice: , it cannot output a new valid signature pair , such that (except with negligible probability). Strong unforgeability implies that an adversary cannot only sign new messages, but also cannot find a new signature on an old message.
In [CDL2016] under some reasonable assumptions BBS signatures were proven to be EUF-CMA. Furthermore, in [TZ2023], under similar assumptions BBS signatures were proven to be SUF-CMA. In both cases the assumptions are related to the hardness of the discrete logarithm problem which is not considered post large scale quantum computing secure.
Under non-quantum computing conditions [CFRG-BBS-SIGNATURE] provides additional security guidelines to BBS signature suite implementors. Further security considerations related to pairing friendly curves are discussed in [CFRG-PAIRING-FRIENDLY].
This section is non-normative.
The security of the derived proof is dependent on the security properties of
the associated BBS proof. Both [CDL2016] and [TZ2023] prove that a
BBS proof is a zero knowledge proof of knowledge of a BBS
signature
.
As explained in [CFRG-BBS-SIGNATURE] this means:
a verifying party in receipt of a proof is unable to determine which signature was used to generate the proof, removing a common source of correlation. In general, each proof generated is indistinguishable from random even for two proofs generated from the same signature.
and
The proofs generated by the scheme prove to a verifier that the party who generated the proof (holder/prover or an agent of theirs) was in possession of a signature without revealing it.
More precisely, verification of a BBS proof requires the original issuers public key as well as the unaltered, revealed BBS message in the proper order.
This section is non-normative.
Selective disclosure permits a holder to minimize the information revealed to a verifier to achieve a particular purpose. In prescribing an overall system that enables selective disclosure, care has to be taken that additional information that was not meant to be disclosed to the verifier is minimized. Such leakage can occur through artifacts of the system. Such artifacts can come from higher layers of the system, such as in the structure of data or from the lower level cryptographic primitives.
For example the BBS signature scheme is an extremely space efficient scheme for producing a signature on multiple messages, i.e., the cryptographic signature sent to the holder is a constant size regardless of the number of messages. The holder then can selectively disclose any of these messages to a verifier, however as part of the encryption scheme, the total number of messages signed by the issuer has to be revealed to the verifier. If such information leakage needs to be avoided then it is recommended to pad the number of messages out to a common length as suggested in the privacy considerations section of [CFRG-BBS-SIGNATURE].
At the higher levels, how data gets mapped into individual statements suitable for selective disclosure, i.e., BBS messages, is a potential source of data leakage. This cryptographic suite is able to eliminate many structural artifacts used to express JSON data that might leak information (nesting, map, or array position, etc.) by using JSON-LD processing to transform inputs into RDF. RDF can then be expressed as a canonical, flat format of simple subject, property, value statements (referred to as claims in the Verifiable Credentials Data Model [VC-DATA-MODEL-2.0]). In the following, we examine RDF canonicalization, a general scheme for mapping a verifiable credential in JSON-LD format into a set of statements (BBS messages), for selective disclosure. We show that after this process is performed, there remains a possible source of information leakage, and we show how this leakage is mitigated via the use of a keyed pseudo random function (PRF).
RDF canonicalization can be used to flatten
a JSON-LD VC into a set of
statements. The algorithm is dependent on the content of the VC and
also employs a cryptographic hash function to help in ordering the
statements. In essence, how this happens is that each JSON object that
represents the subject of claims within a JSON-LD document will be assigned an
id, if it doesn't have an @id
field defined. Such ids are known as
blank node ids. These ids are needed to express claims as simple
subject, property, value statements such that the subject in each claim can be
differentiated. The id values are deterministically set per
[RDF-CANON] and are based on the data in the document and the
output of a cryptographic hash function such as SHA-256.
Below we show two slightly different VCs for a set of windsurf sails and their canonicalization into a set of statements that can be used for selective disclosure. By changing the year of the 6.1 size sail we see a major change in statement ordering between these two VCs. If the holder discloses information about just his larger sails (the 7.0 and 7.8) the verifier could tell something changed about the set of sails, i.e., information leakage.
{ "@context": [ "https://www.w3.org/ns/credentials/v2", { "@vocab": "https://windsurf.grotto-networking.com/selective#" } ], "type": [ "VerifiableCredential" ], "credentialSubject": { "sails": [ { "size": 5.5, "sailName": "Kihei", "year": 2023 }, { "size": 6.1, "sailName": "Lahaina", "year": 2023 // Will change this to see the effect on canonicalization }, { "size": 7.0, "sailName": "Lahaina", "year": 2020 }, { "size": 7.8, "sailName": "Lahaina", "year": 2023 } ] } }
Canonical form of the above VC. Assignment of blank node ids, i.e., the
_:c14nX
labels are dependent upon the content of the VC and this also
affects the ordering of the statements.
_:c14n0 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" . _:c14n0 <https://windsurf.grotto-networking.com/selective#size> "7.8E0"^^<http://www.w3.org/2001/XMLSchema#double> . _:c14n0 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> . _:c14n1 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n4 . _:c14n2 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" . _:c14n2 <https://windsurf.grotto-networking.com/selective#size> "7"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n2 <https://windsurf.grotto-networking.com/selective#year> "2020"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n3 <https://windsurf.grotto-networking.com/selective#sailName> "Kihei" . _:c14n3 <https://windsurf.grotto-networking.com/selective#size> "5.5E0"^^<http://www.w3.org/2001/XMLSchema#double> . _:c14n3 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n0 . _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n2 . _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n3 . _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n5 . _:c14n5 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" . _:c14n5 <https://windsurf.grotto-networking.com/selective#size> "6.1E0"^^<http://www.w3.org/2001/XMLSchema#double> . _:c14n5 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> .
Updated windsurf sail collection, i.e., the 6.1 size sail has been updated to the 2024 model. This changes the ordering of statements via the assignment of blank node ids.
{ "@context": [ "https://www.w3.org/ns/credentials/v2", { "@vocab": "https://windsurf.grotto-networking.com/selective#" } ], "type": [ "VerifiableCredential" ], "credentialSubject": { "sails": [ { "size": 5.5, "sailName": "Kihei", "year": 2023 }, { "size": 6.1, "sailName": "Lahaina", "year": 2024 // New sail to update older model, changes canonicalization }, { "size": 7.0, "sailName": "Lahaina", "year": 2020 }, { "size": 7.8, "sailName": "Lahaina", "year": 2023 } ] } }
Canonical form of the previous VC. Note the difference in blank node id assignment and ordering of statements.
_:c14n0 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" . _:c14n0 <https://windsurf.grotto-networking.com/selective#size> "6.1E0"^^<http://www.w3.org/2001/XMLSchema#double> . _:c14n0 <https://windsurf.grotto-networking.com/selective#year> "2024"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n1 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" . _:c14n1 <https://windsurf.grotto-networking.com/selective#size> "7.8E0"^^<http://www.w3.org/2001/XMLSchema#double> . _:c14n1 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> . _:c14n2 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n5 . _:c14n3 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" . _:c14n3 <https://windsurf.grotto-networking.com/selective#size> "7"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n3 <https://windsurf.grotto-networking.com/selective#year> "2020"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n4 <https://windsurf.grotto-networking.com/selective#sailName> "Kihei" . _:c14n4 <https://windsurf.grotto-networking.com/selective#size> "5.5E0"^^<http://www.w3.org/2001/XMLSchema#double> . _:c14n4 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> . _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n0 . _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n1 . _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n3 . _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n4 .
To prevent such information leakage from the assignment of these blank node ids
and the ordering they impose on the statements, an HMAC based PRF is
run on the blank node ids. The HMAC secret key is only shared between
the issuer and holder and each Base Proof generated
by the issuer uses a new HMAC key. An example of this can be seen in the
canonical HMAC test vector of [DI-ECDSA].
As discussed in the next section, for BBS to preserve unlinkability we do not
use HMAC based blank node ids but produce a shuffled
version of
the ordering based on the HMAC as shown in test vector Example 12.
Note that this furnishes less information hiding concerning blank node
ids than in the ECDSA-SD approach, since information the number of
blank node ids can leak, but prevents linkage attacks via the
essentially unique identifiers produced by applying an HMAC to blank node ids.
In some uses of VCs it can be important to the privacy of a holder to prevent the tracking or linking of multiple different verifier interactions. In particular we consider two important cases (i) verifier to issuer collusion, and (ii) verifier to verifier collusion. In the first case, shown in Figure 1, a verifier reports back to the original issuer of the credential on an interaction with a holder. In this situation, the issuer could track all the holder interactions with various verifiers using the issued VC. In the second situation, shown in Figure 2, multiple verifiers collude to share information about holders with whom they have interacted.
We use the term unlinkability to describe the property of a VC system
to prevent such "linkage attacks" on holder privacy. Although the term
unlinkability is relatively new section 3.3 of [NISTIR8053] discusses and
gives a case study of Re-identification through Linkage Attacks
. A
systemization of knowledge on linkage attack on data privacy
can be found
in [Powar2023]. The most widespread use of linkage attack on user privacy
occurs via the practice of web browser fingerprinting, a survey of which can be
found in [Pugliese2020].
To quantify the notion of linkage, [Powar2023] introduces the idea of an anonymity set. In the VC case we are concerned with here, the anonymity set would contain the holder of a particular VC and other holders associated with a particular issuer. The smaller the anonymity set the more likely the holder can be tracked across verifiers. Since a signed VC contains a reference to a public key of the issuer, the starting size for the anonymity set for a holder possessing a VC from a particular issuer is the number of VC issued by that issuer with that particular public/private key pair. Non-malicious issuers are expected to minimize the number of public/private key pairs used to issue VCs. Note that the anonymity set idea is similar to the group privacy concept in [vc-bitstring-status-list]. When we use the term linkage here we generally mean any mechanism that results in a reduction in size of the anonymity set.
Sources of linkage in a VC system supporting selective disclosure:
We discuss each of these below.
Cryptographic Hashes, HMACs, and digital signatures by their nature generate highly unique identifiers. The output of a hash function such as SHA-256, by its collision resistance properties, are guaranteed to be essentially unique given different inputs and result in a strong linkage, i.e., reduces the anonymity set size to one. Similarly deterministic signature algorithms such as Ed25519 and deterministic ECDSA will produce essentially unique outputs for different inputs and lead to strong linkages.
This implies that holders can be easily tracked across verifiers via digital signature, HMAC, or hash artifacts inside VCs and hence are vulnerable to verifier-verifier collusion and verifier-issuer collusion. Randomized signature algorithms such as some forms of ECDSA can permit the issuer to generate many distinct signatures on the same inputs and send these to the holder for use with different verifiers. Such an approach could be used to prevent verifier-verifier collusion based tracking but cannot help with verifier-issuer collusion.
To achieve unlinkability requires specially designed cryptographic signature
schemes that allow the holder to generate what is called a zero
knowledge proof of knowledge of a signature
(ZKPKS). What this means is that
the holder can take a signature from the issuer in such a
scheme, compute a ZKPKS to send to a verifier. This ZKPKS cannot be
linked back to the original signature, but has all the desirable properties of a
signature, i.e., the verifier can use it to verify that the messages
were signed by the issuers public key and that the messages have not
been altered. In addition, the holder can generate as many ZKPKSs as
desired for different verifiers and these are essentially independent
and unlinkable. BBS is one such signature scheme that supports this capability.
Although the ZKPKS, known as a BBS proof in this document, has guaranteed unlinkability properties. BBS when used with selective disclosure has two artifacts that can contribute to linkability. These are the total number of messages originally signed, and the index values for the revealed statements. See the privacy considerations in [CFRG-BBS-SIGNATURE] for a discussion and mitigation techniques.
As mentioned in the section on Issuer's Public Keys
of
[CFRG-BBS-SIGNATURE] there is the potential threat that an issuer might
use multiple public keys with some of those used to track a specific subset of
users via verifier-issuer collusion. Since the issuers public
key has to be visible to the verifier, i.e., it is referenced in the BBS
proof (derived proof) this can be used as a linkage point if the issuer
has many different public keys and particularly if it uses a subset of those
keys with a small subset of users (holders).
We saw in the section on information leakage that RDF canonicalization uses a
hash function to order statements and that a further shuffle
of the order
of the statements is performed based on an HMAC. This can leave a fingerprint
that might allow for some linkage. How strong of a linkage is dependent on the
number of blank nodes, essentially JSON objects within the VC, and the number of
indexes revealed. Given n blank nodes and k disclosed indexes
in the worst case this would be a reduction in the anonymity set size by a
factor of C(n, k), i.e., the number combinations of size k
chosen from a set of n elements. One can keep this number quite low by
reducing the number of blank nodes in the VC, e.g., keep the VC short and
simple.
JSON-LD is a JSON-based format for serialization of Linked Data. As such, it supports
assigning a globally unambiguous @id
attribute (node identifier) to each object
("node", in JSON-LD terminology) within a document. This allows for the linking
of linked data
, enabling information about the same entity to be correlated.
This correlation can be desirable or undesirable, depending on the use case.
When using BBS for its unlinkability feature, globally unambiguous node
identifiers cannot be used for individuals nor for their personally identifiable
information, since the strong linkage they provide is undesirable. Note that the
use of such identifiers is acceptable when expressing statements about non-personal
information (e.g., using a globally unambiguous identifier to identify a large
country or a concert event). Also note that JSON-LD's use of @context
, which
maps terms to IRIs, does not generally affect unlinkability.
In the [vc-data-integrity] specification, a number of properties of the
proof
attribute of a VC are given. Care has to be taken that optional fields
ought not provide strong linkage across verifiers. The optional fields include:
id, created, expires, domain,
challenge, and nonce. For example the optional
created field is a dateTimeStamp
object which can specify the
creation date for the proof down to an arbitrary sub-second granularity. Such
information, if present, could greatly reduce the size of the anonymity set. If
the issuer wants to include such information they ought to make it as coarse
grained as possible, relative to the number of VCs being issued over time.
The issuer can also compel a holder to reveal certain
statements to a verifier via the mandatoryPointers
input used in the
creation of the Base Proof. See section
3.4.2 Base Proof Transformation (bbs-2023),
Example 9, and
Example 10. By compel
we mean that
a generated Derived Proof will not verify unless these statements are revealed
to the verifier. Care should be taken such that if such information is
required to be disclosed, that the anonymity set remains sufficiently large.
As discussed in [Powar2023] there are many documented cases of re-identification of individuals from linkage attacks. Hence the holder is urged to reveal as little information as possible to help keep the anonymity set large. In addition, it has been shown a number of times that innocuous seeming information can be highly unique and thus leading to re-identification or tracking. See [NISTIR8053] for a walk through of a particularly famous case of a former governor of Massachusetts and [Powar2023] for further analysis and categorization of 94 such public cases.
It ought to be pointed out that maintaining unlinkability, i.e., anonymity, requires care in the systems holding and communicating the VCs. Networking artifacts such as IP address (layer 3) or Ethernet/MAC address (layer 2) are well known sources of linkage. For example, mobile phone MAC addresses can be used to track users if they revisited a particular access point, this led to mobile phone manufacturers providing a MAC address randomization feature. Public IP addresses generally provide enough information to geolocate an individual to a city or region within a country potentially greatly reducing the anonymity set.
This section is non-normative.
Demonstration of selective disclosure features including mandatory disclosure, selective disclosure, and overlap between those, requires an input credential document with more content than previous test vectors. To avoid excessively long test vectors, the starting document test vector is based on a purely fictitious windsurfing (sailing) competition scenario. In addition, we break the test vectors into two groups, based on those that would be generated by the issuer (base proof) and those that would be generated by the holder (derived proof).
To add a selective disclosure base proof to a document, the issuer needs the following cryptographic key material:
The key material used for generating the test vectors to test add base proof is shown below. Hexadecimal representation is used for the BBS key pairs and the HMAC key.
{ "publicKeyHex": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f", "privateKeyHex": "66d36e118832af4c5e28b2dfe1b9577857e57b042a33e06bdea37b811ed09ee0", "hmacKeyString": "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF" }
In our scenario, a sailor is registering with a race organizer for a series of windsurfing races to be held over a number of days on Maui. The organizer will inspect the sailor's equipment to certify that what has been declared is accurate. The sailor's unsigned equipment inventory is shown below.
{ "@context": [ "https://www.w3.org/ns/credentials/v2", { "@vocab": "https://windsurf.grotto-networking.com/selective#" } ], "type": [ "VerifiableCredential" ], "issuer": "https://vc.example/windsurf/racecommittee", "credentialSubject": { "sailNumber": "Earth101", "sails": [ { "size": 5.5, "sailName": "Kihei", "year": 2023 }, { "size": 6.1, "sailName": "Lahaina", "year": 2023 }, { "size": 7.0, "sailName": "Lahaina", "year": 2020 }, { "size": 7.8, "sailName": "Lahaina", "year": 2023 } ], "boards": [ { "boardName": "CompFoil170", "brand": "Wailea", "year": 2022 }, { "boardName": "Kanaha Custom", "brand": "Wailea", "year": 2019 } ] } }
In addition to letting other sailors know what kinds of equipment their competitors may be sailing on, it is mandatory that each sailor disclose the year of their most recent windsurfing board and full details on two of their sails. Note that all sailors are identified by a sail number that is printed on all their equipment. This mandatory information is specified via an array of JSON pointers as shown below.
["/issuer", "/credentialSubject/sailNumber", "/credentialSubject/sails/1", "/credentialSubject/boards/0/year", "/credentialSubject/sails/2"]
The result of applying the above JSON pointers to the sailor's equipment document is shown below.
[ { "pointer": "/sailNumber", "value": "Earth101" }, { "pointer": "/sails/1", "value": { "size": 6.1, "sailName": "Lahaina", "year": 2023 } }, { "pointer": "/boards/0/year", "value": 2022 }, { "pointer": "/sails/2", "value": { "size": 7, "sailName": "Lahaina", "year": 2020 } } ]
Transformation of the unsigned document begins with canonicalizing the document, as shown below.
[ "_:c14n0 <https://windsurf.grotto-networking.com/selective#boardName> \"CompFoil170\" .\n", "_:c14n0 <https://windsurf.grotto-networking.com/selective#brand> \"Wailea\" .\n", "_:c14n0 <https://windsurf.grotto-networking.com/selective#year> \"2022\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:c14n1 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n", "_:c14n1 <https://windsurf.grotto-networking.com/selective#size> \"7.8E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n", "_:c14n1 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:c14n2 <https://windsurf.grotto-networking.com/selective#boardName> \"Kanaha Custom\" .\n", "_:c14n2 <https://windsurf.grotto-networking.com/selective#brand> \"Wailea\" .\n", "_:c14n2 <https://windsurf.grotto-networking.com/selective#year> \"2019\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:c14n3 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n", "_:c14n3 <https://windsurf.grotto-networking.com/selective#size> \"7\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:c14n3 <https://windsurf.grotto-networking.com/selective#year> \"2020\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:c14n4 <https://windsurf.grotto-networking.com/selective#sailName> \"Kihei\" .\n", "_:c14n4 <https://windsurf.grotto-networking.com/selective#size> \"5.5E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n", "_:c14n4 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:c14n5 <https://windsurf.grotto-networking.com/selective#boards> _:c14n0 .\n", "_:c14n5 <https://windsurf.grotto-networking.com/selective#boards> _:c14n2 .\n", "_:c14n5 <https://windsurf.grotto-networking.com/selective#sailNumber> \"Earth101\" .\n", "_:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n1 .\n", "_:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n3 .\n", "_:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n4 .\n", "_:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n6 .\n", "_:c14n6 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n", "_:c14n6 <https://windsurf.grotto-networking.com/selective#size> \"6.1E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n", "_:c14n6 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:c14n7 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:c14n7 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n5 .\n", "_:c14n7 <https://www.w3.org/2018/credentials#issuer> <https://vc.example/windsurf/racecommittee> .\n" ]
To prevent possible information leakage from the ordering of the blank node IDs these are processed through a PRF (i.e., the HMAC) to give the canonicalized HMAC document shown below. This represents an ordered list of statements that will be subject to mandatory and selective disclosure, i.e., it is from this list that statements are grouped.
[ "_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:b0 <https://www.w3.org/2018/credentials#credentialSubject> _:b3 .\n", "_:b0 <https://www.w3.org/2018/credentials#issuer> <https://vc.example/windsurf/racecommittee> .\n", "_:b1 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n", "_:b1 <https://windsurf.grotto-networking.com/selective#size> \"7.8E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n", "_:b1 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:b2 <https://windsurf.grotto-networking.com/selective#boardName> \"CompFoil170\" .\n", "_:b2 <https://windsurf.grotto-networking.com/selective#brand> \"Wailea\" .\n", "_:b2 <https://windsurf.grotto-networking.com/selective#year> \"2022\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:b3 <https://windsurf.grotto-networking.com/selective#boards> _:b2 .\n", "_:b3 <https://windsurf.grotto-networking.com/selective#boards> _:b4 .\n", "_:b3 <https://windsurf.grotto-networking.com/selective#sailNumber> \"Earth101\" .\n", "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b1 .\n", "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b5 .\n", "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b6 .\n", "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b7 .\n", "_:b4 <https://windsurf.grotto-networking.com/selective#boardName> \"Kanaha Custom\" .\n", "_:b4 <https://windsurf.grotto-networking.com/selective#brand> \"Wailea\" .\n", "_:b4 <https://windsurf.grotto-networking.com/selective#year> \"2019\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:b5 <https://windsurf.grotto-networking.com/selective#sailName> \"Kihei\" .\n", "_:b5 <https://windsurf.grotto-networking.com/selective#size> \"5.5E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n", "_:b5 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:b6 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n", "_:b6 <https://windsurf.grotto-networking.com/selective#size> \"6.1E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n", "_:b6 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:b7 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n", "_:b7 <https://windsurf.grotto-networking.com/selective#size> \"7\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n", "_:b7 <https://windsurf.grotto-networking.com/selective#year> \"2020\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ]
The above canonical document gets grouped into mandatory and non-mandatory statements. The final output of the selective disclosure transformation process is shown below. Each statement is now grouped as mandatory or non-mandatory, and its index in the previous list of statements is remembered.
{ "mandatoryPointers": [ "/issuer", "/credentialSubject/sailNumber", "/credentialSubject/sails/1", "/credentialSubject/boards/0/year", "/credentialSubject/sails/2" ], "mandatory": { "dataType": "Map", "value": [ [ 0, "_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n" ], [ 1, "_:b0 <https://www.w3.org/2018/credentials#credentialSubject> _:b3 .\n" ], [ 2, "_:b0 <https://www.w3.org/2018/credentials#issuer> <https://vc.example/windsurf/racecommittee> .\n" ], [ 8, "_:b2 <https://windsurf.grotto-networking.com/selective#year> \"2022\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ], [ 9, "_:b3 <https://windsurf.grotto-networking.com/selective#boards> _:b2 .\n" ], [ 11, "_:b3 <https://windsurf.grotto-networking.com/selective#sailNumber> \"Earth101\" .\n" ], [ 14, "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b6 .\n" ], [ 15, "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b7 .\n" ], [ 22, "_:b6 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n" ], [ 23, "_:b6 <https://windsurf.grotto-networking.com/selective#size> \"6.1E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n" ], [ 24, "_:b6 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ], [ 25, "_:b7 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n" ], [ 26, "_:b7 <https://windsurf.grotto-networking.com/selective#size> \"7\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ], [ 27, "_:b7 <https://windsurf.grotto-networking.com/selective#year> \"2020\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ] ] }, "nonMandatory": { "dataType": "Map", "value": [ [ 3, "_:b1 <https://windsurf.grotto-networking.com/selective#sailName> \"Lahaina\" .\n" ], [ 4, "_:b1 <https://windsurf.grotto-networking.com/selective#size> \"7.8E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n" ], [ 5, "_:b1 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ], [ 6, "_:b2 <https://windsurf.grotto-networking.com/selective#boardName> \"CompFoil170\" .\n" ], [ 7, "_:b2 <https://windsurf.grotto-networking.com/selective#brand> \"Wailea\" .\n" ], [ 10, "_:b3 <https://windsurf.grotto-networking.com/selective#boards> _:b4 .\n" ], [ 12, "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b1 .\n" ], [ 13, "_:b3 <https://windsurf.grotto-networking.com/selective#sails> _:b5 .\n" ], [ 16, "_:b4 <https://windsurf.grotto-networking.com/selective#boardName> \"Kanaha Custom\" .\n" ], [ 17, "_:b4 <https://windsurf.grotto-networking.com/selective#brand> \"Wailea\" .\n" ], [ 18, "_:b4 <https://windsurf.grotto-networking.com/selective#year> \"2019\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ], [ 19, "_:b5 <https://windsurf.grotto-networking.com/selective#sailName> \"Kihei\" .\n" ], [ 20, "_:b5 <https://windsurf.grotto-networking.com/selective#size> \"5.5E0\"^^<http://www.w3.org/2001/XMLSchema#double> .\n" ], [ 21, "_:b5 <https://windsurf.grotto-networking.com/selective#year> \"2023\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" ] ] }, "hmacKeyString": "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF" }
The next step is to create the base proof configuration and canonicalize it. This is shown in the following two examples.
{ "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "@context": [ "https://www.w3.org/ns/credentials/v2", { "@vocab": "https://windsurf.grotto-networking.com/selective#" } ] }
_:c14n0 <http://purl.org/dc/terms/created> "2023-08-15T23:36:38Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/security#DataIntegrityProof> . _:c14n0 <https://w3id.org/security#cryptosuite> "bbs-2023"^^<https://w3id.org/security#cryptosuiteString> . _:c14n0 <https://w3id.org/security#proofPurpose> <https://w3id.org/security#assertionMethod> . _:c14n0 <https://w3id.org/security#verificationMethod> <did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ> .
In the hashing step, we compute the SHA-256 hash of the canonicalized proof
options to produce the proofHash
, and we compute the SHA-256 hash of the
join of all the mandatory N-Quads to produce the mandatoryHash
. These are
shown below in hexadecimal format.
{ "proofHash": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf", "mandatoryHash": "555de05f898817e31301bac187d0c3ff2b03e2cbdb4adb4d568c17de961f9a18" }
Shown below are the computed bbsSignature
in hexadecimal, and the
mandatoryPointers
. These are are fed to the final serialization step with the
hmacKey
.
{ "bbsSignature": "8331f55ad458fe5c322420b2cb806f9a20ea6b2b8a29d51710026d71ace5da080064b488818efc75a439525bd031450822a6a332da781926e19360b90166431124efcf3d060fbc750c6122c714c07f71", "mandatoryPointers": [ "/issuer", "/credentialSubject/sailNumber", "/credentialSubject/sails/1", "/credentialSubject/boards/0/year", "/credentialSubject/sails/2" ] }
Finally, the values above are run through the algorithm of Section
3.3.1 serializeBaseProofValue, to produce the proofValue
which is
used in the signed base document shown below.
{ "@context": [ "https://www.w3.org/ns/credentials/v2", { "@vocab": "https://windsurf.grotto-networking.com/selective#" } ], "type": [ "VerifiableCredential" ], "issuer": "https://vc.example/windsurf/racecommittee", "credentialSubject": { "sailNumber": "Earth101", "sails": [ { "size": 5.5, "sailName": "Kihei", "year": 2023 }, { "size": 6.1, "sailName": "Lahaina", "year": 2023 }, { "size": 7, "sailName": "Lahaina", "year": 2020 }, { "size": 7.8, "sailName": "Lahaina", "year": 2023 } ], "boards": [ { "boardName": "CompFoil170", "brand": "Wailea", "year": 2022 }, { "boardName": "Kanaha Custom", "brand": "Wailea", "year": 2019 } ] }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "proofValue": "u2V0ChVhQgzH1WtRY_lwyJCCyy4BvmiDqayuKKdUXEAJtcazl2ggAZLSIgY78daQ5UlvQMUUIIqajMtp4GSbhk2C5AWZDESTvzz0GD7x1DGEixxTAf3FYQDpbvyXTTZCxjDXNI1e-am9CMB6U_J5S936Tt3PFYUvfVV3gX4mIF-MTAbrBh9DD_ysD4svbSttNVowX3pYfmhhYYKTvGvo9pXVJbxIrm3i4wkdhUxqKCTIGrnxFuAdZwWi6T3omD5wzZ7bAGbRneEEQSxBmXtvnC6Pr59nPv_v3HrAW9wq_uxYzF_NyaX3GPv0h_FV2T2OSao8C6uoyWiqIj1ggABEiM0RVZneImaq7zN3u_wARIjNEVWZ3iJmqu8zd7v-FZy9pc3N1ZXJ4HS9jcmVkZW50aWFsU3ViamVjdC9zYWlsTnVtYmVyeBovY3JlZGVudGlhbFN1YmplY3Qvc2FpbHMvMXggL2NyZWRlbnRpYWxTdWJqZWN0L2JvYXJkcy8wL3llYXJ4Gi9jcmVkZW50aWFsU3ViamVjdC9zYWlscy8y" } }
Random numbers are used, and an optional presentationHeader
can be an input,
for the creation of BBS proofs
. To furnish a deterministic set of test
vectors, we used the Mocked Random Scalars
procedure from
[CFRG-BBS-SIGNATURE]. The seed
and presentationHeader
values we used for
generation of the derived proof test vectors are given in hex, below.
{ "presentationHeaderHex": "113377aa", "pseudoRandSeedHex": "332e313431353932363533353839373933323338343632363433333833323739" }
To create a derived proof, a holder starts with a signed document
containing a base proof. The base document we will use for these test vectors is
the final example from Section A.1 Base Proof, above. The first
step is to run the algorithm of Section 3.3.2 parseBaseProofValue to
recover bbsSignature
, hmacKey
, and mandatoryPointers
, as shown below.
{ "bbsSignature": "8331f55ad458fe5c322420b2cb806f9a20ea6b2b8a29d51710026d71ace5da080064b488818efc75a439525bd031450822a6a332da781926e19360b90166431124efcf3d060fbc750c6122c714c07f71", "hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff", "mandatoryPointers": [ "/issuer", "/credentialSubject/sailNumber", "/credentialSubject/sails/1", "/credentialSubject/boards/0/year", "/credentialSubject/sails/2" ] }
Next, the holder needs to indicate what else, if anything, they wish to reveal to the verifiers, by specifying JSON pointers for selective disclosure. In our windsurfing competition scenario, a sailor (the holder) has just completed their first day of racing, and wishes to reveal to the general public (the verifiers) all the details of the windsurfing boards they used in the competition. These are shown below. Note that this slightly overlaps with the mandatory disclosed information which included only the year of their most recent board.
["/credentialSubject/boards/0", "/credentialSubject/boards/1"]
To produce the revealDocument
(i.e., the unsigned document that will
eventually be signed and sent to the verifier), we append the selective pointers
to the mandatory pointers, and input these combined pointers along with the
document without proof to the selectJsonLd
algorithm of [DI-ECDSA],
to get the result shown below.
{ "@context": [ "https://www.w3.org/ns/credentials/v2", { "@vocab": "https://windsurf.grotto-networking.com/selective#" } ], "type": [ "VerifiableCredential" ], "issuer": "https://vc.example/windsurf/racecommittee", "credentialSubject": { "sailNumber": "Earth101", "sails": [ { "size": 6.1, "sailName": "Lahaina", "year": 2023 }, { "size": 7, "sailName": "Lahaina", "year": 2020 } ], "boards": [ { "year": 2022, "boardName": "CompFoil170", "brand": "Wailea" }, { "boardName": "Kanaha Custom", "brand": "Wailea", "year": 2019 } ] } }
Now that we know what the revealed document looks like, we need to furnish appropriately updated information to the verifier about which statements are mandatory, and the indexes for the selected non-mandatory statements. Running step 6 of the 3.3.3 createDisclosureData yields an abundance of information about various statement groups relative to the original document. Below we show a portion of the indexes for those groups.
{ "combinedIndexes":[0,1,2,6,7,8,9,10,11,14,15,16,17,18,22,23,24,25,26,27], "mandatoryIndexes":[0,1,2,8,9,11,14,15,22,23,24,25,26,27], "nonMandatoryIndexes":[3,4,5,6,7,10,12,13,16,17,18,19,20,21], "selectiveIndexes":[0,1,6,7,8,9,10,16,17,18] }
The verifier needs to be able to aggregate and hash the mandatory statements. To
enable this, we furnish them with a list of indexes of the mandatory statements
adjusted to their positions in the reveal document (i.e., relative to the
combinedIndexes
), while the selectiveIndexes
need to be adjusted relative to
their positions within the nonMandatoryIndexes
. These "adjusted" indexes are
shown below.
{ "adjMandatoryIndexes":[0,1,2,5,6,8,9,10,14,15,16,17,18,19], "adjSelectiveIndexes":[3,4,5,8,9,10] }
The last important piece of disclosure data is a mapping of canonical blank node
IDs to HMAC-based shuffled IDs, the labelMap
, computed according to Section
3.3.3 createDisclosureData. This is shown below along with
the rest of the disclosure data minus the reveal document.
{ "bbsProof":"9831ba06852694fb44eb56cd9f66581330d9493671a3ad5ed28610c2550c5bfda6cada7cbaf37e9af0c873a4ec6813bf857d539543bc45ba1349fe3233b446f6c46190c40aa8456d98312ed7535c3003e3a77af752ed6f7ee162df4e38a268ad87cc5a10ff38dcc6633810e08ac5a80dacfe6e7dec3ca65fb1dab8d1b0da22b8f26040238c700b8310de92c9c2ec118b2de6b0ccdc72fbdd3329ccf7bc729829e8492d0a796f6e09131884f6fdd0df8028d5ef8f05d9aa9817872598c56421526dbe5db40586cd2b83a454652f71637e57917abd22f45bb67d48fcebdf5464671aec2e845f87f87c1d0eb934db3fb9e2310d483d67110b5f64127827888e8cd9259ea78f6683184ca4e71845b803d93a3554f4577716f939bd36f26eb740771bd5c35247ef4abc2b0e701721a6e8edf62a63af3a032df895cde06d0b15ca8c1a7507249118f9d096fcc5a3f9a39ec1a870ef619efa6af61fd93b74b82b24317def59f981fc8ec2b5633d8eb8711b108552b7b6e748648503fecdf52ac0a76eca89306361262cc4767bbb84e904d1a7523bc19d67bc501c78949616bef65470b067f81759d9a29f9c2775c0888a4617b57018ece111e62cd8365b4783fbe53bcec846bf724bdddc196fced05c59c35ebb735aea9a83f0e5233cdb9fbb8fd2e3b007ee7f69cafc37c4993ddfc747d7793b48ea48213154b459260c29da6dd41de9539a3352855afa398b2bafd47d07d765", "labelMap":{"dataType":"Map","value":[["c14n0","b2"],["c14n1","b4"],["c14n2","b3"],["c14n3","b7"],["c14n4","b6"],["c14n5","b0"]]}, "mandatoryIndexes":[0,1,2,5,6,8,9,10,14,15,16,17,18,19], "adjSelectiveIndexes":[3,4,5,8,9,10], "presentationHeader":{"0":17,"1":51,"2":119,"3":170} }
Finally, using the disclosure data above with the algorithm of Section 3.3.6 serializeDerivedProofValue, we obtain the signed derived (reveal) document shown below.
{ "@context": [ "https://www.w3.org/ns/credentials/v2", { "@vocab": "https://windsurf.grotto-networking.com/selective#" } ], "type": [ "VerifiableCredential" ], "issuer": "https://vc.example/windsurf/racecommittee", "credentialSubject": { "sailNumber": "Earth101", "sails": [ { "size": 6.1, "sailName": "Lahaina", "year": 2023 }, { "size": 7, "sailName": "Lahaina", "year": 2020 } ], "boards": [ { "year": 2022, "boardName": "CompFoil170", "brand": "Wailea" }, { "boardName": "Kanaha Custom", "brand": "Wailea", "year": 2019 } ] }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "proofValue": "u2V0DhVkCEJgxugaFJpT7ROtWzZ9mWBMw2Uk2caOtXtKGEMJVDFv9psrafLrzfprwyHOk7GgTv4V9U5VDvEW6E0n-MjO0RvbEYZDECqhFbZgxLtdTXDAD46d691Ltb37hYt9OOKJorYfMWhD_ONzGYzgQ4IrFqA2s_m597DymX7HauNGw2iK48mBAI4xwC4MQ3pLJwuwRiy3msMzccvvdMynM97xymCnoSS0KeW9uCRMYhPb90N-AKNXvjwXZqpgXhyWYxWQhUm2-XbQFhs0rg6RUZS9xY35XkXq9IvRbtn1I_OvfVGRnGuwuhF-H-HwdDrk02z-54jENSD1nEQtfZBJ4J4iOjNklnqePZoMYTKTnGEW4A9k6NVT0V3cW-Tm9NvJut0B3G9XDUkfvSrwrDnAXIabo7fYqY686Ay34lc3gbQsVyowadQckkRj50Jb8xaP5o57BqHDvYZ76avYf2Tt0uCskMX3vWfmB_I7CtWM9jrhxGxCFUre250hkhQP-zfUqwKduyokwY2EmLMR2e7uE6QTRp1I7wZ1nvFAceJSWFr72VHCwZ_gXWdmin5wndcCIikYXtXAY7OER5izYNltHg_vlO87IRr9yS93cGW_O0FxZw167c1rqmoPw5SM825-7j9LjsAfuf2nK_DfEmT3fx0fXeTtI6kghMVS0WSYMKdpt1B3pU5ozUoVa-jmLK6_UfQfXZaYAAgEEAgMDBwQGBQCOAAECBQYICQoODxAREhOGAwQFCAkKRBEzd6o" } }
The first steps in using the anonymous holder binding feature are for the holder to generate its holderSecret value and then compute a commitment with proof for this value according to the commitment computation procedure of [CFRG-Blind-BBS-Signature]. Example values and outputs of this procedure are shown below.
{ "holderSecretHex": "8fc6cc3f65db4ba5e3ed63fe9d2bd57a9c7df9c7f6bf2b898b308d5493b07eb6" }
{ "secretProverBlind": "14c6dd50a5ae34ae83cd585dda6bb0ebbc23327ad3bcc92f321f09cc954435f0", "commitmentWithProof": "b12a3bc39c35ca52631dfe4aee47f5f10d94107fd97f1aa39a94badb291ee66adf650770e08bb280af9340f34836b7ab353365d5769a24ded4a919c598c8831c0b66f83759f32d3b7eddcabf42bc471b475533116151674faec83c4fddc1c514af239f6370359aa03a955751a6b106911b902ae4dc6f14cfda9e0be04d85a3f1105fb7d5c83d263e0ca95217c8017e91" }
The holderSecret and secretProverBlind are retained by the holder and kept secret. The commitmentWithProof value needs to be communicated to the issuer.
The addition of a base proof under the anonymous holder binding option begins with the issuer receiving a commitmentWithProof value from the holder and then verifying that value with the commitment verification procedure of [CFRG-Blind-BBS-Signature]. The cryptographic key material explained and used in section Base Proof will also be used here, and is repeated below.
{ "publicKeyHex": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f", "privateKeyHex": "66d36e118832af4c5e28b2dfe1b9577857e57b042a33e06bdea37b811ed09ee0", "hmacKeyString": "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF" }
As part of the blind signature generation from [CFRG-Blind-BBS-Signature], one can include a signer_blind which we show below.
{ "signerBlindHex": "2c971d5a34c1fd8d79a65afa6a7de15827af471f9c28279007072e845cd7c7b3" }
In this scenario, we consider an electronic version of a drivers license.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/data-integrity/v2", "https://w3id.org/vdl/v1", "https://w3id.org/vdl/aamva/v1" ], "type": [ "VerifiableCredential", "Iso18013DriversLicenseCredential" ], "issuer": { "id": "did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5", "name": "Utopia Department of Motor Vehicles", "url": "https://dmv.utopia.example/", "image": "https://dmv.utopia.example/logo.png" }, "issuanceDate": "2023-11-15T10:00:00-07:00", "expirationDate": "2028-11-15T12:00:00-06:00", "name": "Utopia Driver's License", "image": "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUg...kSuQmCC", "description": "A license granting driving privileges in Utopia.", "credentialSubject": { "type": "LicensedDriver", "driversLicense": { "type": "Iso18013DriversLicense", "document_number": "542426814", "family_name": "TURNER", "given_name": "SUSAN", "portrait": "data:image/jpeg;base64,/9j/4AAQSkZJR...RSClooooP/2Q==", "birth_date": "1998-08-28", "issue_date": "2023-01-15T10:00:00-07:00", "expiry_date": "2028-08-27T12:00:00-06:00", "issuing_country": "UA", "issuing_authority": "UADMV", "driving_privileges": [ { "codes": [ { "code": "D" } ], "vehicle_category_code": "D", "issue_date": "2019-01-01", "expiry_date": "2027-01-01" }, { "codes": [ { "code": "C" } ], "vehicle_category_code": "C", "issue_date": "2019-01-01", "expiry_date": "2017-01-01" } ], "un_distinguishing_sign": "UTA", "aamva_aka_suffix": "1ST", "sex": 2, "aamva_family_name_truncation": "N", "aamva_given_name_truncation": "N" } } }
To preserve the holder's privacy, the only mandatory fields are the "issuer" and "expirationDate", as realized in the mandatory pointers given below.
["/issuer", "/expirationDate"]
Transformation of the unsigned document begins with canonicalizing the document, as shown below.
[ "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/image> <https://dmv.utopia.example/logo.png> .\n", "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/name> \"Utopia Department of Motor Vehicles\" .\n", "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/url> <https://dmv.utopia.example/> .\n", "_:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#Iso18013DriversLicenseCredential> .\n", "_:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:c14n0 <https://schema.org/description> \"A license granting driving privileges in Utopia.\" .\n", "_:c14n0 <https://schema.org/image> <data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUg...kSuQmCC> .\n", "_:c14n0 <https://schema.org/name> \"Utopia Driver's License\" .\n", "_:c14n0 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n1 .\n", "_:c14n0 <https://www.w3.org/2018/credentials#expirationDate> \"2028-11-15T12:00:00-06:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n0 <https://www.w3.org/2018/credentials#issuanceDate> \"2023-11-15T10:00:00-07:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n0 <https://www.w3.org/2018/credentials#issuer> <did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> .\n", "_:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#LicensedDriver> .\n", "_:c14n1 <https://w3id.org/vdl#license> _:c14n2 .\n", "_:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#Iso18013DriversLicense> .\n", "_:c14n2 <https://w3id.org/vdl#birthDate> \"1998-08-28\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n2 <https://w3id.org/vdl#documentNumber> \"542426814\" .\n", "_:c14n2 <https://w3id.org/vdl#drivingPrivileges> \"[{\\\"codes\\\":[{\\\"code\\\":\\\"D\\\"}],\\\"expiry_date\\\":\\\"2027-01-01\\\",\\\"issue_date\\\":\\\"2019-01-01\\\",\\\"vehicle_category_code\\\":\\\"D\\\"},{\\\"codes\\\":[{\\\"code\\\":\\\"C\\\"}],\\\"expiry_date\\\":\\\"2017-01-01\\\",\\\"issue_date\\\":\\\"2019-01-01\\\",\\\"vehicle_category_code\\\":\\\"C\\\"}]\"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON> .\n", "_:c14n2 <https://w3id.org/vdl#expiryDate> \"2028-08-27T12:00:00-06:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n2 <https://w3id.org/vdl#familyName> \"TURNER\" .\n", "_:c14n2 <https://w3id.org/vdl#givenName> \"SUSAN\" .\n", "_:c14n2 <https://w3id.org/vdl#issueDate> \"2023-01-15T10:00:00-07:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n2 <https://w3id.org/vdl#issuingAuthority> \"UADMV\" .\n", "_:c14n2 <https://w3id.org/vdl#issuingCountry> \"UA\" .\n", "_:c14n2 <https://w3id.org/vdl#portrait> <data:image/jpeg;base64,/9j/4AAQSkZJR...RSClooooP/2Q==> .\n", "_:c14n2 <https://w3id.org/vdl#sex> \"2\"^^<http://www.w3.org/2001/XMLSchema#unsignedInt> .\n", "_:c14n2 <https://w3id.org/vdl#unDistinguishingSign> \"UTA\" .\n", "_:c14n2 <https://w3id.org/vdl/aamva#akaSuffix> \"1ST\" .\n", "_:c14n2 <https://w3id.org/vdl/aamva#familyNameTruncation> \"N\" .\n", "_:c14n2 <https://w3id.org/vdl/aamva#givenNameTruncation> \"N\" .\n" ]
To prevent possible information leakage from the ordering of the blank node IDs, these are processed through a PRF (i.e., the HMAC) to give the canonicalized HMAC document shown below. This represents an ordered list of statements that will be subject to mandatory and selective disclosure, i.e., it is from this list that statements are grouped.
[ "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/image> <https://dmv.utopia.example/logo.png> .\n", "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/name> \"Utopia Department of Motor Vehicles\" .\n", "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/url> <https://dmv.utopia.example/> .\n", "_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#LicensedDriver> .\n", "_:b0 <https://w3id.org/vdl#license> _:b2 .\n", "_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#Iso18013DriversLicenseCredential> .\n", "_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:b1 <https://schema.org/description> \"A license granting driving privileges in Utopia.\" .\n", "_:b1 <https://schema.org/image> <data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUg...kSuQmCC> .\n", "_:b1 <https://schema.org/name> \"Utopia Driver's License\" .\n", "_:b1 <https://www.w3.org/2018/credentials#credentialSubject> _:b0 .\n", "_:b1 <https://www.w3.org/2018/credentials#expirationDate> \"2028-11-15T12:00:00-06:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b1 <https://www.w3.org/2018/credentials#issuanceDate> \"2023-11-15T10:00:00-07:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b1 <https://www.w3.org/2018/credentials#issuer> <did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> .\n", "_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#Iso18013DriversLicense> .\n", "_:b2 <https://w3id.org/vdl#birthDate> \"1998-08-28\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b2 <https://w3id.org/vdl#documentNumber> \"542426814\" .\n", "_:b2 <https://w3id.org/vdl#drivingPrivileges> \"[{\\\"codes\\\":[{\\\"code\\\":\\\"D\\\"}],\\\"expiry_date\\\":\\\"2027-01-01\\\",\\\"issue_date\\\":\\\"2019-01-01\\\",\\\"vehicle_category_code\\\":\\\"D\\\"},{\\\"codes\\\":[{\\\"code\\\":\\\"C\\\"}],\\\"expiry_date\\\":\\\"2017-01-01\\\",\\\"issue_date\\\":\\\"2019-01-01\\\",\\\"vehicle_category_code\\\":\\\"C\\\"}]\"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON> .\n", "_:b2 <https://w3id.org/vdl#expiryDate> \"2028-08-27T12:00:00-06:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b2 <https://w3id.org/vdl#familyName> \"TURNER\" .\n", "_:b2 <https://w3id.org/vdl#givenName> \"SUSAN\" .\n", "_:b2 <https://w3id.org/vdl#issueDate> \"2023-01-15T10:00:00-07:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b2 <https://w3id.org/vdl#issuingAuthority> \"UADMV\" .\n", "_:b2 <https://w3id.org/vdl#issuingCountry> \"UA\" .\n", "_:b2 <https://w3id.org/vdl#portrait> <data:image/jpeg;base64,/9j/4AAQSkZJR...RSClooooP/2Q==> .\n", "_:b2 <https://w3id.org/vdl#sex> \"2\"^^<http://www.w3.org/2001/XMLSchema#unsignedInt> .\n", "_:b2 <https://w3id.org/vdl#unDistinguishingSign> \"UTA\" .\n", "_:b2 <https://w3id.org/vdl/aamva#akaSuffix> \"1ST\" .\n", "_:b2 <https://w3id.org/vdl/aamva#familyNameTruncation> \"N\" .\n", "_:b2 <https://w3id.org/vdl/aamva#givenNameTruncation> \"N\" .\n" ]
The above canonical document gets grouped into mandatory and non-mandatory statements. The final output of the selective disclosure transformation process is shown below. Each statement is now grouped as mandatory or non-mandatory, and its index in the previous list of statements is remembered.
{ "mandatoryPointers": [ "/issuer", "/expirationDate" ], "mandatory": { "dataType": "Map", "value": [ [ 0, "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/image> <https://dmv.utopia.example/logo.png> .\n" ], [ 1, "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/name> \"Utopia Department of Motor Vehicles\" .\n" ], [ 2, "<did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> <https://schema.org/url> <https://dmv.utopia.example/> .\n" ], [ 5, "_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#Iso18013DriversLicenseCredential> .\n" ], [ 6, "_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n" ], [ 11, "_:b1 <https://www.w3.org/2018/credentials#expirationDate> \"2028-11-15T12:00:00-06:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ], [ 13, "_:b1 <https://www.w3.org/2018/credentials#issuer> <did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5> .\n" ] ] }, "nonMandatory": { "dataType": "Map", "value": [ [ 3, "_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#LicensedDriver> .\n" ], [ 4, "_:b0 <https://w3id.org/vdl#license> _:b2 .\n" ], [ 7, "_:b1 <https://schema.org/description> \"A license granting driving privileges in Utopia.\" .\n" ], [ 8, "_:b1 <https://schema.org/image> <data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUg...kSuQmCC> .\n" ], [ 9, "_:b1 <https://schema.org/name> \"Utopia Driver's License\" .\n" ], [ 10, "_:b1 <https://www.w3.org/2018/credentials#credentialSubject> _:b0 .\n" ], [ 12, "_:b1 <https://www.w3.org/2018/credentials#issuanceDate> \"2023-11-15T10:00:00-07:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ], [ 14, "_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/vdl#Iso18013DriversLicense> .\n" ], [ 15, "_:b2 <https://w3id.org/vdl#birthDate> \"1998-08-28\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ], [ 16, "_:b2 <https://w3id.org/vdl#documentNumber> \"542426814\" .\n" ], [ 17, "_:b2 <https://w3id.org/vdl#drivingPrivileges> \"[{\\\"codes\\\":[{\\\"code\\\":\\\"D\\\"}],\\\"expiry_date\\\":\\\"2027-01-01\\\",\\\"issue_date\\\":\\\"2019-01-01\\\",\\\"vehicle_category_code\\\":\\\"D\\\"},{\\\"codes\\\":[{\\\"code\\\":\\\"C\\\"}],\\\"expiry_date\\\":\\\"2017-01-01\\\",\\\"issue_date\\\":\\\"2019-01-01\\\",\\\"vehicle_category_code\\\":\\\"C\\\"}]\"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON> .\n" ], [ 18, "_:b2 <https://w3id.org/vdl#expiryDate> \"2028-08-27T12:00:00-06:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ], [ 19, "_:b2 <https://w3id.org/vdl#familyName> \"TURNER\" .\n" ], [ 20, "_:b2 <https://w3id.org/vdl#givenName> \"SUSAN\" .\n" ], [ 21, "_:b2 <https://w3id.org/vdl#issueDate> \"2023-01-15T10:00:00-07:00\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ], [ 22, "_:b2 <https://w3id.org/vdl#issuingAuthority> \"UADMV\" .\n" ], [ 23, "_:b2 <https://w3id.org/vdl#issuingCountry> \"UA\" .\n" ], [ 24, "_:b2 <https://w3id.org/vdl#portrait> <data:image/jpeg;base64,/9j/4AAQSkZJR...RSClooooP/2Q==> .\n" ], [ 25, "_:b2 <https://w3id.org/vdl#sex> \"2\"^^<http://www.w3.org/2001/XMLSchema#unsignedInt> .\n" ], [ 26, "_:b2 <https://w3id.org/vdl#unDistinguishingSign> \"UTA\" .\n" ], [ 27, "_:b2 <https://w3id.org/vdl/aamva#akaSuffix> \"1ST\" .\n" ], [ 28, "_:b2 <https://w3id.org/vdl/aamva#familyNameTruncation> \"N\" .\n" ], [ 29, "_:b2 <https://w3id.org/vdl/aamva#givenNameTruncation> \"N\" .\n" ] ] }, "hmacKeyString": "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF" }
The next steps are to create the base proof configuration and canonicalize it. This is shown in the following two examples.
{ "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/data-integrity/v2", "https://w3id.org/vdl/v1", "https://w3id.org/vdl/aamva/v1" ] }
_:c14n0 <http://purl.org/dc/terms/created> "2023-08-15T23:36:38Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/security#DataIntegrityProof> . _:c14n0 <https://w3id.org/security#cryptosuite> "bbs-2023"^^<https://w3id.org/security#cryptosuiteString> . _:c14n0 <https://w3id.org/security#proofPurpose> <https://w3id.org/security#assertionMethod> . _:c14n0 <https://w3id.org/security#verificationMethod> <did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ> .
In the hashing step, we compute the SHA-256 hash of the canonicalized proof
options to produce the proofHash, and we compute the SHA-256 hash of the
join of all the mandatory N-Quads to produce the mandatoryHash
. These are
shown below in hexadecimal format.
{ "proofHash": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf", "mandatoryHash": "8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb" }
Now we use the blind signature generation procedure of [CFRG-Blind-BBS-Signature] in the 3.4.5 Base Proof Serialization (bbs-2023) procedure. Shown below are the computed bbsSignature, bbsHeader, publicKey, hmacKey, mandatoryPointers, signerBlind, and featureOption, where byte data is shown in hexadecimal.
{ "bbsSignature": "a61f9505bce7a5c9de2313ab6677999f0fb20685ab0c7fe91ca6d967dc4f9b2c6f973c8b04bc5269d3b960be707c0aea34042ba5646ff9892e537513b4b4721029bef35d922c3f3d27ca275984f52f3e", "bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb", "publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f", "hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff", "mandatoryPointers": [ "/issuer", "/expirationDate" ], "signerBlind": "2c971d5a34c1fd8d79a65afa6a7de15827af471f9c28279007072e845cd7c7b3", "featureOption": "anonymous_holder_binding" }
Finally, the values above are run through the algorithm of Section 3.3.1 serializeBaseProofValue, to produce the proofValue which is used in the signed base document shown below.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/data-integrity/v2", "https://w3id.org/vdl/v1", "https://w3id.org/vdl/aamva/v1" ], "type": [ "VerifiableCredential", "Iso18013DriversLicenseCredential" ], "issuer": { "id": "did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5", "name": "Utopia Department of Motor Vehicles", "url": "https://dmv.utopia.example/", "image": "https://dmv.utopia.example/logo.png" }, "issuanceDate": "2023-11-15T10:00:00-07:00", "expirationDate": "2028-11-15T12:00:00-06:00", "name": "Utopia Driver's License", "image": "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUg...kSuQmCC", "description": "A license granting driving privileges in Utopia.", "credentialSubject": { "type": "LicensedDriver", "driversLicense": { "type": "Iso18013DriversLicense", "document_number": "542426814", "family_name": "TURNER", "given_name": "SUSAN", "portrait": "data:image/jpeg;base64,/9j/4AAQSkZJR...RSClooooP/2Q==", "birth_date": "1998-08-28", "issue_date": "2023-01-15T10:00:00-07:00", "expiry_date": "2028-08-27T12:00:00-06:00", "issuing_country": "UA", "issuing_authority": "UADMV", "driving_privileges": [ { "codes": [ { "code": "D" } ], "vehicle_category_code": "D", "issue_date": "2019-01-01", "expiry_date": "2027-01-01" }, { "codes": [ { "code": "C" } ], "vehicle_category_code": "C", "issue_date": "2019-01-01", "expiry_date": "2017-01-01" } ], "un_distinguishing_sign": "UTA", "aamva_aka_suffix": "1ST", "sex": 2, "aamva_family_name_truncation": "N", "aamva_given_name_truncation": "N" } }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "proofValue": "u2V0EhlhQph-VBbznpcneIxOrZneZnw-yBoWrDH_pHKbZZ9xPmyxvlzyLBLxSadO5YL5wfArqNAQrpWRv-YkuU3UTtLRyECm-812SLD89J8onWYT1Lz5YQDpbvyXTTZCxjDXNI1e-am9CMB6U_J5S936Tt3PFYUvfjuoRLATYnhM4gPlnZuuuc2k_dfG7y7qkc9wGJUvexPtYYKTvGvo9pXVJbxIrm3i4wkdhUxqKCTIGrnxFuAdZwWi6T3omD5wzZ7bAGbRneEEQSxBmXtvnC6Pr59nPv_v3HrAW9wq_uxYzF_NyaX3GPv0h_FV2T2OSao8C6uoyWiqIj1ggABEiM0RVZneImaq7zN3u_wARIjNEVWZ3iJmqu8zd7v-CZy9pc3N1ZXJvL2V4cGlyYXRpb25EYXRlWCAslx1aNMH9jXmmWvpqfeFYJ69HH5woJ5AHBy6EXNfHsw" } }
As explained in section we use a mocked random number generation procedure and demonstrate the use of a presentationHeader. The same seed and presentationHeader are used here and are repeated below.
{ "presentationHeaderHex": "113377aa", "pseudoRandSeedHex": "332e313431353932363533353839373933323338343632363433333833323739" }
To create a derived proof, a holder starts with a signed document containing a base proof. The base document we will use for these test vectors is the final example from Section A.3.2 Holder Binding Base Proof, above. The first step is to run the algorithm of Section 3.3.2 parseBaseProofValue to recover bbsSignature, bbsHeader, publicKey, hmacKey, mandatoryPointers, signerBlind, and featureOption as shown below.
{ "bbsSignature": "a61f9505bce7a5c9de2313ab6677999f0fb20685ab0c7fe91ca6d967dc4f9b2c6f973c8b04bc5269d3b960be707c0aea34042ba5646ff9892e537513b4b4721029bef35d922c3f3d27ca275984f52f3e", "bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb", "publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f", "hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff", "mandatoryPointers": [ "/issuer", "/expirationDate" ], "signerBlind": "2c971d5a34c1fd8d79a65afa6a7de15827af471f9c28279007072e845cd7c7b3", "featureOption": "anonymous_holder_binding" }
Next, the holder needs to indicate what else, if anything, they wish to reveal to the verifiers, by specifying JSON pointers for selective disclosure. In this case, the holder only wishes to reveal their driving privileges.
["/credentialSubject/driversLicense/issuing_country", "/credentialSubject/driversLicense/driving_privileges"]
To produce the revealDocument
(i.e., the unsigned document that will
eventually be signed and sent to the verifier), we append the selective pointers
to the mandatory pointers, and input these combined pointers along with the
document without proof to the selectJsonLd
algorithm of [DI-ECDSA],
to get the result shown below.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/data-integrity/v2", "https://w3id.org/vdl/v1", "https://w3id.org/vdl/aamva/v1" ], "type": [ "VerifiableCredential", "Iso18013DriversLicenseCredential" ], "issuer": { "id": "did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5", "name": "Utopia Department of Motor Vehicles", "url": "https://dmv.utopia.example/", "image": "https://dmv.utopia.example/logo.png" }, "expirationDate": "2028-11-15T12:00:00-06:00", "credentialSubject": { "type": "LicensedDriver", "driversLicense": { "type": "Iso18013DriversLicense", "issuing_country": "UA", "driving_privileges": [ { "codes": [ { "code": "D" } ], "vehicle_category_code": "D", "issue_date": "2019-01-01", "expiry_date": "2027-01-01" }, { "codes": [ { "code": "C" } ], "vehicle_category_code": "C", "issue_date": "2019-01-01", "expiry_date": "2017-01-01" } ] } } }
Now that we know what the revealed document looks like, we need to furnish appropriately updated information to the verifier about which statements are mandatory, and the indexes for the selected non-mandatory statements. Running step 6 of the 3.3.3 createDisclosureData yields an abundance of information about various statement groups relative to the original document. Below, we show a portion of the indexes for those groups.
{ "combinedIndexes":[0,1,2,3,4,5,6,10,11,13,14,17,23], "mandatoryIndexes":[0,1,2,5,6,11,13], "nonMandatoryIndexes":[3,4,7,8,9,10,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29], "selectiveIndexes":[3,4,5,6,10,14,17,23] }
The verifier needs to be able to aggregate and hash the mandatory statements. To
enable this, we furnish them with a list of indexes of the mandatory statements
adjusted to their positions in the reveal document (i.e., relative to the
combinedIndexes
), while the selectiveIndexes
need to be adjusted relative to
their positions within the nonMandatoryIndexes
. These "adjusted" indexes are
shown below.
{ "adjMandatoryIndexes":[0,1,2,5,6,8,9], "adjSelectiveIndexes":[0,1,5,7,10,16] }
The last important piece of disclosure data is a mapping of canonical blank node
IDs to HMAC-based shuffled IDs, the labelMap
, computed according to Section
3.3.3 createDisclosureData. This is shown below, along with
the rest of the disclosure data minus the reveal document. Note that here we are
showing the results appropriate to the featureOption equal to
"anonymous_holder_binding"
which uses the blind proof generation
procedure of [CFRG-Blind-BBS-Signature]. Note that blindAdjDisclosedIdxs is
the final set of BBS selective indexes used in the proof serialization process
and comes from the blind BBS proof generation function which takes
the adjSelectiveIndexes as inputs.
{ "bbsProof":"8621d7b34d4e0a2eae538d4a24b75b353518b9b2b4fd8e1d1131c33bb7b0708de00592ea8e959f05d278dc1ae449f68f87651657392d7d92cdfc23c967f4bd7ccb5d7e51201730aacb8ea15fc3667ee9ffad64e87e840cf9af5630b8f895b9cf8298dbdabdcf83b86038a152f668c572ec0ac2a5671a60e9ff55f01a6e937d0304cc525ac0386d500c17a52997c247ad23e0c5dfa1987e33fb14c5a44edcce4d7060fb9bdefc60e18e1328ad1824572741edb84314c3dc446b22e9891c13d200f240ec32859d96a63dc4b962a45160851bc7dfb2b5ab3c8e469cbfa2370e04b022221d30bffed0a759bde1c2d56363b543b6faa59f7dfeee8eaea1db0e73c0932a77ce39bc3b1f8008af4a8c20a630e7716e9fbe5636ae1ce30f6c1373b0cec62d803532a8101f633d7260fdba6e55ba36956cf3bbd9aae52193a108b4012b12e67d7a51498e44b10430aadc3857eef73e7bfa34b0aebd511823dae91cf29b68c618a7b3b7b804e97d599a92efd895975309e19edd932474534f3a447cf9c4d3cc228559ff70c17d2ee3544c9ba5051c43feedc9a02acd185a339f0307fb80cf209955368f60a0fd18d55efb249f22a805249bc6ec8cba9be2b4237e8866460cc4d063f16e0cb2fe82ad9b229d565d3c472c5e574fec5867ad90ed41c8a87e4e59f513bb937309f6135923950f119fcf6f7e682ea2917120f6830f38ff3bad1057908555d5cb884f2a4775e22cb311ee67355fe474e93a26129995c03ec4f76b4e4d191391a5e03f49e72f72971b35d2164f30717d7ce906d822bd7c993eecdbcf4ecfd0b0edb1f0dbf73de2a1cc7d0c34a5b2cff4dee896ce12c9a1d4b4f48f7a50918685c7007854d98945dc6563515377cc50fc2e47ac23a1bda1f9fcacdd4fa5519edc27250640d93a7358a48c6b733235c6ef4683e4a78f5b3da71be9cdaf153a26290becc72578b414a2a5d3c33c01bf7026a06dd7c5cedb9aa7b661507718631f84b47ee3a78331ef9a9abccf389a06521a598ffba6aff68cd31a982a67a11f2dd3cefdf5a3447688ddb24e97686373ab5efab6438586022f0cc7844355057e2f7bdb9fee7ad1661635a8056401df5b48b9958d92874c8d44119479d69d16ebb82ec741e8ffe1175e1bf7732038fe02a2063f83e0e11a77ebd37e146a0b59b39adc653255acfe19f5a5fc21db139652cb085d7c49ebe6bee66f3e9c9a888bb0679bf570e862c3cb68867cf401", "labelMap":{"dataType":"Map","value":[["c14n0","b1"],["c14n1","b2"],["c14n2","b0"]]}, "mandatoryIndexes":[0,1,2,5,6,8,9],"adjSelectiveIndexes":[0,1,5,7,10,16], "presentationHeader":{"0":17,"1":51,"2":119,"3":170}, "featureOption":"anonymous_holder_binding", "lengthBBSMessages":23 }
Finally, using the disclosure data above with the algorithm of Section 3.3.6 serializeDerivedProofValue, we obtain the signed derived (reveal) document shown below.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/data-integrity/v2", "https://w3id.org/vdl/v1", "https://w3id.org/vdl/aamva/v1" ], "type": [ "VerifiableCredential", "Iso18013DriversLicenseCredential" ], "issuer": { "id": "did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5", "name": "Utopia Department of Motor Vehicles", "url": "https://dmv.utopia.example/", "image": "https://dmv.utopia.example/logo.png" }, "expirationDate": "2028-11-15T12:00:00-06:00", "credentialSubject": { "type": "LicensedDriver", "driversLicense": { "type": "Iso18013DriversLicense", "issuing_country": "UA", "driving_privileges": [ { "codes": [ { "code": "D" } ], "vehicle_category_code": "D", "issue_date": "2019-01-01", "expiry_date": "2027-01-01" }, { "codes": [ { "code": "C" } ], "vehicle_category_code": "C", "issue_date": "2019-01-01", "expiry_date": "2017-01-01" } ] } }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "proofValue": "u2V0FhlkDcIYh17NNTgourlONSiS3WzU1GLmytP2OHRExwzu3sHCN4AWS6o6VnwXSeNwa5En2j4dlFlc5LX2SzfwjyWf0vXzLXX5RIBcwqsuOoV_DZn7p_61k6H6EDPmvVjC4-JW5z4KY29q9z4O4YDihUvZoxXLsCsKlZxpg6f9V8Bpuk30DBMxSWsA4bVAMF6Upl8JHrSPgxd-hmH4z-xTFpE7czk1wYPub3vxg4Y4TKK0YJFcnQe24QxTD3ERrIumJHBPSAPJA7DKFnZamPcS5YqRRYIUbx9-ytas8jkacv6I3DgSwIiIdML_-0KdZveHC1WNjtUO2-qWfff7ujq6h2w5zwJMqd845vDsfgAivSowgpjDncW6fvlY2rhzjD2wTc7DOxi2ANTKoEB9jPXJg_bpuVbo2lWzzu9mq5SGToQi0ASsS5n16UUmORLEEMKrcOFfu9z57-jSwrr1RGCPa6Rzym2jGGKezt7gE6X1ZmpLv2JWXUwnhnt2TJHRTTzpEfPnE08wihVn_cMF9LuNUTJulBRxD_u3JoCrNGFoznwMH-4DPIJlVNo9goP0Y1V77JJ8iqAUkm8bsjLqb4rQjfohmRgzE0GPxbgyy_oKtmyKdVl08RyxeV0_sWGetkO1ByKh-Tln1E7uTcwn2E1kjlQ8Rn89vfmguopFxIPaDDzj_O60QV5CFVdXLiE8qR3XiLLMR7mc1X-R06TomEpmVwD7E92tOTRkTkaXgP0nnL3KXGzXSFk8wcX186QbYIr18mT7s289Oz9Cw7bHw2_c94qHMfQw0pbLP9N7ols4SyaHUtPSPelCRhoXHAHhU2YlF3GVjUVN3zFD8LkesI6G9ofn8rN1PpVGe3CclBkDZOnNYpIxrczI1xu9Gg-Snj1s9pxvpza8VOiYpC-zHJXi0FKKl08M8Ab9wJqBt18XO25qntmFQdxhjH4S0fuOngzHvmpq8zziaBlIaWY_7pq_2jNMamCpnoR8t08799aNEdojdsk6XaGNzq176tkOFhgIvDMeEQ1UFfi9725_uetFmFjWoBWQB31tIuZWNkodMjUQRlHnWnRbruC7HQej_4RdeG_dzIDj-AqIGP4Pg4Rp369N-FGoLWbOa3GUyVaz-GfWl_CHbE5ZSywhdfEnr5r7mbz6cmoiLsGeb9XDoYsPLaIZ89AGjAAEBAgIAhwABAgUGCAmGAAEFBwoQRBEzd6oX" } }
To issue a credential under the pseudonym with issuer-known PID feature, the issuer generates a cryptographically random pid value for a holder. This value is shared with the holder but is otherwise kept secret. This value is shown below.
{ "pidHex": "5105adaaa2b9d6a48a9ab9e46471b40d875febc15d35663016ddb5461619d6d1" }
This example will make use of the same key material as shown in Example 29, the same unsigned document as shown in Example 31, and the same mandatory pointers as shown in Example 32. This results in the same canonical document as in Example 33, the same HMAC document as in Example 34, and the same "add base transformation" as in Example 35.
This example makes use of the same proof configuration as Example 36. This results in the same canonical base proof as in Example 37. Combining this with the above assumptions leads to the same base hashes as in Example 38.
Since featureOption is equal to "pseudonym_issuer_pid"
, the procedure of
section Base Proof
Serialization will produce the output shown below. This makes use of the
signature generation algorithm of [CFRG-Pseudonym-BBS-Signature]. Note the
inclusion of the
pid value, as this needs to be communicated to the holder.
{ "bbsSignature": "af6ee041b56f890cf0794788acfc7cbfa81674b03bc29f55b86f43e199ac36fcf5fb958c453bfdcf1babb93cc33204190eb4cf77e229dfa85b4a031065db8a51c6408898d77f427dcec67c26c2de54e3", "bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb", "publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f", "hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff", "mandatoryPointers": [ "/issuer", "/expirationDate" ], "pidHex": "5105adaaa2b9d6a48a9ab9e46471b40d875febc15d35663016ddb5461619d6d1", "featureOption": "pseudonym_issuer_pid" }
Finally, the values above are run through the algorithm of Section
3.3.1 serializeBaseProofValue, to produce the proofValue
which is
used in the signed base document shown below.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/data-integrity/v2", "https://w3id.org/vdl/v1", "https://w3id.org/vdl/aamva/v1" ], "type": [ "VerifiableCredential", "Iso18013DriversLicenseCredential" ], "issuer": { "id": "did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5", "name": "Utopia Department of Motor Vehicles", "url": "https://dmv.utopia.example/", "image": "https://dmv.utopia.example/logo.png" }, "issuanceDate": "2023-11-15T10:00:00-07:00", "expirationDate": "2028-11-15T12:00:00-06:00", "name": "Utopia Driver's License", "image": "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUg...kSuQmCC", "description": "A license granting driving privileges in Utopia.", "credentialSubject": { "type": "LicensedDriver", "driversLicense": { "type": "Iso18013DriversLicense", "document_number": "542426814", "family_name": "TURNER", "given_name": "SUSAN", "portrait": "data:image/jpeg;base64,/9j/4AAQSkZJR...RSClooooP/2Q==", "birth_date": "1998-08-28", "issue_date": "2023-01-15T10:00:00-07:00", "expiry_date": "2028-08-27T12:00:00-06:00", "issuing_country": "UA", "issuing_authority": "UADMV", "driving_privileges": [ { "codes": [ { "code": "D" } ], "vehicle_category_code": "D", "issue_date": "2019-01-01", "expiry_date": "2027-01-01" }, { "codes": [ { "code": "C" } ], "vehicle_category_code": "C", "issue_date": "2019-01-01", "expiry_date": "2017-01-01" } ], "un_distinguishing_sign": "UTA", "aamva_aka_suffix": "1ST", "sex": 2, "aamva_family_name_truncation": "N", "aamva_given_name_truncation": "N" } }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "proofValue": "u2V0GhlhQr27gQbVviQzweUeIrPx8v6gWdLA7wp9VuG9D4ZmsNvz1-5WMRTv9zxuruTzDMgQZDrTPd-Ip36hbSgMQZduKUcZAiJjXf0J9zsZ8JsLeVONYQDpbvyXTTZCxjDXNI1e-am9CMB6U_J5S936Tt3PFYUvfjuoRLATYnhM4gPlnZuuuc2k_dfG7y7qkc9wGJUvexPtYYKTvGvo9pXVJbxIrm3i4wkdhUxqKCTIGrnxFuAdZwWi6T3omD5wzZ7bAGbRneEEQSxBmXtvnC6Pr59nPv_v3HrAW9wq_uxYzF_NyaX3GPv0h_FV2T2OSao8C6uoyWiqIj1ggABEiM0RVZneImaq7zN3u_wARIjNEVWZ3iJmqu8zd7v-CZy9pc3N1ZXJvL2V4cGlyYXRpb25EYXRlWCBRBa2qornWpIqaueRkcbQNh1_rwV01ZjAW3bVGFhnW0Q" } }
As explained in section A.2 Derived Proof, we use a mocked random number generation procedure and demonstrate the use of a presentationHeader. The same seed and presentationHeader as given in Example 19 are used here.
To create a derived proof, a holder starts with a signed document containing a base proof. The base document we will use for these test vectors is the final example from Example 51, above. The first step is to run the algorithm of Section 3.3.2 parseBaseProofValue to recover bbsSignature, bbsHeader, publicKey, hmacKey, mandatoryPointers, pid, and featureOption, as shown below.
{ "bbsSignature": "af6ee041b56f890cf0794788acfc7cbfa81674b03bc29f55b86f43e199ac36fcf5fb958c453bfdcf1babb93cc33204190eb4cf77e229dfa85b4a031065db8a51c6408898d77f427dcec67c26c2de54e3", "bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb", "publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f", "hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff", "mandatoryPointers": [ "/issuer", "/expirationDate" ], "pidHex": "5105adaaa2b9d6a48a9ab9e46471b40d875febc15d35663016ddb5461619d6d1", "featureOption": "pseudonym_issuer_pid" }
Next, the holder needs to indicate what else, if anything, they wish to reveal to the verifiers, by specifying JSON pointers for selective disclosure. In this case, the holder reveals the same information as given in Example 43. This results in the same revealDocument as shown in Example 44.
Running 3.3.3 createDisclosureData yields the same information for "derived group indexes" as shown in Example 45 and for "adjusted mandatory and selective indexes" as shown in Example 46.
Within 3.3.3 createDisclosureData, we compute the pseudonym based on the verfifier_id shown below.
{ "verifierId": "https://car.rental.verifier.example/" }
The final output of 3.3.3 createDisclosureData is shown below. Note the inclusion of the computed pseudonym and the featureOption value.
{ "bbsProof":"b1e7e101612e445e05c355545a0eaeda60c4d5f6b2118bd5bab4addd3d5a74a3c7296b1947079033b37e5e7ffead71c3a67b4251662fd1bb4cdbb6ed3b5aa916fa3f41e5bfdb2352c8cd0c7c2a9c16ee5d7b4e9195a92240c9d3c7403dadddccad4628e3c761fe9bb0983fd754efc28d36cc379e747074fa7029dc11187583ed87a8ead2e2105e834539c3cf5d1e47402a228a0668ef2bb124d41a2d7f11a026612da4138ef61d67bf28867a593615c312932ad74068a4eb54e8d56728574708057c3f88a30b4b380b90dcdbdd1fb7c54b6d11d348b4f33d1567fe23015fab3283fbf29ad2641cf0672a53b16ea9f20a0fb3a7e07a1f8951db23a794fdc4b97f3f2fe1b053f68a5db2159b8034b2b3544925f8e4e407ecaf1a8f1f025eff50e9cbad11192038d0ba07fb44b33fd77a695f9ea089bc86856d8d93f3891c5d230f0d2d4930d79671c9e8e8de3a40487dc869d5169a5397839a49baec8f409659ee9c45b15e39b0fd482ad76beeda9d5bd3143bd3be5312828b08dc889962bf1ea45d42c8d9ba34fb40a76082e375b004990d3806e90024fe211c4dec5b104f6ba01d69916f56605e32228c7a47449e94072a4887b9460573ec8fa5e92cb6ab21bcf4a6549af5f630493f42a584d49cd8a072b53bfd030f3863f79ef66167ff6b270f396c345520872facd16d75444f9fb333ec93043f0e4dad12ef3182fedd7d6fc2e430bca67506540c61a9a9bd84d5790c1711463e78d085f91b81629c0b22f55f8241ec5c3182ecd51cfa112beee6901aef8bec9f3ae27e82e509318d989b5a6a6d794562792ac0d138a1f75faada8e40c21a4519b841b313e1b0f1c8f3e7ce8b324c95fe29c202a3678f184ee7b70a10998fd6d80698b322f12806cc74fadc9ca2d4df487975a21e392bad0dae4add605dc5c8ad816da5cbf7ba19893d0d2388248504c375e7786ef6fffca18b0428184d25662f81f11f1dc276c71d8651367570d1263559e5d81049ee3b3c2d8eb4534367752e8b197af1d1989e1ebf55f8b71a616e49a98d09a456c0267e58cc1458997a8cfe00b499ffa91fbf0d01f5122329c9b822e981e42fa30c4e6a9511c53c2bcc34ca99350132260230296cbaf7a25ad678ef8a409b707ca78b51f016b52f571438d832b85f3c5fcfb67d7957113790616c9100684f1aaefb2335bed05a", "labelMap":{"dataType":"Map","value":[["c14n0","b1"],["c14n1","b2"],["c14n2","b0"]]}, "mandatoryIndexes":[0,1,2,5,6,8,9], "adjSelectiveIndexes":[0,1,5,7,10,16], "presentationHeader":{"0":17,"1":51,"2":119,"3":170}, "pseudonym":"b2981ced4b1acc7ddcaef1df51de385b344d697727ad5c8aee2b60d76a349146b4995d348607363070dd47b31a558be1", "lengthBBSMessages":24, "featureOption":"pseudonym_issuer_pid" }
Finally, using the disclosure data above with the algorithm of Section 3.3.6 serializeDerivedProofValue, we obtain the signed derived (reveal) document shown below.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/data-integrity/v2", "https://w3id.org/vdl/v1", "https://w3id.org/vdl/aamva/v1" ], "type": [ "VerifiableCredential", "Iso18013DriversLicenseCredential" ], "issuer": { "id": "did:key:z6MkjxvA4FNrQUhr8f7xhdQuP1VPzErkcnfxsRaU5oFgy2E5", "name": "Utopia Department of Motor Vehicles", "url": "https://dmv.utopia.example/", "image": "https://dmv.utopia.example/logo.png" }, "expirationDate": "2028-11-15T12:00:00-06:00", "credentialSubject": { "type": "LicensedDriver", "driversLicense": { "type": "Iso18013DriversLicense", "issuing_country": "UA", "driving_privileges": [ { "codes": [ { "code": "D" } ], "vehicle_category_code": "D", "issue_date": "2019-01-01", "expiry_date": "2027-01-01" }, { "codes": [ { "code": "C" } ], "vehicle_category_code": "C", "issue_date": "2019-01-01", "expiry_date": "2017-01-01" } ] } }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "bbs-2023", "created": "2023-08-15T23:36:38Z", "verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ", "proofPurpose": "assertionMethod", "proofValue": "u2V0Hh1kDULHn4QFhLkReBcNVVFoOrtpgxNX2shGL1bq0rd09WnSjxylrGUcHkDOzfl5__q1xw6Z7QlFmL9G7TNu27TtaqRb6P0Hlv9sjUsjNDHwqnBbuXXtOkZWpIkDJ08dAPa3dzK1GKOPHYf6bsJg_11Tvwo02zDeedHB0-nAp3BEYdYPth6jq0uIQXoNFOcPPXR5HQCoiigZo7yuxJNQaLX8RoCZhLaQTjvYdZ78ohnpZNhXDEpMq10BopOtU6NVnKFdHCAV8P4ijC0s4C5Dc290ft8VLbRHTSLTzPRVn_iMBX6syg_vymtJkHPBnKlOxbqnyCg-zp-B6H4lR2yOnlP3EuX8_L-GwU_aKXbIVm4A0srNUSSX45OQH7K8ajx8CXv9Q6cutERkgONC6B_tEsz_XemlfnqCJvIaFbY2T84kcXSMPDS1JMNeWccno6N46QEh9yGnVFppTl4OaSbrsj0CWWe6cRbFeObD9SCrXa-7anVvTFDvTvlMSgosI3IiZYr8epF1CyNm6NPtAp2CC43WwBJkNOAbpACT-IRxN7FsQT2ugHWmRb1ZgXjIijHpHRJ6UBypIh7lGBXPsj6XpLLarIbz0plSa9fYwST9CpYTUnNigcrU7_QMPOGP3nvZhZ_9rJw85bDRVIIcvrNFtdURPn7Mz7JMEPw5NrRLvMYL-3X1vwuQwvKZ1BlQMYampvYTVeQwXEUY-eNCF-RuBYpwLIvVfgkHsXDGC7NUc-hEr7uaQGu-L7J864n6C5QkxjZibWmpteUVieSrA0Tih91-q2o5AwhpFGbhBsxPhsPHI8-fOizJMlf4pwgKjZ48YTue3ChCZj9bYBpizIvEoBsx0-tycotTfSHl1oh45K60NrkrdYF3FyK2BbaXL97oZiT0NI4gkhQTDded4bvb__KGLBCgYTSVmL4HxHx3CdscdhlE2dXDRJjVZ5dgQSe47PC2OtFNDZ3Uuixl68dGYnh6_Vfi3GmFuSamNCaRWwCZ-WMwUWJl6jP4AtJn_qR-_DQH1EiMpybgi6YHkL6MMTmqVEcU8K8w0ypk1ATImAjApbLr3olrWeO-KQJtwfKeLUfAWtS9XFDjYMrhfPF_Ptn15VxE3kGFskQBoTxqu-yM1vtBaowABAQICAIcAAQIFBggJhgABBQcKEEQRM3eqWDCymBztSxrMfdyu8d9R3jhbNE1pdyetXIruK2DXajSRRrSZXTSGBzYwcN1HsxpVi-EYGA" } }
This section is non-normative.
Work on this specification has been supported by the Rebooting the Web of Trust community facilitated by Christopher Allen, Shannon Appelcline, Kiara Robles, Brian Weller, Betty Dhamers, Kaliya Young, Manu Sporny, Drummond Reed, Joe Andrieu, Heather Vescent, Kim Hamilton Duffy, Samantha Chase, Andrew Hughes, Erica Connell, Shigeya Suzuki, and Zaïda Rivai. The participants in the Internet Identity Workshop, facilitated by Phil Windley, Kaliya Young, Doc Searls, and Heidi Nobantu Saul, also supported the refinement of this work through numerous working sessions designed to educate about, debate on, and improve this specification.
The Working Group also thanks our Chair, Brent Zundel, our ex-Chair Kristina Yasuda, as well as our W3C Staff Contact, Ivan Herman, for their expert management and steady guidance of the group through the W3C standardization process.
Portions of the work on this specification have been funded by the United States Department of Homeland Security's Science and Technology Directorate under contracts 70RSAT20T00000003, 70RSAT20T00000029, 70RSAT20T00000033, 70RSAT21T00000016, 70RSAT23T00000005, 70RSAT20T00000010/P00001, 70RSAT20T00000029, 70RSAT21T00000016/P00001, 70RSAT23T00000005, 70RSAT23C00000030, 70RSAT23R00000006, and the National Science Foundation through NSF 22-572. The content of this specification does not necessarily reflect the position or the policy of the U.S. Government and no official endorsement should be inferred.
The Working Group would like to thank the following individuals for reviewing and providing feedback on the specification (in alphabetical order):
Will Abramson, Mahmoud Alkhraishi, Christopher Allen, Joe Andrieu, Bohdan Andriyiv, Anthony, George Aristy, Hadley Beeman, Greg Bernstein, Bob420, Sarven Capadisli, Melvin Carvalho, David Chadwick, Matt Collier, Gabe Cohen, Sebastian Crane, Kyle Den Hartog, Veikko Eeva, Eric Elliott, Raphael Flechtner, Julien Fraichot, Benjamin Goering, Kim Hamilton Duffy, Joseph Heenan, Helge, Ivan Herman, Michael Herman, Anil John, Andrew Jones, Michael B. Jones, Rieks Joosten, Gregory K, Gregg Kellogg, Filip Kolarik, David I. Lehn, Charles E. Lehner, Christine Lemmer-Webber, Eric Lim, Dave Longley, Tobias Looker, Jer Miller, nightpool, Luis Osta, Nate Otto, George J. Padayatti, Addison Phillips, Mike Prorock, Brian Richter, Anders Rundgren, Eugeniu Rusu, Markus Sabadello, silverpill, Wesley Smith, Manu Sporny, Patrick St-Louis, Orie Steele, Henry Story, Oliver Terbu, Ted Thibodeau Jr, John Toohey, Bert Van Nuffelen, Mike Varley, Snorre Lothar von Gohren Edwin, Jeffrey Yasskin, Kristina Yasuda, Benjamin Young, Dmitri Zagidulin, and Brent Zundel.