Copyright © 2025 World Wide Web Consortium . W3C ® liability , trademark and permissive document license rules apply.
This specification describes Data Integrity cryptosuites for use when generating a digital signature using the Elliptic Curve Digital Signature Algorithm (ECDSA).
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 at https://www.w3.org/TR/.
This document was published by the Verifiable Credentials Working Group as a Proposed Recommendation using the Recommendation track .
Publication as a Proposed Recommendation does not imply endorsement by W3C and its Members.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
The W3C Membership and other interested parties are invited to review the document and send comments through 17 April 2025. Advisory Committee Representatives should consult their WBS questionnaires . Note that substantive technical comments were expected during the Candidate Recommendation review period that ended 19 January 2025.
This document was produced by a group operating under the W3C Patent Policy . W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy .
This document is governed by the 03 November 2023 W3C Process Document .
This specification defines a cryptographic suite for the purpose of creating, and verifying proofs for ECDSA signatures in conformance with the Data Integrity [ VC-DATA-INTEGRITY ] specification. ECDSA signatures are specified in [ FIPS-186-5 ] with elliptic curves P-256 and P-384 specified in [ NIST-SP-800-186 ]. [ FIPS-186-5 ] includes the deterministic ECDSA algorithm which is also specified in [ RFC6979 ].
The elliptic curves P-256 and P-384 of [ NIST-SP-800-186 ] are respectively referred to as secp256r1 and secp384r1 in [ SECG2 ]. This notation is sometimes also used by ECDSA software libraries.
Developers are cautioned to not confuse secp256 r 1 terms with secp256 k 1 terms; the latter are from a third, different , elliptic curve, that is not used by this specification. ECDSA software libraries might not implement all of these curves, so developers need to take care when choosing an ECDSA software library for their implementation.
This specification uses either the RDF Dataset Canonicalization Algorithm [ RDF-CANON ] or the JSON Canonicalization Scheme [ RFC8785 ] to transform the input document into its canonical form. It uses one of two mechanisms to digest and sign: SHA-256 [ RFC6234 ] as the message digest algorithm and ECDSA with Curve P-256 as the signature algorithm, or SHA-384 [ RFC6234 ] as the message digest algorithm and ECDSA with Curve P-384 as the signature algorithm.
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 , 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 to express verification methods, such as cryptographic public keys, and data integrity proofs, such as digital signatures.
These verification methods are used to verify Data Integrity Proofs [ VC-DATA-INTEGRITY ] produced using Elliptic Curve cryptographic key material that is compliant with [ FIPS-186-5 ]. 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
P-256
or
P-384
public
key.
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
ECDSA
256-bit
public
key
value
or
an
ECDSA
384-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
0x1200
or
0x1201
being
used
in
a
publicKeyMultibase
value.
{
"id": "https://example.com/issuer/123#key-0",
"type": "Multikey",
"controller": "https://example.com/issuer/123",
"publicKeyMultibase": "zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv"
}
{
"id": "https://example.com/issuer/123#key-0",
"type": "Multikey",
"controller": "https://example.com/issuer/123",
"publicKeyMultibase": "z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJ
Uz2sG9FE42shbn2xkZJh54"
}
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1"
],
"id": "did:example:123",
"verificationMethod": [{
"id": "https://example.com/issuer/123#key-1",
"type": "Multikey",
"controller": "https://example.com/issuer/123",
"publicKeyMultibase": "zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv"
}, {
"id": "https://example.com/issuer/123#key-2",
"type": "Multikey",
"controller": "https://example.com/issuer/123",
"publicKeyMultibase": "z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJ
Uz2sG9FE42shbn2xkZJh54"
}],
"authentication": [
"did:example:123#key-1"
],
"assertionMethod": [
"did:example:123#key-2"
],
"capabilityDelegation": [
"did:example:123#key-2"
],
"capabilityInvocation": [
"did:example:123#key-2"
]
}
The
secretKeyMultibase
property
represents
a
Multibase-encoded
Multikey
expression
of
a
P-256
or
P-384
secret
key
(also
sometimes
referred
to
as
a
private
key).
The
secretKeyMultibase
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
ECDSA
256-bit
secret
key
value
or
an
ECDSA
384-bit
secret
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
prevent
accidental
publication
of
a
representation
of
a
secret
key,
and
to
not
export
the
secretKeyMultibase
property
by
default,
when
serializing
key
pairs
as
Multikey.
This section details the proof representation formats that are defined by this specification.
A proof contains the attributes specified in the Proofs section of [ VC-DATA-INTEGRITY ] with the following restrictions.
The
type
property
MUST
be
DataIntegrityProof
.
The
cryptosuite
property
MUST
be
ecdsa-rdfc-2019
,
ecdsa-jcs-2019
,
or
ecdsa-sd-2023
.
The
value
of
the
proofValue
property
is
produced
according
to
the
cryptosuite
type
and
is
specified
in
either
Section
3.2.1
Create
Proof
(ecdsa-rdfc-2019)
,
or
Section
3.3.1
Create
Proof
(ecdsa-jcs-2019)
,
or
Section
3.6.1
Create
Base
Proof
(ecdsa-sd-2023)
,
or
Section
3.6.6
Add
Derived
Proof
(ecdsa-sd-2023)
.
{
"@context": [
{"myWebsite": "https://vocabulary.example/myWebsite"},
"https://www.w3.org/ns/credentials/v2"
],
"myWebsite": "https://hello.world.example/",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "https://vc.example/issuers/5678#zDnaepBuvsQ8cpsWrVKw8
fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"proofValue": "z2iAR3F2Sk3mWfYyrinKzSQpSbvfxnz9kkv7roxxumB5RZDP9JUw5QAXuchUd
huiwE18hyyZTjiEreKmhH3oj9Q8"
}
}
The following section describes multiple Data Integrity cryptographic suites that utilize the Elliptic Curve Digital Signature Algorithm (ECDSA) [ FIPS-186-5 ]. When generating ECDSA signatures, the signature value MUST be expressed according to section 7 of [ RFC4754 ] (sometimes referred to as the IEEE P1363 format) and encoded according to the specific cryptosuite proof generation algorithm. All ECDSA signatures SHOULD use the deterministic variant of the algorithm defined in [ FIPS-186-5 ].
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 (RDFC-1.0) [ RDF-CANON ] is used with ECDSA algorithms, the cryptographic hashing function used by RDFC-1.0 is chosen based on the size of the associated public key. For P-256 keys, the default hashing function, SHA-2 with 256 bits of output, MUST be used. For P-384 keys, SHA-2 with 384-bits of output MUST be used, specified via the RDFC-1.0 implementation-specific parameter .
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
.
ecdsa-rdfc-2019
then:
ecdsa-jcs-2019
then:
ecdsa-sd-2023
then:
The
ecdsa-rdfc-2019
cryptographic
suite
takes
an
input
document,
canonicalizes
the
document
using
the
RDF
Dataset
Canonicalization
[
RDF-CANON
],
and
then
cryptographically
hashes
and
signs
the
output
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 ), and a set of proof options ( map options ). A data integrity proof ( map ), or an error, is produced as output.
The following algorithm specifies how to verify a data integrity proof given an secured data document . Required inputs are an 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
proof
value
removed.
proofValue
removed.
true
,
otherwise
Null
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.2.4 Hashing (ecdsa-rdfc-2019) .
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 ) and a cryptosuite identifier ( cryptosuite ). A transformed data document is produced as output. Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.
DataIntegrityProof
and
options
.
cryptosuite
is
not
set
to
the
string
ecdsa-rdfc-2019
,
an
error
MUST
be
raised
and
SHOULD
convey
an
error
type
of
PROOF_TRANSFORMATION_ERROR
.
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.2.6 Proof Serialization (ecdsa-rdfc-2019) or Section 3.2.7 Proof Verification (ecdsa-rdfc-2019) . One must use the hash algorithm appropriate in security level to the curve used, i.e., for curve P-256 one uses SHA-256 and for curve P-384 one uses SHA-384.
The required inputs to this algorithm are a transformed data document ( transformedDocument ) and canonical proof configuration ( canonicalProofConfig ). A single hash data value represented as series of bytes is produced as output.
The following algorithm specifies how to generate a proof configuration from a set of proof options that is used as input to the proof hashing algorithm .
The required inputs to this algorithm are proof options ( options ). The proof options MUST contain a type identifier for the cryptographic suite ( type ) and MUST contain a cryptosuite identifier ( cryptosuite ). A proof configuration object is produced as output.
DataIntegrityProof
and/or
proofConfig
.
cryptosuite
is
not
set
to
ecdsa-rdfc-2019
,
an
error
MUST
be
raised
and
SHOULD
convey
an
error
type
of
PROOF_GENERATION_ERROR
.
The following algorithm specifies how to serialize a digital signature from a set of cryptographic hash data. 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 ) and proof options ( options ). The proof options MUST contain a type identifier for the cryptographic suite ( type ) and MAY contain a cryptosuite identifier ( cryptosuite ). A single digital proof value represented as series of bytes is produced as output.
The following algorithm specifies how to verify a digital signature from a set of cryptographic hash data. 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 ), a digital signature ( proofBytes ) and proof options ( options ). A verification result represented as a boolean value is produced as output.
The
ecdsa-jcs-2019
cryptographic
suite
takes
an
input
document,
canonicalizes
the
document
using
the
JSON
Canonicalization
Scheme
[
RFC8785
],
and
then
cryptographically
hashes
and
signs
the
output
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 ), and a set of proof options ( map options ). A data integrity proof ( map ), or an error, is produced as output.
The following algorithm specifies how to verify a data integrity proof given an secured data document . Required inputs are an secured data document ( map securedDocument ). This algorithm returns a verification result , which is a struct whose items are:
true
or
false
true
,
an
unsecured
data
document
;
otherwise
Null
proof
value
removed.
proofValue
removed.
false
and
skip
to
the
last
step.
true
,
unsecuredDocument
;
otherwise,
Null
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.3.4 Hashing (ecdsa-jcs-2019) .
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 ) and a cryptosuite identifier ( cryptosuite ). A transformed data document is produced as output. Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.
DataIntegrityProof
or
options
.
cryptosuite
is
not
set
to
the
string
ecdsa-jcs-2019
,
an
error
MUST
be
raised
and
SHOULD
convey
an
error
type
of
PROOF_TRANSFORMATION_ERROR
.
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.3.6 Proof Serialization (ecdsa-jcs-2019) or Section 3.3.7 Proof Verification (ecdsa-jcs-2019) . One must use the hash algorithm appropriate in security level to the curve used, i.e., for curve P-256 one uses SHA-256, and for curve P-384 one uses SHA-384.
The required inputs to this algorithm are a transformed data document ( transformedDocument ) and a canonical proof configuration ( canonicalProofConfig ). A single hash data value represented as series of bytes is produced as output.
The following algorithm specifies how to generate a proof configuration from a set of proof options that is used as input to the proof hashing algorithm .
The required inputs to this algorithm are the proof options ( options ). The proof options MUST contain a type identifier for the cryptographic suite ( type ) and MUST contain a cryptosuite identifier ( cryptosuite ). A proof configuration object is produced as output.
DataIntegrityProof
and/or
proofConfig
.
cryptosuite
is
not
set
to
ecdsa-jcs-2019
,
an
error
MUST
be
raised
and
SHOULD
convey
an
error
type
of
PROOF_GENERATION_ERROR
.
The following algorithm specifies how to serialize a digital signature from a set of cryptographic hash data. 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 ) and proof options ( options ). The proof options MUST contain a type identifier for the cryptographic suite ( type ) and MAY contain a cryptosuite identifier ( cryptosuite ). A single digital proof value represented as series of bytes is produced as output.
The following algorithm specifies how to verify a digital signature from a set of cryptographic hash data. 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 ), a digital signature ( proofBytes ), and proof options ( options ). A verification result represented as a boolean value is produced as output.
The following section contains a set of functions that are used throughout cryptographic suites that perform selective disclosure.
The following algorithm canonicalizes an array of N-Quad [ N-QUADS ] strings and replaces any blank node identifiers in the canonicalized result using a label map factory function, labelMapFactoryFunction . The required inputs are an array of N-Quad strings ( nquads ), and a label map factory function ( labelMapFactoryFunction ). Any custom options can also be passed. An N-Quads representation of the canonicalNQuads as an array of N-Quad strings, with the replaced blank node labels, and a map from the old blank node IDs to the new blank node IDs, labelMap , is produced as output.
The following algorithm canonicalizes a JSON-LD document and replaces any blank node identifiers in the canonicalized result using a label map factory function, labelMapFactoryFunction . The required inputs are a JSON-LD document ( document ) and a label map factory function ( labelMapFactoryFunction ). Additional custom options (such as a document loader) can also be passed. An N-Quads representation of the canonicalNQuads as an array of N-Quad strings, with the replaced blank node labels, and a map from the old blank node IDs to the new blank node IDs, labelMap , is produced as output.
The following algorithm creates a label map factory function that uses an input label map to replace canonical blank node identifiers with another value. The required input is a label map, labelMap . A function, labelMapFactoryFunction , is produced as output.
The following algorithm creates a label map factory function that uses an HMAC to replace canonical blank node identifiers with their encoded HMAC digests. The required input is an HMAC (previously initialized with a secret key), HMAC . A function, labelMapFactoryFunction , is produced as output.
A different primitive could be created that returned a label map factory function that would instead sort the resulting HMAC digests and assign labels in the produced label map using a prefix and integers based on their sorted order. This primitive might be useful for selective disclosure schemes, such as BBS, that favor unlinkability over minimizing unrevealed data leakage.
The following algorithm replaces all blank node identifiers in an array of N-Quad strings with custom scheme URNs. The required inputs are an array of N-Quad strings ( inputNQuads ) and a URN scheme ( urnScheme ). An array of N-Quad strings, skolemizedNQuads , is produced as output. This operation is intended to be reversible through the use of the algorithm in Section 3.4.6 deskolemizeNQuads .
s1.replace(/(_:([^\s]+))/g,
'<urn:custom-scheme:$2>')
.
The following algorithm replaces all custom scheme URNs in an array of N-Quad statements with a blank node identifier. The required inputs are an array of N-Quad strings ( inputNQuads ) and a URN scheme ( urnScheme ). An array of N-Quad strings, deskolemizedNquads , is produced as output. This operation is intended to reverse use of the algorithm in Section 3.4.6 deskolemizeNQuads .
s1.replace(/(<urn:custom-scheme:([^>]+)>)/g,
'_:$2').
.
The following algorithm replaces all blank node identifiers in an expanded JSON-LD document with custom-scheme URNs, including assigning such URNs to blank nodes that are unlabeled. The required inputs are an expanded JSON-LD document ( expanded ), a custom URN scheme ( urnScheme ), a UUID string or other comparably random string ( randomString ), and reference to a shared integer ( count ). Any additional custom options (such as a document loader) can also be passed. It produces the expanded form of the skolemized JSON-LD document ( skolemizedExpandedDocument as output. The skolemization used in this operation is intended to be reversible through the use of the algorithm in Section 3.4.9 toDeskolemizedNQuads .
_:b0
,
the
blank
node
identifier
is
b0
).
The following algorithm replaces all blank node identifiers in a compact JSON-LD document with custom-scheme URNs. The required inputs are a compact JSON-LD document ( document ) and a custom URN scheme ( urnScheme ) which defaults to "custom-scheme:". The document is assumed to use only one @context property at the top level of the document. Any additional custom options (such as a document loader) can also be passed. It produces both an expanded form of the skolemized JSON-LD document ( skolemizedExpandedDocument and a compact form of the skolemized JSON-LD document ( skolemizedCompactDocument ) as output. The skolemization used in this operation is intended to be reversible through the use of the algorithm in Section 3.4.9 toDeskolemizedNQuads which uses the same custom URN scheme ( urnScheme ).
The following algorithm converts a skolemized JSON-LD document, such as one created using the algorithm in Section 3.4.8 skolemizeCompactJsonLd , to an array of deskolemized N-Quads. The required input is a JSON-LD document, skolemizedDocument . Additional custom options (such as a document loader) can be passed. An array of deskolemized N-Quad strings ( deskolemizedNQuads ) is produced as output.
The following algorithm converts a JSON Pointer [ RFC6901 ] to an array of paths into a JSON tree. The required input is a JSON Pointer string ( pointer ). An array of paths ( paths ) is produced as output.
pointer.split('/').slice(1)
~
,
then
add
path
to
paths
,
converting
it
to
an
integer
if
it
parses
as
one,
leaving
it
as
a
string
if
it
does
not.
The following algorithm creates an initial selection (a fragment of a JSON-LD document) based on a JSON-LD object. This is a helper function used within the algorithm in Section 3.4.13 selectJsonLd . The required input is a JSON-LD object ( source ). A JSON-LD document fragment object ( selection ) is produced as output.
id
that
is
not
a
blank
node
identifier,
set
selection
.
id
to
its
value.
Note:
All
non-blank
node
identifiers
in
the
path
of
any
JSON
Pointer
MUST
be
included
in
the
selection,
this
includes
any
root
document
identifier.
type
s
in
the
path
of
any
JSON
Pointer,
including
any
root
document
type
.
The following algorithm selects a portion of a compact JSON-LD document using paths parsed from a parsed JSON Pointer. This is a helper function used within the algorithm in Section 3.4.13 selectJsonLd . The required inputs are an array of paths ( paths ) parsed from a JSON Pointer, a compact JSON-LD document ( document ), a selection document ( selectionDocument ) to be populated, and an array of arrays ( arrays ) for tracking selected arrays. This algorithm produces no output; instead it populates the given selectionDocument with any values selected via paths .
{...selectedValue,
…deepCopy(value)}
.
The
following
algorithm
selects
a
portion
of
a
compact
JSON-LD
document
using
an
array
of
JSON
Pointers.
The
required
inputs
are
an
array
of
JSON
Pointers
(
pointers
)
and
a
compact
JSON-LD
document
(
document
).
The
document
is
assumed
to
use
a
JSON-LD
context
that
aliases
@id
and
@type
to
id
and
type
,
respectively,
and
to
use
only
one
@context
property
at
the
top
level
of
the
document.
A
new
JSON-LD
document
that
represents
a
selection
(
selectionDocument
)
of
the
original
JSON-LD
document
is
produced
as
output.
null
.
This
indicates
nothing
has
been
selected
from
the
original
document.
@context
property
in
selectionDocument
to
a
copy
of
the
value
of
the
@context
property
in
document
.
The following algorithm relabels the blank node identifiers in an array of N-Quad strings using a blank node label map. The required inputs are an array of N-Quad strings ( nquads ) and a blank node label map ( labelMap ). An array of N-Quad strings with relabeled blank node identifiers ( relabeledNQuads ) is produced as output.
The
following
algorithm
selects
a
portion
of
a
skolemized
compact
JSON-LD
document
using
an
array
of
JSON
Pointers,
and
outputs
the
resulting
canonical
N-Quads
with
any
blank
node
labels
replaced
using
the
given
label
map.
The
required
inputs
are
an
array
of
JSON
Pointers
(
pointers
),
a
skolemized
compact
JSON-LD
document
(
skolemizedCompactDocument
),
and
a
blank
node
label
map
(
labelMap
).
Additional
custom
options
(such
as
a
document
loader)
can
be
passed.
The
document
is
assumed
to
use
a
JSON-LD
context
that
aliases
@id
and
@type
to
id
and
type
,
respectively,
and
to
use
only
one
@context
property
at
the
top
level
of
the
document.
An
object
containing
the
new
JSON-LD
document
that
represents
a
selection
of
the
original
JSON-LD
document
(
selectionDocument
),
an
array
of
deskolemized
N-Quad
strings
(
deskolemizedNQuads
),
and
an
array
of
canonical
N-Quads
with
replacement
blank
node
labels
(
nquads
)
is
produced
as
output.
The following algorithm is used to output canonical N-Quad strings that match custom selections of a compact JSON-LD document. It does this by canonicalizing a compact JSON-LD document (replacing any blank node identifiers using a label map) and grouping the resulting canonical N-Quad strings according to the selection associated with each group. Each group will be defined using an assigned name and array of JSON pointers. The JSON pointers will be used to select portions of the skolemized document, such that the output can be converted to canonical N-Quads to perform group matching.
The
required
inputs
are
a
compact
JSON-LD
document
(
document
),
a
label
map
factory
function
(
labelMapFactoryFunction
),
and
a
map
of
named
group
definitions
(
groupDefinitions
).
Additional
custom
options
(such
as
a
document
loader)
can
be
passed.
The
document
is
assumed
to
use
a
JSON-LD
context
that
aliases
@id
and
@type
to
id
and
type
,
respectively,
and
to
use
only
one
@context
property
at
the
top
level
of
the
document.
An
object
containing
the
created
groups
(
groups
),
the
skolemized
compact
JSON-LD
document
(
skolemizedCompactDocument
),
the
skolemized
expanded
JSON-LD
document
(
skolemizedExpandedDocument
),
the
deskolemized
N-Quad
strings
(
deskolemizedNQuads
),
the
blank
node
label
map
(
labelMap
),
and
the
canonical
N-Quad
strings
nquads
,
is
produced
as
output.
The following algorithm cryptographically hashes an array of mandatory to disclose N-Quads using a provided hashing API. The required input is an array of mandatory to disclose N-Quads ( mandatory ) and a hashing function ( hasher ). A cryptographic hash ( mandatoryHash ) is produced as output.
bytes
to
the
UTF-8
representation
of
the
joined
mandatory
N-Quads.
mandatoryHash
to
the
result
of
using
hasher
to
hash
bytes
.
mandatoryHash
.
This
section
contains
subalgorithms
that
are
useful
to
the
ecdsa-sd-2023
cryptographic
suite.
The following algorithm serializes the data that is to be signed by the private key associated with the base proof verification method. The required inputs are the proof options hash ( proofHash ), the proof-scoped multikey-encoded public key ( publicKey ), and the mandatory hash ( mandatoryHash ). A single sign data value, represented as series of bytes, is produced as output.
The following algorithm serializes the base proof value, including the base signature, public key, HMAC key, signatures, and mandatory pointers. The required inputs are a base signature baseSignature , a public key publicKey , an HMAC key hmacKey , an array of signatures , and an array of mandatoryPointers . A single base proof string value is produced as output.
u
"
and
ending
with
the
base64url-no-pad-encoded
value
of
proofValue
.
The
following
algorithm
parses
the
components
of
an
ecdsa-sd-2023
selective
disclosure
base
proof
value.
The
required
inputs
are
a
proof
value
(
proofValue
).
A
single
object
parsed
base
proof
,
containing
five
elements,
using
the
names
baseSignature
,
publicKey
,
hmacKey
,
signatures
,
and
mandatoryPointers
,
is
produced
as
output.
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
0x00
,
an
error
MUST
be
raised
and
SHOULD
convey
an
error
type
of
PROOF_VERIFICATION_ERROR
.
baseSignature
,
publicKey
,
hmacKey
,
signatures
,
and
mandatoryPointers
,
respectively.
The following algorithm creates data to be used to generate a derived proof. The inputs include a JSON-LD document ( document ), an ECDSA-SD base proof ( proof ), an array of JSON pointers to use to selectively disclose statements ( selectivePointers ), and any custom JSON-LD API options, such as a document loader). A single object, disclosure data , is produced as output, which contains the "baseSignature", "publicKey", "signatures" for "filteredSignatures", "labelMap", "mandatoryIndexes", and "revealDocument" fields.
"mandatory"
and
value
of
mandatoryPointers
,
key
of
the
string
"selective"
and
value
of
selectivePointers
,
and
key
of
the
string
"combined"
and
value
of
combinedPointers
.
0
.
signatures
for
filteredSignatures
,
verifierLabelMap
for
labelMap
,
mandatoryIndexes
,
and
revealDocument
.
The following algorithm compresses a label map. The required inputs are label map ( labelMap ). The output is a 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 .
The following algorithm serializes a derived proof value. The required inputs are a base signature ( baseSignature ), public key ( publicKey ), an array of signatures ( signatures ), a label map ( labelMap ), and an array of mandatory indexes ( mandatoryIndexes ). A single derived proof value, serialized as a byte string, is produced as output.
0xd9
,
0x5d
,
and
0x01
.
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 value object is produced as output, which contains a set to five elements, using the names "baseSignature", "publicKey", "signatures", "labelMap", and "mandatoryIndexes".
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
0x01
,
an
error
MUST
be
raised
and
SHOULD
convey
an
error
type
of
PROOF_VERIFICATION_ERROR
.
The following algorithm creates the data needed to perform verification of an ECDSA-SD-protected verifiable credential . The inputs include a JSON-LD document ( document ), an ECDSA-SD 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: "baseSignature", "proofHash", "publicKey", "signatures", "nonMandatory", and "mandatoryHash".
The
ecdsa-sd-2023
cryptographic
suite
takes
an
input
document,
canonicalizes
the
document
using
the
RDF
Dataset
Canonicalization
[
RDF-CANON
],
and
then
cryptographically
hashes
and
signs
the
output
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 ), and a set of proof options ( map options ). A data integrity proof ( map ), or an error, is produced as output.
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.6.3 Base Proof Hashing (ecdsa-sd-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.
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.6.5 Base Proof Serialization (ecdsa-sd-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
and
mandatoryHash
as
mandatoryHash
to
that
object.
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
ecdsa-sd-2023
,
an
error
MUST
be
raised
and
SHOULD
convey
an
error
type
of
PROOF_GENERATION_ERROR
.
The following algorithm specifies how to create a base proof; called by an issuer of an ECDSA-SD-protected Verifiable Credential. 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 ) and proof options ( options ). The proof options MUST contain a type identifier for the cryptographic suite ( type ) and MAY contain a cryptosuite identifier ( cryptosuite ). A single digital proof value represented as series of bytes is produced as output.
2
for
an
even
y
coordinate
and
3
for
an
odd
one
followed
by
the
x
coordinate
of
the
public
key).
The
following
algorithm
creates
a
selective
disclosure
derived
proof;
called
by
a
holder
of
an
ecdsa-sd-2023
-protected
verifiable
credential
.
The
derived
proof
is
to
be
given
to
the
verifier
.
The
inputs
include
a
JSON-LD
document
(
document
),
an
ECDSA-SD
base
proof
(
proof
),
an
array
of
JSON
pointers
to
use
to
selectively
disclose
statements
(
selectivePointers
),
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.
The
following
algorithm
attempts
verification
of
an
ecdsa-sd-2023
derived
proof.
This
algorithm
is
called
by
a
verifier
of
an
ECDSA-SD-protected
verifiable
credential
.
The
inputs
include
a
JSON-LD
document
(
document
),
an
ECDSA-SD
disclosure
proof
(
proof
),
and
any
custom
JSON-LD
API
options,
such
as
a
document
loader.
This
algorithm
returns
a
verification
result
:
proof
value
removed.
false
,
set
verified
to
false.
false
,
set
verified
to
false.
true
,
otherwise
Null
This section is non-normative.
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 .
The integrity and authenticity of a secured document that is protected by this cryptographic suite is dependent on a number of factors including the following:
In the following sections, we review these important points and direct the reader to additional information.
This section is non-normative.
The ECDSA signature scheme has the EUF-CMA ( existential unforgeability under chosen message attacks ) security property. This property guarantees that any efficient adversary who has the public key pk 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).
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 pk of the signer and received an arbitrary number of signatures on messages of its choice, it cannot output a new valid signature pair for a new message nor a new signature for an old message (except with negligible probability). ECDSA signature scheme does not have the SUF-CMA property, while other schemes such as EdDSA [ FIPS-186-5 ] do.
Per [ NIST-SP-800-57-Part-1 ] in the absence of large scale quantum computers a security strength level of 128 bits requires a key size of approximately 256 bits while a security strength level of 192 bits requires a key size of 384 bits. [ NIST-SP-800-186 ] recommendations includes curves P-256 and P-384 at these respective security strength levels.
This section is non-normative.
The ECDSA algorithm as detailed in [ FIPS-186-5 ] states: "A new secret random number k , 0 < k < n , shall be generated prior to the generation of each digital signature for use during the signature generation process." The failure to properly generate this k value has lead to some highly publicized integrity breaches in widely deployed systems. To counter this problem, a hash-based method of determining the secret number k , called deterministic ECDSA , is given in [ FIPS-186-5 ] and [ RFC6979 ].
Verification of a ECDSA signature is independent of the method of generating k . Hence it is generally recommended to use deterministic ECDSA unless other requirements dictate otherwise. For example, using different k values results in different signature values for the same document which might be a desirable property in some privacy enhancing situations.
This section is non-normative.
The security of the ECDSA algorithm is dependent on the quality and protection of its private signing key . Guidance in the management of cryptographic keys is a large subject and the reader is referred to [ NIST-SP-800-57-Part-1 ] for more extensive recommendations and discussion. As strongly recommended in both [ FIPS-186-5 ] and [ NIST-SP-800-57-Part-1 ], an ECDSA private signing key is not to be used for any other purpose than ECDSA signatures.
ECDSA private signing keys and public verification keys are strongly advised to have limited cryptoperiods [ NIST-SP-800-57-Part-1 ], where a cryptoperiod is "the time span during which a specific key is authorized for use by legitimate entities or the keys for a given system will remain in effect." [ NIST-SP-800-57-Part-1 ] gives extensive guidance on cryptoperiods for different key types under different situations and generally recommends a 1-3 year cryptoperiod for a private signing key.
To deal with potential private key compromises, [ NIST-SP-800-57-Part-1 ] gives recommendations for protective measures, harm reduction, and revocation. Although we have been emphasizing the security of the private signing key, assurance of public key validity is highly recommended on all public keys before using them, per [ NIST-SP-800-57-Part-1 ].
Before reading this section, readers are urged to familiarize themselves with general privacy advice provided in the Privacy Considerations section of the Data Integrity specification .
The following section describes privacy considerations that developers implementing this specification should be aware of in order to avoid violating privacy assumptions.
The cryptographic suites described in this specification do not support unlinkable disclosure . If unlinkable disclosure is of interest, the Data Integrity BBS Cryptosuites v1.0 specification provides an unlinkable digital signature mechanism.
This section is non-normative.
All test vectors are produced using deterministic ECDSA . The implementation was validated against the test vectors in [ RFC6979 ].
The signer needs to generate a private/public key pair with the private key used for signing and the public key made available for verification. The representation of the public key, and the representation of the private key, are shown below.
{
"publicKeyMultibase": "zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"secretKeyMultibase": "z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN"
}
Signing begins with a credential without an attached proof, which is converted to canonical form, which is then hashed, as shown in the following three examples.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": ["VerifiableCredential", "AlumniCredential"],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
}
}
<did:example:abcdefgh> <https://www.w3.org/ns/credentials/examples#alumniOf> "The School of Examples" . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/ns/credentials/examples#AlumniCredential> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://schema.org/description> "A minimum viable example of an Alumni Credential." . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://schema.org/name> "Alumni Credential" . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://www.w3.org/2018/credentials#credentialSubject> <did:example:abcdefgh> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://www.w3.org/2018/credentials#issuer> <https://vc.example/issuers/5678> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://www.w3.org/2018/credentials#validFrom> "2023-01-01T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
517744132ae165a5349155bef0bb0cf2258fff99dfe1dbd914b938d775a36017
The next step is to take the proof options document, convert it to canonical form, and obtain its hash, as shown in the next three examples.
{
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
]
}
_:c14n0 <http://purl.org/dc/terms/created> "2023-02-24T23: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> "ecdsa-rdfc-2019"^^<https://w3id.org/security#cryptosuiteString> . _:c14n0 <https://w3id.org/security#proofPurpose> <https://w3id.org/security#assertionMethod> . _:c14n0 <https://w3id.org/security#verificationMethod> <did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP> .
3a8a522f689025727fb9d1f0fa99a618da023e8494ac74f51015d009d35abc2e
Finally, we concatenate the hash of the proof options followed by the hash of the credential without proof, use the private key with the combined hash to compute the ECDSA signature, and then base-58-btc encode the signature.
3a8a522f689025727fb9d1f0fa99a618da023e8494ac74f51015d009d35abc2e517744132ae165a5349155bef0bb0cf2258fff99dfe1dbd914b938d775a36017
1cb4290918ffb04a55ff7ae1e55e316a9990fda8eec67325eac7fcbf2ddf9dd2b06716a657e72b284c9604df3a172ecbf06a1a475b49ac807b1d9162df855636
zaHXrr7AQdydBk3ahpCDpWbxfLokDqmCToYm2dyWvpcFVyWooC2he63w1f7UNQoAMKdhaRtcnaE2KTo5o5vTCcfw
Assemble the signed credential with the following two steps:
proofValue
field
with
the
previously
computed
base-58-btc
value
to
the
proof
options
document.
proof
field
of
the
credential
to
the
augmented
proof
option
document.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"proofValue": "zaHXrr7AQdydBk3ahpCDpWbxfLokDqmCToYm2dyWvpcFVyWooC2he63w1f7UNQoAMKdhaRtcnaE2KTo5o5vTCcfw"
}
}
Here
we
again
go
through
the
steps
of
creating
an
ecdsa-rdfc-2019
with
curve
P-256
signed
credential
but
with
a
more
complicated
input
document.
The
representation
of
the
public
key,
and
the
representation
of
the
private
key,
are
shown
below.
{
"publicKeyMultibase": "zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"secretKeyMultibase": "z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN"
}
Signing begins with a credential without an attached proof, which is converted to canonical form, which is then hashed, as shown in the following three examples.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"givenName": "JOHN",
"additionalName": "JACOB",
"familyName": "SMITH",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==",
"gender": "Male",
"residentSince": "2015-01-01",
"birthCountry": "Bahamas",
"birthDate": "1999-07-17",
"employmentAuthorizationDocument": {
"type": "EmploymentAuthorizationDocument",
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"name": "Employment Authorization Document",
"description": "Example Employment Authorization Document.",
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z"
}
<did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg==> . _:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocumentCredential> . _:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> . _:c14n0 <https://schema.org/description> "Example Employment Authorization Document." . _:c14n0 <https://schema.org/name> "Employment Authorization Document" . _:c14n0 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n1 . _:c14n0 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> . _:c14n0 <https://www.w3.org/2018/credentials#validFrom> "2019-12-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n0 <https://www.w3.org/2018/credentials#validUntil> "2029-12-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> . _:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmployablePerson> . _:c14n1 <https://schema.org/additionalName> "JACOB" . _:c14n1 <https://schema.org/birthDate> "1999-07-17"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n1 <https://schema.org/familyName> "SMITH" . _:c14n1 <https://schema.org/gender> "Male" . _:c14n1 <https://schema.org/givenName> "JOHN" . _:c14n1 <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==> . _:c14n1 <https://w3id.org/citizenship#birthCountry> "Bahamas" . _:c14n1 <https://w3id.org/citizenship#employmentAuthorizationDocument> _:c14n2 . _:c14n1 <https://w3id.org/citizenship#residentSince> "2015-01-01"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocument> . _:c14n2 <https://schema.org/identifier> "83627465" . _:c14n2 <https://w3id.org/citizenship#lprCategory> "C09" . _:c14n2 <https://w3id.org/citizenship#lprNumber> "999-999-999" .
03f59e5b04ab575b1172cb684f22eede72f0e9033e0b5c67d0e2506768d6ce11
The next step is to take the proof options document, convert it to canonical form, and obtain its hash, as shown in the next three examples.
{
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
]
}
_:c14n0 <http://purl.org/dc/terms/created> "2023-02-24T23: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> "ecdsa-rdfc-2019"^^<https://w3id.org/security#cryptosuiteString> . _:c14n0 <https://w3id.org/security#proofPurpose> <https://w3id.org/security#assertionMethod> . _:c14n0 <https://w3id.org/security#verificationMethod> <did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP> .
3a8a522f689025727fb9d1f0fa99a618da023e8494ac74f51015d009d35abc2e
Finally, we concatenate the hash of the proof options followed by the hash of the credential without proof, use the private key with the combined hash to compute the ECDSA signature, and then base-58-btc encode the signature.
3a8a522f689025727fb9d1f0fa99a618da023e8494ac74f51015d009d35abc2e03f59e5b04ab575b1172cb684f22eede72f0e9033e0b5c67d0e2506768d6ce11
c6798ff29f725dfd39aa4daf60fbb423cf9baf4e157f6b49f112c201015c6e730dc877154e65cf467f8ee2b61ec86d98ed78334b1cc9f3dba2e1745f37205e92
z4y9rJ7JxwfZZUBAHgDHJh7FzMbsycPhEtcSHqrfyn7fx3S5MWdajNu1r6SsJmirzfcWHe7vp9XKHmRqW6qe7u3d3
Assemble the signed credential with the following two steps:
proofValue
field
with
the
previously
computed
base-58-btc
value
to
the
proof
options
document.
proof
field
of
the
credential
to
the
augmented
proof
option
document.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"givenName": "JOHN",
"additionalName": "JACOB",
"familyName": "SMITH",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==",
"gender": "Male",
"residentSince": "2015-01-01",
"birthCountry": "Bahamas",
"birthDate": "1999-07-17",
"employmentAuthorizationDocument": {
"type": "EmploymentAuthorizationDocument",
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"name": "Employment Authorization Document",
"description": "Example Employment Authorization Document.",
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"proofValue": "z4y9rJ7JxwfZZUBAHgDHJh7FzMbsycPhEtcSHqrfyn7fx3S5MWdajNu1r6SsJmirzfcWHe7vp9XKHmRqW6qe7u3d3"
}
}
The signer needs to generate a private/public key pair with the private key used for signing and the public key made available for verification. The representation of the public key, and the representation of the private key, are shown below.
{
"publicKeyMultibase": "z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"secretKeyMultibase": "z2fanyY7zgwNpZGxX5fXXibvScNaUWNprHU9dKx7qpVj7mws9J8LLt4mDB5TyH2GLHWkUc"
}
Signing begins with a credential without an attached proof, which is converted to canonical form, and then hashed, as shown in the following three examples.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": ["VerifiableCredential", "AlumniCredential"],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
}
}
<did:example:abcdefgh> <https://www.w3.org/ns/credentials/examples#alumniOf> "The School of Examples" . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/ns/credentials/examples#AlumniCredential> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://schema.org/description> "A minimum viable example of an Alumni Credential." . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://schema.org/name> "Alumni Credential" . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://www.w3.org/2018/credentials#credentialSubject> <did:example:abcdefgh> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://www.w3.org/2018/credentials#issuer> <https://vc.example/issuers/5678> . <urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33> <https://www.w3.org/2018/credentials#validFrom> "2023-01-01T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
8bf6e01df72c5b62f91b685231915ac4b8c58ea95f002c6b8f6bfafa1b251df476b56b8e01518e317dab099d3ecbff96
The next step is to take the proof options document, convert it to canonical form, and obtain its hash, as shown in the next three examples.
{
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
]
}
_:c14n0 <http://purl.org/dc/terms/created> "2023-02-24T23: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> "ecdsa-rdfc-2019"^^<https://w3id.org/security#cryptosuiteString> . _:c14n0 <https://w3id.org/security#proofPurpose> <https://w3id.org/security#assertionMethod> . _:c14n0 <https://w3id.org/security#verificationMethod> <did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ> .
e32805a26492eac777aa7a138f6d8da3c74e0c7be7b296dcaccf97420c3b92eaad7be6449ca565e165031567f5c7cbc1
Finally, we concatenate the hash of the proof options followed by the hash of the credential without proof, use the private key with the combined hash to compute the ECDSA signature, and then base-58-btc encode the signature.
e32805a26492eac777aa7a138f6d8da3c74e0c7be7b296dcaccf97420c3b92eaad7be6449ca565e165031567f5c7cbc18bf6e01df72c5b62f91b685231915ac4b8c58ea95f002c6b8f6bfafa1b251df476b56b8e01518e317dab099d3ecbff96
177ac088806c2506d49f0bfec16056a6a80ace62cd029888ad561aba22a59d192d77d9b1fc28df80dea5ee6c8bceb16f1b8bff6bd6ff2d8f8778bdde48bafa7b6cc1f914c0168b5c04499882f632deea9cb7d977e888bb0e1ee9fb20ff03b025
z967Mvv5bxtmLNqTzPZ8KmJjFmFXaAKeQNzq7GWnQkMcLtaGSSmuozE5WtJ8PipMe178B1tE28K1vsJur9bGVJhz6jgSJsRHFSQeqgH8hhjcg8gZDFJC1b9FsR5ggNmDBqHv
Assemble the signed credential with the following two steps:
proofValue
field
with
the
previously
computed
base-58-btc
value
to
the
proof
options
document.
proof
field
of
the
credential
to
the
augmented
proof
option
document.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"proofPurpose": "assertionMethod",
"proofValue": "z967Mvv5bxtmLNqTzPZ8KmJjFmFXaAKeQNzq7GWnQkMcLtaGSSmuozE5WtJ8PipMe178B1tE28K1vsJur9bGVJhz6jgSJsRHFSQeqgH8hhjcg8gZDFJC1b9FsR5ggNmDBqHv"
}
}
Here
we
again
go
through
the
steps
of
creating
an
ecdsa-rdfc-2019
with
curve
P-384
signed
credential
but
with
a
more
complicated
input
document.
The
representation
of
the
public
key,
and
the
representation
of
the
private
key,
are
shown
below.
{
"publicKeyMultibase": "z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"secretKeyMultibase": "z2fanyY7zgwNpZGxX5fXXibvScNaUWNprHU9dKx7qpVj7mws9J8LLt4mDB5TyH2GLHWkUc"
}
Signing begins with a credential without an attached proof, which is converted to canonical form, and then hashed, as shown in the following three examples.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"givenName": "JOHN",
"additionalName": "JACOB",
"familyName": "SMITH",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==",
"gender": "Male",
"residentSince": "2015-01-01",
"birthCountry": "Bahamas",
"birthDate": "1999-07-17",
"employmentAuthorizationDocument": {
"type": "EmploymentAuthorizationDocument",
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"name": "Employment Authorization Document",
"description": "Example Employment Authorization Document.",
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z"
}
<did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg==> . _:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocument> . _:c14n0 <https://schema.org/identifier> "83627465" . _:c14n0 <https://w3id.org/citizenship#lprCategory> "C09" . _:c14n0 <https://w3id.org/citizenship#lprNumber> "999-999-999" . _:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> . _:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmployablePerson> . _:c14n1 <https://schema.org/additionalName> "JACOB" . _:c14n1 <https://schema.org/birthDate> "1999-07-17"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n1 <https://schema.org/familyName> "SMITH" . _:c14n1 <https://schema.org/gender> "Male" . _:c14n1 <https://schema.org/givenName> "JOHN" . _:c14n1 <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==> . _:c14n1 <https://w3id.org/citizenship#birthCountry> "Bahamas" . _:c14n1 <https://w3id.org/citizenship#employmentAuthorizationDocument> _:c14n0 . _:c14n1 <https://w3id.org/citizenship#residentSince> "2015-01-01"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocumentCredential> . _:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> . _:c14n2 <https://schema.org/description> "Example Employment Authorization Document." . _:c14n2 <https://schema.org/name> "Employment Authorization Document" . _:c14n2 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n1 . _:c14n2 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> . _:c14n2 <https://www.w3.org/2018/credentials#validFrom> "2019-12-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> . _:c14n2 <https://www.w3.org/2018/credentials#validUntil> "2029-12-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
1033878f36ffb458c6495fec9c8814dad5215aad131041e6667db28fef6ea718d0de0eb4546bf527746ad2bc908a4320
The next step is to take the proof options document, convert it to canonical form, and obtain its hash, as shown in the next three examples.
{
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
]
}
_:c14n0 <http://purl.org/dc/terms/created> "2023-02-24T23: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> "ecdsa-rdfc-2019"^^<https://w3id.org/security#cryptosuiteString> . _:c14n0 <https://w3id.org/security#proofPurpose> <https://w3id.org/security#assertionMethod> . _:c14n0 <https://w3id.org/security#verificationMethod> <did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ> .
e32805a26492eac777aa7a138f6d8da3c74e0c7be7b296dcaccf97420c3b92eaad7be6449ca565e165031567f5c7cbc1
Finally, we concatenate the hash of the proof options followed by the hash of the credential without proof, use the private key with the combined hash to compute the ECDSA signature, and then base-58-btc encode the signature.
e32805a26492eac777aa7a138f6d8da3c74e0c7be7b296dcaccf97420c3b92eaad7be6449ca565e165031567f5c7cbc11033878f36ffb458c6495fec9c8814dad5215aad131041e6667db28fef6ea718d0de0eb4546bf527746ad2bc908a4320
a5999d1154a3fb5db8805fa762c8c41c1b7f40a231a5d42460d36245349771835f43fe0005295d2061be1789589c1f6385312f0e2e36709c310c77e8289587b79b29ecf7aad14ef61a1393cc2e1f93a7a354bd76bab47d558df060c6ae218975
zz3ca1oME3iYPHM8SgApWFUFVQjiaL9moPqCZ1NAENj3biEQ34qc1ex5VJNLD4jh4N4MY2cmDyDCYGv7EyD87yCGYwag8wRwiJE1xiHKLhTEhDQFNfuNMsgLiZnqpkCDJPye
Assemble the signed credential with the following two steps:
proofValue
field
with
the
previously
computed
base-58-btc
value
to
the
proof
options
document.
proof
field
of
the
credential
to
the
augmented
proof
option
document.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"givenName": "JOHN",
"additionalName": "JACOB",
"familyName": "SMITH",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==",
"gender": "Male",
"residentSince": "2015-01-01",
"birthCountry": "Bahamas",
"birthDate": "1999-07-17",
"employmentAuthorizationDocument": {
"type": "EmploymentAuthorizationDocument",
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"name": "Employment Authorization Document",
"description": "Example Employment Authorization Document.",
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-rdfc-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"proofPurpose": "assertionMethod",
"proofValue": "zz3ca1oME3iYPHM8SgApWFUFVQjiaL9moPqCZ1NAENj3biEQ34qc1ex5VJNLD4jh4N4MY2cmDyDCYGv7EyD87yCGYwag8wRwiJE1xiHKLhTEhDQFNfuNMsgLiZnqpkCDJPye"
}
}
The signer needs to generate a private/public key pair with the private key used for signing and the public key made available for verification. The representation of the public key, and the representation of the private key, are shown below.
{
"publicKeyMultibase": "zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"secretKeyMultibase": "z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN"
}
Signing begins with a credential without an attached proof, which is converted to canonical form, which is then hashed, as shown in the following three examples.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": ["VerifiableCredential", "AlumniCredential"],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
}
}
{"@context":["https://www.w3.org/ns/credentials/v2","https://www.w3.org/ns/credentials/examples/v2"],"credentialSubject":{"alumniOf":"The
School
of
Examples","id":"did:example:abcdefgh"},"description":"A
minimum
viable
example
of
an
Alumni
Credential.","id":"urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33","issuer":"https://vc.example/issuers/5678","name":"Alumni
Credential","type":["VerifiableCredential","AlumniCredential"],"validFrom":"2023-01-01T00:00:00Z"}
59b7cb6251b8991add1ce0bc83107e3db9dbbab5bd2c28f687db1a03abc92f19
The next step is to take the proof options document, convert it to canonical form, and obtain its hash, as shown in the next three examples.
{
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-jcs-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
]
}
{"@context":["https://www.w3.org/ns/credentials/v2","https://www.w3.org/ns/credentials/examples/v2"],"created":"2023-02-24T23:36:38Z","cryptosuite":"ecdsa-jcs-2019","proofPurpose":"assertionMethod","type":"DataIntegrityProof","verificationMethod":"did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP"}
fe5799489119c7fe3c528715e72bd39d2ec6b4ab345978df32e9a9312648ec25
Finally, we concatenate the hash of the proof options followed by the hash of the credential without proof, use the private key with the combined hash to compute the ECDSA signature, and then base-58-btc encode the signature.
fe5799489119c7fe3c528715e72bd39d2ec6b4ab345978df32e9a9312648ec2559b7cb6251b8991add1ce0bc83107e3db9dbbab5bd2c28f687db1a03abc92f19
f15c3b599eb9b3cad05df9d8e8b39a70a86375833b53743c764ac0a88c4457d60707fd7d073e03d906130631d87803f80a9824dc9939632ba92d418181be9d16
z5ptCet75SaEgzG4v4zJhbJtfNi74Wv7Fq15hhKouJQQjEPQvPZKaYxcMXAMLPQS2FXrkCWokNJkFVkwxNzZfD5oT
Assemble the signed credential with the following three steps:
proofValue
field
with
the
previously
computed
base-58-btc
value
to
the
proof
options
document.
@context
field
to
the
value
of
the
unsecuredDocument.@context
.
proof
field
of
the
credential
to
the
augmented
proof
option
document.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-jcs-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"proofValue": "z5ptCet75SaEgzG4v4zJhbJtfNi74Wv7Fq15hhKouJQQjEPQvPZKaYxcMXAMLPQS2FXrkCWokNJkFVkwxNzZfD5oT"
}
}
The signer needs to generate a private/public key pair with the private key used for signing and the public key made available for verification. The representation of the public key, and the representation of the private key, are shown below.
{
"publicKeyMultibase": "z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"secretKeyMultibase": "z2fanyY7zgwNpZGxX5fXXibvScNaUWNprHU9dKx7qpVj7mws9J8LLt4mDB5TyH2GLHWkUc"
}
Signing begins with a credential without an attached proof, which is converted to canonical form, which is then hashed, as shown in the following three examples.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": ["VerifiableCredential", "AlumniCredential"],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
}
}
{"@context":["https://www.w3.org/ns/credentials/v2","https://www.w3.org/ns/credentials/examples/v2"],"credentialSubject":{"alumniOf":"The
School
of
Examples","id":"did:example:abcdefgh"},"description":"A
minimum
viable
example
of
an
Alumni
Credential.","id":"urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33","issuer":"https://vc.example/issuers/5678","name":"Alumni
Credential","type":["VerifiableCredential","AlumniCredential"],"validFrom":"2023-01-01T00:00:00Z"}
3e0be671cc1881035d463158c80921973dab3534d4f8dfacf4ff2725a4115eb718e49d66de0e90e7365cd6062abf2259
The next step is to take the proof options document, convert it to canonical form, and obtain its hash, as shown in the next three examples.
{
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-jcs-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
]
}
{"@context":["https://www.w3.org/ns/credentials/v2","https://www.w3.org/ns/credentials/examples/v2"],"created":"2023-02-24T23:36:38Z","cryptosuite":"ecdsa-jcs-2019","proofPurpose":"assertionMethod","type":"DataIntegrityProof","verificationMethod":"did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ"}
83e5057817abb0c6872eafeaba1a9e53893c58eeb7414fb6d8aa3fa8c7917f7ad4792890b257c598baa17f4fbe6d183c
Finally, we concatenate the hash of the proof options followed by the hash of the credential without proof, use the private key with the combined hash to compute the ECDSA signature, and then base-58-btc encode the signature.
83e5057817abb0c6872eafeaba1a9e53893c58eeb7414fb6d8aa3fa8c7917f7ad4792890b257c598baa17f4fbe6d183c3e0be671cc1881035d463158c80921973dab3534d4f8dfacf4ff2725a4115eb718e49d66de0e90e7365cd6062abf2259
8b7462ce62db0c8ff19878c4b3561c49eb71b4a743086b6d5b0eda70ecf0afc5a03fd88eb207d66b262ed87fd200a4e8e62716e0b329c032b67726b4b0fc737a44c1cefdba2fdccb3ece74cc5845aaa93374455a726f6ee4f5f30da9427f608a
zq3EuTeLiGurmB2JR5oL8oWEsT7u2tba4HT1oZbiMYWc5qzsoW2kLYcBcF4HM5vCpJyTkceULKrVXuJQkXeN5seL4uXrFNFRMm53GWy1Yrto8rTWxZi9DkNeWP7yUPs7ELAm
Assemble the signed credential with the following three steps:
proofValue
field
with
the
previously
computed
base-58-btc
value
to
the
proof
options
document.
@context
field
to
the
value
of
the
unsecuredDocument.@context
.
proof
field
of
the
credential
to
the
augmented
proof
option
document.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"name": "Alumni Credential",
"description": "A minimum viable example of an Alumni Credential.",
"issuer": "https://vc.example/issuers/5678",
"validFrom": "2023-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:abcdefgh",
"alumniOf": "The School of Examples"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-jcs-2019",
"created": "2023-02-24T23:36:38Z",
"verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
"proofPurpose": "assertionMethod",
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"proofValue": "zq3EuTeLiGurmB2JR5oL8oWEsT7u2tba4HT1oZbiMYWc5qzsoW2kLYcBcF4HM5vCpJyTkceULKrVXuJQkXeN5seL4uXrFNFRMm53GWy1Yrto8rTWxZi9DkNeWP7yUPs7ELAm"
}
}
To demonstrate selective disclosure features 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).
In order 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 add base proof test vectors is shown below. Multibase representation is use for the P-256 key pairs and the HMAC key is given as a hexadecimal string.
{
"baseKeyPair": {
"publicKeyMultibase": "zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"secretKeyMultibase": "z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN"
},
"proofKeyPair": {
"publicKeyMultibase": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"secretKeyMultibase": "z42tqvNGyzyXRzotAYn43UhcFtzDUVdxJ7461fwrfhBPLmfY"
},
"hmacKeyString": "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF"
}
In our scenario a person will be issued an employment authorization document as shown below.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"givenName": "JOHN",
"additionalName": "JACOB",
"familyName": "SMITH",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==",
"gender": "Male",
"residentSince": "2015-01-01",
"birthCountry": "Bahamas",
"birthDate": "1999-07-17",
"employmentAuthorizationDocument": {
"type": "EmploymentAuthorizationDocument",
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"name": "Employment Authorization Document",
"description": "Example Employment Authorization Document.",
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z"
}
The mandatory information as specified by the issuer is specified via an array of JSON pointers as shown below.
["/issuer"]
The result of applying the above JSON pointers to the employment authorization document is shown below.
[
{
"pointer": "/issuer",
"value": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
}
}
]
Transformation of the unsigned document begins with canonicalizing the document as shown below.
[ "<did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg==> .\n", "_:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocumentCredential> .\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> \"Example Employment Authorization Document.\" .\n", "_:c14n0 <https://schema.org/name> \"Employment Authorization Document\" .\n", "_:c14n0 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n1 .\n", "_:c14n0 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> .\n", "_:c14n0 <https://www.w3.org/2018/credentials#validFrom> \"2019-12-03T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n0 <https://www.w3.org/2018/credentials#validUntil> \"2029-12-03T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\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#EmployablePerson> .\n", "_:c14n1 <https://schema.org/additionalName> \"JACOB\" .\n", "_:c14n1 <https://schema.org/birthDate> \"1999-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:c14n1 <https://schema.org/familyName> \"SMITH\" .\n", "_:c14n1 <https://schema.org/gender> \"Male\" .\n", "_:c14n1 <https://schema.org/givenName> \"JOHN\" .\n", "_:c14n1 <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==> .\n", "_:c14n1 <https://w3id.org/citizenship#birthCountry> \"Bahamas\" .\n", "_:c14n1 <https://w3id.org/citizenship#employmentAuthorizationDocument> _:c14n2 .\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#EmploymentAuthorizationDocument> .\n", "_:c14n2 <https://schema.org/identifier> \"83627465\" .\n", "_:c14n2 <https://w3id.org/citizenship#lprCategory> \"C09\" .\n", "_:c14n2 <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\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 canonized 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:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg==> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmployablePerson> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/additionalName> \"JACOB\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/birthDate> \"1999-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/familyName> \"SMITH\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/gender> \"Male\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/givenName> \"JOHN\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#birthCountry> \"Bahamas\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#employmentAuthorizationDocument> _:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#residentSince> \"2015-01-01\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocumentCredential> .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://schema.org/description> \"Example Employment Authorization Document.\" .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://schema.org/name> \"Employment Authorization Document\" .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#credentialSubject> _:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#validFrom> \"2019-12-03T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#validUntil> \"2029-12-03T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocument> .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://schema.org/identifier> \"83627465\" .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://w3id.org/citizenship#lprCategory> \"C09\" .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\n" ]
The above canonical document gets grouped in to mandatory and non-mandatory statements. The final output of the selective disclosure transformation process is shown below. Each statement is now grouped as mandatory and non-mandatory and its index in the previous list of statements is remembered.
{
"mandatoryPointers": [
"/issuer"
],
"mandatory": {
"dataType": "Map",
"value": [
[
0,
"<did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg==> .\n"
],
[
12,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocumentCredential> .\n"
],
[
13,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n"
],
[
17,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76> .\n"
]
]
},
"nonMandatory": {
"dataType": "Map",
"value": [
[
1,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n"
],
[
2,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmployablePerson> .\n"
],
[
3,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/additionalName> \"JACOB\" .\n"
],
[
4,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/birthDate> \"1999-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
5,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/familyName> \"SMITH\" .\n"
],
[
6,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/gender> \"Male\" .\n"
],
[
7,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/givenName> \"JOHN\" .\n"
],
[
8,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==> .\n"
],
[
9,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#birthCountry> \"Bahamas\" .\n"
],
[
10,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#employmentAuthorizationDocument> _:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw .\n"
],
[
11,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#residentSince> \"2015-01-01\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
14,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://schema.org/description> \"Example Employment Authorization Document.\" .\n"
],
[
15,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://schema.org/name> \"Employment Authorization Document\" .\n"
],
[
16,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#credentialSubject> _:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg .\n"
],
[
18,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#validFrom> \"2019-12-03T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
19,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://www.w3.org/2018/credentials#validUntil> \"2029-12-03T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
20,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#EmploymentAuthorizationDocument> .\n"
],
[
21,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://schema.org/identifier> \"83627465\" .\n"
],
[
22,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://w3id.org/citizenship#lprCategory> \"C09\" .\n"
],
[
23,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\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": "ecdsa-sd-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"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> "ecdsa-sd-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:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP> .
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
nquads
to
produce
the
mandatoryHash
.
These
are
shown
below
in
hexadecimal
format.
{
"proofHash": "9c5c9b189f06cfa9d9f21a838ccb9b04316f07ad1a517bfd4955ee28c6a8229c",
"mandatoryHash": "a042dc047c236816f49fbe5282a79c5e77abe111e47f4c20203b5064c7f0f059"
}
We
compute
the
baseSignature
over
the
concatenation
of
the
proofHash
,
proofPublicKey
,
and
mandatoryHash
using
the
issuers
long
term
privateKey
.
We
compute
the
signatures
array
by
signing
each
non-mandatory
nquad
using
the
per
proofPrivateKey
.
These
signatures,
the
proofPublicKey
,
and
mandatoryPointers
which
are
fed
to
the
final
serialization
step
are
shown
below.
{
"baseSignature": "b8dc55afeb6427a990e9d60c0d363b654306d92703e5036210ca29619d8ed204194ba3d86e31cdbc99f4ee9d5f25f0cc1c1f44f5fa39abec9a50cdf519b457e0",
"publicKey": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"signatures": [
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"c92e6ea5f65343c704ac9450da4d55f87342829b9bad7aface8300a0879bc9972ec4879eebbaaffd9ad9e3f91d291971c8ffe5d768497d62fa27256a7e03bf99",
"5d98f7d800ae2aa62927a65e0345a5ae02df041c9cd26de1525a63431b9360c24216737d2374d0789d4e40acdd0bf75b077c06534a6d258084ad8beb149980d6",
"c8d70ede67864b3219dcb3c3831401ca069ac5f8db9e2714d5f57f367c76320d1e0a9fa4917551add811a415e19bcc32c017ef5ba02e81fed672c72711230b10",
"3a6263590ab7fbc4e5ef7bc6c3f6b9cdd8a96c7c4d9a1f120612213ca39a50f39d7b56d6365ead6054bdbe4b971b2769d61841a3f7236a7434e5f1b0f6e2e8fc",
"f5f1fe2990af59361ccd4863359405164ce6a0807dfedd2d1972826e6b79ee051df16f5dfc43d57ed0d57743b94c4f57dd5784fbb04a9bf2b6b7258f5c595524",
"44b68330d1b12ceec6c07ed560587b6bfd49c831fa90c1a8725a41a3e3247f2950bcfe51a0b26bf422e94f811001dc17b1b93b3f82423457acc5c19f214da5e1",
"c29744b9bfb68a250eb17aaf49416a8a77a5eed01be18c3278a3784db8f6731bda3da956855bc27f3bc91e3f8331371e100722fc223becb47072a45b7653be08",
"2b66d296f2d09ff280d4cdec1d02b6c38065ed36c99b6db40a9a800f4faea46187c7b42c6cb232b5103bc88445f5e1f32c89692071546f316a836cd31a979f8d",
"016fdf24189adefa773c26ad2e0482aebf74a7bb8d5a142723d43d18adc049c408faafdcef8bb11cdc9c728d8f746ae32e03197767bb1aa91fd61a8fc4993abe",
"e7ee420aa027ba4671b926c29e2c574f94461660a0b3d6c828cce50314d9e1e4c346ed119352adf6141c66e2fce4a2cb7486c3f81cc42e388a5f921285677d94",
"ff516e1c599ef23779cdd5a6ae34a7db1a1d244514d32308a809752e6c2d112e5a7b473360c0b8caf27949aa161d10876d19c77b50e76160736f1ea4cfdefaa2",
"c85373002c77fb25e7880c1b2df2e2fa6c25decf563b0a88332e4654773b08b9286b65effe00f8689df03df6e2dfcd4575eff23a08c92bd360e285c22bfa2b5d",
"09e91f89dfd0a252f79a970caec55814cd570a8e41ec2ac25c33bd8afe479a70b8e744d363bc7daa313625d0cb4c1ea8c64c87577835e9b7416b4615bb82def9",
"b181986ef2cfb77b71f27cfb4365b8860799d9e84c3df62b3863319250d57a91d429cb15127122c36fd34a92ea0745b4a641454c561c55c37741ee247a866264",
"13d02a9caf0d96b9fbec397d4faad90e78c56d0cbd933224d58b5c81623e3571b22aa15bc4ad201c364e3566793c9dda9c983e9965f47c7ce5ff6e1b42484dd4",
"91cc9524b4aa346fc6e409e94b28b8a9891491ae627e47e60f0cd36d90034eb97a8595fcb35a07d3faa5fc213e759b0bea03cb82c58a3711c9de299b7e77904b",
"22d951c202cd2dbf92a5fd20483f618177f16c08aa798fd6e8a0631fba6d059e304c1ed96a3785aa1be2539eb1fac22caace1f450b5a3a48602c7fb4c68f2d7b",
"d0fbcf518ec15c3f10d8d2b275963807030ad7e4b03e6c7a6ca0e6b73d61f15a94d76097fc91e1a828c7d9272b178b8ced6422db36e9a1a85ce2a18e39115542",
"be6366acec557376a71a450f862979f60e642b8edafc104eaf4691784bb48245f3d79f093cd1f631d55217ae2f9f30f17d9ba1b98aae45e02461e1db9bde121f"
],
"mandatoryPointers": [
"/issuer"
]
}
Finally,
the
values
above
are
run
through
the
algorithm
of
Section
3.5.2
serializeBaseProofValue
to
produce
the
proofValue
which
is
used
in
the
signed
based
document
shown
below.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"givenName": "JOHN",
"additionalName": "JACOB",
"familyName": "SMITH",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==",
"gender": "Male",
"residentSince": "2015-01-01",
"birthCountry": "Bahamas",
"birthDate": "1999-07-17",
"employmentAuthorizationDocument": {
"type": "EmploymentAuthorizationDocument",
"identifier": "83627465",
"lprCategory": "C09",
"lprNumber": "999-999-999"
}
},
"name": "Employment Authorization Document",
"description": "Example Employment Authorization Document.",
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-sd-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0AhVhAuNxVr-tkJ6mQ6dYMDTY7ZUMG2ScD5QNiEMopYZ2O0gQZS6PYbjHNvJn07p1fJfDMHB9E9fo5q-yaUM31GbRX4FgjgCQCKnLOGbY_FuM-ASpSkkOxsIR2E8n7Ml2q1UQ6tEwzi5NYIAARIjNEVWZ3iJmqu8zd7v8AESIzRFVmd4iZqrvM3e7_lFhA_ZHsSLNSSWX3oUU-n_oGcFTspvfWM4qEUl6zKIuwyvepZR8C_uFNbTPuFnmqiCg0jMxXThlNf1f8qL41TBsw91hAyS5upfZTQ8cErJRQ2k1V-HNCgpubrXr6zoMAoIebyZcuxIee67qv_ZrZ4_kdKRlxyP_l12hJfWL6JyVqfgO_mVhAXZj32ACuKqYpJ6ZeA0WlrgLfBByc0m3hUlpjQxuTYMJCFnN9I3TQeJ1OQKzdC_dbB3wGU0ptJYCErYvrFJmA1lhAyNcO3meGSzIZ3LPDgxQBygaaxfjbnicU1fV_Nnx2Mg0eCp-kkXVRrdgRpBXhm8wywBfvW6Augf7WcscnESMLEFhAOmJjWQq3-8Tl73vGw_a5zdipbHxNmh8SBhIhPKOaUPOde1bWNl6tYFS9vkuXGydp1hhBo_cjanQ05fGw9uLo_FhA9fH-KZCvWTYczUhjNZQFFkzmoIB9_t0tGXKCbmt57gUd8W9d_EPVftDVd0O5TE9X3VeE-7BKm_K2tyWPXFlVJFhARLaDMNGxLO7GwH7VYFh7a_1JyDH6kMGoclpBo-MkfylQvP5RoLJr9CLpT4EQAdwXsbk7P4JCNFesxcGfIU2l4VhAwpdEub-2iiUOsXqvSUFqinel7tAb4YwyeKN4Tbj2cxvaPalWhVvCfzvJHj-DMTceEAci_CI77LRwcqRbdlO-CFhAK2bSlvLQn_KA1M3sHQK2w4Bl7TbJm220CpqAD0-upGGHx7QsbLIytRA7yIRF9eHzLIlpIHFUbzFqg2zTGpefjVhAAW_fJBia3vp3PCatLgSCrr90p7uNWhQnI9Q9GK3AScQI-q_c74uxHNycco2PdGrjLgMZd2e7Gqkf1hqPxJk6vlhA5-5CCqAnukZxuSbCnixXT5RGFmCgs9bIKMzlAxTZ4eTDRu0Rk1Kt9hQcZuL85KLLdIbD-BzELjiKX5IShWd9lFhA_1FuHFme8jd5zdWmrjSn2xodJEUU0yMIqAl1LmwtES5ae0czYMC4yvJ5SaoWHRCHbRnHe1DnYWBzbx6kz976olhAyFNzACx3-yXniAwbLfLi-mwl3s9WOwqIMy5GVHc7CLkoa2Xv_gD4aJ3wPfbi381Fde_yOgjJK9Ng4oXCK_orXVhACekfid_QolL3mpcMrsVYFM1XCo5B7CrCXDO9iv5HmnC450TTY7x9qjE2JdDLTB6oxkyHV3g16bdBa0YVu4Le-VhAsYGYbvLPt3tx8nz7Q2W4hgeZ2ehMPfYrOGMxklDVepHUKcsVEnEiw2_TSpLqB0W0pkFFTFYcVcN3Qe4keoZiZFhAE9AqnK8Nlrn77Dl9T6rZDnjFbQy9kzIk1YtcgWI-NXGyKqFbxK0gHDZONWZ5PJ3anJg-mWX0fHzl_24bQkhN1FhAkcyVJLSqNG_G5AnpSyi4qYkUka5ifkfmDwzTbZADTrl6hZX8s1oH0_ql_CE-dZsL6gPLgsWKNxHJ3imbfneQS1hAItlRwgLNLb-Spf0gSD9hgXfxbAiqeY_W6KBjH7ptBZ4wTB7ZajeFqhviU56x-sIsqs4fRQtaOkhgLH-0xo8te1hA0PvPUY7BXD8Q2NKydZY4BwMK1-SwPmx6bKDmtz1h8VqU12CX_JHhqCjH2ScrF4uM7WQi2zbpoahc4qGOORFVQlhAvmNmrOxVc3anGkUPhil59g5kK47a_BBOr0aReEu0gkXz158JPNH2MdVSF64vnzDxfZuhuYquReAkYeHbm94SH4FnL2lzc3Vlcg"
}
}
In
order
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.7.1
Base
Proof
above.
The
first
step
is
to
run
the
algorithm
of
Section
3.5.3
parseBaseProofValue
to
recover
baseSignature
,
publicKey
,
hmacKey
,
signatures
,
and
mandatoryPointers
as
shown
below.
{
"baseSignature": "b8dc55afeb6427a990e9d60c0d363b654306d92703e5036210ca29619d8ed204194ba3d86e31cdbc99f4ee9d5f25f0cc1c1f44f5fa39abec9a50cdf519b457e0",
"proofPublicKey": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"signatures": [
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"c92e6ea5f65343c704ac9450da4d55f87342829b9bad7aface8300a0879bc9972ec4879eebbaaffd9ad9e3f91d291971c8ffe5d768497d62fa27256a7e03bf99",
"5d98f7d800ae2aa62927a65e0345a5ae02df041c9cd26de1525a63431b9360c24216737d2374d0789d4e40acdd0bf75b077c06534a6d258084ad8beb149980d6",
"c8d70ede67864b3219dcb3c3831401ca069ac5f8db9e2714d5f57f367c76320d1e0a9fa4917551add811a415e19bcc32c017ef5ba02e81fed672c72711230b10",
"3a6263590ab7fbc4e5ef7bc6c3f6b9cdd8a96c7c4d9a1f120612213ca39a50f39d7b56d6365ead6054bdbe4b971b2769d61841a3f7236a7434e5f1b0f6e2e8fc",
"f5f1fe2990af59361ccd4863359405164ce6a0807dfedd2d1972826e6b79ee051df16f5dfc43d57ed0d57743b94c4f57dd5784fbb04a9bf2b6b7258f5c595524",
"44b68330d1b12ceec6c07ed560587b6bfd49c831fa90c1a8725a41a3e3247f2950bcfe51a0b26bf422e94f811001dc17b1b93b3f82423457acc5c19f214da5e1",
"c29744b9bfb68a250eb17aaf49416a8a77a5eed01be18c3278a3784db8f6731bda3da956855bc27f3bc91e3f8331371e100722fc223becb47072a45b7653be08",
"2b66d296f2d09ff280d4cdec1d02b6c38065ed36c99b6db40a9a800f4faea46187c7b42c6cb232b5103bc88445f5e1f32c89692071546f316a836cd31a979f8d",
"016fdf24189adefa773c26ad2e0482aebf74a7bb8d5a142723d43d18adc049c408faafdcef8bb11cdc9c728d8f746ae32e03197767bb1aa91fd61a8fc4993abe",
"e7ee420aa027ba4671b926c29e2c574f94461660a0b3d6c828cce50314d9e1e4c346ed119352adf6141c66e2fce4a2cb7486c3f81cc42e388a5f921285677d94",
"ff516e1c599ef23779cdd5a6ae34a7db1a1d244514d32308a809752e6c2d112e5a7b473360c0b8caf27949aa161d10876d19c77b50e76160736f1ea4cfdefaa2",
"c85373002c77fb25e7880c1b2df2e2fa6c25decf563b0a88332e4654773b08b9286b65effe00f8689df03df6e2dfcd4575eff23a08c92bd360e285c22bfa2b5d",
"09e91f89dfd0a252f79a970caec55814cd570a8e41ec2ac25c33bd8afe479a70b8e744d363bc7daa313625d0cb4c1ea8c64c87577835e9b7416b4615bb82def9",
"b181986ef2cfb77b71f27cfb4365b8860799d9e84c3df62b3863319250d57a91d429cb15127122c36fd34a92ea0745b4a641454c561c55c37741ee247a866264",
"13d02a9caf0d96b9fbec397d4faad90e78c56d0cbd933224d58b5c81623e3571b22aa15bc4ad201c364e3566793c9dda9c983e9965f47c7ce5ff6e1b42484dd4",
"91cc9524b4aa346fc6e409e94b28b8a9891491ae627e47e60f0cd36d90034eb97a8595fcb35a07d3faa5fc213e759b0bea03cb82c58a3711c9de299b7e77904b",
"22d951c202cd2dbf92a5fd20483f618177f16c08aa798fd6e8a0631fba6d059e304c1ed96a3785aa1be2539eb1fac22caace1f450b5a3a48602c7fb4c68f2d7b",
"d0fbcf518ec15c3f10d8d2b275963807030ad7e4b03e6c7a6ca0e6b73d61f15a94d76097fc91e1a828c7d9272b178b8ced6422db36e9a1a85ce2a18e39115542",
"be6366acec557376a71a450f862979f60e642b8edafc104eaf4691784bb48245f3d79f093cd1f631d55217ae2f9f30f17d9ba1b98aae45e02461e1db9bde121f"
],
"mandatoryPointers": [
"/issuer"
]
}
Next, the holder needs to indicate what, if anything else, they wish to reveal to the verifiers by specifying JSON pointers for selective disclosure.
["/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
algorithm
of
Section
3.4.13
selectJsonLd
to
give
the
result
shown
below.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v4rc1"
],
"type": [
"VerifiableCredential",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z",
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"birthCountry": "Bahamas"
}
}
Now that we know what the revealed document looks like, we need to furnish appropriately updated information to the verifier on which statements are mandatory, the signatures for the selected non-mandatory statements, and the mapping between canonical blank node ids for the reveal document and a subset of the HMAC blank node ids. Running step 6 of the 3.5.4 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,9,12,13,16,17,18,19],
"mandatoryIndexes":[0,12,13,17],
"nonMandatoryIndexes":[1,2,3,4,5,6,7,8,9,10,11,14,15,16,18,19,20,21,22,23],
"selectiveIndexes":[1,2,9,12,13,16,18,19]
}
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.
In
the
previous
example
the
combinedIndexes
show
the
indexes
of
all
the
original
nquads
(statements)
that
make
up
the
reveal
document,
in
order.
To
come
up
with
the
adjusted
mandatory
indexes
shown
below
we
obtain
the
index
of
each
of
original
mandatory
indexes
relative
to
the
combinedIndexes
as
shown
below.
{
"adjMandatoryIndexes":[0,4,5,7]
}
We have to furnish the verifier with a list of signatures for those selective statements (nquads) that are not mandatory. The original list of signatures corresponds to every non-mandatory statement and the indexes of these in the original document are given above. We now compute a list of adjusted signature indexes by computing the index of each selective index in the non-mandatory index list, ignoring any selective index not present in the list. We then use the adjusted signature indexes to obtain the filtered signature list. These lists are shown below.
{
"adjSignatureIndexes":[0,1,8,13,14,15],
"filteredSignatures":[
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"c92e6ea5f65343c704ac9450da4d55f87342829b9bad7aface8300a0879bc9972ec4879eebbaaffd9ad9e3f91d291971c8ffe5d768497d62fa27256a7e03bf99",
"2b66d296f2d09ff280d4cdec1d02b6c38065ed36c99b6db40a9a800f4faea46187c7b42c6cb232b5103bc88445f5e1f32c89692071546f316a836cd31a979f8d",
"09e91f89dfd0a252f79a970caec55814cd570a8e41ec2ac25c33bd8afe479a70b8e744d363bc7daa313625d0cb4c1ea8c64c87577835e9b7416b4615bb82def9",
"b181986ef2cfb77b71f27cfb4365b8860799d9e84c3df62b3863319250d57a91d429cb15127122c36fd34a92ea0745b4a641454c561c55c37741ee247a866264",
"13d02a9caf0d96b9fbec397d4faad90e78c56d0cbd933224d58b5c81623e3571b22aa15bc4ad201c364e3566793c9dda9c983e9965f47c7ce5ff6e1b42484dd4"
]
}
The
last
important
piece
of
disclosure
data
is
a
mapping
of
canonical
blank
node
ids
to
HMAC
based
ids,
the
labelMap
,
computed
according
to
Section
3.5.4
createDisclosureData
steps
12-14.
This
is
shown
below
along
with
the
rest
of
the
disclosure
data
minus
the
reveal
document.
{
"baseSignature": "b8dc55afeb6427a990e9d60c0d363b654306d92703e5036210ca29619d8ed204194ba3d86e31cdbc99f4ee9d5f25f0cc1c1f44f5fa39abec9a50cdf519b457e0",
"publicKey": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"signatures": [
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"c92e6ea5f65343c704ac9450da4d55f87342829b9bad7aface8300a0879bc9972ec4879eebbaaffd9ad9e3f91d291971c8ffe5d768497d62fa27256a7e03bf99",
"2b66d296f2d09ff280d4cdec1d02b6c38065ed36c99b6db40a9a800f4faea46187c7b42c6cb232b5103bc88445f5e1f32c89692071546f316a836cd31a979f8d",
"09e91f89dfd0a252f79a970caec55814cd570a8e41ec2ac25c33bd8afe479a70b8e744d363bc7daa313625d0cb4c1ea8c64c87577835e9b7416b4615bb82def9",
"b181986ef2cfb77b71f27cfb4365b8860799d9e84c3df62b3863319250d57a91d429cb15127122c36fd34a92ea0745b4a641454c561c55c37741ee247a866264",
"13d02a9caf0d96b9fbec397d4faad90e78c56d0cbd933224d58b5c81623e3571b22aa15bc4ad201c364e3566793c9dda9c983e9965f47c7ce5ff6e1b42484dd4"
],
"labelMap": {
"dataType": "Map",
"value": [
[
"c14n0",
"u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg"
],
[
"c14n1",
"u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38"
]
]
},
"mandatoryIndexes": [
0,
4,
5,
7
]
}
Finally using the disclosure data above with the algorithm of Section 3.5.7 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",
"EmploymentAuthorizationDocumentCredential"
],
"issuer": {
"id": "did:key:zDnaegE6RR3atJtHKwTRTWHsJ3kNHqFwv7n9YjTgmU7TyfU76",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgUPr/HwADaAIhG61j/AAAAABJRU5ErkJggg=="
},
"validFrom": "2019-12-03T00:00:00Z",
"validUntil": "2029-12-03T00:00:00Z",
"credentialSubject": {
"type": [
"Person",
"EmployablePerson"
],
"birthCountry": "Bahamas"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "ecdsa-sd-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0BhVhAuNxVr-tkJ6mQ6dYMDTY7ZUMG2ScD5QNiEMopYZ2O0gQZS6PYbjHNvJn07p1fJfDMHB9E9fo5q-yaUM31GbRX4FgjgCQCKnLOGbY_FuM-ASpSkkOxsIR2E8n7Ml2q1UQ6tEwzi5OGWED9kexIs1JJZfehRT6f-gZwVOym99YzioRSXrMoi7DK96llHwL-4U1tM-4WeaqIKDSMzFdOGU1_V_yovjVMGzD3WEDJLm6l9lNDxwSslFDaTVX4c0KCm5utevrOgwCgh5vJly7Eh57ruq_9mtnj-R0pGXHI_-XXaEl9YvonJWp-A7-ZWEArZtKW8tCf8oDUzewdArbDgGXtNsmbbbQKmoAPT66kYYfHtCxssjK1EDvIhEX14fMsiWkgcVRvMWqDbNMal5-NWEAJ6R-J39CiUvealwyuxVgUzVcKjkHsKsJcM72K_keacLjnRNNjvH2qMTYl0MtMHqjGTIdXeDXpt0FrRhW7gt75WECxgZhu8s-3e3HyfPtDZbiGB5nZ6Ew99is4YzGSUNV6kdQpyxUScSLDb9NKkuoHRbSmQUVMVhxVw3dB7iR6hmJkWEAT0Cqcrw2WufvsOX1PqtkOeMVtDL2TMiTVi1yBYj41cbIqoVvErSAcNk41Znk8ndqcmD6ZZfR8fOX_bhtCSE3UogBYINy79kKRYKPmAHoHNXEECliRVtrBI0BehX7mdFRKDCh4AVgg4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC3-EAAQFBw"
}
}
Here
we
provide
an
additional
example
of
basic
ecdsa-sd-2023
processing.
To
demonstrate
selective
disclosure
features
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).
In order 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 add base proof test vectors is shown below. Multibase representation is use for the P-256 key pairs and the HMAC key is given as a hexadecimal string.
{
"baseKeyPair": {
"publicKeyMultibase": "zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"secretKeyMultibase": "z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN"
},
"proofKeyPair": {
"publicKeyMultibase": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"secretKeyMultibase": "z42tqvNGyzyXRzotAYn43UhcFtzDUVdxJ7461fwrfhBPLmfY"
},
"hmacKeyString": "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF"
}
In our scenario a person will be issued an permanent resident credential 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": "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"
}
The mandatory information as specified by the issuer is specified via an array of JSON pointers as shown below.
["/issuer"]
The result of applying the above JSON pointers to the permanent resident credential 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 from the ordering of the blank node ids these are processed through a PRF, i.e., the HMAC to give the canonized 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:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg==> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResident> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/birthDate> \"1978-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/familyName> \"SMITH\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/gender> \"Female\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/givenName> \"JANE\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v43hPwAHIgK1v4tX6wAAAABJRU5ErkJggg==> .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#birthCountry> \"Arcadia\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#commuterClassification> \"C1\" .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#permanentResidentCard> _:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 .\n", "_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#residentSince> \"2015-01-01\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCard> .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://schema.org/identifier> \"83627465\" .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://w3id.org/citizenship#lprCategory> \"C09\" .\n", "_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCardCredential> .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://schema.org/description> \"Permanent Resident Card from Government of Utopia.\" .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://schema.org/name> \"Permanent Resident Card\" .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://www.w3.org/2018/credentials#credentialSubject> _:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://www.w3.org/2018/credentials#validFrom> \"2024-12-16T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n", "_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://www.w3.org/2018/credentials#validUntil> \"2025-12-16T23:59:59Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n" ]
The above canonical document gets grouped in to mandatory and non-mandatory statements. The final output of the selective disclosure transformation process is shown below. Each statement is now grouped as mandatory and non-mandatory and its index in the previous list of statements is remembered.
{
"mandatoryPointers": [
"/issuer"
],
"mandatory": {
"dataType": "Map",
"value": [
[
0,
"<did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z/DiPwAG0ALnwgz64QAAAABJRU5ErkJggg==> .\n"
],
[
16,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCardCredential> .\n"
],
[
17,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .\n"
],
[
21,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://www.w3.org/2018/credentials#issuer> <did:key:zDnaeTHxNEBZoKaEo6PdA83fq98ebiFvo3X273Ydu4YmV96rg> .\n"
]
]
},
"nonMandatory": {
"dataType": "Map",
"value": [
[
1,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n"
],
[
2,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResident> .\n"
],
[
3,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/birthDate> \"1978-07-17\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
4,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/familyName> \"SMITH\" .\n"
],
[
5,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/gender> \"Female\" .\n"
],
[
6,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/givenName> \"JANE\" .\n"
],
[
7,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v43hPwAHIgK1v4tX6wAAAABJRU5ErkJggg==> .\n"
],
[
8,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#birthCountry> \"Arcadia\" .\n"
],
[
9,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#commuterClassification> \"C1\" .\n"
],
[
10,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#permanentResidentCard> _:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 .\n"
],
[
11,
"_:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg <https://w3id.org/citizenship#residentSince> \"2015-01-01\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
12,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/citizenship#PermanentResidentCard> .\n"
],
[
13,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://schema.org/identifier> \"83627465\" .\n"
],
[
14,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://w3id.org/citizenship#lprCategory> \"C09\" .\n"
],
[
15,
"_:u4YIOZn1MHES1Z4Ij2hWZG3R4dEYBqg5fHTyDEvYhC38 <https://w3id.org/citizenship#lprNumber> \"999-999-999\" .\n"
],
[
18,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://schema.org/description> \"Permanent Resident Card from Government of Utopia.\" .\n"
],
[
19,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://schema.org/name> \"Permanent Resident Card\" .\n"
],
[
20,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://www.w3.org/2018/credentials#credentialSubject> _:u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg .\n"
],
[
22,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <https://www.w3.org/2018/credentials#validFrom> \"2024-12-16T00:00:00Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime> .\n"
],
[
23,
"_:uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw <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": "ecdsa-sd-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"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> "ecdsa-sd-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:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP> .
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
nquads
to
produce
the
mandatoryHash
.
These
are
shown
below
in
hexadecimal
format.
{
"proofHash": "9c5c9b189f06cfa9d9f21a838ccb9b04316f07ad1a517bfd4955ee28c6a8229c",
"mandatoryHash": "b76d8d5bf67d27f51597519d19d95809c75e35212cc65291bd71bbe36007f979"
}
We
compute
the
baseSignature
over
the
concatenation
of
the
proofHash
,
proofPublicKey
,
and
mandatoryHash
using
the
issuers
long
term
privateKey
.
We
compute
the
signatures
array
by
signing
each
non-mandatory
nquad
using
the
per
proofPrivateKey
.
These
signatures,
the
proofPublicKey
,
and
mandatoryPointers
which
are
fed
to
the
final
serialization
step
are
shown
below.
{
"baseSignature": "1c00d200b76a4c87ed57aae0f09a6a05eb4e254898842a758d3b0069517ea8977f9a118b4dcc17bec33e9f9ef41b83dcde0957dc08643f546c8ca2360d1b1f2f",
"publicKey": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"signatures": [
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"3568e1402af672cb1a4c360ed7030ca8b1a744eed3c4572774e96d23e3a890db148de8dbd06594244a283f46247a540e78d14789e0e0c64ee96b6e53863707bc",
"008fb2b467d7b2a46f16727532ae32e4027fc7746d478815c332d0a5c46021031bf72b20b0835166e21d0d3b50a6d15d75f30df14eb9b1ca10af521644564837",
"3a6263590ab7fbc4e5ef7bc6c3f6b9cdd8a96c7c4d9a1f120612213ca39a50f39d7b56d6365ead6054bdbe4b971b2769d61841a3f7236a7434e5f1b0f6e2e8fc",
"1b922ea997916494648491373084bc71df1fe0918665021f530829b4a387eccb48630f76015da36a079b3882f6ff70a3f87acbce78608e66867e5b2fc31df82f",
"270f83139fe21ea6cb2176e6855580f7dc3f6694f0ab3efb723edc7844c376d2e3566b5ee1674834a8e69d197aae793e13a8a355423431a38daa442b6b440ada",
"0106894e5850a53d4306eb237f52b11579e25916aaa97ae4f91fd258bd3806a6e24443609d469792598b17bd54da1595b8266efa20aaaee271ce1aeab7c74042",
"ddc8430a1bf8cdbbb6e8c1e2dcb434dc0db59ab0c5501bd7dacee9e2c0234e2399ed95765d62ef4cabf0fe8117ee32f24b8f8c64d1955ddd4362269d9493035e",
"a16b9b2761a89b79428a1c8bbf19216e4d07271022bf9867d11a0055a8f19aa9583196d01234ad63a390b2971eebde0ae748258593500277a90f0d74fd2164f1",
"c6b8ab5a139770eef2fdabcc24ae63fbdf93a250238df7f29e2c905591e660e8fc87f74ac53eba18fe0487c6effeebbf8c9e4d075d5ae91b2ed7842c67e0b429",
"e7ee420aa027ba4671b926c29e2c574f94461660a0b3d6c828cce50314d9e1e4c346ed119352adf6141c66e2fce4a2cb7486c3f81cc42e388a5f921285677d94",
"8cc617955838bc95f849c8a782955374baf151727e8d12e5b4d0a200b406dcd839dbe5d5f760cc3b02bd65081d915138cbf14846b06e898916d8e30c725aaa5f",
"e10f849d052c6de7aa2459d93552ac5ea2ebf52d2e4ec6257b10654734066553a09e418bef1154f4af9f942c4b5cc0ad5a36ea3758c858d60cad68971398ed7f",
"acc0b0b8913da9043fdf1b5b19ac08a31dc809e128128bf9fde0558d3a05ca9198c49c152a3a55e6c3a6ab0bd59736cbe1e0c5b43af83c1a7a753a452a0241b5",
"2aadfc3bf665674c59537988413cc3fd945536501aa6fa541bb02bc398f50d12522b52775d39921a1ed3b8c17b4c9c7f418973b9b08f6fee1d60e9e48904e1c2",
"e41fcb03a010398c1a0a89103dbaa61f606e81548e7237a26b208ac40d5787664bd76ec4a68b6bc97aad0e771a5e884493501c5aa52aadd74fe1181bed6d4d6e",
"b9638d13bc4c1aecb987e0f713ef5e0a9290cf69cb182f48c2761530a5d6095db9f4196e706835bf35492d23215b9b50632256ac605f74df01c55144863bf202",
"d54d0056b279a17c591bd8580014f89c8cdabe20c80d84f7c137c4a36f97850dd0803fd6f1d70814a0b58dce9d50f30192c980d5bc451dea9a6569f90eb5d8b8",
"a678ac62c5416d0e93b9dbd3efa9add4c1e1a79e6707ba3d831ffc119f6837c184a7652340cb8a62004f459c905067b9cc03f43b3c677a022eeab1d7d7243c05",
"63730c42010acac32391d72d4f755b08588e1c289ab93e2a2c2d9a5d85a6d3d06fdeb39939f614efb4b3191966bae6f500ee44267ae44990f30b44e6c92943b4"
],
"mandatoryPointers": [
"/issuer"
]
}
Finally,
the
values
above
are
run
through
the
algorithm
of
Section
3.5.2
serializeBaseProofValue
to
produce
the
proofValue
which
is
used
in
the
signed
based
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=="
},
"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": "ecdsa-sd-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0AhVhAHADSALdqTIftV6rg8JpqBetOJUiYhCp1jTsAaVF-qJd_mhGLTcwXvsM-n570G4Pc3glX3AhkP1RsjKI2DRsfL1gjgCQCKnLOGbY_FuM-ASpSkkOxsIR2E8n7Ml2q1UQ6tEwzi5NYIAARIjNEVWZ3iJmqu8zd7v8AESIzRFVmd4iZqrvM3e7_lFhA_ZHsSLNSSWX3oUU-n_oGcFTspvfWM4qEUl6zKIuwyvepZR8C_uFNbTPuFnmqiCg0jMxXThlNf1f8qL41TBsw91hANWjhQCr2cssaTDYO1wMMqLGnRO7TxFcndOltI-OokNsUjejb0GWUJEooP0YkelQOeNFHieDgxk7pa25ThjcHvFhAAI-ytGfXsqRvFnJ1Mq4y5AJ_x3RtR4gVwzLQpcRgIQMb9ysgsINRZuIdDTtQptFddfMN8U65scoQr1IWRFZIN1hAOmJjWQq3-8Tl73vGw_a5zdipbHxNmh8SBhIhPKOaUPOde1bWNl6tYFS9vkuXGydp1hhBo_cjanQ05fGw9uLo_FhAG5IuqZeRZJRkhJE3MIS8cd8f4JGGZQIfUwgptKOH7MtIYw92AV2jagebOIL2_3Cj-HrLznhgjmaGflsvwx34L1hAJw-DE5_iHqbLIXbmhVWA99w_ZpTwqz77cj7ceETDdtLjVmte4WdINKjmnRl6rnk-E6ijVUI0MaONqkQra0QK2lhAAQaJTlhQpT1DBusjf1KxFXniWRaqqXrk-R_SWL04BqbiRENgnUaXklmLF71U2hWVuCZu-iCqruJxzhrqt8dAQlhA3chDChv4zbu26MHi3LQ03A21mrDFUBvX2s7p4sAjTiOZ7ZV2XWLvTKvw_oEX7jLyS4-MZNGVXd1DYiadlJMDXlhAoWubJ2Gom3lCihyLvxkhbk0HJxAiv5hn0RoAVajxmqlYMZbQEjStY6OQspce694K50glhZNQAnepDw10_SFk8VhAxrirWhOXcO7y_avMJK5j-9-TolAjjffyniyQVZHmYOj8h_dKxT66GP4Eh8bv_uu_jJ5NB11a6Rsu14QsZ-C0KVhA5-5CCqAnukZxuSbCnixXT5RGFmCgs9bIKMzlAxTZ4eTDRu0Rk1Kt9hQcZuL85KLLdIbD-BzELjiKX5IShWd9lFhAjMYXlVg4vJX4ScingpVTdLrxUXJ-jRLltNCiALQG3Ng52-XV92DMOwK9ZQgdkVE4y_FIRrBuiYkW2OMMclqqX1hA4Q-EnQUsbeeqJFnZNVKsXqLr9S0uTsYlexBlRzQGZVOgnkGL7xFU9K-flCxLXMCtWjbqN1jIWNYMrWiXE5jtf1hArMCwuJE9qQQ_3xtbGawIox3ICeEoEov5_eBVjToFypGYxJwVKjpV5sOmqwvVlzbL4eDFtDr4PBp6dTpFKgJBtVhAKq38O_ZlZ0xZU3mIQTzD_ZRVNlAapvpUG7Arw5j1DRJSK1J3XTmSGh7TuMF7TJx_QYlzubCPb-4dYOnkiQThwlhA5B_LA6AQOYwaCokQPbqmH2BugVSOcjeiayCKxA1Xh2ZL127EpotryXqtDncaXohEk1AcWqUqrddP4Rgb7W1NblhAuWONE7xMGuy5h-D3E-9eCpKQz2nLGC9IwnYVMKXWCV259BlucGg1vzVJLSMhW5tQYyJWrGBfdN8BxVFEhjvyAlhA1U0AVrJ5oXxZG9hYABT4nIzaviDIDYT3wTfEo2-XhQ3QgD_W8dcIFKC1jc6dUPMBksmA1bxFHeqaZWn5DrXYuFhApnisYsVBbQ6TudvT76mt1MHhp55nB7o9gx_8EZ9oN8GEp2UjQMuKYgBPRZyQUGe5zAP0OzxnegIu6rHX1yQ8BVhAY3MMQgEKysMjkdctT3VbCFiOHCiauT4qLC2aXYWm09Bv3rOZOfYU77SzGRlmuub1AO5EJnrkSZDzC0TmySlDtIFnL2lzc3Vlcg"
}
}
In
order
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.7.1
Base
Proof
above.
The
first
step
is
to
run
the
algorithm
of
Section
3.5.3
parseBaseProofValue
to
recover
baseSignature
,
publicKey
,
hmacKey
,
signatures
,
and
mandatoryPointers
as
shown
below.
{
"baseSignature": "1c00d200b76a4c87ed57aae0f09a6a05eb4e254898842a758d3b0069517ea8977f9a118b4dcc17bec33e9f9ef41b83dcde0957dc08643f546c8ca2360d1b1f2f",
"proofPublicKey": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"hmacKey": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"signatures": [
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"3568e1402af672cb1a4c360ed7030ca8b1a744eed3c4572774e96d23e3a890db148de8dbd06594244a283f46247a540e78d14789e0e0c64ee96b6e53863707bc",
"008fb2b467d7b2a46f16727532ae32e4027fc7746d478815c332d0a5c46021031bf72b20b0835166e21d0d3b50a6d15d75f30df14eb9b1ca10af521644564837",
"3a6263590ab7fbc4e5ef7bc6c3f6b9cdd8a96c7c4d9a1f120612213ca39a50f39d7b56d6365ead6054bdbe4b971b2769d61841a3f7236a7434e5f1b0f6e2e8fc",
"1b922ea997916494648491373084bc71df1fe0918665021f530829b4a387eccb48630f76015da36a079b3882f6ff70a3f87acbce78608e66867e5b2fc31df82f",
"270f83139fe21ea6cb2176e6855580f7dc3f6694f0ab3efb723edc7844c376d2e3566b5ee1674834a8e69d197aae793e13a8a355423431a38daa442b6b440ada",
"0106894e5850a53d4306eb237f52b11579e25916aaa97ae4f91fd258bd3806a6e24443609d469792598b17bd54da1595b8266efa20aaaee271ce1aeab7c74042",
"ddc8430a1bf8cdbbb6e8c1e2dcb434dc0db59ab0c5501bd7dacee9e2c0234e2399ed95765d62ef4cabf0fe8117ee32f24b8f8c64d1955ddd4362269d9493035e",
"a16b9b2761a89b79428a1c8bbf19216e4d07271022bf9867d11a0055a8f19aa9583196d01234ad63a390b2971eebde0ae748258593500277a90f0d74fd2164f1",
"c6b8ab5a139770eef2fdabcc24ae63fbdf93a250238df7f29e2c905591e660e8fc87f74ac53eba18fe0487c6effeebbf8c9e4d075d5ae91b2ed7842c67e0b429",
"e7ee420aa027ba4671b926c29e2c574f94461660a0b3d6c828cce50314d9e1e4c346ed119352adf6141c66e2fce4a2cb7486c3f81cc42e388a5f921285677d94",
"8cc617955838bc95f849c8a782955374baf151727e8d12e5b4d0a200b406dcd839dbe5d5f760cc3b02bd65081d915138cbf14846b06e898916d8e30c725aaa5f",
"e10f849d052c6de7aa2459d93552ac5ea2ebf52d2e4ec6257b10654734066553a09e418bef1154f4af9f942c4b5cc0ad5a36ea3758c858d60cad68971398ed7f",
"acc0b0b8913da9043fdf1b5b19ac08a31dc809e128128bf9fde0558d3a05ca9198c49c152a3a55e6c3a6ab0bd59736cbe1e0c5b43af83c1a7a753a452a0241b5",
"2aadfc3bf665674c59537988413cc3fd945536501aa6fa541bb02bc398f50d12522b52775d39921a1ed3b8c17b4c9c7f418973b9b08f6fee1d60e9e48904e1c2",
"e41fcb03a010398c1a0a89103dbaa61f606e81548e7237a26b208ac40d5787664bd76ec4a68b6bc97aad0e771a5e884493501c5aa52aadd74fe1181bed6d4d6e",
"b9638d13bc4c1aecb987e0f713ef5e0a9290cf69cb182f48c2761530a5d6095db9f4196e706835bf35492d23215b9b50632256ac605f74df01c55144863bf202",
"d54d0056b279a17c591bd8580014f89c8cdabe20c80d84f7c137c4a36f97850dd0803fd6f1d70814a0b58dce9d50f30192c980d5bc451dea9a6569f90eb5d8b8",
"a678ac62c5416d0e93b9dbd3efa9add4c1e1a79e6707ba3d831ffc119f6837c184a7652340cb8a62004f459c905067b9cc03f43b3c677a022eeab1d7d7243c05",
"63730c42010acac32391d72d4f755b08588e1c289ab93e2a2c2d9a5d85a6d3d06fdeb39939f614efb4b3191966bae6f500ee44267ae44990f30b44e6c92943b4"
],
"mandatoryPointers": [
"/issuer"
]
}
Next, the holder needs to indicate what, if anything else, they wish to reveal to the verifiers by specifying JSON pointers for selective disclosure.
["/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
algorithm
of
Section
3.4.13
selectJsonLd
to
give
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 revealed document looks like, we need to furnish appropriately updated information to the verifier on which statements are mandatory, the signatures for the selected non-mandatory statements, and the mapping between canonical blank node ids for the reveal document and a subset of the HMAC blank node ids. Running step 6 of the 3.5.4 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,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
indexes
of
the
mandatory
statements
adjusted
to
their
positions
in
the
reveal
document.
In
the
previous
example
the
combinedIndexes
show
the
indexes
of
all
the
original
nquads
(statements)
that
make
up
the
reveal
document,
in
order.
To
come
up
with
the
adjusted
mandatory
indexes
shown
below
we
obtain
the
index
of
each
of
original
mandatory
indexes
relative
to
the
combinedIndexes
as
shown
below.
{
"adjMandatoryIndexes":[0,4,5,7]
}
We have to furnish the verifier with a list of signatures for those selective statements (nquads) that are not mandatory. The original list of signatures corresponds to every non-mandatory statement and the indexes of these in the original document are given above. We now compute a list of adjusted signature indexes by computing the index of each selective index in the non-mandatory index list, ignoring any selective index not present in the list. We then use the adjusted signature indexes to obtain the filtered signature list. These lists are shown below.
{
"adjSignatureIndexes":[0,1,7,17,18,19],
"filteredSignatures":[
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"3568e1402af672cb1a4c360ed7030ca8b1a744eed3c4572774e96d23e3a890db148de8dbd06594244a283f46247a540e78d14789e0e0c64ee96b6e53863707bc",
"ddc8430a1bf8cdbbb6e8c1e2dcb434dc0db59ab0c5501bd7dacee9e2c0234e2399ed95765d62ef4cabf0fe8117ee32f24b8f8c64d1955ddd4362269d9493035e",
"d54d0056b279a17c591bd8580014f89c8cdabe20c80d84f7c137c4a36f97850dd0803fd6f1d70814a0b58dce9d50f30192c980d5bc451dea9a6569f90eb5d8b8",
"a678ac62c5416d0e93b9dbd3efa9add4c1e1a79e6707ba3d831ffc119f6837c184a7652340cb8a62004f459c905067b9cc03f43b3c677a022eeab1d7d7243c05",
"63730c42010acac32391d72d4f755b08588e1c289ab93e2a2c2d9a5d85a6d3d06fdeb39939f614efb4b3191966bae6f500ee44267ae44990f30b44e6c92943b4"
]
}
The
last
important
piece
of
disclosure
data
is
a
mapping
of
canonical
blank
node
ids
to
HMAC
based
ids,
the
labelMap
,
computed
according
to
Section
3.5.4
createDisclosureData
steps
12-14.
This
is
shown
below
along
with
the
rest
of
the
disclosure
data
minus
the
reveal
document.
{
"baseSignature": "1c00d200b76a4c87ed57aae0f09a6a05eb4e254898842a758d3b0069517ea8977f9a118b4dcc17bec33e9f9ef41b83dcde0957dc08643f546c8ca2360d1b1f2f",
"publicKey": "zDnaeTHfhmSaQKBc7CmdL3K7oYg3D6SC7yowe2eBeVd2DH32r",
"signatures": [
"fd91ec48b3524965f7a1453e9ffa067054eca6f7d6338a84525eb3288bb0caf7a9651f02fee14d6d33ee1679aa8828348ccc574e194d7f57fca8be354c1b30f7",
"3568e1402af672cb1a4c360ed7030ca8b1a744eed3c4572774e96d23e3a890db148de8dbd06594244a283f46247a540e78d14789e0e0c64ee96b6e53863707bc",
"ddc8430a1bf8cdbbb6e8c1e2dcb434dc0db59ab0c5501bd7dacee9e2c0234e2399ed95765d62ef4cabf0fe8117ee32f24b8f8c64d1955ddd4362269d9493035e",
"d54d0056b279a17c591bd8580014f89c8cdabe20c80d84f7c137c4a36f97850dd0803fd6f1d70814a0b58dce9d50f30192c980d5bc451dea9a6569f90eb5d8b8",
"a678ac62c5416d0e93b9dbd3efa9add4c1e1a79e6707ba3d831ffc119f6837c184a7652340cb8a62004f459c905067b9cc03f43b3c677a022eeab1d7d7243c05",
"63730c42010acac32391d72d4f755b08588e1c289ab93e2a2c2d9a5d85a6d3d06fdeb39939f614efb4b3191966bae6f500ee44267ae44990f30b44e6c92943b4"
],
"labelMap": {
"dataType": "Map",
"value": [
[
"c14n0",
"u3Lv2QpFgo-YAegc1cQQKWJFW2sEjQF6FfuZ0VEoMKHg"
],
[
"c14n1",
"uVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKw"
]
]
},
"mandatoryIndexes": [
0,
4,
5,
7
]
}
Finally using the disclosure data above with the algorithm of Section 3.5.7 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": "ecdsa-sd-2023",
"created": "2023-08-15T23:36:38Z",
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0BhVhAHADSALdqTIftV6rg8JpqBetOJUiYhCp1jTsAaVF-qJd_mhGLTcwXvsM-n570G4Pc3glX3AhkP1RsjKI2DRsfL1gjgCQCKnLOGbY_FuM-ASpSkkOxsIR2E8n7Ml2q1UQ6tEwzi5OGWED9kexIs1JJZfehRT6f-gZwVOym99YzioRSXrMoi7DK96llHwL-4U1tM-4WeaqIKDSMzFdOGU1_V_yovjVMGzD3WEA1aOFAKvZyyxpMNg7XAwyosadE7tPEVyd06W0j46iQ2xSN6NvQZZQkSig_RiR6VA540UeJ4ODGTulrblOGNwe8WEDdyEMKG_jNu7boweLctDTcDbWasMVQG9fazuniwCNOI5ntlXZdYu9Mq_D-gRfuMvJLj4xk0ZVd3UNiJp2UkwNeWEDVTQBWsnmhfFkb2FgAFPicjNq-IMgNhPfBN8Sjb5eFDdCAP9bx1wgUoLWNzp1Q8wGSyYDVvEUd6pplafkOtdi4WECmeKxixUFtDpO529Pvqa3UweGnnmcHuj2DH_wRn2g3wYSnZSNAy4piAE9FnJBQZ7nMA_Q7PGd6Ai7qsdfXJDwFWEBjcwxCAQrKwyOR1y1PdVsIWI4cKJq5PiosLZpdhabT0G_es5k59hTvtLMZGWa65vUA7kQmeuRJkPMLRObJKUO0ogBYINy79kKRYKPmAHoHNXEECliRVtrBI0BehX7mdFRKDCh4AVggVkUuBrlOaELGVQWJD4M_qW5bcKEHWGNbOrPA_qAOKKyEAAQFBw"
}
}
This section is non-normative.
This section contains the substantive changes that have been made to this specification over time.
Changes since the Second Candidate Recommendation :
Changes since the First Candidate Recommendation :
created
proof
option
is
not
required
and
additional
proof
options
are
included
in
the
generated
proof.
Changes since the First Public Working Draft :
secretKeymultibase
representation.
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, Zaïda Rivai, Will Abramson, and Eric Schuh. 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 Working Group Chair Brent Zundel, and 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 cycle. We also thank the Chairs of the W3C Credentials Community Group, Christopher Allen, Joe Andrieu, Kim Hamilton Duffy, Heather Vescent, Wayne Chang, Mike Prorock, Harrison Tang, Kimberly Wilson Linson, and Will Abramson, who oversaw the incubation of this work.
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 70RSAT20T00000029, 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 and implementations of the specification (in alphabetical order by last name):
Greg Bernstein, Simon Bihel, Sebastian Crane, Stas Dmytryshyn, Tashi D. Gyeltshen, Ivan Herman, Andrew Jones, Filip Kolarik, Helge Krueger, Dominik Kuziński, Charles E. Lehner, Dave Longley, Tomislav Markovski, Tyler Minard, Bryan Newbold, Marty Reed, Brian Richter, Eugeniu Rusu, Markus Sabadello, Pritam Singh, Patrick St-Louis, Manu Sporny, Orie Steele, Ted Thibodeau Jr., Benjamin Young, and Dmitri Zagidulin.
Referenced in:
Referenced in: