W3C Candidate Recommendation Snapshot
Copyright © 2026 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 standards and drafts index .
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 Snapshot using the Recommendation track .
Publication as a Candidate Recommendation does not imply endorsement by W3C and its Members. A Candidate Recommendation Snapshot has received wide review , is intended to gather implementation experience , and has commitments from Working Group members to royalty-free licensing for implementations.
This Candidate Recommendation is not expected to advance to Proposed Recommendation any earlier than 04 May 2024.
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 that 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 18 August 2025 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 , defined in Controlled Identifiers v1.0 , 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
381-bit
public
key
in
the
G2
group.
The
publicKeyMultibase
value
of
the
verification
method
MUST
start
with
the
base-58-btc
prefix
(
z
),
as
defined
in
the
Multibase
section
of
Controlled
Identifiers
v1.0
.
A
Multibase-encoded
BLS12-381
381-bit
public
key
value
follows,
as
defined
in
the
Multikey
section
of
Controlled
Identifiers
v1.0
.
Any
other
encoding
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
Multicodec
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, possibly a signer_nym_entropy value. A single base proof string value is produced as output.
"baseline"
:
0xd9
,
0x5d
,
and
0x02
.
"anonymous_holder_binding"
:
0xd9
,
0x5d
,
and
0x04
.
"pseudonym"
:
0xd9
,
0x5d
,
and
0x06
.
"holder_binding_pseudonym"
:
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
"signer_nym_entropy",
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"
.
0xd9
,
0x5d
,
and
0x08
,
set
featureOption
to
"holder_binding_pseudonym"
.
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",
and
"mandatoryPointers",
in
that
order,
and
add
featureOption
as
a
property.
"pseudonym"
,
set
the
property
names
for
the
object
based
on
components
to
"bbsSignature",
"bbsHeader",
"publicKey",
"hmacKey",
"mandatoryPointers",
and
"signer_nym_entropy",
in
that
order,
and
add
featureOption
as
a
property.
"holder_binding_pseudonym"
,
set
the
property
names
for
the
object
based
on
components
to
"bbsSignature",
"bbsHeader",
"publicKey",
"hmacKey",
"mandatoryPointers",
and
"signer_nym_entropy",
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 following fields: bbsProof , labelMap , mandatoryIndexes , selectiveIndexes , presentationHeader , revealDocument , and, if computed, pseudonym .
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
,
and
commitment_with_proof
.
The
holder
will
also
furnish
its
holder_secret
,
and
the
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"
,
use
the
"Verification
and
Finalization"
operation
from
[
CFRG-Pseudonym-BBS-Signature
]
with
an
empty
committed_messages
array
to
both
verify
the
bbsSignature
and
compute
the
nym_secret
value.
This
operation
uses
the
prover_nym
,
signer_nym_entropy
,
and
secret_prover_blind
.
"holder_binding_pseudonym"
,
use
the
"Verification
and
Finalization"
operation
from
[
CFRG-Pseudonym-BBS-Signature
]
with
the
committed_messages
array
containing
the
holder_secret
as
its
only
value,
to
both
verify
the
bbsSignature
and
compute
the
nym_secret
value.
This
operation
uses
the
prover_nym
,
signer_nym_entropy
,
and
secret_prover_blind
.
"anonymous_holder_binding"
,
"pseudonym"
,
or
"holder_binding_pseudonym"
set
the
lengthBBSMessages
parameter
to
the
length
of
the
bbsMessages
array.
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 ), a BBS presentation header ( presentationHeader ), the featureOption indicator, and, depending on the featureOption value, a nym_domain , 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"
:
0xd9
,
0x5d
,
and
0x07
.
"holder_binding_pseudonym"
:
0xd9
,
0x5d
,
and
0x09
.
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 to nine elements, having the names "bbsProof", "labelMap", "mandatoryIndexes", "selectiveIndexes", "presentationHeader", "featureOption", and, depending on the value of the featureOption parameter, "nym_domain", "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"
.
0xd9
,
0x5d
,
and
0x09
,
set
featureOption
to
"holder_binding_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,
seven,
or
eight
elements,
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 .
createLabelMapFunction
"
algorithm
of
[
DI-ECDSA
],
passing
labelMap
.
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"
,
or
"holder_binding_pseudonym"
.
Note
that
"baseline"
is
used
to
denote
the
case
of
no
optional
features.
If
featureOption
is
set
to
"anonymous_holder_binding"
,
"pseudonym"
,
or
"holder_binding_pseudonym"
,
the
commitment_with_proof
input
MUST
be
supplied.
If
featureOption
is
set
to
"pseudonym"
or
"holder_binding_pseudonym"
,
the
signer_nym_entropy
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 ) and the unsecured data document ( unsecuredDocument ). 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"
,
"pseudonym"
,
or
"holder_binding_pseudonym"
,
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
.
If
featureOption
is
set
to
"pseudonym"
or
"holder_binding_pseudonym"
,
the
signer_nym_entropy
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
.
This
provides
for
the
Anonymous
Holder
Binding
feature.
"pseudonym"
or
"holder_binding_pseudonym"
,
the
issuer
generates
a
cryptographically
random
value
for
the
signer_nym_entropy
and
computes
the
bbsSignature
using
the
"Blind
Issuance"
operation
from
[
CFRG-Pseudonym-BBS-Signature
]
with
appropriate
key
material,
bbsHeader
for
the
header
,
bbsMessages
for
the
messages
,
commitment_with_proof
for
the
commitment_with_proof
,
and
signer_nym_entropy
values.
If
the
issuer
might
ever
need
to
reissue
a
credential
to
this
holder
that
is
bound
to
the
same
nym_secret
,
they
should
retain
the
signer_nym_entropy
value;
otherwise,
this
value
can
be
discarded.
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"
,
the
REQUIRED
additional
inputs
are
prover_nym
and
proverBlind
,
which
are
both
known
to
the
holder,
and
nym_dofmain
,
which
is
either
set
by
the
holder
or
communicated
to
the
holder
by
the
verifier.
See
Credential-Bound
Pseudonyms
for
background
information.
If
featureOption
equals
"holder_binding_pseudonym"
,
the
REQUIRED
additional
inputs
are
holder_secret
,
prover_nym
,
and
proverBlind
,
which
are
all
known
to
the
holder,
and
nym_dofmain
,
which
is
either
set
by
the
holder
or
communicated
to
the
holder
by
the
verifier.
See
Holder
Binding
and
Pseudonyms
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"
or
"holder_binding_pseudonym"
,
initialize
verified
to
the
result
of
applying
the
"Proof
Verification
with
Pseudonym"
operation
from
[
CFRG-Pseudonym-BBS-Signature
]
using
lengthBBSMessages
for
the
"L"
parameter
and
an
empty
committed_messages
array.
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 , holder_secret , prover_nym , signer_nym_entropy , 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 Computation" operation 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 Computation" operation 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 this specification, and uses the "Blind Signature Generation" operation of [ CFRG-Blind-BBS-Signature ] to produce a base proof (signature) over the document, with the commitment_with_proof furnished by the holder.
When the holder wants to create a selectively disclosed document with derived proof, they use the procedures of this specification and the "Proof Generation" operation of [ CFRG-Blind-BBS-Signature ]. They use their holder_secret as the only "message" in the commited messages array, and supply their secret_prover_blind .
Verification of the revealed document with derived proof uses the procedures of this specification and the "Proof Verification" operation of [ CFRG-Blind-BBS-Signature ].
BBS-signed Verifiable Credentials as specified in this document allow for selective disclosure and unlinkable cryptographic proof artifacts. By "unlinkable", we mean that the cryptographic information in the derived proofs cannot be linked to other proofs nor the original signature. This implies that a verifier cannot determine whether a holder has presented the same credential before (with a different proof instantiation), nor can they assert some type of identity. Credential-bound pseudonyms provide a privacy preserving mechanism to allow for the limited linkability of a cryptographic pseudonym. Such a pseudonym may be determined strictly by the holder, or jointly by the holder and the verifier.
This type of cryptographic pseudonym (cryptographic identifier/name) is computed from two parts. The first part, the nym_secret , is specified by, and will only be known by, the holder; the second part, the nym_domain , may be specified by either the holder or the verifier, and will be shared between the holder and verifier. An issuer binds a credential to a nym_secret during the issuance process. A holder can then compute pseudonyms from the nym_secret and prove to verifiers that these pseudonyms are bound to the credential they are presenting. Cryptographic pseudonyms computed from the same nym_secret but different nym_domain values are unlinkable.
The
holder
might
choose
a
nym_domain
to
give
themselves
a
pseudonym
for
some
type
of
public
forum,
e.g.,
choose
nym_domain
=
"Mark
Twain"
.
The
cryptographic
pseudonym
calculated
by
the
holder
from
this
nym_domain
with
their
nym_secret
is
essentially
unique,
and
no
entity
that
does
not
both
know
the
nym_secret
and
possess
the
base
verifiable
credential
bound
to
the
pseudonym
could
assert
this
pseudonymous
identity.
Note
that
the
doublet
of
(
nym_domain
,
pseudonym)
has
to
be
sent
with
the
derived
credential
to
assert
this
pseudonymous
identity.
In
a
different
situation,
a
holder
may
be
using
a
service
from
a
verifier
where
the
verifier
wants
to
track
visits
over
time
or
monitor
use
of
some
resource
by
the
holder.
In
this
case,
the
verifier
chooses
the
nym_domain
that
the
holder
needs
to
use
when
presenting
their
derived
credential.
For
example,
a
verifier
might
specify
a
public
nym_domain
tied
to
their
DNS
domain
(e.g.,
"www.nym.example"
)
for
the
holder
to
use.
A
verifier
could
also
demonstrate
that
they
support
data
minimization,
of
a
sort,
by
periodically
changing
the
nym_domain
(e.g.,
tying
it
to
a
date,
"www.nym.example/2025-01-02"
).
This
specification
does
not
dictate
values
for
the
nym_domain
.
Finally, to prevent a malicious holder who obtains another holder's nym_secret from getting a credential bound to that value, the operations from the [ CFRG-Pseudonym-BBS-Signature ] have the issuer add a randomization factor, signer_nym_entropy , that is securely "mixed" with the holder's portion, the prover_nym , during signature generation. This results in a nym_secret for which the issuer can provide cryptographic assurance that it is unique, to be used by the holder.
An outline of the creation and use of credential-bound pseudonyms is shown in the steps below.
Commitment
"
operation
from
[
CFRG-Pseudonym-BBS-Signature
]
with
an
empty
committed_messages
array
to
compute
the
commitment_with_proof
and
the
secret_prover_blind
.
The
holder
sends
the
commitment_with_proof
to
the
issuer
with
a
request
for
a
credential,
but
never
discloses
prover_nym
and
secret_prover_blind
,
keeping
them
for
later
use.
"pseudonym"
),
along
with
the
commitment_with_proof
.
The
issuer
generates
a
cryptographically
random
value
for
the
signer_nym_entropy
and
uses
the
"Blind
Issuance"
operation
from
[
CFRG-Pseudonym-BBS-Signature
]
to
produce
the
base
proof.
Among
other
information,
the
base
proof
will
contain
the
signer_nym_entropy
value.
If
the
issuer
might
ever
need
to
reissue
a
credential
to
this
holder
that
is
bound
to
the
same
nym_secret
,
they
should
retain
the
signer_nym_entropy
value;
otherwise,
this
value
can
be
discarded.
Anonymous
holder
binding
and
credential-bound
pseudonyms
are,
in
a
sense,
orthogonal
features,
and
a
holder
and
credential
ecosystem
may
wish
to
use
both
at
the
same
time.
For
instance,
a
holder
may
wish
to
bind
a
verifiable
credential
to
a
holder_secret
,
so
that
only
a
holder
knowing
this
value
can
generate
a
derived
proof
from
the
base
proof,
and
bind
a
nym_secret
to
the
base
proof
so
that
pseudonyms
can
be
bound
to
the
derived
proof.
This
corresponds
to
the
featureOption
being
equal
to
"holder_binding_pseudonym"
.
An outline of the creation and use of both anonymous holder binding and credential bound pseudonyms is given in the following steps.
"pseudonym"
,
along
with
the
commitment_with_proof
.
The
issuer
uses
the
procedures
in
this
specification
and
generates
a
cryptographically
random
value
for
the
signer_nym_entropy
and
uses
the
"Blind
Issuance"
operation
from
[
CFRG-Pseudonym-BBS-Signature
]
to
produce
the
base
proof.
Among
other
information
the
base
proof
will
contain
the
signer_nym_entropy
value.
If
the
issuer
ever
needs
reissue
a
credential
to
this
holder
that
is
bound
to
the
same
nym_secret
they
should
retain
the
signer_nym_entropy
value,
otherwise
this
value
can
be
discarded.
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 | baseline + commitment with proof from holder | Blind BBS |
| Credential-Bound Pseudonyms | baseline + generate signer_nym_entropy | baseline + signer_nym_entropy , commitment with proof from holder | Pseudonym BBS |
| Holder Binding and Pseudonyms | baseline + generate signer_nym_entropy | baseline + signer_nym_entropy , commitment with proof from holder | Pseudonym 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 |
| Credential-Bound Pseudonyms |
0xd9
,
0x5d
,
and
0x06
|
baseline + signer_nym_entropy |
| Holder Binding and Pseudonyms |
0xd9
,
0x5d
,
and
0x08
|
baseline + signer_nym_entropy |
| 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) | Blind BBS |
| Credential Bound Pseudonyms | baseline + compute nym_secret , compute pseudonym | baseline + prover_nym , prover_blind (all known to holder), signer_nym_entropy (included in base from issuer), nym_domain | Pseudonym BBS |
| Holder Binding and Pseudonyms | baseline + compute nym_secret , compute pseudonym | baseline + holder_secret , prover_nym , prover_blind (all known to holder), signer_nym_entropy (included in base from issuer), nym_domain | Pseudonym 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 |
| Credential Bound Pseudonyms |
0xd9
,
0x5d
,
and
0x07
|
baseline + pseudonym , nym_domain |
| Holder Binding and Pseudonyms |
0xd9
,
0x5d
,
and
0x09
|
baseline + pseudonym , nym_domain |
| Name | Inputs | Proof Verification Algorithm |
|---|---|---|
| BBS baseline | baseline : (from derived proof serialization) bbsProof, compressedLabelMap, mandatoryIndexes, selectiveIndexes, presentationHeader | BBS |
| Anonymous Holder Binding | baseline | Blind BBS |
| Credential-Bound Pseudonyms | baseline + pseudonym (included in derived proof), nym_domain | Pseudonym BBS |
| Holder Binding and Pseudonyms | baseline + pseudonym (included in derived proof), nym_domain | 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.
The document test vectors are based on a purely fictitious permanent resident card, and broken into two groups — 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 permanent resident credential is being issued. The unsigned permanent resident document is shown below.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"PermanentResidentCardCredential"
],
"issuer": {
"id": "did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg=="
},
"name": "Permanent Resident Card",
"description": "Government of Utopia Permanent Resident Card.",
"credentialSubject": {
"type": [
"PermanentResident",
"Person"
],
"givenName": "JANE",
"familyName": "SMITH",
"gender": "Female",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v43hPwAHIgK1v4tX6wAAAABJRU5ErkJggg==",
"residentSince": "2015-01-01",
"commuterClassification": "C1",
"birthCountry": "Arcadia",
"birthDate": "1978-07-17",
"permanentResidentCard": {
"type": [
"PermanentResidentCard"
],
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"validFrom": "2024-12-16T00:00:00Z",
"validUntil": "2025-12-16T23:59:59Z"
}
This mandatory information is specified via an array of JSON pointers, as shown below.
["/issuer"]
The result of applying the above JSON pointers to the document is shown below.
[
{
"pointer": "/issuer",
"value": {
"id": "did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg=="
}
}
]
Transformation of the unsigned document begins with canonicalizing the document, as shown below.
[ "<did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg==> .\n", "_:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCard> .\n", "_:c14n0 <https://schema.org/identifier> \"83627465\" .\n", "_:c14n0 <https://w3id.org/citizenship#lprCategory> \"C09\" .\n", "_:c14n0 <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\n", "_:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n", "_:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResident> .\n", "_:c14n1 <https://schema.org/birthDate> \"1978-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n1 <https://schema.org/familyName> \"SMITH\" .\n", "_:c14n1 <https://schema.org/gender> \"Female\" .\n", "_:c14n1 <https://schema.org/givenName> \"JANE\" .\n", "_:c14n1 <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v43hPwAHIgK1v4tX6wAAAABJRU5ErkJggg==> .\n", "_:c14n1 <https://w3id.org/citizenship#birthCountry> \"Arcadia\" .\n", "_:c14n1 <https://w3id.org/citizenship#commuterClassification> \"C1\" .\n", "_:c14n1 <https://w3id.org/citizenship#permanentResidentCard> _:c14n0 .\n", "_:c14n1 <https://w3id.org/citizenship#residentSince> \"2015-01-01\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCardCredential> .\n", "_:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:c14n2 <https://schema.org/description> \"Permanent Resident Card from Government of Utopia.\" .\n", "_:c14n2 <https://schema.org/name> \"Permanent Resident Card\" .\n", "_:c14n2 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n1 .\n", "_:c14n2 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> .\n", "_:c14n2 <https://www.w3.org/2018/credentials#validFrom> \"2024-12-16T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n2 <https://www.w3.org/2018/credentials#validUntil> \"2025-12-16T23:59:59Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ]
To prevent possible information leakage via the ordering of the blank node IDs, these IDs 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" (or "non-mandatory") disclosure, i.e., when these statements are grouped based on their disclosure requirements, they will still be ordered as in this list.
[ "<did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg==> .\n", "_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n", "_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResident> .\n", "_:b0 <https://schema.org/birthDate> \"1978-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b0 <https://schema.org/familyName> \"SMITH\" .\n", "_:b0 <https://schema.org/gender> \"Female\" .\n", "_:b0 <https://schema.org/givenName> \"JANE\" .\n", "_:b0 <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v43hPwAHIgK1v4tX6wAAAABJRU5ErkJggg==> .\n", "_:b0 <https://w3id.org/citizenship#birthCountry> \"Arcadia\" .\n", "_:b0 <https://w3id.org/citizenship#commuterClassification> \"C1\" .\n", "_:b0 <https://w3id.org/citizenship#permanentResidentCard> _:b1 .\n", "_:b0 <https://w3id.org/citizenship#residentSince> \"2015-01-01\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCard> .\n", "_:b1 <https://schema.org/identifier> \"83627465\" .\n", "_:b1 <https://w3id.org/citizenship#lprCategory> \"C09\" .\n", "_:b1 <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\n", "_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCardCredential> .\n", "_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:b2 <https://schema.org/description> \"Permanent Resident Card from Government of Utopia.\" .\n", "_:b2 <https://schema.org/name> \"Permanent Resident Card\" .\n", "_:b2 <https://www.w3.org/2018/credentials#credentialSubject> _:b0 .\n", "_:b2 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> .\n", "_:b2 <https://www.w3.org/2018/credentials#validFrom> \"2024-12-16T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:b2 <https://www.w3.org/2018/credentials#validUntil> \"2025-12-16T23:59:59Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ]
The list from the canonical document above gets grouped into mandatory and non-mandatory statements. The final output of the selective disclosure transformation process is shown below. Note that the statements are now grouped as mandatory or non-mandatory disclosure, and the index of each statement in the previous list is remembered.
{
"mandatoryPointers": [
"/issuer"
],
"mandatory": {
"dataType": "Map",
"value": [
[
0,
"<did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg==> .\n"
],
[
16,
"_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCardCredential> .\n"
],
[
17,
"_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n"
],
[
21,
"_:b2 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> .\n"
]
]
},
"nonMandatory": {
"dataType": "Map",
"value": [
[
1,
"_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n"
],
[
2,
"_:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResident> .\n"
],
[
3,
"_:b0 <https://schema.org/birthDate> \"1978-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
4,
"_:b0 <https://schema.org/familyName> \"SMITH\" .\n"
],
[
5,
"_:b0 <https://schema.org/gender> \"Female\" .\n"
],
[
6,
"_:b0 <https://schema.org/givenName> \"JANE\" .\n"
],
[
7,
"_:b0 <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v43hPwAHIgK1v4tX6wAAAABJRU5ErkJggg==> .\n"
],
[
8,
"_:b0 <https://w3id.org/citizenship#birthCountry> \"Arcadia\" .\n"
],
[
9,
"_:b0 <https://w3id.org/citizenship#commuterClassification> \"C1\" .\n"
],
[
10,
"_:b0 <https://w3id.org/citizenship#permanentResidentCard> _:b1 .\n"
],
[
11,
"_:b0 <https://w3id.org/citizenship#residentSince> \"2015-01-01\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
12,
"_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCard> .\n"
],
[
13,
"_:b1 <https://schema.org/identifier> \"83627465\" .\n"
],
[
14,
"_:b1 <https://w3id.org/citizenship#lprCategory> \"C09\" .\n"
],
[
15,
"_:b1 <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\n"
],
[
18,
"_:b2 <https://schema.org/description> \"Permanent Resident Card from Government of Utopia.\" .\n"
],
[
19,
"_:b2 <https://schema.org/name> \"Permanent Resident Card\" .\n"
],
[
20,
"_:b2 <https://www.w3.org/2018/credentials#credentialSubject> _:b0 .\n"
],
[
22,
"_:b2 <https://www.w3.org/2018/credentials#validFrom> \"2024-12-16T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
23,
"_:b2 <https://www.w3.org/2018/credentials#validUntil> \"2025-12-16T23:59:59Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\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",
"https://w3id.org/citizenship/v4rc1"
]
}
_: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": "8e7cc22c318dd2094e02d0bf06c5d73a5dba717611a40f6d1bedc5ea7c300fd6"
}
Shown
below
are
the
computed
bbsSignature
in
hexadecimal,
and
the
mandatoryPointers
.
These
are
are
fed
to
the
final
serialization
step
with
the
hmacKey
.
{
"bbsSignature": "86168dd2b5d0c7c6a56a30f4212ed116a53def05d0d6708207d483c7ff2053aefa22d24ba7659d60852694f8d85be0fa2adc3974c7dc4cc68b3db17b2423975047104162c24502b41591879ac24f1bb1",
"mandatoryPointers": [
"/issuer"
]
}
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,
as
shown
below.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"PermanentResidentCardCredential"
],
"issuer": {
"id": "did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg=="
},
"name": "Permanent Resident Card",
"description": "Permanent Resident Card from Government of Utopia.",
"credentialSubject": {
"type": [
"PermanentResident",
"Person"
],
"givenName": "JANE",
"familyName": "SMITH",
"gender": "Female",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v43hPwAHIgK1v4tX6wAAAABJRU5ErkJggg==",
"residentSince": "2015-01-01",
"commuterClassification": "C1",
"birthCountry": "Arcadia",
"birthDate": "1978-07-17",
"permanentResidentCard": {
"type": [
"PermanentResidentCard"
],
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"validFrom": "2024-12-16T00:00:00Z",
"validUntil": "2025-12-16T23:59:59Z",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "bbs-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0ChVhQhhaN0rXQx8alajD0IS7RFqU97wXQ1nCCB9SDx_8gU676ItJLp2WdYIUmlPjYW-D6Ktw5dMfcTMaLPbF7JCOXUEcQQWLCRQK0FZGHmsJPG7FYQDpbvyXTTZCxjDXNI1e-am9CMB6U_J5S936Tt3PFYUvfjnzCLDGN0glOAtC_BsXXOl26cXYRpA9tG-3F6nwwD9ZYYKTvGvo9pXVJbxIrm3i4wkdhUxqKCTIGrnxFuAdZwWi6T3omD5wzZ7bAGbRneEEQSxBmXtvnC6Pr59nPv_v3HrAW9wq_uxYzF_NyaX3GPv0h_FV2T2OSao8C6uoyWiqIj1ggABEiM0RVZneImaq7zN3u_wARIjNEVWZ3iJmqu8zd7v-BZy9pc3N1ZXI"
}
}
Random
numbers
are
used,
and
an
optional
presentationHeader
can
be
an
additional
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.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": "86168dd2b5d0c7c6a56a30f4212ed116a53def05d0d6708207d483c7ff2053aefa22d24ba7659d60852694f8d85be0fa2adc3974c7dc4cc68b3db17b2423975047104162c24502b41591879ac24f1bb1",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"mandatoryPointers": [
"/issuer"
]
}
Next, the holder needs to indicate what non-mandatory statements, if any, they wish to reveal to the verifiers, by specifying JSON pointers for selective disclosure. These are shown below.
["/validFrom", "/validUntil", "/credentialSubject/birthCountry"]
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
].
This
gets
the
result
shown
below.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"PermanentResidentCardCredential"
],
"issuer": {
"id": "did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg=="
},
"validFrom": "2024-12-16T00:00:00Z",
"validUntil": "2025-12-16T23:59:59Z",
"credentialSubject": {
"type": [
"PermanentResident",
"Person"
],
"birthCountry": "Arcadia"
}
}
Now that we know what the reveal document looks like, we need to furnish appropriately updated information to the verifier about which statements are mandatory, and the indexes of the selected non-mandatory statements. Running step 6 of the 3.3.3 createDisclosureData yields abundant 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,8,16,17,20,21,22,23],"mandatoryIndexes":[0,16,17,21],"nonMandatoryIndexes":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,18,19,20,22,23],"selectiveIndexes":[1,2,8,16,17,20,22,23]}
The
verifier
needs
to
be
able
to
aggregate
and
hash
the
mandatory
statements.
To
enable
this,
we
furnish
them
with
a
list
of
the
indexes
of
the
mandatory
statements,
adjusted
to
their
positions
in
the
reveal
document
(i.e.,
relative
to
the
combinedIndexes
),
while
the
selectiveIndexes
are
adjusted
relative
to
their
positions
within
the
nonMandatoryIndexes
.
These
"adjusted"
indexes
are
shown
below.
{"adjMandatoryIndexes":[0,4,5,7],"adjSelectiveIndexes":[0,1,7,17,18,19]}
The
last
important
piece
of
disclosure
data
is
the
labelMap
,
a
mapping
of
canonical
blank
node
IDs
to
HMAC-based
shuffled
IDs,
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":"96ac5ff7b89bf2d8b0f3cc51c547f1a22b01e24e246579d212362cdf6bf0fabe18be0c9d1f84c904bb4c6c613fd0ecabb7ad92e615341da97a45a918721626cc859c455b473a36e39572561d5fc483c637424717a43dcffb3b130d8fe11f88a8802f3b231efe2444f8b47feded0b621e3d5cd22cb3ec23ebc4f6dca745b5c1ce2f42a710b92510a71225a7d39e00e0c26da2fae242cdf154e93de42017270b99023fe95b42c42a461a2eab19e04aa44839af39aa71f830162cb424a5aa0acc046dc7e7b8bdfc73cf3641c76aeeb7fbb56cd936776050dbd632bf7fc80d33c621dc6b837184ade619630f72bd25d8aea626ba994d15a65def1b0dc8af09c54a0cf5e5b54d1b1b28047aa2dbf63805fec9533bab46d12349ca47dfd83ff30454cedacd23da4eb9a3ebe198c80ac1992e2a203ffcf46afaa3482a63b7b00033df1a2da361d600a1cfd5139be010ca302e082af7ee34a5ff3d24cc7062f57fa36d47846edd5219e59bd438576bff709bfd7920d6bad8367b0fe8c749318ef8726beda9c1d9095bed738e4fd1c38333a27f4f2071a21a863671b43fe521f737444be865e887cbf33caa39226fb8013003721e37c6d949867befba1c8b7bf641bd647851ad92aed3da91af52f17d058a9f74eb30744304c05813840be6a528f54cd5a24b73ae2f42dec1bfc2e1354fb061a96c0df3ab96ddc9ada96cb882571cccb89774fcf0326e1c8b2b87cc4cf4eafbd75632518919cbe58a9f86ade12b0f6989c0886e358d801b99b1dd32c7e6e56a653c0e264a84b51d2d23679c75e282451af3bcaa6f19ec7bc3aa603fec87db5a57d42961e2907d899a8fd5d1ce17dde8a75cd1192494cd93b112da7774c2bb2f679f5b4b404dabe485d78a017b2be81e5ff8bacf90d5f24b2e83ab4169f8f55ca6f703141f91565abbec7445e6cf4663f5e34b9188283d57cedf36c586b18a130b83652436bf6862673ddeebd9aefdc2fbfc97dde80e36483491c4357ccd2fc131fb","labelMap":{"dataType":"Map","value":[["c14n0","b0"],["c14n1","b2"]]},"mandatoryIndexes":[0,4,5,7],"adjSelectiveIndexes":[0,1,7,17,18,19],"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",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"PermanentResidentCardCredential"
],
"issuer": {
"id": "did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg=="
},
"validFrom": "2024-12-16T00:00:00Z",
"validUntil": "2025-12-16T23:59:59Z",
"credentialSubject": {
"type": [
"PermanentResident",
"Person"
],
"birthCountry": "Arcadia"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "bbs-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ#zUC7DerdEmfZ8f4pFajXgGwJoMkV1ofMTmEG5UoNvnWiPiLuGKNeqgRpLH2TV4Xe5mJ2cXV76gRN7LFQwapF1VFu6x2yrr5ci1mXqC1WNUrnHnLgvfZfMH7h6xP6qsf9EKRQrPQ",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0DhVkC0JasX_e4m_LYsPPMUcVH8aIrAeJOJGV50hI2LN9r8Pq-GL4MnR-EyQS7TGxhP9Dsq7etkuYVNB2pekWpGHIWJsyFnEVbRzo245VyVh1fxIPGN0JHF6Q9z_s7Ew2P4R-IqIAvOyMe_iRE-LR_7e0LYh49XNIss-wj68T23KdFtcHOL0KnELklEKcSJafTngDgwm2i-uJCzfFU6T3kIBcnC5kCP-lbQsQqRhouqxngSqRIOa85qnH4MBYstCSlqgrMBG3H57i9_HPPNkHHau63-7Vs2TZ3YFDb1jK_f8gNM8Yh3GuDcYSt5hljD3K9Jdiupia6mU0Vpl3vGw3IrwnFSgz15bVNGxsoBHqi2_Y4Bf7JUzurRtEjScpH39g_8wRUztrNI9pOuaPr4ZjICsGZLiogP_z0avqjSCpjt7AAM98aLaNh1gChz9UTm-AQyjAuCCr37jSl_z0kzHBi9X-jbUeEbt1SGeWb1DhXa_9wm_15INa62DZ7D-jHSTGO-HJr7anB2Qlb7XOOT9HDgzOif08gcaIahjZxtD_lIfc3REvoZeiHy_M8qjkib7gBMANyHjfG2UmGe--6HIt79kG9ZHhRrZKu09qRr1LxfQWKn3TrMHRDBMBYE4QL5qUo9UzVoktzri9C3sG_wuE1T7BhqWwN86uW3cmtqWy4glcczLiXdPzwMm4ciyuHzEz06vvXVjJRiRnL5Yqfhq3hKw9picCIbjWNgBuZsd0yx-blamU8DiZKhLUdLSNnnHXigkUa87yqbxnse8OqYD_sh9taV9QpYeKQfYmaj9XRzhfd6Kdc0RkklM2TsRLad3TCuy9nn1tLQE2r5IXXigF7K-geX_i6z5DV8ksug6tBafj1XKb3AxQfkVZau-x0RebPRmP140uRiCg9V87fNsWGsYoTC4NlJDa_aGJnPd7r2a79wvv8l93oDjZINJHENXzNL8Ex-6IAAAEChAAEBQeGAAEHERITRBEzd6o"
}
}
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.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 their 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": "12901a77b3906af68d9e4214dce887d127b2a51d6311bbe7d087d45737acd2db",
"commitmentWithProof": "ab77a14fddfafc7ae6ea82b0ef6048059225f96c9206903a34c6ec6beba702652e9d64fac1917e372853867d944e4a8059e0c26bc871cac14736e73685cd3006299539b93df64cdf661af2bc6300976528c5092c6dc842abaaa624f2184d3d5b75be0ede9c4822161149ef51a965ddda260e10b9246ecaea020ef952e3b3ed6e724bcb5d1a9c4004f0aea2cba030c27c"
}
The holderSecret and secretProverBlind are to be retained and kept secret by the holder. The commitmentWithProof value is 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"
}
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 , and featureOption , where byte data is shown in hexadecimal.
{
"bbsSignature": "90eadd70a16661f3d596f3560fc485f7c23ba969eb7c237d481b3596b2f66279bd5a62fa523777eb73b5cfa361885f1a00864b960baf1b92d2b55c0652ebe39024f88e1377911c40bf14cb5fbc808ee1",
"bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb",
"publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"mandatoryPointers": [
"/issuer",
"/expirationDate"
],
"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": "u2V0EhVhQkOrdcKFmYfPVlvNWD8SF98I7qWnrfCN9SBs1lrL2Ynm9WmL6Ujd363O1z6NhiF8aAIZLlguvG5LStVwGUuvjkCT4jhN3kRxAvxTLX7yAjuFYQDpbvyXTTZCxjDXNI1e-am9CMB6U_J5S936Tt3PFYUvfjuoRLATYnhM4gPlnZuuuc2k_dfG7y7qkc9wGJUvexPtYYKTvGvo9pXVJbxIrm3i4wkdhUxqKCTIGrnxFuAdZwWi6T3omD5wzZ7bAGbRneEEQSxBmXtvnC6Pr59nPv_v3HrAW9wq_uxYzF_NyaX3GPv0h_FV2T2OSao8C6uoyWiqIj1ggABEiM0RVZneImaq7zN3u_wARIjNEVWZ3iJmqu8zd7v-CZy9pc3N1ZXJvL2V4cGlyYXRpb25EYXRl"
}
}
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 , and featureOption , as shown below.
{
"bbsSignature": "90eadd70a16661f3d596f3560fc485f7c23ba969eb7c237d481b3596b2f66279bd5a62fa523777eb73b5cfa361885f1a00864b960baf1b92d2b55c0652ebe39024f88e1377911c40bf14cb5fbc808ee1",
"bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb",
"publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"mandatoryPointers": [
"/issuer",
"/expirationDate"
],
"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":"a19db05cca1237d9965b0bb3197c4962a7fb49c97af131c80ea2d8f949078ff5642acdb33d27d06b97f87ff906a2a23bb0c3dd778572b892785faefdc25811318b0b46e25b8863898b0600701a71c256ee9a7347a1a577fe2e3793b1c0390e4d8f9fff9161074eebba852bcca8089eed76416ac9f178b850e7688c26cfbdee344fa75d9ba2cf22417e3c70be7891f6de040928d4a665005ddbe3b7372ecb87baad726f1535d4600a0198d3a36a17ad673160f8ef5e5fd74f2542b214cc4534ee82b0a90c0501ca9749c8327afcb97e14220f2e516dfc3cb2ed2ffdd3845a25cb64e1a2aa9987bbc122755158d787a2356e28f2affff31b83a2cdff26d5ac1aa72f4d6c40fe96ad230ce09fd4e9b8998357c2964da031e59c3b8c2241da00bc66a6216af7cd02b535577fa3b54bf9a0d230183b03aa145dbabc7fed3710d879c6b8d4273e6e377bed382de985f561ff9b2b3445f29957655600cbd1b29714f52c55ff05bc204203e65bdf6f818e976c690becfed9284b27c2dead96803efad949ffb519b7024530b08b5ed4c8e7472ed20c3866b79658e1b2d2c5b88a60da07614afa4906c73a6e5ad9113282288173e265236fa57d72c97f85c86b43349516f8e2f52f756d43cd2d9cf8c673db404d14007706ebbd4f7b5bbd19cdce9f48b2dac2db7f0f0c3fb18bd8e66e28fe46dafc3961e5945779faf5407190a33ce00efd07222cc142d40cab9b9d591589a30d056dae47d376d3ac5fab3201bbada604dd8e5e292185f38e2bcd58e81b2fec1e7b5754b7b28bd127abc929e950cb75100e94695f1ad13c09c1d394664029b66bdd49304df3ae1e2a90a6309f07c47555ccaea9cd17d80eaad6b7c29e9335a69338446ff666ac5802cfe36057c449d392bda99d2657fb8b6cf02d7ce4d9dccd8e97033accc5c10f092ec7bf0b3c0b2afc64a1a429d81cc485388f6f390dd97f648c3712ee0b93a7e96b268437e6e3537fb7918cee2a4ac3f895c7945988d7d3880238b8cf6062da171aa87545cf62072b20e698eb4ac12450c0b95a77e946fada8d46102abfa9a5a12d2a71380dedb51e2a57c97514813c17ea93e6ca19077c2a2511bf8fd158c4ed7361590b040915a3cb76f323300111303d8dd31c55474d514209bf01ed6639d4d81a1b30be54444e523e2ddef9a0a6bfe792d3037944aec29154c02bb79d09bd53856797dceb6c599f4103ff7f13dfdb8b2d18477832e5fe21","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": "u2V0FhlkDcKGdsFzKEjfZllsLsxl8SWKn-0nJevExyA6i2PlJB4_1ZCrNsz0n0GuX-H_5BqKiO7DD3XeFcriSeF-u_cJYETGLC0biW4hjiYsGAHAaccJW7ppzR6Gld_4uN5OxwDkOTY-f_5FhB07ruoUrzKgInu12QWrJ8Xi4UOdojCbPve40T6ddm6LPIkF-PHC-eJH23gQJKNSmZQBd2-O3Ny7Lh7qtcm8VNdRgCgGY06NqF61nMWD4715f108lQrIUzEU07oKwqQwFAcqXScgyevy5fhQiDy5Rbfw8su0v_dOEWiXLZOGiqpmHu8EidVFY14eiNW4o8q__8xuDos3_JtWsGqcvTWxA_patIwzgn9TpuJmDV8KWTaAx5Zw7jCJB2gC8ZqYhavfNArU1V3-jtUv5oNIwGDsDqhRdurx_7TcQ2HnGuNQnPm43e-04LemF9WH_mys0RfKZV2VWAMvRspcU9SxV_wW8IEID5lvfb4GOl2xpC-z-2ShLJ8LerZaAPvrZSf-1GbcCRTCwi17UyOdHLtIMOGa3lljhstLFuIpg2gdhSvpJBsc6blrZETKCKIFz4mUjb6V9csl_hchrQzSVFvji9S91bUPNLZz4xnPbQE0UAHcG671Pe1u9Gc3On0iy2sLbfw8MP7GL2OZuKP5G2vw5YeWUV3n69UBxkKM84A79ByIswULUDKubnVkViaMNBW2uR9N206xfqzIBu62mBN2OXikhhfOOK81Y6Bsv7B57V1S3sovRJ6vJKelQy3UQDpRpXxrRPAnB05RmQCm2a91JME3zrh4qkKYwnwfEdVXMrqnNF9gOqta3wp6TNaaTOERv9masWALP42BXxEnTkr2pnSZX-4ts8C185NnczY6XAzrMxcEPCS7Hvws8Cyr8ZKGkKdgcxIU4j285Ddl_ZIw3Eu4Lk6fpayaEN-bjU3-3kYzuKkrD-JXHlFmI19OIAji4z2Bi2hcaqHVFz2IHKyDmmOtKwSRQwLlad-lG-tqNRhAqv6mloS0qcTgN7bUeKlfJdRSBPBfqk-bKGQd8KiURv4_RWMTtc2FZCwQJFaPLdvMjMAERMD2N0xxVR01RQgm_Ae1mOdTYGhswvlRETlI-Ld75oKa_55LTA3lErsKRVMArt50JvVOFZ5fc62xZn0ED_38T39uLLRhHeDLl_iGjAAEBAgIAhwABAgUGCAmGAAEFBwoQRBEzd6oX"
}
}
The first steps in using the credential-bound pseudonym feature are for the holder to generate their secret prover_nym value, and then compute a commitment with proof for this value according to the "Commitment" operation from [ CFRG-Pseudonym-BBS-Signature ]. Example values and outputs of this procedure are shown below.
{
"proverNymHex": "5e2087638f71057ef108f83923189a71cea1f7c4b4ef69afb473c9a7074ddf49"
}
{
"secretProverBlind": "2df3cd3d451b21069b72269f9984df449219c41273b19b1a8487d836fbb8baa1",
"commitmentWithProof": "a80f61f9470cb8ab88644fbef3616eaf5d3b147c4dc1dcad810148a5f2e73186cb3ffa27ea55728a6df470d0c3928be1408b95f5d261cee4d66992ecacf5ca2d6348c33bb7f90c2cef513cdc88be536550e9701d9a466320f49ce097551f8097317c530e2b80710748362b03f5a74280669c00eb29145eb3ec51975d8189fdf2c810d7fadefe36f93b0d2068a494175c"
}
The prover_nym and secretProverBlind are to be retained and kept secret by the holder. The commitmentWithProof value is to be communicated to the issuer.
The addition of a base proof under the pseudonym feature option begins with the issuer receiving a commitmentWithProof value from the holder and generating a cryptographically random value for signer_nym_entropy .
{
"signerNymEntropyHex": "25555cf635188a1c33989056f5129e6ab4be0e7c5cc588c48d308e0254eed140"
}
This example will make use of the same key material as shown in Example 27 , the same unsigned document as shown in Example 50 , and the same mandatory pointers as shown in Example 51 . This results in the same canonical document as shown in Example 52 , the same canonical HMAC document as shown in Example 53 , and the same "add base transformation" as shown in Example 54 .
This example makes use of the same proof configuration as in Example 55 . This results in the same canonical base proof as in Example 56 . Combining this with the above assumptions leads to the same base hashes as in Example 57 .
Since
featureOption
is
equal
to
"pseudonym"
,
the
procedure
of
section
3.4.5
Base
Proof
Serialization
(bbs-2023)
will
produce
the
output
shown
below.
This
makes
use
of
the
signature
generation
algorithm
of
[
CFRG-Pseudonym-BBS-Signature
].
Note
the
inclusion
of
the
signer_nym_entropy
and
featureOption
values,
as
these
need
to
be
communicated
to
the
holder.
{
"bbsSignature": "b9389149bab1b5a6032c20781732105a5cbc209592e712e182eec5c055f2072877683dee2949af32290d350ed9e9ffa246f65b8c3f6f199c4d29009d2ce6dff374ed4f22f2f9a7e12dc3c342e8c18107",
"bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb",
"publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"mandatoryPointers": [
"/issuer",
"/expirationDate"
],
"signerNymEntropyHex": "25555cf635188a1c33989056f5129e6ab4be0e7c5cc588c48d308e0254eed140",
"featureOption": "pseudonym"
}
Finally,
the
values
above
are
run
through
the
algorithm
of
section
3.3.1
serializeBaseProofValue
,
producing
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": "u2V0IhlhQuTiRSbqxtaYDLCB4FzIQWly8IJWS5xLhgu7FwFXyByh3aD3uKUmvMikNNQ7Z6f-iRvZbjD9vGZxNKQCdLObf83TtTyLy-afhLcPDQujBgQdYQDpbvyXTTZCxjDXNI1e-am9CMB6U_J5S936Tt3PFYUvfjuoRLATYnhM4gPlnZuuuc2k_dfG7y7qkc9wGJUvexPtYYKTvGvo9pXVJbxIrm3i4wkdhUxqKCTIGrnxFuAdZwWi6T3omD5wzZ7bAGbRneEEQSxBmXtvnC6Pr59nPv_v3HrAW9wq_uxYzF_NyaX3GPv0h_FV2T2OSao8C6uoyWiqIj1ggABEiM0RVZneImaq7zN3u_wARIjNEVWZ3iJmqu8zd7v-CZy9pc3N1ZXJvL2V4cGlyYXRpb25EYXRlwlggJVVc9jUYihwzmJBW9RKearS-DnxcxYjEjTCOAlTu0UA"
}
}
As explained in section A.1.2 Derived Proof , we used a mocked random number generation procedure to 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 from Example 72 , above. The first step is to run the algorithm of Section 3.3.2 parseBaseProofValue to recover bbsSignature , bbsHeader , publicKey , hmacKey , mandatoryPointers , signer_nym_entropy , and featureOption , as shown below.
{
"bbsSignature": "b9389149bab1b5a6032c20781732105a5cbc209592e712e182eec5c055f2072877683dee2949af32290d350ed9e9ffa246f65b8c3f6f199c4d29009d2ce6dff374ed4f22f2f9a7e12dc3c342e8c18107",
"bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb",
"publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"mandatoryPointers": [
"/issuer",
"/expirationDate"
],
"signerNymEntropy": "25555cf635188a1c33989056f5129e6ab4be0e7c5cc588c48d308e0254eed140",
"featureOption": "pseudonym"
}
Next, the holder uses the the "Verification and Finalization" operation from [ CFRG-Pseudonym-BBS-Signature ] to both verify the signature and compute the nym_secret value. This operation uses the prover_nym , signer_nym_entropy , and secret_prover_blind values, amongst others.
{
"nymSecretHex": "f883d069aec1252f167b0880e8960d72fa2623e11b6967541a457aa5c3cb088"
}
Next, the holder needs to indicate what non-mandatory statements, if any, 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 62 . This results in the same revealDocument as shown in Example 63 .
Running 3.3.3 createDisclosureData yields the same information for derived group indexes as shown in Example 64 and the same adjusted mandatory and selective indexes as shown in Example 65 .
Within 3.3.3 createDisclosureData , we compute the pseudonym based on the same verfifier_id shown in . The final output of 3.3.3 createDisclosureData is shown below. Note the inclusion of the featureOption and computed pseudonym values.
{
"bbsProof":"b394693d54d67937aae0e4175ecf4331200c23470171188ac5513b30d27d9bd2e06173d44e1aca7c743ba30b3f59af0595965bf8256437bce6bef824fe243183af6aa14a1e8224ed7e4eeb16445594df13a46e75d8dfbae0a3e2e1e0871260e68f71de7be4309eb53523a446b8189446b8d5c60892bdd855b5067e0433b46d5b9ffc4dc54b712ff97ec9d7c44cff648929d826bf9e3a7f873c9bcd07c6a3747fc6befceaf892c4d8d38d385c19c399ab342a76c000a3ff9050fa9223e20acfdf4404f43605a24c44622ebcaaf144b161226a6cbe7c08474f9fb80a736be3a818e4e62aa738e701007871859bea36e062324ff3afd8670a5de8b69911fae58aa40e48e29a046c37b9f9cc3868c30482d2339746955c3deaf6f1d4c8cf8be8e503f3ea4715d11e385eb7ed9de6379b7de8436a4e89cf4427d53358b1882e27c6e1e3ba2e81cf10fbc792cf3461a0fdd63f35a151b8c8350505a9b6d612e9adc1dca11b2698a3d0a9f0df6e9bc0ece7aa462afab02d93a87fd5bebb0eee058770c81c5f2fe6eeefcb0a657d9f116b96e2b04b4cc7f4baad4fe784bd9563aea20272138f2dbe94a5e25d30633b5f83eac4b42af25f144bddb631738bf3d54206e8d8b5172c8d52d3c272f799b782c73d480e1289e262ddbb70ab29491cf85a8428c4672437677407524a6dacb53332565dab5d056dbc5451becb123f91d173f6a7c785b7d9f19c43864a785bd941db248322539a097e9ac06244308a3b8df88b5213724cf09715b09e06425448c400680b943ba4711f14a719920b06ec2c6aff908ecf4f5793afd233d270a5ef92131606035517a89e4118dc65dbeb9051f92797036f54f8400910fa56cdd7b87b122e39e41233ea493239fab55c4c836a0a38732a68e6a9f9e11d32b991599e19edbb386f0d364b91e10dd9bf82898f79e90045a0c4987a0cf365d37d8380539a794284841c50c83f2bc3ee9cf7432f44dbfca897ff99feabf224e51137313630c5000d39429d9ea69a2a8237fe3a1857121c14ebb00d57b90db39e2e11bfa37858187d183027c45e317a72e5334681de26788e3176bd48d5761d54c1f2af0a6c3549a0de05b21d0a066c732a540072ae7676b867027b18323e08fcbfaf38ec22aeccd3375bb7b6965d9f6ab3ac4adc2a0700a4bc82fe58afbdd035af48fb85fcd8bf14f81d5ca3f2626be8962cbea13da31ff3cc6c6ebfeeef42f25708af872a14019f83",
"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":"838607ff2c8dcb2a0740ef13c2c87418efb57559243232a69daf1e294dd092af833ad4df1e99e0034c737b932916f378",
"featureOption":"pseudonym",
"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": "u2V0Jh1kDcLOUaT1U1nk3quDkF17PQzEgDCNHAXEYisVROzDSfZvS4GFz1E4aynx0O6MLP1mvBZWWW_glZDe85r74JP4kMYOvaqFKHoIk7X5O6xZEVZTfE6RuddjfuuCj4uHghxJg5o9x3nvkMJ61NSOkRrgYlEa41cYIkr3YVbUGfgQztG1bn_xNxUtxL_l-ydfETP9kiSnYJr-eOn-HPJvNB8ajdH_Gvvzq-JLE2NONOFwZw5mrNCp2wACj_5BQ-pIj4grP30QE9DYFokxEYi68qvFEsWEiamy-fAhHT5-4CnNr46gY5OYqpzjnAQB4cYWb6jbgYjJP86_YZwpd6LaZEfrliqQOSOKaBGw3ufnMOGjDBILSM5dGlVw96vbx1MjPi-jlA_PqRxXRHjhet-2d5jebfehDak6Jz0Qn1TNYsYguJ8bh47ougc8Q-8eSzzRhoP3WPzWhUbjINQUFqbbWEumtwdyhGyaYo9Cp8N9um8Ds56pGKvqwLZOof9W-uw7uBYdwyBxfL-bu78sKZX2fEWuW4rBLTMf0uq1P54S9lWOuogJyE48tvpSl4l0wYztfg-rEtCryXxRL3bYxc4vz1UIG6Ni1FyyNUtPCcveZt4LHPUgOEoniYt27cKspSRz4WoQoxGckN2d0B1JKbay1MzJWXatdBW28VFG-yxI_kdFz9qfHhbfZ8ZxDhkp4W9lB2ySDIlOaCX6awGJEMIo7jfiLUhNyTPCXFbCeBkJUSMQAaAuUO6RxHxSnGZILBuwsav-Qjs9PV5Ov0jPScKXvkhMWBgNVF6ieQRjcZdvrkFH5J5cDb1T4QAkQ-lbN17h7Ei455BIz6kkyOfq1XEyDago4cypo5qn54R0yuZFZnhntuzhvDTZLkeEN2b-CiY956QBFoMSYegzzZdN9g4BTmnlChIQcUMg_K8PunPdDL0Tb_KiX_5n-q_Ik5RE3MTYwxQANOUKdnqaaKoI3_joYVxIcFOuwDVe5DbOeLhG_o3hYGH0YMCfEXjF6cuUzRoHeJniOMXa9SNV2HVTB8q8KbDVJoN4Fsh0KBmxzKlQAcq52drhnAnsYMj4I_L-vOOwirszTN1u3tpZdn2qzrErcKgcApLyC_livvdA1r0j7hfzYvxT4HVyj8mJr6JYsvqE9ox_zzGxuv-7vQvJXCK-HKhQBn4OjAAEBAgIAhwABAgUGCAmGAAEFBwoQRBEzd6pYMIOGB_8sjcsqB0DvE8LIdBjvtXVZJDIypp2vHilN0JKvgzrU3x6Z4ANMc3uTKRbzeBc"
}
}
The first steps in using the holder binding and pseudonym feature are for the holder to generate its holder_secret and prover_nym values, and then compute a commitment with proof for these values, according to the "Commitment" operation from [ CFRG-Pseudonym-BBS-Signature ]. Example values and outputs of this procedure are shown below.
{
"holderSecretHex": "8fc6cc3f65db4ba5e3ed63fe9d2bd57a9c7df9c7f6bf2b898b308d5493b07eb6"
}
{
"proverNymHex": "5e2087638f71057ef108f83923189a71cea1f7c4b4ef69afb473c9a7074ddf49"
}
{
"secretProverBlind": "0d215067232c77c94a7572eb80794592090da8aff35cca53d2d528d059e70fce",
"commitmentWithProof": "ab72f3e6d7a4185d100ede6ce7dde1c69db9a2128ad11d1b6991a018c340ca2672d7be636f153398be50f44ee434edf14322dd115f7527e770a0f0c41d8aeb2088d004f2703548db6ce15e2505368a1f686f20702aa9ff46bce301330ea0c4c16ef4d8bbf624064a60df3a563142d7b236cad6cf6bcf1f3694d0bf4c2b5ffce55bb26abc05e31f9aaf8b60674fefe02666f89c150c479694f4a89a9088b28a1e6e2cf0c2caaa01810d2e3a52853f3a2a"
}
The holder_secret , prover_nym , and secretProverBlind need to be retained and kept secret by the holder. The commitmentWithProof value needs to be communicated to the issuer.
The addition of a base proof under the pseudonym feature option begins with the issuer receiving a commitmentWithProof value from the holder and generating a cryptographically random value for signer_nym_entropy .
{
"signerNymEntropyHex": "25555cf635188a1c33989056f5129e6ab4be0e7c5cc588c48d308e0254eed140"
}
This example will make use of the same key material as shown in Example 27 , and the same unsigned document as shown in Example 50 , and the same mandatory pointers as shown in Example 51 . This results in the same canonical document as shown in Example 52 , the same canonical HMAC document as shown in Example 53 , and the same "add base transformation" as shown in Example 54 .
This example makes use of the same proof configuration as in Example 55 . This results in the same canonical base proof as in Example 56 . Combining this with the above assumptions leads to the same base hashes as in Example 57 .
Since
featureOption
is
equal
to
"holder_binding_pseudonym"
,
the
procedure
of
section
3.4.5
Base
Proof
Serialization
(bbs-2023)
will
produce
the
output
shown
below.
This
makes
use
of
the
signature
generation
algorithm
of
[
CFRG-Pseudonym-BBS-Signature
].
Note
the
inclusion
of
the
signer_nym_entropy
and
featureOption
values,
as
these
need
to
be
communicated
to
the
holder.
{
"bbsSignature": "9251f497cb002c19f959a760fa24c5e961df9cb8ff5fbaaef14f2b7f1f41649990c30bd8c1d373e878a5d120123d658a326141275eee7833352d611cc1c05175c9c0f0ddeb0fdec09ad1bfad8796e410",
"bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb",
"publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"mandatoryPointers": [
"/issuer",
"/expirationDate"
],
"signerNymEntropyHex": "25555cf635188a1c33989056f5129e6ab4be0e7c5cc588c48d308e0254eed140",
"featureOption": "holder_binding_pseudonym"
}
Finally,
the
values
above
are
run
through
the
algorithm
of
section
3.3.1
serializeBaseProofValue
,
producing
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": "u2V0IhlhQklH0l8sALBn5Wadg-iTF6WHfnLj_X7qu8U8rfx9BZJmQwwvYwdNz6Hil0SASPWWKMmFBJ17ueDM1LWEcwcBRdcnA8N3rD97AmtG_rYeW5BBYQDpbvyXTTZCxjDXNI1e-am9CMB6U_J5S936Tt3PFYUvfjuoRLATYnhM4gPlnZuuuc2k_dfG7y7qkc9wGJUvexPtYYKTvGvo9pXVJbxIrm3i4wkdhUxqKCTIGrnxFuAdZwWi6T3omD5wzZ7bAGbRneEEQSxBmXtvnC6Pr59nPv_v3HrAW9wq_uxYzF_NyaX3GPv0h_FV2T2OSao8C6uoyWiqIj1ggABEiM0RVZneImaq7zN3u_wARIjNEVWZ3iJmqu8zd7v-CZy9pc3N1ZXJvL2V4cGlyYXRpb25EYXRlwlggJVVc9jUYihwzmJBW9RKearS-DnxcxYjEjTCOAlTu0UA"
}
}
As explained in section A.1.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 from Example 72 , above. The first step is to run the algorithm of Section 3.3.2 parseBaseProofValue to recover bbsSignature , bbsHeader , publicKey , hmacKey , mandatoryPointers , signer_nym_entropy , and featureOption , as shown below.
{
"bbsSignature": "9251f497cb002c19f959a760fa24c5e961df9cb8ff5fbaaef14f2b7f1f41649990c30bd8c1d373e878a5d120123d658a326141275eee7833352d611cc1c05175c9c0f0ddeb0fdec09ad1bfad8796e410",
"bbsHeader": "3a5bbf25d34d90b18c35cd2357be6a6f42301e94fc9e52f77e93b773c5614bdf8eea112c04d89e133880f96766ebae73693f75f1bbcbbaa473dc06254bdec4fb",
"publicKey": "a4ef1afa3da575496f122b9b78b8c24761531a8a093206ae7c45b80759c168ba4f7a260f9c3367b6c019b4677841104b10665edbe70ba3ebe7d9cfbffbf71eb016f70abfbb163317f372697dc63efd21fc55764f63926a8f02eaea325a2a888f",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"mandatoryPointers": [
"/issuer",
"/expirationDate"
],
"signerNymEntropy": "25555cf635188a1c33989056f5129e6ab4be0e7c5cc588c48d308e0254eed140",
"featureOption": "holder_binding_pseudonym"
}
Next, the holder uses the the "Verification and Finalization" operation from [ CFRG-Pseudonym-BBS-Signature ] to both verify the signature and compute the nym_secret value. This operation uses the holder_secret , prover_nym , signer_nym_entropy , and secret_prover_blind values, amongst others.
{"nymSecretHex":"f883d069aec1252f167b0880e8960d72fa2623e11b6967541a457aa5c3cb088"}
Next, the holder needs to indicate what non-mandatory statements, if any, 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 62 . This results in the same revealDocument as shown in Example 63 .
Running 3.3.3 createDisclosureData yields the same information for derived group indexes as shown in Example 64 and the same adjusted mandatory and selective indexes as shown in Example 65 .
Within 3.3.3 createDisclosureData , we compute the pseudonym based on the same verfifier_id shown in . The final output of 3.3.3 createDisclosureData is shown below. Note the inclusion of the the featureOption and computed pseudonym values.
{
"bbsProof":"94752c678297191b42617aca412377d4a5b3d7872779ffea31e0b418f50e95056d923a97e8dc156edc2a3a3a54e7b27cafa26a989fc3e8a8bc7a08b84e706a1863bd06c396b973b1af0da4f6c20ea463e124d2ad97060a25ccc3ff695c71977ba2e83a6468205d9e0bfb756089ad40dededab480eeb13cf00265f49824c5f89e23ac48d07fa3164823741df5c066bdc31a231a7d4fecb75c912adb800b1efe8da3cd26805ffa56775b1c32da34e36e9716a4da909fa6803ca0aa2df2d82f697229ccb210503274d4d61c7386a44e9fb459c020fbcd62c7f437da8ffd5ea7e56d2c4e7d9c3f593b2a964346f24f71bec30a2c3ededa0bd3707e2e06cac2dddb66762135a229dc09b67fa61d690d33be78150bc60f3655ac1063f96d6fe95a260004c7bf9e924cc7439c6426f951d0cee963985557097788d2387b72c9aeb390f9a4fa4b519bc11ca81dfca8a4fd3c77805e1a0ef5c165b16c3cdc564e7a5593f0ddd0560f3514393c1b305d3950c29fbb72cc8b58979843cec768e9a77b14f70704771f877c49fc0d0d4ffbe3f0aaf8e472a83b14e32e46207d5012e79b9bcfc6197c858eb18ad97f589dddb5dc45e9ef65f482d3c07fbcbfef92bf293643539fffc94a8bc98b3b4dd3335bb8b248aa606a751330516f148211d5f2d513e02d45ec5a51add1f878948a673a0349d7cb4417b1f9c16945e1f607bdecf6ca3b96a64fb14ee1fc5dbecf751be23041df32842367285f2b3b02c13512c28c0e7671874699b9ff169e35f91debc796fd487d3e41dcc5f12949558f2705be3e8195d4c93a6c149dcb5f63e62d3ce0bf51034021251b74ed2a1186fd77741ce3bf51f57f19a9d4a9e6315a88024062269a9fec426a73199882113168573da451ca38aeacf28f7eef3892181f0bc511562fba00d035f608c4f85579fc9614618763fa4e6c2210184e12f83e1c22078dd4ca488de41dbf2c146a2e0c47137be7f006c6810f44746a819229349b50ca59a51f7c51bb62cacc1a1cc4a6f089680514d41800da57470ef275f390eb4a08db78789e71bd32bd8929961c9f79d1ca071a2608a393f162c2f644584473f11b41cc35c838f11fbd2adf47051829d378ac9dc151e64bc70cd21b2ea6bca3f77b9c2b35abcebb0ecbf1c09365a8e372a2fce74b97088c9e9505c5c0272a4d6959bec54911a99b6c8a1654395f0cd4e7d38d695ab45875ecc535439dde3fb3d4658d9ff9427d8e36d7bd19ea53fb875c4b138f6ffc06bfd496b1a744a63283ebc0fa34ea828d98",
"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":"838607ff2c8dcb2a0740ef13c2c87418efb57559243232a69daf1e294dd092af833ad4df1e99e0034c737b932916f378",
"featureOption":"holder_binding_pseudonym",
"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": "u2V0Jh1kDkJR1LGeClxkbQmF6ykEjd9Sls9eHJ3n_6jHgtBj1DpUFbZI6l-jcFW7cKjo6VOeyfK-iapifw-iovHoIuE5wahhjvQbDlrlzsa8NpPbCDqRj4STSrZcGCiXMw_9pXHGXe6LoOmRoIF2eC_t1YImtQN7e2rSA7rE88AJl9JgkxfieI6xI0H-jFkgjdB31wGa9wxojGn1P7LdckSrbgAse_o2jzSaAX_pWd1scMto0426XFqTakJ-mgDygqi3y2C9pcinMshBQMnTU1hxzhqROn7RZwCD7zWLH9Dfaj_1ep-VtLE59nD9ZOyqWQ0byT3G-wwosPt7aC9Nwfi4GysLd22Z2ITWiKdwJtn-mHWkNM754FQvGDzZVrBBj-W1v6VomAATHv56STMdDnGQm-VHQzuljmFVXCXeI0jh7csmus5D5pPpLUZvBHKgd_Kik_Tx3gF4aDvXBZbFsPNxWTnpVk_Dd0FYPNRQ5PBswXTlQwp-7csyLWJeYQ87HaOmnexT3BwR3H4d8SfwNDU_74_Cq-ORyqDsU4y5GIH1QEuebm8_GGXyFjrGK2X9Ynd213EXp72X0gtPAf7y_75K_KTZDU5__yUqLyYs7TdMzW7iySKpganUTMFFvFIIR1fLVE-AtRexaUa3R-HiUimc6A0nXy0QXsfnBaUXh9ge97PbKO5amT7FO4fxdvs91G-IwQd8yhCNnKF8rOwLBNRLCjA52cYdGmbn_Fp41-R3rx5b9SH0-QdzF8SlJVY8nBb4-gZXUyTpsFJ3LX2PmLTzgv1EDQCElG3TtKhGG_Xd0HOO_UfV_GanUqeYxWogCQGImmp_sQmpzGZiCETFoVz2kUco4rqzyj37vOJIYHwvFEVYvugDQNfYIxPhVefyWFGGHY_pObCIQGE4S-D4cIgeN1MpIjeQdvywUai4MRxN75_AGxoEPRHRqgZIpNJtQylmlH3xRu2LKzBocxKbwiWgFFNQYANpXRw7ydfOQ60oI23h4nnG9Mr2JKZYcn3nRygcaJgijk_FiwvZEWERz8RtBzDXIOPEfvSrfRwUYKdN4rJ3BUeZLxwzSGy6mvKP3e5wrNavOuw7L8cCTZajjcqL850uXCIyelQXFwCcqTWlZvsVJEambbIoWVDlfDNTn041pWrRYdezFNUOd3j-z1GWNn_lCfY42170Z6lP7h1xLE49v_Aa_1Jaxp0SmMoPrwPo06oKNmKMAAQECAgCHAAECBQYICYYAAQUHChBEETN3qlgwg4YH_yyNyyoHQO8Twsh0GO-1dVkkMjKmna8eKU3Qkq-DOtTfHpngA0xze5MpFvN4Fw"
}
}
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, 70RSAT24T00000011, 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.